[enh] adds clitools

This commit is contained in:
alban 2020-09-27 00:33:30 +02:00
parent 0e9e7717c9
commit 249932a9dd
5 changed files with 519 additions and 0 deletions

70
clitools/README.md Normal file
View File

@ -0,0 +1,70 @@
# Chaining Lasers In Submission Tools for LJ
Alright everybody, ready for some fun? Here comes The Piping And Plumbing Your Way To The Top Show!
You're going to push so many points to this laser it will hog and cry...
BOOM | WIIIIIZ :: PHHHHHRACKRACKRACK ~~ WOOP ~~###~~ WIIT
## The basic loop
```
python3 generators/dummy.py -f 2 | filters/kaleidoscope.py | exports/toRedis.py -v
------------------------------ --------------------- -------------------
\/ \/ \/
Generator Filter Export
```
1. The Generator
Use it to produce some points in any manner, orderly or total chaos.
Don't be that boring Sinusoids bugger! Flash Maps of Dooms, Disbitnic sprites, Dismorphic HexaFonts all over the walls!
2. The Filter(s)
These babies will modify data on the wire by passing around the points and modifying them in sequence.
Want your Double Heavy Laser Cannons to bounce together like they been drinking Jagerbombs for two hours? That's the place.
3. The Exporter
Now, this IS the most boring part. Send your points to whatever output system. Yawn. Are we there yet?
## Hacking around
Say what!? Why, this is exactly the place for that!
Take a seat and copy paste the "dummy.py" files, they present the basic structure you need to play around.
Just be cautious to use the `debug` method if you're the kind of miss that debugs by outputing data structures (who does not, yah know, sometimes?). Or you'll break the chain.
### Generators
They must send list of points to standard out. Don't forget the "flush" argument, or the piping will be breaking, ain't no Mario lazering.
* dummy.py : sends always the same list of points. The Monomaniac.
* @todo : read texts from redis and others
### Filters
These do listen and read on STDIN and do the same print'n'flush on STDOUT.
* kaleidoscope.py : mirrors the points based on a pivot
* @todo : fourier analysis and other realtime reaction
### Export
Read from STDIN and send to redis mostly
* toRedis.py : provide a key, server IP, etc.
### Common parameters
Every command can be called with a `-h/--help` flag to get some help
Every command has a `-v/--verbose` flag to send debug info to STDERR.
Generators have a `-f/--fps` param for FPS, to be fast but not so furious on your machine
Filters and Exports are their own beasts

55
clitools/exports/toRedis.py Executable file
View File

@ -0,0 +1,55 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
redis exporter
v0.1.0
A basic exporter
LICENCE : CC
by cocoa
'''
from __future__ import print_function
import sys
import os
import argparse
import redis
import time
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
args = argsparser.parse_args()
ip = args.ip
port = args.port
key = args.key
verbose=args.verbose
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
r=redis.StrictRedis(host=ip, port=port, db=0)
try:
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
line = line.rstrip('\n')
if r.set(key,line)==True:
debug("exports::redis set("+str(key)+") to "+line)
except EOFError:
debug("break")# no more information

161
clitools/filters/kaleidoscope.py Executable file
View File

@ -0,0 +1,161 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
kaleidoscop
v0.1.0
A simple effect : mirror a quadrant of the input
LICENCE : CC
by Sam Neurohack
'''
from __future__ import print_function
import sys
import ast
import os
import argparse
ljpath = r'%s' % os.getcwd().replace('\\','/')
sys.path.append(ljpath +'/../libs/')
sys.path.append(ljpath +'/libs/')
import time
name = "filters::kaleidoscope"
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
argsparser.add_argument("-x","--centerX",help="geometrical center X position",default=300,type=int)
argsparser.add_argument("-y","--centerY",help="geometrical center Y position",default=300,type=int)
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
args = argsparser.parse_args()
fps = args.fps
centerX = args.centerX
centerY = args.centerY
verbose = args.verbose
optimal_looptime = 1 / fps
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
def kaleidoscope( pl ):
# Stage 1: Crop points in single quadrant
quad1 = []
# Iterate trough the segments
for i in range( 0, len(pl) - 1 ):
#debug(name+" point #", i)
currentpoint = cp = pl[i]
nextpoint = pl[i+1]
cx,cy,cc = [cp[0],cp[1],cp[2]]
nx,ny,nc = [nextpoint[0],nextpoint[1],nextpoint[2]]
rect=[[cx,cy],[cx,ny],[nx,ny],[nx,cy]]
right = wrong = 0
#debug(name+" rect: ", rect,"curr",currentpoint,"next",nextpoint )
# Enumerate the points in rectangle to see
# how many right / wrong there are to add or skip early
#
for iterator, p in enumerate(rect):
if p[0] >= centerX and p[1] >= centerY:
right += 1
else:
#if p[0] <= centerX and p[1] <= centerY:
wrong += 1
# If all rectangle points are in the right quadrant, Add and Skip
if right == 4:
quad1.append(pl[i])
#debug(name+" found valid point", pl[i])
continue
# If all rectangle points in wrong quadrant, Skip
if wrong == 4:
#debug(name+" found bad point", pl[i])
continue
# Find the (x,y) intersections
#
#debug(name+" Looking for crossing point between ("+str(cx)+","+str(cy)+") and ("+str(nx)+","+str(ny)+")")
delta=[ nx - cx, ny - cy ]
#debug(name+" delta:",delta)
crossX = None
crossY = None
absnewX = 0
absnewY = 0
# If one point has negative x, search y axis crossing
if cx < centerX or nx < centerX:
if delta[0] == 0 :
delta[0] = 0.0000001
v=[ delta[0]/abs(delta[0]), delta[1]/abs(delta[0]) ]
absnewX = abs( centerX - cx )
#print("on y axis, v=",str(v)," and absnewX=",str(absnewX))
crossX = [( absnewX*v[0] + cx ),( absnewX*v[1]+cy ), nc]
# If one point has negative y, search x axis crossing
if cy < centerY or ny < centerY:
if delta[1] == 0 :
delta[1] = 0.0000001
v=[ delta[0]/abs(delta[1]), delta[1]/abs(delta[1])]
absnewY = abs( centerY - cy )
#print("on x axis, v=",str(v)," and absnewY=",str(absnewY))
crossY = [( absnewY*v[0] + cy ),( absnewY*v[1]+cy ), nc]
# Inject in order
# If current is valid, Add
if cx >= centerX and cy >= centerY :
quad1.append( currentpoint )
# If absnewX smaller, it is closest to currentPoint
if absnewX < absnewY:
if None != crossX : quad1.append( crossX )
if None != crossY : quad1.append( crossY )
else :
if None != crossY : quad1.append( crossY )
if None != crossX : quad1.append( crossX )
## Stage 2 : Mirror points
#
quad2 = []
# quad2 = vertical symetric of quad1
for iterator in range( len(quad1) -1 , -1, -1):
point = quad1[iterator]
quad2.append([ point[0], 2*centerY - point[1], point[2] ])
# quad3 is the merge of 1 and 2
quad3 = quad1 + quad2
# quad4 is the horizontal symetric of quad3
quad4 = []
for iterator in range( len(quad3) -1, -1, -1):
point = quad3[iterator]
quad4.append([ 2*centerX - point[0], point[1], point[2] ])
#debug(name+" quad1:",quad1)
#debug(name+" quad2:", quad2 )
debug(name+" quad3:", quad3 )
debug(name+" quad4:", quad4 )
return quad3+quad4
try:
while True:
start = time.time()
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
line = line.rstrip('\n')
pointsList = ast.literal_eval(line)
# Do the filter
result = kaleidoscope( pointsList )
print( result, flush=True )
looptime = time.time() - start
# debug(name+" looptime:"+str(looptime))
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
# debug(name+" micro sleep:"+str( optimal_looptime - looptime))
except EOFError:
debug(name+" break")# no more information

View File

@ -0,0 +1,51 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
This is the most basic generator you can imagine: straight up static!
v0.1.0
Use it to test your filters and outputs
LICENCE : CC
by cocoa
'''
from __future__ import print_function
import time
import argparse
import sys
name="generator::dummy"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="Dummy generator")
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
args = argsparser.parse_args()
fps=args.fps
verbose=args.verbose
optimal_looptime = 1 / fps
debug(name+" optimal looptime "+str(optimal_looptime))
while True:
start = time.time()
#print("[(100.0, 100.0, 65280), (100.0, 500.0, 65280), (500.0, 500.0, 65280), (500.0, 100.0, 65280), (100.0, 100.0, 65280)]", flush=True);
print("[(100.0, 100.0, 65280), (110.0, 500.0, 65280), (510.0, 500.0, 65280), (510.0, 100.0, 65280), (100.0, 110.0, 65280)]", flush=True);
looptime = time.time() - start
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
debug(name+" micro sleep:"+str( optimal_looptime - looptime))

View File

@ -0,0 +1,182 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
example, based on custom
v0.1.0
A copy of square.py you can modify to code your plugin.
custom1 has necessary hooks in LJ.conf, webui and so on.
LICENCE : CC
by Sam Neurohack
'''
import sys
import os
ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
sys.path.append(ljpath +'/../../libs/')
#import from LJ
sys.path.append(ljpath +'/libs/')
print(ljpath+'/../libs/')
import lj23layers as lj
sys.path.append('../libs')
import math
import time
import argparse
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Custom1 example for LJ")
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",default=0,type=int)
args = argsparser.parse_args()
# Useful variables init.
white = lj.rgb2int(255,255,255)
red = lj.rgb2int(255,0,0)
blue = lj.rgb2int(0,0,255)
green = lj.rgb2int(0,255,0)
width = 800
height = 600
centerX = width / 2
centerY = height / 2
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
# Anaglyph computation parameters for right and left eyes.
# algorythm come from anaglyph geo maps
eye_spacing = 100
nadir = 0.5
observer_altitude = 30000
map_layerane_altitude = 0.0
# square coordinates : vertices that compose each of the square.
vertices = [
(- 1.0, 1.0,- 1.0),
( 1.0, 1.0,- 1.0),
( 1.0,- 1.0,- 1.0),
(- 1.0,- 1.0,- 1.0)
]
face = [0,1,2,3]
#
# LJ inits
#
layer = 0
# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
Leftsquare = lj.FixedObject('Leftsquare', True, 255, [], red, 255, 0, 0, layer , True)
Rightsquare = lj.FixedObject('Rightsquare', True, 255, [], green, 0, 255, 0, layer , True)
# 'Destination' for given layer : name, number, active, layer , scene, laser
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
#
# Anaglyph computation : different X coordinate for each eye
#
def LeftShift(elevation):
diff = elevation - map_layerane_altitude
return nadir * eye_spacing * diff / (observer_altitude - elevation)
def RightShift(elevation):
diff = map_layerane_altitude - elevation
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
def Proj(x,y,z,angleX,angleY,angleZ):
rad = angleX * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y2 = y
y = y2 * cosa - z * sina
z = y2 * sina + z * cosa
rad = angleY * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z2 = z
z = z2 * cosa - x * sina
x = z2 * sina + x * cosa
rad = angleZ * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x2 = x
x = x2 * cosa - y * sina
y = x2 * sina + y * cosa
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + centerX
y = - y * factor + centerY
return (x,y)
#
# Main
#
def Run():
Left = []
Right = []
counter =0
try:
while True:
Left = []
Right = []
x = vertices[0][0]
y = vertices[0][1]
z = vertices[0][2]
# lj tracers will "move" the laser to this first point in black, then move to the next with second point color.
# for more accuracy in dac emulator, repeat this first point.
# generate all points in square.
for point in face:
x = vertices[point][0]
y = vertices[point][1]
z = vertices[point][2]
left.append(proj(x+leftshift(z*25),y,z,0,counter,0))
right.append(proj(x+rightshift(z*25),y,z,0,counter,0))
lj.polylineonecolor(left, c = leftsquare.color , layer = leftsquare.layer, closed = leftsquare.closed)
lj.polylineonecolor(right, c = rightsquare.color , layer = rightsquare.layer, closed = rightsquare.closed)
lj.drawdests()
time.sleep(0.1)
counter += 1
if counter > 360:
counter = 0
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj.ClosePlugin()
Run()