diff --git a/LJ.conf b/LJ.conf index b7e6daa..f6f5da8 100644 --- a/LJ.conf +++ b/LJ.conf @@ -1,13 +1,13 @@ [General] lasernumber = 1 -debug = 0 +debug = 1 ljayserverip = 127.0.0.1 nozoscip = 127.0.0.1 bhoroscip = 127.0.0.1 [laser0] color = -1 -ip = 127.0.0.1 +ip = 192.168.1.3 kpps = 25000 centerx = -1610 centery = 0 @@ -26,7 +26,7 @@ warpdest = [[-1500., 1500.], [laser1] color = -1 -ip = 192.168.1.3 +ip = 127.0.0.1 kpps = 25000 centerx = 506 centery = 413 @@ -81,3 +81,16 @@ warpdest = [[-1500., 1500.], [ 1500.,-1500.], [-1500.,-1500.]] +[plugins] +plugins = { + "nozoid": {"OSC": 8003, "command": ""}, + "glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py"}, + "planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py"}, + "words": {"OSC": 8006, "command": "python3 plugins/livewords.py"}, + "cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py"}, + "simu": {"OSC": 8008, "command": "python plugins/simu.py"}, + "bank0": {"OSC": 8010, "command": "python3 plugins/VJing/bank0.py"}, + "ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py"}, + "laserwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py"} + } + diff --git a/README.md b/README.md index 966dfc8..b512b28 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -LJ v0.7.1 +LJ v0.8.1 By Sam Neurohack, Loloster, Cocoa @@ -36,6 +36,7 @@ LJ supports Linux and OS X. Windows is unkown but welcome, if someone want to ju + # # Install # @@ -86,7 +87,7 @@ Check in your client code if the laser server IP is the good one Run your client -to monitor redis server : +to monitor redis server, there is app for that or : redis-cli monitor @@ -110,9 +111,21 @@ to monitor redis server : redis-cli -h redisserverIP monitor +# +# Plugins +# + +LJ comes with different plugins : + +- LiveWords : Fill the input form and it's displayed. One word / laser. +- Textcycl : Cycle some words with adjustable length on one laser. +- Anaglyph : A green/red rotating cube. Try it with green/red 3D glasses ! +- Planetarium : A 4 lasers planetarium. +- LaserPong : Our laser Pong is back ! + # -# Program your own "Client" +# Program your own "Plugin" # @@ -122,7 +135,12 @@ The server approach is based on redis, so you write and run your laser client so - There is a clients folders with examples in different languages. - Generate at least one point list array (say a square). - Feed your point list array in string format to redis server. -- +- Tell LJ.conf your plugin configuration : OSC port and command line to start it. + +# +# Nannou etherdeam simulator +# + # diff --git a/cli.py b/cli.py index ca134a4..6179cfb 100644 --- a/cli.py +++ b/cli.py @@ -25,7 +25,7 @@ def handle(): argsparser = argparse.ArgumentParser(description="LJ v0.8") argsparser.add_argument("-r","--redisIP",help="IP address to bind builtin servers (OSC and websocket) also must be the Redis server IP ",type=str) argsparser.add_argument("-L","--Lasers",help="Number of lasers connected.",type=int) - argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2.",type=int) + argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2 (0 by default)",type=int) argsparser.add_argument("-x","--invx",help="Invert laser 0 X axis again",action="store_true") argsparser.add_argument("-y","--invy",help="Invert laser 0 Y axis again",action="store_true") argsparser.add_argument("-d","--display",help="Point List number displayed in simulator",type=int) @@ -47,6 +47,8 @@ def handle(): if args.verbose != None: #print "setting gstt.debug to", args.verbose gstt.debug = args.verbose + else: + gstt.debug = 0 # Ports arguments if args.iport: @@ -62,7 +64,7 @@ def handle(): oport = gstt.oport if gstt.debug > 0: - print "gstt.oport:",gstt.oport + print "Accept OSC on port",gstt.oport print "gstt.iport:",gstt.iport diff --git a/clients/laserglyph.py b/clients/laserglyph.py index da9e9e1..7dd419c 100644 --- a/clients/laserglyph.py +++ b/clients/laserglyph.py @@ -10,17 +10,25 @@ LICENCE : CC ''' import redis -import lj +import lj3 import math import time import argparse +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * + +OSCinPort = 8004 + print ("") print ("Arguments parsing if needed...") argsparser = argparse.ArgumentParser(description="Text Cycling for LJ") argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) args = argsparser.parse_args() @@ -41,7 +49,14 @@ if args.redisIP != None: else: redisIP = '127.0.0.1' -lj.Config(redisIP,ljclient) + +if args.verbose: + debug = args.verbose +else: + debug = 0 + + +lj3.Config(redisIP,ljclient) width = 800 @@ -94,6 +109,13 @@ def rgb2int(r,g,b): return int('0x%02x%02x%02x' % (r,g,b),0) +def OSCljclient(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /glyph/ljclient with value", value) + ljclient = value + lj3.LjClient(ljclient) + + def Proj(x,y,z,angleX,angleY,angleZ): rad = angleX * math.pi / 180 @@ -130,58 +152,82 @@ def Run(): Left = [] Right = [] counter =0 + WebStatus("LaserGlyph") - while 1: + # OSC Server callbacks + print("Starting OSC at 127.0.0.1 port",OSCinPort,"...") + osc_startup() + osc_udp_server("127.0.0.1", OSCinPort, "InPort") + osc_method("/ping*", lj3.OSCping) + osc_method("/glyph/ljclient", OSCljclient) - Left = [] - Right = [] + try: - x = vertices[0][0] - y = vertices[0][1] - z = vertices[0][2] + while 1: + Left = [] + Right = [] + + x = vertices[0][0] + y = vertices[0][1] + z = vertices[0][2] + + # The cube start always with vertice 0 + # 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. + + # Cube Y axis rotation of 'counter' angle and 3d-2d Proj function. + #Left.append( Proj(x+LeftShift(z*5),y,z,0,counter,0)) + #Right.append(Proj(x+RightShift(z*5),y,z,0,counter,0)) + + + # Add all the cube points face by face. + for fa in faces: + for point in fa: + 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)) + + + # Drawing step, 2 possibilities + + # Red and Green drawn by laser 0 + lj3.PolyLineOneColor(Left, c = red, PL = 0, closed = True) + lj3.PolyLineOneColor(Right, c = green, PL = 0, closed = True) + lj3.DrawPL(0) + + ''' + # Red on laser 1 and green on laser 2 + lj3.PolyLineOneColor(Left, c = red, PL = 1, closed = True) + lj3.PolyLineOneColor(Right, c = green, PL = 2, closed = True) + lj3.DrawPL(1) + lj3.DrawPL(2) + + ''' + + time.sleep(0.1) + + counter += 1 + if counter >360: + counter =0 - # The cube start always with vertice 0 - # 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. + except KeyboardInterrupt: + pass - # Cube Y axis rotation of 'counter' angle and 3d-2d Proj function. - #Left.append( Proj(x+LeftShift(z*5),y,z,0,counter,0)) - #Right.append(Proj(x+RightShift(z*5),y,z,0,counter,0)) + # Gently stop on CTRL C + finally: - # Add all the cube points face by face. - for fa in faces: - for point in fa: - x = vertices[point][0] - y = vertices[point][1] - z = vertices[point][2] + WebStatus("Glyph Exit") + print("Stopping OSC...") + lj3.OSCstop() + pass - Left.append( Proj(x+LeftShift(z*25),y,z,0,counter,0)) - Right.append(Proj(x+RightShift(z*25),y,z,0,counter,0)) + print ("LaserGlyph Stopped.") - # Drawing step, 2 possibilities - - # Red and Green drawn by laser 0 - lj.PolyLineOneColor(Left, c = red, PL = 0, closed = True) - lj.PolyLineOneColor(Right, c = green, PL = 0, closed = True) - lj.DrawPL(0) - - ''' - # Red on laser 1 and green on laser 2 - lj.PolyLineOneColor(Left, c = red, PL = 1, closed = True) - lj.PolyLineOneColor(Right, c = green, PL = 2, closed = True) - lj.DrawPL(1) - lj.DrawPL(2) - - ''' - - time.sleep(0.1) - - counter += 1 - if counter >360: - counter =0 - white = rgb2int(255,255,255) red = rgb2int(255,0,0) blue = rgb2int(0,0,255) diff --git a/clients/textcycl.py b/clients/textcycl.py deleted file mode 100644 index 40685a0..0000000 --- a/clients/textcycl.py +++ /dev/null @@ -1,83 +0,0 @@ -# coding=UTF-8 - -''' -Cycling text on one LJ laser. -LICENCE : CC -''' - -import redis -import lj -import sys,time -import argparse - -duration = 300 -lasertext = ["TEAMLASER","FANFAN","LOLOSTER","SAM"] - -''' -is_py2 = sys.version[0] == '2' -if is_py2: - from Queue import Queue -else: - from queue import Queue -''' -print ("") -print ("Arguments parsing if needed...") -argsparser = argparse.ArgumentParser(description="Text Cycling for LJ") -argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) -argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) -argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) - -args = argsparser.parse_args() - - -if args.client: - ljclient = args.client -else: - ljclient = 0 - -if args.laser: - plnumber = args.laser -else: - plnumber = 0 - -# Redis Computer IP -if args.redisIP != None: - redisIP = args.redisIP -else: - redisIP = '127.0.0.1' - -lj.Config(redisIP,ljclient) -#r = redis.StrictRedis(host=redisIP, port=6379, db=0) - - -# If you want to use rgb for color : -def rgb2int(r,g,b): - return int('0x%02x%02x%02x' % (r,g,b),0) - - -def Run(): - - counter =0 - step = 0 - timing = -1 - color = rgb2int(255,255,255) - - - while 1: - - if timing == duration or timing == -1: - message = lasertext[step] - lj.Text(message, color, PL = 0, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) - lj.DrawPL(0) - timing = 0 - - else: - step += 1 - if step >3: - step =0 - timing += 1 - time.sleep(0.01) - -Run() - - diff --git a/commands.py b/commands.py index ae489c0..fb26345 100644 --- a/commands.py +++ b/commands.py @@ -43,6 +43,9 @@ lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]" /order value : instruct tracer what to do. +/planet will be forwarded to planetarium client. +/nozoid will be forwarded to nozoid client. + 0 : display user pointlist with current client key. See below for client key. 1 : pull in redis a new correction matrix (EDH) 2 : display black @@ -83,6 +86,8 @@ import redis r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0) +GenericCommands = ["start","ljclient","clientnumber","noteon","pong","mouse","emergency","simu","status","run","nozoid","planet","live","words","ai","bank0"] + def UserOn(laser): @@ -161,16 +166,22 @@ def handler(oscpath, args): print "" print "OSC handler in commands.py got oscpath[1] :",oscpath[1], "with args :",args - # 2 incoming cases : generic or specific for a given lasernumber - # Need better programming - if oscpath[1] == "client" or oscpath[1] =="noteon" or oscpath[1]=="mouse" or oscpath[1]=="emergency" or oscpath[1]=="simu" or oscpath[1]=="status" or oscpath[1]=="run" or oscpath[1]=="nozoid" or oscpath[1]=="planet" or oscpath[1]=="live" or oscpath[1]=="planet" : - - if oscpath[1] == "client": + # 2 incoming cases : generic or specific for a given lasernumber : + # Generic : Commands without a laser number + #if oscpath[1] == "client" or oscpath[1]=="clientnumber" or oscpath[1] =="noteon" or oscpath[1]=="pong" or oscpath[1]=="mouse" or oscpath[1]=="emergency" or oscpath[1]=="simu" or oscpath[1]=="status" or oscpath[1]=="run" or oscpath[1]=="nozoid" or oscpath[1]=="planet" or oscpath[1]=="live" or oscpath[1]=="planet" : + + if oscpath[1] in GenericCommands: + + if oscpath[1] == "ljclient": LasClientChange(int(args[0])) elif oscpath[1] == "noteon": NoteOn(int(args[0])) + elif oscpath[1] == "pong": + print "" + print "Got pong from ",args + elif oscpath[1] == "mouse": Mouse(int(args[0]),int(args[1]),int(args[2]),int(args[3])) @@ -187,7 +198,7 @@ def handler(oscpath, args): print "Back to normal for laser ", laser UserOn(laser) - + # Commands with a laser number else: pathlength = len(oscpath) @@ -207,7 +218,7 @@ def handler(oscpath, args): else: print "No grid for laser ", laser UserOn(laser) - + # /ip/lasernumber value if oscpath[1] == "ip": diff --git a/gstt.py b/gstt.py index f8982d1..8874703 100644 --- a/gstt.py +++ b/gstt.py @@ -102,8 +102,8 @@ JumpFlag =0 # OSC ports #temporaray fix hack : iport=nozoport -iport = 8001 #LJay (bhorosc) input port -oport = 8002 #LJay (bhorosc) output port +iport = 8002 # LJ input port +oport = 8001 # LJ output port noziport=8003 #nozosc.py receiving commands port nozoport=8001 #nozosc.py sending port to LJay (main.py) nozuport=0 #linux serial usb port connecting nozoid devices ACM0 by default diff --git a/main.py b/main.py index 7885de2..d87d2ff 100755 --- a/main.py +++ b/main.py @@ -2,16 +2,26 @@ # -*- coding: utf-8 -*- # -*- mode: Python -*- ''' -LJ Laser Server v0.8 +LJ Laser Server v0.8.1 Laser server + webUI servers (ws + OSC) - get point list to draw : /pl/lasernumber - for report /lstt/lasernumber /lack/lasernumber /cap/lasernumber - A nice ws debug tool : websocat +- a "plugin" is a code that send point to LJ. Plugins if they have an open OSC port can be checked and restart if in the same computer. -todo : +Todo : +- If no plugin ping is not received, restart the plugin. +- upgrade to python3 + + +All used ports: + +8002 OSC incoming +9001 WS communication with WebGUI +Plugins Ports (see LJ.conf) ''' @@ -22,8 +32,8 @@ import redis print "" print "" -print "LJ Laser Servers" -print "v0.8.0" +print "LJ Laser Server" +print "v0.8.1" print "" import settings @@ -39,11 +49,15 @@ import homographyp import commands import font1 +import subprocess +import sys +import os from OSC import OSCServer, OSCClient, OSCMessage from websocket_server import WebsocketServer #import socket import types, thread, time +import plugins r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0) args =[0,0] @@ -108,14 +122,18 @@ extoscPORTout = 8001 # With Nozoid # OSC Client : to send OSC message to Nozoid inport 8003 NozoscIPout = nozoscIP -NozoscPORTout = 8003 +NozoscPORTout = plugins.Port("nozoid") # With Planetarium # OSC Client : to send OSC message to planetarium inport 8005 planetIPout = nozoscIP -planetPORTout = 8005 +planetPORTout = plugins.Port("planet") +# With Bank0 +# OSC Client : to send OSC message to bank0 inport 8010 +bank0IPout = nozoscIP +bank0PORTout = plugins.Port("bank0") oscserver = OSCServer( (extoscIPin, extoscPORTin) ) oscserver.timeout = 0 @@ -127,6 +145,7 @@ def handle_timeout(self): oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver) +''' osclientext = OSCClient() oscmsg = OSCMessage() osclientext.connect((extoscIPout, extoscPORTout)) @@ -198,6 +217,31 @@ def sendplanet(oscaddress,oscargs=''): #time.sleep(0.001) +# send UI string as OSC message to Bank 0 8010 +# sendbank0(oscaddress, [arg1, arg2,...]) + +osclientbank0 = OSCClient() +osclientbank0.connect((planetIPout, planetPORTout)) + +def sendbank0(oscaddress,oscargs=''): + + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + print "Sending OSC to Bank0 server :", oscaddress,'with args :', oscargs + try: + osclientbank0.sendto(oscmsg, (bank0IPout, bank0PORTout)) + oscmsg.clearData() + except: + print 'OSC send to bank0 IP', bank0IPout, 'port', bank0PORTout, "refused : died ?" + sendWSall("/bank0/start 0") + sendWSall("/status No Bank0") + + #time.sleep(0.001) + +''' + # OSC default path handler : send incoming OSC message to UI via websocket 9001 def handler(path, tags, args, source): @@ -210,7 +254,6 @@ def handler(path, tags, args, source): # print "OSC said path", path," oscpath ", oscpath," args", args sendWSall(path + " " + str(args[0])) - commands.handler(oscpath,args) @@ -280,14 +323,12 @@ def osc_thread(): traceback.print_tb(sys.exc_info()[2]) print "\n" - - # # Websocket part # # Called for every WS client connecting (after handshake) -def new_client(client, server): +def new_client(client, wserver): print("New WS client connected and was given id %d" % client['id']) sendWSall("/status Hello %d" % client['id']) @@ -307,12 +348,13 @@ def new_client(client, server): sendWSall("/swap/Y/" + str(laserid)+ " 0") # Called for every WS client disconnecting -def client_left(client, server): +def client_left(client, wserver): print("WS Client(%d) disconnected" % client['id']) -# Called for each ws received message. -def message_received(client, server, message): +# Called for each WS received message. +def message_received(client, wserver, message): + if len(message) > 200: message = message[:200]+'..' @@ -325,19 +367,65 @@ def message_received(client, server, message): oscpath = message.split(" ") print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath - # If message included "planet" forward the message as OSC to planet IP port 8005 - if oscpath[0].find("planet") != -1: - if len(oscpath) == 1: - sendplanet(oscpath[0], oscargs='noargs') - else: - sendplanet(oscpath[0], oscargs=oscpath[1]) + for plugin in gstt.plugins.keys(): + if plugins.Send(plugin,oscpath): + print "Plugin", plugin, "processed",oscpath + ''' + if plugins.Send("planet",oscpath): + pass - # If message included "nozoid" forward the message as OSC to nozoid IP port 8003 - elif oscpath[0].find("nozoid") != -1: - if len(oscpath) == 1: - sendnozosc(oscpath[0], oscargs='noargs') + elif plugins.Send("nozoid",oscpath): + pass + + elif plugins.Send("ai",oscpath): + pass + + elif plugins.Send("lissa",oscpath): + pass + + elif plugins.Send("bank0",oscpath): + pass + + elif plugins.Send("simu",oscpath): + pass + + elif len(oscpath) > 1: + args[0] = str(oscpath[1]) + commands.handler(oscpath[0].split("/"),args) + #print oscpath[0].split("/"),oscpath[1] + + + # current UI has no dedicated off button so /on 0 trigs /off to extosc + if oscpath[0] == "/on": + if oscpath[1] == "1": + sendextosc("/on") else: - sendnozosc(oscpath[0], oscargs=oscpath[1]) + sendextosc("/off") + ''' + + if len(oscpath) == 1: + args[0] = "noargs" + commands.handler(oscpath[0].split("/"),args) + + + ''' + # I message included "nozoid" forward the message as OSC to nozoid IP port 8003 + elif oscpath[0].find("nozoid") != -1: + + if plugins.Ping("nozoid"): + + sendWSall("/nozoid/start 1") + + if oscpath[0].find("start") != -1: + print "Nozoid 0",oscpath[0],"1", oscpath[1] + + if len(oscpath) == 1: + sendnozosc(oscpath[0], oscargs='noargs') + else: + sendnozosc(oscpath[0], oscargs=oscpath[1]) + else: + sendWSall("/status Nozoid offline") + sendWSall("/planet/start 0") # If message included "ai" do something elif oscpath[0].find("ai") != -1: @@ -347,26 +435,19 @@ def message_received(client, server, message): elif oscpath[0].find("lissa") != -1: print "lissa order ", oscpath - # If message included "vj" do something - elif oscpath[0].find("vj") != -1: - print "VJ order ", oscpath + # If message included "bank0" do something + elif oscpath[0].find("bank0") != -1: - elif len(oscpath) > 1: - args[0] = str(oscpath[1]) - #print oscpath[0].split("/"),oscpath[1] - - # current UI has no dedicated off button so /on 0 trigs /off to extosc - elif oscpath[0] == "/on": - if oscpath[1] == "1": - sendextosc("/on") + if plugins.Ping("bank0"): + if len(oscpath) == 1: + sendbank0(oscpath[0], oscargs='noargs') + else: + sendbank0(oscpath[0], oscargs=oscpath[1]) else: - sendextosc("/off") + sendWSall("/status Bank0 offline") + ''' - else: - args[0] = "noargs" - commands.handler(oscpath[0].split("/"),args) - - + # if needed a loop back : WS Client -> server -> WS Client #sendWSall("ws"+message) @@ -378,7 +459,7 @@ def handle_timeout(self): def sendWSall(message): #if gstt.debug >0: #print("WS sending %s" % (message)) - server.send_message_to_all(message) + wserver.send_message_to_all(message) @@ -425,12 +506,14 @@ if lasernumber >2: print "Launching Laser 3 Process..." dac_worker3.start() + # Main loop do nothing. Maybe do the webui server ? try: #while True: # Websocket startup - server = WebsocketServer(wsPORT,host=serverIP) + wserver = WebsocketServer(wsPORT,host=serverIP) + plugins.Init(wserver) # Launch OSC thread listening to extosc print "" @@ -444,13 +527,13 @@ try: - #print server + #print wserver print "" print "Launching webUI Websocket server..." print "at", serverIP, "port",wsPORT - server.set_fn_new_client(new_client) - server.set_fn_client_left(client_left) - server.set_fn_message_received(message_received) + wserver.set_fn_new_client(new_client) + wserver.set_fn_client_left(client_left) + wserver.set_fn_message_received(message_received) print "" print "Resetting all Homographies.." for laserid in range(0,gstt.LaserNumber): @@ -458,7 +541,7 @@ try: print "" print "ws server running forver..." - server.run_forever() + wserver.run_forever() except KeyboardInterrupt: diff --git a/plugins.py b/plugins.py new file mode 100644 index 0000000..cf189d7 --- /dev/null +++ b/plugins.py @@ -0,0 +1,181 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- +''' + +LJ Laser Server v0.8.1 + +Plugins Handler. + +''' + +from OSC import OSCServer, OSCClient, OSCMessage +from websocket_server import WebsocketServer +import gstt +import os +import subprocess +import sys + + +def Init(wserver): + global WSserver + + WSserver = wserver + + +def sendWSall(message): + #if gstt.debug >0: + #print("WS sending %s" % (message)) + WSserver.send_message_to_all(message) + +# What is plugin's OSC port ? +def Port(name): + + data = gstt.plugins.get(name) + return data.get("OSC") + +# How to start the plugin ? +def Command(name): + + data = gstt.plugins.get(name) + return data.get("command") + +# Get all plugin current state +def Data(name): + + return gstt.plugins.get(name) + + +def Start(name): + + # get Plugin configuration. + command = Command(name) + + # Maybe it's not fully started + data = Data(name) + + if command != "" and "pid" not in data : + + sendWSall("/status Starting...") + # Get LJ path + ljpath = r'%s' % os.getcwd().replace('\\','/') + print "" + print "Starting plugin :", name + print "LJ path :", ljpath + # Construct the command with absolute path. + + PluginPath = command.split(" ") + # Launch as a subprocess + PluginProcess = subprocess.Popen([PluginPath[0], ljpath + "/" + PluginPath[1]]) + print "New process pid for ", name, ":", PluginProcess.pid + + data = Data(name) + + data["pid"] = PluginProcess.pid + data["process"] = PluginProcess + + # Process can be terminated with : + # PluginProcess.terminate() + +def OSCsend(name, oscaddress, oscargs =''): + + PluginPort = Port(name) + sendWSall("/status Checking "+ name + "...") + if gstt.debug >0: + print "" + print "Checking plugin ",name, "..." + print "Plugin ", name, "is at", gstt.LjayServerIP, "and has OSC port : " + str(PluginPort) + print "Sending", oscaddress, oscargs,"to plugin ", name + + osclientplugin = OSCClient() + osclientplugin.connect((gstt.LjayServerIP, PluginPort)) + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + try: + osclientplugin.sendto(oscmsg, (gstt.LjayServerIP, PluginPort)) + oscmsg.clearData() + if gstt.debug >0: + print oscaddress, oscargs, "was sent to",name + return True + + except: + print "" + print 'Connection to plugin IP', gstt.LjayServerIP ,'port', PluginPort,' refused : died ?' + #sendWSall("/status No plugin.") + sendWSall("/status No plugin.") + #PluginStart(name) + return False + + +def Ping(name): + + return OSCsend(name,"/ping") + + +def Kill(name): + + data = Data(name) + print "" + if data["process"] != None: + print name, "plugin is owned by LJ." + print "Killing plugin", name + + OSCsend(name,"/quit") + #data["process"].terminate() + + sendWSall("/status Killing "+ name +".") + else: + print "Killing asked but plugin is not owned by LJ" + sendWSall("/status Not own plugin") + + +# Send a command to given plugin. Will also start it if command contain /start 1 +def Send(name,oscpath): + + + if oscpath[0].find(name) != -1: + + # Plugin is online ? + if Ping(name): + + # Light up the plugin button + sendWSall("/" + name + "/start 1") + sendWSall("/status " + name + " online") + if gstt.debug >0: + print "Plugin " + name + " online." + print "Command", oscpath + + + # If start 0, try to kill plugin + if oscpath[0].find("start") != -1 and oscpath[1] == "0": + + if gstt.debug >0: + print "start 0, so killing", name, "..." + Kill(name) + + # Send osc command + elif len(oscpath) == 1: + OSCsend(name,oscpath[0], oscargs='noargs') + else: + OSCsend(name,oscpath[0], oscargs=oscpath[1]) + return True + + # Plugin not online.. + else: + + if gstt.debug >0: + print "Plugin " + name + " offline." + print "Command", oscpath + + sendWSall("/status Plugin " + name + " offline") + sendWSall("/"+ name + "/start 0") + + # Try to Start it if /start 1 + if oscpath[0].find("start") != -1 and oscpath[1] == "1": + if gstt.debug >0: + print "Trying to start", name, "..." + Start(name) + + return False diff --git a/plugins/VJing/bank0.py b/plugins/VJing/bank0.py new file mode 100644 index 0000000..502d046 --- /dev/null +++ b/plugins/VJing/bank0.py @@ -0,0 +1,706 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + +''' +VJing Bank 0 + +was Franken for compo laser at coockie 2018 demoparty + +0 : many Starfields +1 : generic pose animations +2 : Faces +3 : Dancers + +LICENCE : CC +Sam Neurohack, Loloster, + +''' + + +import math +#import gstt +#from globalVars import * +import numpy as np +import pdb +from datetime import datetime +from random import randrange +import redis +import lj3 +import sys,time + +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * +import argparse + +#f_sine = 0 + + +screen_size = [400,400] +xy_center = [screen_size[0]/2,screen_size[1]/2] + +message = "Hello" +OSCinPort = 8010 + +redisIP = '127.0.0.1' +ljclient = 0 + +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="VJ Bank 0 for LJ") +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) + +args = argsparser.parse_args() + + +if args.verbose: + debug = args.verbose +else: + debug = 0 + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + + +lj3.Config(redisIP,ljclient) + +def OSCljclient(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /bank0/ljclient with value", value) + ljclient = value + lj3.LjClient(ljclient) + +def hex2rgb(hexcode): + return tuple(map(ord,hexcode[1:].decode('hex'))) + + +def rgb2hex(rgb): + return int('0x%02x%02x%02x' % tuple(rgb),0) + + + +# Curve 0 many starfields +def prepareSTARFIELD(): + global star, stars0, stars1, stars2, starfieldcount, starspeed, displayedstars, displayedstars, num_stars, max_depth + + stars0=[] + stars1=[] + stars2=[] + #stars3=[] + num_stars = 50 + max_depth = 20 + stars = [] + starfieldcount = 0 + displayedstars = 5 + starspeed = 0.05 + + for i in range(num_stars): + # A star is represented as a list with this format: [X,Y,Z] + star = [randrange(-25,25), randrange(-25,25), randrange(1, max_depth)] + stars0.append(star) + star = [randrange(-25,25), randrange(-25,25), randrange(1, max_depth)] + stars1.append(star) + star = [randrange(-25,25), randrange(-25,25), randrange(1, max_depth)] + stars2.append(star) + +def Starfield(hori=0,verti=0): + global star, stars0, stars1, stars2, starfieldcount, starspeed, displayedstars, displayedstars, num_stars, max_depth + + starfieldcount += 1 + #print starfieldcount + starpoints = [] + + # Move starfield according to joypads. Not used in the demo + ''' + # Tflight joystick : + # y axis 1 top -1 bottom 1 + # x axis 0 left -1 right 1 + # Main fire button 5 + # hat (x,y) x -1 left x 1 right y -1 bottom y 1 top + # speed axis 3 backward 1 forward -1 + + if Nbpads > 0: + # Move center on X axis according to pad + if pad1.get_axis(0)<-0.1 or pad1.get_axis(0)>0.1: + hori = pad1.get_axis(0) + #print hori + # Move center on Y axis according to pad + if pad1.get_axis(1)<-0.1 or pad1.get_axis(1)>0.1: + verti= pad1.get_axis(1) + #print verti + ''' + + #print displayedstars, 'stars displayed' + + # Increase number of + if displayedstars < num_stars and starfieldcount % 15 == 0: + displayedstars += 1 + + if displayedstars == num_stars and starfieldcount % 10 == 0: + starspeed += 0.005 + + #if Nbpads > 0: + # starspeed = (1-pad1.get_axis(3)) + + #print starspeed + + for starnumber in range(0,displayedstars): + + # The Z component is decreased on each frame. + stars0[starnumber][2] -= starspeed * 3 + stars1[starnumber][2] -= starspeed * 3 + stars2[starnumber][2] -= starspeed * 3 + + # If the star has past the screen (I mean Z<=0) then we + # reposition it far away from the screen (Z=max_depth) + # with random X and Y coordinates. + if stars0[starnumber][2] <= 0: + stars0[starnumber][0] = randrange(-25,25) + stars0[starnumber][1] = randrange(-25,25) + stars0[starnumber][2] = max_depth + + if stars1[starnumber][2] <= 0: + stars1[starnumber][0] = randrange(-25,25) + stars1[starnumber][1] = randrange(-25,25) + stars1[starnumber][2] = max_depth + + if stars2[starnumber][2] <= 0: + stars2[starnumber][0] = randrange(-25,25) + stars2[starnumber][1] = randrange(-25,25) + stars2[starnumber][2] = max_depth + + + # Convert the 3D coordinates to 2D using perspective projection. + k0 = 128.0 / stars0[starnumber][2] + k1 = 128.0 / stars1[starnumber][2] + k2 = 128.0 / stars2[starnumber][2] + + # Move Starfield origin. + # if stars xpos/ypos is same sign (i.e left stars xpos is <0) than (joystick or code) acceleration (hori and verti moves the star field origin) + if np.sign(stars0[starnumber][0]) == np.sign(hori): + x0 = int(stars0[starnumber][0] * k0 + xy_center[0] + (hori*600)) + else: + x0 = int(stars0[starnumber][0] * k0 + xy_center[0] + (hori*300)) + + if np.sign(stars0[starnumber][1]) == np.sign(verti): + y0 = int(stars0[starnumber][1] * k0 + xy_center[1] + (verti*600)) + else: + y0 = int(stars0[starnumber][1] * k0 + xy_center[1] + (verti*300)) + + + if np.sign(stars1[starnumber][0]) == np.sign(hori): + x1 = int(stars1[starnumber][0] * k1 + xy_center[0] + (hori*600)) + else: + x1 = int(stars1[starnumber][0] * k1 + xy_center[0] + (hori*300)) + + if np.sign(stars1[starnumber][1]) == np.sign(verti): + y1 = int(stars1[starnumber][1] * k1 + xy_center[1] + (verti*600)) + else: + y1 = int(stars1[starnumber][1] * k1 + xy_center[1] + (verti*300)) + + + if np.sign(stars2[starnumber][0]) == np.sign(hori): + x2 = int(stars2[starnumber][0] * k2 + xy_center[0] + (hori*600)) + else: + x2 = int(stars2[starnumber][0] * k2 + xy_center[0] + (hori*300)) + + if np.sign(stars2[starnumber][1]) == np.sign(verti): + y2 = int(stars2[starnumber][1] * k2 + xy_center[1] + (verti*600)) + else: + y2 = int(stars2[starnumber][1] * k2 + xy_center[1] + (verti*300)) + + + # Add star to pointlist PL 0 + if 0 <= x0 < screen_size[0] - 2 and 0 <= y0 < screen_size[1] - 2: + #f.LineTo((x,y), 0x80000000) + lj3.PolyLineOneColor([(x0,y0),((x0+1),(y0+1))], c = rgb2hex([255,255,255]), PL = 0, closed = False) + #fwork.PolyLineOneColor([(x0,y0),((x0+1),(y0+1))], c=rgb2hex([255,255,255]), PL = 0, closed = False) + + # Add star to pointlist PL 1 + if 0 <= x1 < screen_size[0] - 2 and 0 <= y1 < screen_size[1] - 2: + lj3.PolyLineOneColor([(x1,y1),((x1+1),(y1+1))], c = rgb2hex([255,255,255]), PL = 0, closed = False) + + #fwork.PolyLineOneColor([(x1,y1),((x1+1),(y1+1))], c=rgb2hex([255,255,255]), PL = 1, closed = False) + + # Add star to pointlist PL 2 + #if 0 <= x2 < screen_size[0] - 2 and 0 <= y2 < screen_size[1] - 2: + # fwork.PolyLineOneColor([(x2,y2),((x2+1),(y2+1))], c=colorify.rgb2hex([255,255,255]), PL = 2, closed = False) + # #f.PolyLineOneColor([(x,y),((x+2),(y+2))], COLOR_WHITE) + + ''' + if starfieldcount < 200: + + if 0 <= x3 < screen_size[0] - 2 and 0 <= y3 < screen_size[1] - 2: + fwork.PolyLineOneColor([(x3,y3),((x3+2),(y3+2))], c=colorify.rgb2hex([255,255,255]), PL = 3, closed = False) + ''' + + + lj3.Text(message, color, PL = 2, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(0) + lj3.DrawPL(1) + lj3.DrawPL(2) + #lj3.DrawPL(3) + + +# Curve 1 : generic pose animations +import json +CurrentPose = 1 + +# get absolute body position points +def getCOCO(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + if len(pose_json['part_candidates'][people][str(dot)]) != 0: + dots.append((pose_json['part_candidates'][people][str(dot)][0], pose_json['part_candidates'][people][str(dot)][1])) + return dots + + +# get relative (-1 0 1) body position points. a position -1, -1 means doesn't exist +def getBODY(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + #print pose_points + if len(pose_json['people'][people]['pose_keypoints_2d']) != 0: + #print "people 0" + if pose_json['people'][people]['pose_keypoints_2d'][dot * 3] != -1 and pose_json['people'][people]['pose_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][people]['pose_keypoints_2d'][dot * 3], pose_json['people'][people]['pose_keypoints_2d'][(dot * 3)+1])) + return dots + + +# get absolute face position points +def getFACE(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + + if len(pose_json['people'][people]['face_keypoints_2d']) != 0: + #print "people 0" + if pose_json['people'][people]['face_keypoints_2d'][dot * 3] != -1 and pose_json['people'][people]['face_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][people]['face_keypoints_2d'][dot * 3], pose_json['people'][people]['face_keypoints_2d'][(dot * 3)+1])) + + return dots + + +# Body parts +def bodyCOCO(pose_json, people): + pose_points = [10,9,8,1,11,12,13] + return getBODY(pose_json,pose_points, people) + +def armCOCO(pose_json, people): + pose_points = [7,6,5,1,2,3,4] + return getBODY(pose_json,pose_points, people) + +def headCOCO(pose_json, people): + pose_points = [1,0] + return getBODY(pose_json,pose_points, people) + + +# Face keypoints +def face(pose_json, people): + pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + return getFACE(pose_json,pose_points, people) + +def browL(pose_json, people): + pose_points = [26,25,24,23,22] + return getFACE(pose_json,pose_points, people) + +def browR(pose_json, people): + pose_points = [21,20,19,18,17] + return getFACE(pose_json,pose_points, people) + +def eyeR(pose_json, people): + pose_points = [36,37,38,39,40,41,36] + return getFACE(pose_json,pose_points, people) + +def eyeL(pose_json, people): + pose_points = [42,43,44,45,46,47,42] + return getFACE(pose_json,pose_points, people) + +def nose(pose_json, people): + pose_points = [27,28,29,30] + return getFACE(pose_json,pose_points, people) + +def mouth(pose_json, people): + pose_points = [48,59,58,57,56,55,54,53,52,51,50,49,48,60,67,66,65,64,63,62,61,60] + return getFACE(pose_json,pose_points, people) + +import os + + +# Get frame number for pose path describe in PoseDir +def lengthPOSE(pose_dir): + + if debug > 0: + print("Check directory",'poses/' + pose_dir) + if os.path.exists('poses/' + pose_dir): + numfiles = sum(1 for f in os.listdir('poses/' + pose_dir) if os.path.isfile(os.path.join('poses/' + pose_dir + '/', f)) and f[0] != '.') + if debug > 0: + print(numfiles,"images") + return numfiles + else: + if debug > 0: + print("but it doesn't even exist!") + return 0 + +def preparePOSE(): + global anims0, anims1, anims2 + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frames is fetched from directory file count + + anims1 = [['sky',50,100,300,0,0,0,1],['2dancer1', 400,100, 300,0,0,0,1],['1dancer', 400,100, 300,0,0,0,1],['window1',100,100,300,0,0,0,1]] + anims2 = [['window1', 400,200, 300,0,0,0,1],['2dancer1',100,200,300,0,0,0,1]] + + for anim in anims1: + anim[5]= lengthPOSE(anim[0]) + anims0 = anims1 + + +# display n pose animations on Laser 0 +def Pose(): + global anims0, anims1, anims2 + + for anim in anims0: + PL = 0 + dots = [] + print(anim, anim[5]) + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + for people in range(len(pose_json['people'])): + + lj3.rPolyLineOneColor(bodyCOCO(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(armCOCO(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(headCOCO(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + # Face + ''' + #lj3.rPolyLineOneColor(face(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(browL(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(browR(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeR(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeL(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(nose(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(mouth(pose_json, people), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + ''' + + lj3.DrawPL(PL) + time.sleep(0.02) + + + # decrease current frame + if keystates[pygame.K_w]: # and not keystates_prev[pygame.K_w]: + CurrentPose -= 1 + if CurrentPose < 2: + CurrentPose = numfiles -1 + #time.sleep(0.033) + print("Frame : ",CurrentPose) + + # increaser current frame + if keystates[pygame.K_x]: # and not keystates_prev[pygame.K_x]: + CurrentPose += 1 + if CurrentPose > numfiles -1: + CurrentPose = 1 + #time.sleep(0.033) + print("Frame : ",CurrentPose) + + + +# Curve 2 Faces +import json +CurrentPose = 1 + +def prepareFACES(): + + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frame is fetched from directory file count + + anims[0] = [['detroit1', 300,300, 100,0,0,0,1]] + anims[1] = [['detroit1', 400,200, 200,0,0,0,1]] + anims[2] = [['detroit1', 500,200, 300,0,0,0,1]] + + ''' + # read anims number of frames from disk. + for anim in range(len(anims0)): + anims0[anim][5]= lengthPOSE(anims0[anim][0]) + for anim in range(len(anims1)): + anims1[anim][5]= lengthPOSE(anims1[anim][0]) + for anim in range(len(anims2)): + anims2[anim][5]= lengthPOSE(anims2[anim][0]) + ''' + + #replace code below + ''' + for laseranims in range(3): + if debug > 0: + print "anims:",anims[laseranims], + for anim in range(len(anims[laseranims])): + anims[laseranims][anim][5]= lengthPOSE(anims[laseranims][anim][0]) + if debug > 1: + print anims[laseranims][anim][5] + ''' + #by this one + #thanks to https://stackoverflow.com/questions/19184335/is-there-a-need-for-rangelena + + for laseranims in anims: + if debug > 1: + print("anims:",laseranims) + for anim in laseranims: + anim[5]=lengthPOSE(anim[0]) + if debug > 1: + print(anim[5]) + + + +# display the face animation describe in PoseDir +def Faces(): + + for laseranims in range(3): + for anim in anims[laseranims]: + PL = laseranims + #print PL, anim + dots = [] + #print anim, anim[5] + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + # Face + + for people in range(len(pose_json['people'])): + + #lj3.PolyLineOneColor(face(pose), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(browL(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(browR(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeR(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeL(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(nose(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(mouth(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + lj3.DrawPL(PL) + time.sleep(0.02) + +# Curve 3 +# Dancers +import json +CurrentPose = 1 + +def prepareDANCERS(): + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frame is fetched from directory file count + + anims[0] = [['1dancer',500,200,300,0,0,0,10]] + anims[1] = [['2dancer1',500,200,300,0,0,0,10]] + anims[2] = [['window1',500,200,300,0,0,0,10]] + #anims[1] = [['2dancer1',100,200,300,0,0,0,10]] + #anims[2] = [['window1',400,200, 300,0,0,0,10]] + # read anims number of frames from disk. + + for laseranims in range(3): + for anim in range(len(anims[laseranims])): + anims[laseranims][anim][5]= lengthPOSE(anims[laseranims][anim][0]) + +# display the pose animation describe in PoseDir +def Dancers(): + + for laseranims in range(3): + + for anim in anims[laseranims]: + PL = laseranims + #print PL, anim + dots = [] + #print anim, anim[5] + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + #bhorosc.sendresol("/layer1/clip1/connect",1) + #bhorosc.sendresol("/layer1/clip1/connect",0) + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + + for people in range(len(pose_json['people'])): + lj3.rPolyLineOneColor(bodyCOCO(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(armCOCO(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + lj3.rPolyLineOneColor(browL(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(browR(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeR(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(eyeL(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(nose(pose_json, people), c=color, PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.rPolyLineOneColor(mouth(pose_json, people), c=color, PL = laseranims, closed = False,xpos = anim[1], ypos = anim[2], resize = anim[3]) + + + lj3.DrawPL(PL) + + ''' + lj3.PolyLineOneColor(bodyCOCO(pose_json), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.PolyLineOneColor(armCOCO(pose_json), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + lj3.PolyLineOneColor(headCOCO(pose_json), c=color, PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + + PL[PL] = fwork.LinesPL(PL) + ''' + +def OSCljclient(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /bank0/ljclient with value", value) + ljclient = value + lj3.LjClient(ljclient) + + +# Dancers, Starfield, Pose, Face +def OSCrun(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /run with value", value) + doit = value + + +def WebStatus(message): + lj3.Send("/status",message) + + +#doit = Starfield +doit = Pose +#doit = Faces +#doit = Dancers + +print('Loading Bank0...') + +WebStatus("Load Bank0") + +# OSC Server callbacks +print("Starting OSC at 127.0.0.1 port",OSCinPort,"...") +osc_startup() +osc_udp_server("127.0.0.1", OSCinPort, "InPort") + +osc_method("/bank0/run*", OSCrun) +osc_method("/bank0/ping*", lj3.OSCping) +osc_method("/bank0/ljclient", OSCljclient) + + +import pygame +pygame.init() +Nbpads = pygame.joystick.get_count() +print ("Joypads : ", str(Nbpads)) + +''' +if Nbpads != 2: + + print ('') + print ('') + print ("THIS VERSION NEEDS 2 PADS. PLEASE CONNECT THEM.") + print ('') + sys.exit() +''' + + +if Nbpads > 1: + + pad2 = pygame.joystick.Joystick(1) + pad2.init() + print ("Pad2 :", pad2.get_name()) + numButtons = pad2.get_numbuttons() + #print ("Axis Pad 2 :", str(pad2.get_numaxes())) + #print ("Buttons Pad 2 :" , str(numButtons)) + + # joy is pad abstraction to handle many different devices. + joy2 = lj3.setup_controls(pad2) + +if Nbpads > 0: + + pad1 = pygame.joystick.Joystick(0) + pad1.init() + print ("Pad1 :",pad1.get_name()) + numButtons = pad1.get_numbuttons() + joy1 = lj3.setup_controls(pad1) + #print ("Axis Pad 1 :", str(pad1.get_numaxes())) + #print ("Buttons Pad 1 :" , str(numButtons)) + + + + +anims =[[],[],[],[]] +color = lj3.rgb2int(255,255,255) + +prepareSTARFIELD() +preparePOSE() +prepareDANCERS() +prepareFACES() + +WebStatus("Bank0 ready.") +print("Bank0 ready") + +def Run(): + + try: + while 1: + #Starfield(hori=0,verti=0) + doit() + + except KeyboardInterrupt: + pass + + # Gently stop on CTRL C + + finally: + + WebStatus("Bank0 Exit") + print("Stopping OSC...") + lj3.OSCstop() + + print ("Bank0 Stopped.") + +Run() diff --git a/plugins/VJing/lj3.py b/plugins/VJing/lj3.py new file mode 100644 index 0000000..ef09124 --- /dev/null +++ b/plugins/VJing/lj3.py @@ -0,0 +1,618 @@ +# coding=UTF-8 + +''' +LJ v0.8.1 in python3 +Some LJ functions useful for python clients (was framy.py) + +OSC functions commented, waiting working on OSC in python3 + +Config(redisIP, client number) +PolyLineOneColor +rPolyLineOneColor + +Text(word, color, PL, xpos, ypos, resize, rotx, roty, rotz) : Display a word +Send(adress,message) : remote control. See commands.py +WebStatus(message) : display message on webui +DrawPL(point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers. +rgb2int(r,g,b) + +OSCstart(): Start the OSC system. +OSCframe(): +OSCstop(): Properly close the OSC system +OSCping(value): Answer to LJ pings + +setup_controls(joystick) + +XboxController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger +Ps3Controller : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger, getUp, getDown, getLeft, getRight, getFire1, getFire2(self): +MySaitekController : getLeftHori,getLeftVert, getRightHori,getRightVert, getLeftTrigger,getRightTrigger +MyThrustController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger +CSLController : getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftTrigger,getRightTrigger,getFire1,getFire2 +my USB Joystick : getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2 + + +LICENCE : CC +Sam Neurohack + +''' + +import math +import redis + +# Import needed modules from osc4py3 +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse + + +redisIP = '127.0.0.1' +r = redis.StrictRedis(host=redisIP, port=6379, db=0) + +ClientNumber = 0 + +point_list = [] +pl = [[],[],[],[]] + +# +# OSC interaction with LJ +# + +def OSCstart(): + # Start the system. + osc_startup() + #osc_udp_client(redisIP, 8002, "LJ 8002") + +def OSCframe(): + #print("OSCprocess") + osc_process() + +# Properly close the system. Todo +def OSCstop(): + osc_terminate() + + +# Answer to LJ pings +def OSCping(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /ping with value", value) + Send("/pong",value) + + +def Send(oscaddress,oscargs=''): + + try: + msg = oscbuildparse.OSCMessage(oscaddress, None, [oscargs]) + osc_send(msg, "LJ 8002") + OSCframe() + + except: + print ('Connection to LJ refused : died ?') + pass +''' +def handlerfunction(s, x, y): + # Will receive message data unpacked in s, x, y + pass + +def handlerfunction2(address, s, x, y): + # Will receive message address, and message data flattened in s, x, y + pass + +# Make server channels to receive packets. +osc_udp_server("127.0.0.1", 3721, "localhost") +osc_udp_server("0.0.0.0", 3724, "anotherserver") +''' + + + +ASCII_GRAPHICS = [ + +# caracteres corrects + + [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0 + [(-20,30), (0,-30), (-20,30)], #1 + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #2 + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #3 + [(30,10), (-30,10), (0,-30), (0,30)], #4 + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #5 + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #6 + [(-30,-30), (30,-30), (-30,30)], #7 + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #8 + [(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], #9 + +# caracteres a implementer + [(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #: + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #; + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #< + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #= + [(30,10), (-30,10), (0,-30), (0,30)], #> + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #? + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #@ + +# Caracteres corrects + + + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #B + [(30,30), (-30,30), (-30,-30), (30,-30)], #C + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #D + [(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #E + [(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #F + [(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], #G + [(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], #H + [(0,30), (0,-30)], #I + [(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], #J + [(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], #K + [(30,30), (-30,30), (-30,-30)], #L + [(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], #M + [(-30,30), (-30,-30), (30,30), (30,-30)], #N + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #O + [(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], #P + [(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], #Q + [(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], #R + [(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], #S + [(0,30), (0,-30), (-30,-30), (30,-30)], #T + [(-30,-30), (-30,30), (30,30), (30,-30)], #U + [(-30,-30), (0,30), (30,-30)], #V + [(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], #W + [(-30,30), (30,-30)], [(-30,-30), (30,30)], #X + [(0,30), (0,0), (30,-30), (0,0), (-30,-30)], #Y + [(30,30), (-30,30), (30,-30), (-30,-30)], #Z + + # A implementer + + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #[ + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #\ + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #] + [(30,10), (-30,10), (0,-30), (0,30)], #^ + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #_ + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #` + + # Implementé + + [(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], #a + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], #b + [(20,20), (-20,20), (-20,-20), (20,-20)], #c + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #d + [(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #e + [(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #f + [(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], #g + [(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], #H + [(0,20), (0,-20)], #I + [(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], #J + [(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], #K + [(20,20), (-20,20), (-20,-20)], #L + [(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], #M + [(-20,20), (-20,-20), (20,20), (20,-20)], #N + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #O + [(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], #P + [(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], #Q + [(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], #R + [(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], #S + [(0,20), (0,-20), (-20,-20), (20,-20)], #T + [(-20,-20), (-20,20), (20,20), (20,-20)], #U + [(-20,-20), (0,20), (20,-20)], #V + [(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], #W + [(-20,20), (20,-20)], [(-20,-20), (20,20)], #X + [(0,20), (0,0), (20,-20), (0,0), (-20,-20)], #Y + [(20,20), (-20,20), (20,-20), (-20,-20)], #Z + + [(-2,15), (2,15)] # Point a la place de { +] + +def rgb2int(r,g,b): + return int('0x%02x%02x%02x' % (r,g,b),0) + + +def Config(redisIP,client): + global ClientNumber + + r = redis.StrictRedis(host=redisIP, port=6379, db=0) + ClientNumber = client + osc_udp_client(redisIP, 8002, "LJ 8002") + + +def LjClient(client): + global ClientNumber + + ClientNumber = client + + + +def LineTo(xy, c, PL): + + pl[PL].append((xy + (c,))) + +def Line(xy1, xy2, c, PL): + LineTo(xy1, 0, PL) + LineTo(xy2, c , PL) + + +def PolyLineOneColor(xy_list, c, PL , closed ): + #print "--" + #print "c",c + #print "xy_list",xy_list + #print "--" + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + #print "xy0:",xy0 + LineTo(xy0,0, PL) + LineTo(xy0,c, PL) + else: + #print "xy:",xy + LineTo(xy,c, PL) + if closed: + LineTo(xy0,c, PL) + + +# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates +def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): + + x = xy[0] * resize + y = xy[1] * resize + z = 0 + + rad = rotx * math.pi / 180 + cosaX = math.cos(rad) + sinaX = math.sin(rad) + + y2 = y + y = y2 * cosaX - z * sinaX + z = y2 * sinaX + z * cosaX + + rad = roty * math.pi / 180 + cosaY = math.cos(rad) + sinaY = math.sin(rad) + + z2 = z + z = z2 * cosaY - x * sinaY + x = z2 * sinaY + x * cosaY + + rad = rotz * math.pi / 180 + cosZ = math.cos(rad) + sinZ = math.sin(rad) + + x2 = x + x = x2 * cosZ - y * sinZ + y = x2 * sinZ + y * cosZ + + #print xy, (x + xpos,y+ ypos) + return (x + xpos,y+ ypos) + ''' + to understand why it get negative Y + + # 3D to 2D projection + factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z) + print xy, (x * factor + xpos, - y * factor + ypos ) + return (x * factor + xpos, - y * factor + ypos ) + ''' + +# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos +#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): +def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0): + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL) + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + else: + LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL) + if closed: + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + + +def LinesPL(PL): + print ("Stupido !! your code is to old : use DrawPL() instead of LinesPL()") + DrawPL(PL) + +def DrawPL(PL): + #print '/pl/0/'+str(PL), str(pl[PL]) + if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True: + pl[PL] = [] + return True + else: + return False + +def ResetPL(self, PL): + pl[PL] = [] + + + +def DigitsDots(number,color): + dots =[] + for dot in ASCII_GRAPHICS[number]: + #print dot + dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color)) + #self.point_list.append((xy + (c,))) + return dots + +def CharDots(char,color): + + dots =[] + for dot in ASCII_GRAPHICS[ord(char)-46]: + dots.append((dot[0],dot[1],color)) + return dots + +def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): + + dots =[] + + l = len(message) + i= 0 + #print message + + for ch in message: + + #print "" + # texte centre en x automatiquement selon le nombre de lettres l + x_offset = 26 * (- (0.9*l) + 3*i) + #print i,x_offset + # if digit + if ord(ch)<58: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 48] + else: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 46 ] + + char_draw = [] + #dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0)) + + for xy in char_pl_list: + char_draw.append((xy[0] + x_offset,xy[1],c)) + i +=1 + #print ch,char_pl_list,char_draw + rPolyLineOneColor(char_draw, c, PL , False, xpos, ypos, resize, rotx, roty, rotz) + #print ("laser",PL,"message",message) + #dots.append(char_draw) + + + +import re + +def setup_controls(joystick): + """ + Joystick wrapper. + """ + if re.search('playstation', joystick.get_name(), re.I): + return Ps3Controller(joystick) + + elif re.search('X-box', joystick.get_name(), re.I): + return XboxController(joystick) + + elif re.search('Saitek', joystick.get_name(), re.I): + return MySaitekController(joystick) + + elif re.search('Thrustmaster dual analog 3.2', joystick.get_name(), re.I): + return MyThrustController(joystick) + + elif re.search('2n1 USB', joystick.get_name(), re.I): + return CSLController(joystick) + + elif re.search('Joystick', joystick.get_name(), re.I): + return USBController(joystick) + + return Controller(joystick) + +class Controller(object): + + def __init__(self, joystick): + """Pass a PyGame joystick instance.""" + self.js = joystick + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(9) + + def getRightTrigger(self): + return self.js.get_button(2) + +class XboxController(Controller): + + def __init__(self, joystick): + super(XboxController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(4) + + def getLeftTrigger(self): + return self.js.get_axis(2) + + def getRightTrigger(self): + return self.js.get_button(11) + +class Ps3Controller(Controller): + +#up 4 _DOWN 6 left 7 right 5 croix 14 rond 13 triangle 12 + + def __init__(self, joystick): + super(Ps3Controller, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + # TODO: Verify + return self.js.get_button(8) + + def getRightTrigger(self): + # TODO: Verify + return self.js.get_button(9) + + def getUp(self): + return self.js.get_button(4) + + def getDown(self): + return self.js.get_button(6) + + def getLeft(self): + return self.js.get_button(7) + + def getRight(self): + return self.js.get_button(5) + + def getFire1(self): + return self.js.get_button(14) + + def getFire2(self): + return self.js.get_button(13) + + +class MySaitekController(Controller): + + def __init__(self, joystick): + super(MySaitekController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(2) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + +class MyThrustController(Controller): + + def __init__(self, joystick): + super(MyThrustController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + return self.js.get_button(5) + + def getRightTrigger(self): + return self.js.get_button(7) + + +class CSLController(Controller): + + def __init__(self, joystick): + super(CSLController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + + def getFire1(self): + return self.js.get_button(2) + + def getFire2(self): + return self.js.get_button(1) + +class USBController(Controller): + + +# my USB Joystick +#up axis 0 -1 DOWN axis 0 1 left axis 1 1 right axis 1 -1 bouton gauche 10 bouton droite 9 + + def __init__(self, joystick): + super(USBController, self).__init__(joystick) + + + def getUp(self): + if self.js.get_axis(0) == -1: + return 1 + else: + return 0 + + def getDown(self): + if self.js.get_axis(0) > 0.9: + return 1 + else: + return 0 + + def getLeft(self): + if self.js.get_axis(1) == 1: + return 1 + else: + return 0 + + def getRight(self): + if self.js.get_axis(1) == -1: + return 1 + else: + return 0 + + def getLeftTrigger(self): + return self.js.get_button(10) + + def getRightTrigger(self): + return self.js.get_button(9) + + def getFire1(self): + if self.js.get_button(10) == 1: + print ("fire 1") + return self.js.get_button(10) + + def getFire2(self): + if self.js.get_button(9) == 1: + print ("fire 2") + return self.js.get_button(9) + + + + diff --git a/plugins/VJing/poses b/plugins/VJing/poses new file mode 120000 index 0000000..d5b5859 --- /dev/null +++ b/plugins/VJing/poses @@ -0,0 +1 @@ +../../../LJay/poses \ No newline at end of file diff --git a/plugins/VJing/poses.py b/plugins/VJing/poses.py new file mode 100644 index 0000000..a805b87 --- /dev/null +++ b/plugins/VJing/poses.py @@ -0,0 +1,598 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + +''' +Laser Jaying + +LICENCE : CC +Sam Neurohack, Loloster, + +Openpose json files animations + +Set for amiral castle : + +Curve 0 : Mapping +Curve 1 : Pose align on Laser 0 for the moment +Curve 2 : Faces +Curve 3 : Dancers + +''' + + +import math +import gstt +from globalVars import * +import bhoroscp +import colorify +import numpy as np +import pdb +import time +from datetime import datetime +import settings + + +# For Mapping() +# dedicated settings handler is in settings.py +import pygame + +f_sine = 0 + + + +# Curve 0 +# Edit shape mode / Run Mode + +def MappingConf(section): + global mouse_prev, sections + + print "" + print "For Mapping(), reading Architecture Points" + gstt.EditStep = 0 + gstt.CurrentWindow = -1 + gstt.CurrentCorner = 0 + gstt.CurrentSection = section + mouse_prev = ((405, 325), (0, 0, 0)) + + # Get all shapes points (="corners") for the given section of the conf file -> gstt.Windows + gstt.Windows = [] + sections = settings.MappingSections() + + print "" + #print "Sections : ", sections + print "Reading Section : ", sections[gstt.CurrentSection] + + gstt.Laser = settings.MappingRead([sections[gstt.CurrentSection],'laser']) + print "Laser : ", gstt.Laser + gstt.simuPL = gstt.Laser + + for Window in xrange(settings.Mapping(sections[gstt.CurrentSection])-1): + print "Reading option : ", str(Window) + shape = [sections[gstt.CurrentSection], str(Window)] + WindowPoints = settings.MappingRead(shape) + gstt.Windows.append(WindowPoints) + + print "Section points : " ,gstt.Windows + + + + +# section 0 is "General", then first screen shapes in section 1 +# Todo : Should search automatically first screen in settings file sections. +# MappingConf(1) should be call only if curve 0 is selected + + +def Mapping(fwork, keystates, keystates_prev): + global mouse_prev, sections + + PL = gstt.Laser + dots = [] + + #switch to edit mode Key E ? + if keystates[pygame.K_e] and not keystates_prev[pygame.K_e] and gstt.EditStep == 0: + print "Switching to Edit Mode" + gstt.EditStep = 1 + gstt.CurrentWindow = 0 + gstt.CurrentCorner = 0 + + # Back to normal if ENTER key is pressed ? + if keystates[pygame.K_RETURN] and gstt.EditStep == 1: + + print "Switching to Run Mode" + gstt.EditStep =0 + + + + # EDIT MODE : cycle windows if press e key to adjust corner position + # Escape edit mode with enter key + if gstt.EditStep >0: + + dots = [] + CurrentWindowPoints = gstt.Windows[gstt.CurrentWindow] + + # Draw all windows points or "corners" + for corner in xrange(len(CurrentWindowPoints)): + dots.append(proj(int(CurrentWindowPoints[corner][0]),int(CurrentWindowPoints[corner][1]),0)) + fwork.PolyLineOneColor( dots, c=colorify.rgb2hex(gstt.color), PL = PL, closed = False ) + + # Left mouse is clicked, modify current Corner coordinate + if gstt.mouse[1][0] == mouse_prev[1][0] and mouse_prev[1][0] == 1: + deltax = gstt.mouse[0][0]-mouse_prev[0][0] + deltay = gstt.mouse[0][1]-mouse_prev[0][1] + CurrentWindowPoints[gstt.CurrentCorner][0] += (deltax *2) + CurrentWindowPoints[gstt.CurrentCorner][1] -= (deltay * 2) + + # Change corner if Z key is pressed. + if keystates[pygame.K_z] and not keystates_prev[pygame.K_z]: + if gstt.CurrentCorner < settings.Mapping(sections[gstt.CurrentSection]) - 1: + gstt.CurrentCorner += 1 + print "Corner : ", gstt.CurrentCorner + + # Press E inside Edit mode : Next window + if keystates[pygame.K_e] and not keystates_prev[pygame.K_e]: + + # Save current Window and switch to the next one. + if gstt.CurrentWindow < settings.Mapping(sections[gstt.CurrentSection]) -1: + print "saving " + settings.MappingWrite(sections,str(gstt.CurrentWindow),CurrentWindowPoints) + gstt.CurrentWindow += 1 + gstt.CurrentCorner = -1 + if gstt.CurrentWindow == settings.Mapping(sections[gstt.CurrentSection]) -1: + gstt.EditStep == 0 + gstt.CurrentWindow = 0 + print "Now Editing window ", gstt.CurrentWindow + + mouse_prev = gstt.mouse + gstt.PL[PL] = fwork.LinesPL(PL) + + # Press A : Next section ? + if keystates[pygame.K_a] and not keystates_prev[pygame.K_a]: + + print "current section : ", gstt.CurrentSection + if gstt.CurrentSection < len(sections)-1: + gstt.CurrentSection += 1 + print "Next section name is ", sections[gstt.CurrentSection] + if "screen" in sections[gstt.CurrentSection]: + print "" + print "switching to section ", gstt.CurrentSection, " ", sections[gstt.CurrentSection] + MappingConf(gstt.CurrentSection) + else: + gstt.CurrentSection = -1 + + + # RUN MODE + if gstt.EditStep == 0: + + # Add all windows to PL for display + for Window in gstt.Windows: + + dots = [] + for corner in xrange(len(Window)): + #print "Editing : ", WindowPoints[corner] + #print Window[corner][0] + dots.append(proj(int(Window[corner][0]),int(Window[corner][1]),0)) + + fwork.PolyLineOneColor( dots, c=colorify.rgb2hex(gstt.color), PL = PL, closed = False ) + + gstt.PL[PL] = fwork.LinesPL(PL) + + + +# Curve 1 : generic pose animations +import json +gstt.CurrentPose = 1 +''' +# get absolute body position points +def getCOCO(pose_json,pose_points): + + dots = [] + for dot in pose_points: + if len(pose_json['part_candidates'][0][str(dot)]) != 0: + dots.append((pose_json['part_candidates'][0][str(dot)][0], pose_json['part_candidates'][0][str(dot)][1])) + return dots + + +# get relative (-1 0 1) body position points. a position -1, -1 means doesn't exist +def getBODY(pose_json,pose_points): + + dots = [] + for dot in pose_points: + #print pose_points + if len(pose_json['people'][0]['pose_keypoints_2d']) != 0: + #print "people 0" + if pose_json['people'][0]['pose_keypoints_2d'][dot * 3] != -1 and pose_json['people'][0]['pose_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][0]['pose_keypoints_2d'][dot * 3], pose_json['people'][0]['pose_keypoints_2d'][(dot * 3)+1])) + + #if len(pose_json['people']) != 1: + #print "people1" + #print "people 1", pose_json['people'][1]['pose_keypoints_2d'] + #print len(pose_json['people']) + + return dots + + +# get absolute face position points +def getFACE(pose_json,pose_points): + + dots = [] + for dot in pose_points: + + if len(pose_json['people'][0]['face_keypoints_2d']) != 0: + print "people 0" + if pose_json['people'][0]['face_keypoints_2d'][dot * 3] != -1 and pose_json['people'][0]['face_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][0]['face_keypoints_2d'][dot * 3], pose_json['people'][0]['face_keypoints_2d'][(dot * 3)+1])) + + if len(pose_json['people']) != 1: + print "people 1" + #print "people 1", pose_json['people'][1]['face_keypoints_2d'] + return dots + + +# Body parts +def bodyCOCO(pose_json): + pose_points = [10,9,8,1,11,12,13] + return getBODY(pose_json,pose_points) + +def armCOCO(pose_json): + pose_points = [7,6,5,1,2,3,4] + return getBODY(pose_json,pose_points) + +def headCOCO(pose_json): + pose_points = [1,0] + return getBODY(pose_json,pose_points) + + +# Face keypoints +def face(pose_json): + pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + return getFACE(pose_json,pose_points) + +def browL(pose_json): + pose_points = [26,25,24,23,22] + return getFACE(pose_json,pose_points) + +def browR(pose_json): + pose_points = [21,20,19,18,17] + return getFACE(pose_json,pose_points) + +def eyeR(pose_json): + pose_points = [36,37,38,39,40,41,36] + return getFACE(pose_json,pose_points) + +def eyeL(pose_json): + pose_points = [42,43,44,45,46,47,42] + return getFACE(pose_json,pose_points) + +def nose(pose_json): + pose_points = [27,28,29,30] + return getFACE(pose_json,pose_points) + +def mouth(pose_json): + pose_points = [48,59,58,57,56,55,54,53,52,51,50,49,48,60,67,66,65,64,63,62,61,60] + return getFACE(pose_json,pose_points) + + +# best order face : face browL browr eyeR eyeL nose mouth +''' + + +# get absolute body position points +def getCOCO(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + if len(pose_json['part_candidates'][people][str(dot)]) != 0: + dots.append((pose_json['part_candidates'][people][str(dot)][0], pose_json['part_candidates'][people][str(dot)][1])) + return dots + + +# get relative (-1 0 1) body position points. a position -1, -1 means doesn't exist +def getBODY(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + #print pose_points + if len(pose_json['people'][people]['pose_keypoints_2d']) != 0: + #print "people 0" + if pose_json['people'][people]['pose_keypoints_2d'][dot * 3] != -1 and pose_json['people'][people]['pose_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][people]['pose_keypoints_2d'][dot * 3], pose_json['people'][people]['pose_keypoints_2d'][(dot * 3)+1])) + + + return dots + + +# get absolute face position points +def getFACE(pose_json,pose_points, people): + + dots = [] + for dot in pose_points: + + if len(pose_json['people'][people]['face_keypoints_2d']) != 0: + #print "people 0" + if pose_json['people'][people]['face_keypoints_2d'][dot * 3] != -1 and pose_json['people'][people]['face_keypoints_2d'][(dot * 3)+1] != -1: + dots.append((pose_json['people'][people]['face_keypoints_2d'][dot * 3], pose_json['people'][people]['face_keypoints_2d'][(dot * 3)+1])) + ''' + if len(pose_json['people']) > 1: + print len(pose_json['people']) + print "people 1 face ", pose_json['people'][1]['face_keypoints_2d'] + ''' + + return dots + + +# Body parts +def bodyCOCO(pose_json, people): + pose_points = [10,9,8,1,11,12,13] + return getBODY(pose_json,pose_points, people) + +def armCOCO(pose_json, people): + pose_points = [7,6,5,1,2,3,4] + return getBODY(pose_json,pose_points, people) + +def headCOCO(pose_json, people): + pose_points = [1,0] + return getBODY(pose_json,pose_points, people) + + +# Face keypoints +def face(pose_json, people): + pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + return getFACE(pose_json,pose_points, people) + +def browL(pose_json, people): + pose_points = [26,25,24,23,22] + return getFACE(pose_json,pose_points, people) + +def browR(pose_json, people): + pose_points = [21,20,19,18,17] + return getFACE(pose_json,pose_points, people) + +def eyeR(pose_json, people): + pose_points = [36,37,38,39,40,41,36] + return getFACE(pose_json,pose_points, people) + +def eyeL(pose_json, people): + pose_points = [42,43,44,45,46,47,42] + return getFACE(pose_json,pose_points, people) + +def nose(pose_json, people): + pose_points = [27,28,29,30] + return getFACE(pose_json,pose_points, people) + +def mouth(pose_json, people): + pose_points = [48,59,58,57,56,55,54,53,52,51,50,49,48,60,67,66,65,64,63,62,61,60] + return getFACE(pose_json,pose_points, people) + +import os + + +# Get frame number for pose path describe in gstt.PoseDir +def lengthPOSE(pose_dir): + + + if gstt.debug > 0: + print "Check directory ",'poses/' + pose_dir + '/' + numfiles = sum(1 for f in os.listdir('poses/' + pose_dir + '/') if os.path.isfile(os.path.join('poses/' + pose_dir + '/', f)) and f[0] != '.') + if gstt.debug > 0: + print "Pose : ", pose_dir, numfiles, "images" + return numfiles + + +def preparePOSE(): + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frames is fetched from directory file count + + anims1 = [['sky',50,100,300,0,0,0,1],['2dancer1', 400,100, 300,0,0,0,1],['1dancer', 400,100, 300,0,0,0,1],['window1',100,100,300,0,0,0,1]] + anims2 = [['window1', 400,200, 300,0,0,0,1],['2dancer1',100,200,300,0,0,0,1]] + + for anim in anims1: + anim[5]= lengthPOSE(anim[0]) + gstt.anims0 = anims1 + + +# display n pose animations on Laser 0 +def Pose(fwork): + + for anim in gstt.anims0: + PL = 0 + dots = [] + print anim, anim[5] + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + for people in range(len(pose_json['people'])): + + fwork.rPolyLineOneColor(bodyCOCO(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(armCOCO(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(headCOCO(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + # Face + ''' + #fwork.rPolyLineOneColor(face(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(browL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(browR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(nose(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(mouth(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + ''' + + gstt.PL[PL] = fwork.LinesPL(PL) + time.sleep(0.02) + + + # decrease current frame + if gstt.keystates[pygame.K_w]: # and not gstt.keystates_prev[pygame.K_w]: + gstt.CurrentPose -= 1 + if gstt.CurrentPose < 2: + gstt.CurrentPose = gstt.numfiles -1 + #time.sleep(0.033) + print "Frame : ",gstt.CurrentPose + + # increaser current frame + if gstt.keystates[pygame.K_x]: # and not gstt.keystates_prev[pygame.K_x]: + gstt.CurrentPose += 1 + if gstt.CurrentPose > gstt.numfiles -1: + gstt.CurrentPose = 1 + #time.sleep(0.033) + print "Frame : ",gstt.CurrentPose + + + +# Curve 2 Faces +import json +gstt.CurrentPose = 1 + +def prepareFACES(): + + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frame is fetched from directory file count + + gstt.anims[0] = [['detroit1', 300,300, 100,0,0,0,1]] + gstt.anims[1] = [['detroit1', 400,200, 200,0,0,0,1]] + gstt.anims[2] = [['detroit1', 500,200, 300,0,0,0,1]] + + ''' + # read anims number of frames from disk. + for anim in range(len(gstt.anims0)): + gstt.anims0[anim][5]= lengthPOSE(gstt.anims0[anim][0]) + for anim in range(len(gstt.anims1)): + gstt.anims1[anim][5]= lengthPOSE(gstt.anims1[anim][0]) + for anim in range(len(gstt.anims2)): + gstt.anims2[anim][5]= lengthPOSE(gstt.anims2[anim][0]) + ''' + + for laseranims in range(3): + print laseranims + for anim in range(len(gstt.anims[laseranims])): + gstt.anims[laseranims][anim][5]= lengthPOSE(gstt.anims[laseranims][anim][0]) + +# display the face animation describe in gstt.PoseDir +def Faces(fwork): + + for laseranims in range(3): + for anim in gstt.anims[laseranims]: + PL = laseranims + #print PL, anim + dots = [] + #print anim, anim[5] + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + # Face + + for people in range(len(pose_json['people'])): + + #fwork.rPolyLineOneColor(face(pose), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(browL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(browR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(nose(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(mouth(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + gstt.PL[PL] = fwork.LinesPL(PL) + time.sleep(0.02) + +# Curve 3 +# Dancers +import json +gstt.CurrentPose = 1 + +def prepareDANCERS(): + + # anim format (name, xpos,ypos, resize, currentframe, totalframe, count, speed) + # total frame is fetched from directory file count + + gstt.anims[0] = [['1dancer',500,200,300,0,0,0,10]] + gstt.anims[1] = [['2dancer1',500,200,300,0,0,0,10]] + gstt.anims[2] = [['window1',500,200,300,0,0,0,10]] + #gstt.anims[1] = [['2dancer1',100,200,300,0,0,0,10]] + #gstt.anims[2] = [['window1',400,200, 300,0,0,0,10]] + # read anims number of frames from disk. + print gstt.anims + + for laseranims in range(3): + print laseranims + for anim in range(len(gstt.anims[laseranims])): + gstt.anims[laseranims][anim][5]= lengthPOSE(gstt.anims[laseranims][anim][0]) + +# display the pose animation describe in gstt.PoseDir +def Dancers(fwork): + + for laseranims in range(3): + for anim in gstt.anims[laseranims]: + PL = laseranims + #print PL, anim + dots = [] + #print anim, anim[5] + # repeat anim[7] time the same frame + anim[6] +=1 + if anim[6] == anim[7]: + + anim[6] = 0 + # increase current frame and compare to total frame + anim[4] += 1 + if anim[4] == anim[5]: + anim[4] = 0 + + + #bhorosc.sendresol("/layer1/clip1/connect",1) + #bhorosc.sendresol("/layer1/clip1/connect",0) + + posename = 'poses/' + anim[0] + '/' + anim[0] +'-'+str("%05d"%anim[4])+'.json' + posefile = open(posename , 'r') + posedatas = posefile.read() + pose_json = json.loads(posedatas) + + + for people in range(len(pose_json['people'])): + fwork.rPolyLineOneColor(bodyCOCO(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(armCOCO(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + fwork.rPolyLineOneColor(browL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(browR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeR(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(eyeL(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(nose(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(mouth(pose_json, people), c=colorify.rgb2hex(gstt.color), PL = laseranims, closed = False,xpos = anim[1], ypos = anim[2], resize = anim[3]) + + + gstt.PL[PL] = fwork.LinesPL(PL) + + ''' + fwork.rPolyLineOneColor(bodyCOCO(pose_json), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(armCOCO(pose_json), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + fwork.rPolyLineOneColor(headCOCO(pose_json), c=colorify.rgb2hex(gstt.color), PL = 0, closed = False, xpos = anim[1], ypos = anim[2], resize = anim[3]) + + + gstt.PL[PL] = fwork.LinesPL(PL) + ''' diff --git a/clients/games/ljpong/controller.py b/plugins/games/ljpong/controller.py similarity index 100% rename from clients/games/ljpong/controller.py rename to plugins/games/ljpong/controller.py diff --git a/clients/games/ljpong/entities.py b/plugins/games/ljpong/entities.py similarity index 100% rename from clients/games/ljpong/entities.py rename to plugins/games/ljpong/entities.py diff --git a/clients/games/ljpong/lj.py b/plugins/games/ljpong/lj.py similarity index 100% rename from clients/games/ljpong/lj.py rename to plugins/games/ljpong/lj.py diff --git a/clients/games/ljpong/main.py b/plugins/games/ljpong/main.py similarity index 100% rename from clients/games/ljpong/main.py rename to plugins/games/ljpong/main.py diff --git a/plugins/livewords.py b/plugins/livewords.py new file mode 100644 index 0000000..407ac2c --- /dev/null +++ b/plugins/livewords.py @@ -0,0 +1,154 @@ +# coding=UTF-8 + +''' +Live words on different lasers +LICENCE : CC +''' + +import redis +import lj3 +import sys,time +import argparse + +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * + + +duration = 300 + +OSCinPort = 8006 + +Word0 = "0" +Word1 = "1" +Word2 = "2" +Word3 = "3" + +''' +is_py2 = sys.version[0] == '2' +if is_py2: + from Queue import Queue +else: + from queue import Queue +''' +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="Text Cycling for LJ") +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) + +args = argsparser.parse_args() + + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + + +if args.verbose: + debug = args.verbose +else: + debug = 0 + + +lj3.Config(redisIP,ljclient) +#r = redis.StrictRedis(host=redisIP, port=6379, db=0) + + +def OSCword0(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /words with value", value) + Word0 = value + +def OSCword1(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /words with value", value) + Word1 = value + +def OSCword2(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /words with value", value) + Word3 = value + +def OSCword3(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /words with value", value) + Word3 = value + +def OSCljclient(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /words/ljclient with value", value) + ljclient = value + lj3.LjClient(ljclient) + + +def WebStatus(message): + lj3.Send("/status",message) + + + +def Run(): + + WebStatus("Load Words") + + # OSC Server callbacks + print("Starting OSC at 127.0.0.1 port",OSCinPort,"...") + osc_startup() + osc_udp_server("127.0.0.1", OSCinPort, "InPort") + osc_method("/words/0*", OSCword0) + osc_method("/words/1*", OSCword1) + osc_method("/words/2*", OSCword2) + osc_method("/words/3*", OSCword3) + osc_method("/ping*", lj3.OSCping) + osc_method("/words/ljclient", OSCljclient) + + color = lj3.rgb2int(255,255,255) + + WebStatus("Words ready.") + + try: + + while 1: + + lj3.OSCframe() + + lj3.Text(Word0, color, PL = 0, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(0) + + lj3.Text(Word1, color, PL = 1, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(1) + + lj3.Text(Word2, color, PL = 2, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(2) + + lj3.Text(Word3, color, PL = 3, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(3) + + time.sleep(0.01) + + except KeyboardInterrupt: + pass + + # Gently stop on CTRL C + + finally: + + WebStatus("Words Exit") + print("Stopping OSC...") + lj3.OSCstop() + + print ("Words Stopped.") + + +Run() + + diff --git a/plugins/lj3.py b/plugins/lj3.py new file mode 100644 index 0000000..7716ec9 --- /dev/null +++ b/plugins/lj3.py @@ -0,0 +1,620 @@ +# coding=UTF-8 + +''' +LJ v0.8.1 in python3 +Some LJ functions useful for python clients (was framy.py) + +OSC functions commented, waiting working on OSC in python3 + +Config(redisIP, client number) +PolyLineOneColor +rPolyLineOneColor + +Text(word, color, PL, xpos, ypos, resize, rotx, roty, rotz) : Display a word +Send(adress,message) : remote control. See commands.py +WebStatus(message) : display message on webui +DrawPL(point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers. +rgb2int(r,g,b) + +OSCstart(): Start the OSC system. +OSCframe(): +OSCstop(): Properly close the OSC system +OSCping(value): Answer to LJ pings + +setup_controls(joystick) + +XboxController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger +Ps3Controller : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger, getUp, getDown, getLeft, getRight, getFire1, getFire2(self): +MySaitekController : getLeftHori,getLeftVert, getRightHori,getRightVert, getLeftTrigger,getRightTrigger +MyThrustController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger +CSLController : getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftTrigger,getRightTrigger,getFire1,getFire2 +my USB Joystick : getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2 + + +LICENCE : CC +Sam Neurohack + +''' + +import math +import redis + +# Import needed modules from osc4py3 +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * + + +redisIP = '127.0.0.1' +r = redis.StrictRedis(host=redisIP, port=6379, db=0) + +ClientNumber = 0 + +point_list = [] +pl = [[],[],[],[]] + +# +# OSC interaction with LJ +# + +def OSCstart(): + # Start the system. + osc_startup() + #osc_udp_client(redisIP, 8002, "LJ 8002") + +def OSCframe(): + #print("OSCprocess") + osc_process() + +# Properly close the system. Todo +def OSCstop(): + osc_terminate() + + +# Answer to LJ pings +def OSCping(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /ping with value", value) + Send("/pong",value) + + +def Send(oscaddress,oscargs=''): + + try: + msg = oscbuildparse.OSCMessage(oscaddress, None, [oscargs]) + osc_send(msg, "LJ 8002") + OSCframe() + + except: + print ('Connection to LJ refused : died ?') + pass +''' +def handlerfunction(s, x, y): + # Will receive message data unpacked in s, x, y + pass + +def handlerfunction2(address, s, x, y): + # Will receive message address, and message data flattened in s, x, y + pass + +# Make server channels to receive packets. +osc_udp_server("127.0.0.1", 3721, "localhost") +osc_udp_server("0.0.0.0", 3724, "anotherserver") +''' + + + +ASCII_GRAPHICS = [ + +# caracteres corrects + + [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0 + [(-20,30), (0,-30), (-20,30)], #1 + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #2 + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #3 + [(30,10), (-30,10), (0,-30), (0,30)], #4 + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #5 + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #6 + [(-30,-30), (30,-30), (-30,30)], #7 + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #8 + [(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], #9 + +# caracteres a implementer + [(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #: + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #; + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #< + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #= + [(30,10), (-30,10), (0,-30), (0,30)], #> + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #? + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #@ + +# Caracteres corrects + + + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #B + [(30,30), (-30,30), (-30,-30), (30,-30)], #C + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #D + [(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #E + [(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #F + [(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], #G + [(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], #H + [(0,30), (0,-30)], #I + [(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], #J + [(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], #K + [(30,30), (-30,30), (-30,-30)], #L + [(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], #M + [(-30,30), (-30,-30), (30,30), (30,-30)], #N + [(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #O + [(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], #P + [(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], #Q + [(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], #R + [(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], #S + [(0,30), (0,-30), (-30,-30), (30,-30)], #T + [(-30,-30), (-30,30), (30,30), (30,-30)], #U + [(-30,-30), (0,30), (30,-30)], #V + [(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], #W + [(-30,30), (30,-30)], [(-30,-30), (30,30)], #X + [(0,30), (0,0), (30,-30), (0,0), (-30,-30)], #Y + [(30,30), (-30,30), (30,-30), (-30,-30)], #Z + + # A implementer + + [(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #[ + [(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #\ + [(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #] + [(30,10), (-30,10), (0,-30), (0,30)], #^ + [(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #_ + [(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #` + + # Implementé + + [(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], #a + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], #b + [(20,20), (-20,20), (-20,-20), (20,-20)], #c + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #d + [(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #e + [(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #f + [(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], #g + [(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], #H + [(0,20), (0,-20)], #I + [(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], #J + [(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], #K + [(20,20), (-20,20), (-20,-20)], #L + [(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], #M + [(-20,20), (-20,-20), (20,20), (20,-20)], #N + [(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #O + [(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], #P + [(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], #Q + [(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], #R + [(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], #S + [(0,20), (0,-20), (-20,-20), (20,-20)], #T + [(-20,-20), (-20,20), (20,20), (20,-20)], #U + [(-20,-20), (0,20), (20,-20)], #V + [(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], #W + [(-20,20), (20,-20)], [(-20,-20), (20,20)], #X + [(0,20), (0,0), (20,-20), (0,0), (-20,-20)], #Y + [(20,20), (-20,20), (20,-20), (-20,-20)], #Z + + [(-2,15), (2,15)] # Point a la place de { +] + +def rgb2int(r,g,b): + return int('0x%02x%02x%02x' % (r,g,b),0) + + +def Config(redisIP,client): + global ClientNumber + + r = redis.StrictRedis(host=redisIP, port=6379, db=0) + ClientNumber = client + osc_udp_client(redisIP, 8002, "LJ 8002") + + +def LjClient(client): + global ClientNumber + + ClientNumber = client + + + +def LineTo(xy, c, PL): + + pl[PL].append((xy + (c,))) + +def Line(xy1, xy2, c, PL): + LineTo(xy1, 0, PL) + LineTo(xy2, c , PL) + + +def PolyLineOneColor(xy_list, c, PL , closed ): + #print "--" + #print "c",c + #print "xy_list",xy_list + #print "--" + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + #print "xy0:",xy0 + LineTo(xy0,0, PL) + LineTo(xy0,c, PL) + else: + #print "xy:",xy + LineTo(xy,c, PL) + if closed: + LineTo(xy0,c, PL) + + +# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates +def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): + + x = xy[0] * resize + y = xy[1] * resize + z = 0 + + rad = rotx * math.pi / 180 + cosaX = math.cos(rad) + sinaX = math.sin(rad) + + y2 = y + y = y2 * cosaX - z * sinaX + z = y2 * sinaX + z * cosaX + + rad = roty * math.pi / 180 + cosaY = math.cos(rad) + sinaY = math.sin(rad) + + z2 = z + z = z2 * cosaY - x * sinaY + x = z2 * sinaY + x * cosaY + + rad = rotz * math.pi / 180 + cosZ = math.cos(rad) + sinZ = math.sin(rad) + + x2 = x + x = x2 * cosZ - y * sinZ + y = x2 * sinZ + y * cosZ + + #print xy, (x + xpos,y+ ypos) + return (x + xpos,y+ ypos) + ''' + to understand why it get negative Y + + # 3D to 2D projection + factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z) + print xy, (x * factor + xpos, - y * factor + ypos ) + return (x * factor + xpos, - y * factor + ypos ) + ''' + +# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos +#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0): +def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0): + xy0 = None + for xy in xy_list: + if xy0 is None: + xy0 = xy + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL) + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + else: + LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL) + if closed: + LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL) + + +def LinesPL(PL): + print ("Stupido !! your code is to old : use DrawPL() instead of LinesPL()") + DrawPL(PL) + +def DrawPL(PL): + #print '/pl/0/'+str(PL), str(pl[PL]) + if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True: + pl[PL] = [] + return True + else: + return False + +def ResetPL(self, PL): + pl[PL] = [] + + + +def DigitsDots(number,color): + dots =[] + for dot in ASCII_GRAPHICS[number]: + #print dot + dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color)) + #self.point_list.append((xy + (c,))) + return dots + +def CharDots(char,color): + + dots =[] + for dot in ASCII_GRAPHICS[ord(char)-46]: + dots.append((dot[0],dot[1],color)) + return dots + +def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): + + dots =[] + + l = len(message) + i= 0 + #print message + + for ch in message: + + #print "" + # texte centre en x automatiquement selon le nombre de lettres l + x_offset = 26 * (- (0.9*l) + 3*i) + #print i,x_offset + # if digit + if ord(ch)<58: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 48] + else: + char_pl_list = ASCII_GRAPHICS[ord(ch) - 46 ] + + char_draw = [] + #dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0)) + + for xy in char_pl_list: + char_draw.append((xy[0] + x_offset,xy[1],c)) + i +=1 + #print ch,char_pl_list,char_draw + rPolyLineOneColor(char_draw, c, PL , False, xpos, ypos, resize, rotx, roty, rotz) + #print ("laser",PL,"message",message) + #dots.append(char_draw) + + + +import re + +def setup_controls(joystick): + """ + Joystick wrapper. + """ + if re.search('playstation', joystick.get_name(), re.I): + return Ps3Controller(joystick) + + elif re.search('X-box', joystick.get_name(), re.I): + return XboxController(joystick) + + elif re.search('Saitek', joystick.get_name(), re.I): + return MySaitekController(joystick) + + elif re.search('Thrustmaster dual analog 3.2', joystick.get_name(), re.I): + return MyThrustController(joystick) + + elif re.search('2n1 USB', joystick.get_name(), re.I): + return CSLController(joystick) + + elif re.search('Joystick', joystick.get_name(), re.I): + return USBController(joystick) + + return Controller(joystick) + +class Controller(object): + + def __init__(self, joystick): + """Pass a PyGame joystick instance.""" + self.js = joystick + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(9) + + def getRightTrigger(self): + return self.js.get_button(2) + +class XboxController(Controller): + + def __init__(self, joystick): + super(XboxController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(4) + + def getLeftTrigger(self): + return self.js.get_axis(2) + + def getRightTrigger(self): + return self.js.get_button(11) + +class Ps3Controller(Controller): + +#up 4 _DOWN 6 left 7 right 5 croix 14 rond 13 triangle 12 + + def __init__(self, joystick): + super(Ps3Controller, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + # TODO: Verify + return self.js.get_button(8) + + def getRightTrigger(self): + # TODO: Verify + return self.js.get_button(9) + + def getUp(self): + return self.js.get_button(4) + + def getDown(self): + return self.js.get_button(6) + + def getLeft(self): + return self.js.get_button(7) + + def getRight(self): + return self.js.get_button(5) + + def getFire1(self): + return self.js.get_button(14) + + def getFire2(self): + return self.js.get_button(13) + + +class MySaitekController(Controller): + + def __init__(self, joystick): + super(MySaitekController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(3) + + def getRightVert(self): + return self.js.get_axis(2) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + +class MyThrustController(Controller): + + def __init__(self, joystick): + super(MyThrustController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(0) + + def getLeftVert(self): + return self.js.get_axis(1) + + def getRightHori(self): + return self.js.get_axis(2) + + def getRightVert(self): + return self.js.get_axis(3) + + def getLeftTrigger(self): + return self.js.get_button(5) + + def getRightTrigger(self): + return self.js.get_button(7) + + +class CSLController(Controller): + + def __init__(self, joystick): + super(CSLController, self).__init__(joystick) + + def getLeftHori(self): + return self.js.get_axis(2) + + def getLeftVert(self): + return self.js.get_axis(3) + + def getRightHori(self): + return self.js.get_axis(0) + + def getRightVert(self): + return self.js.get_axis(1) + + def getLeftTrigger(self): + return self.js.get_button(6) + + def getRightTrigger(self): + return self.js.get_button(7) + + def getFire1(self): + return self.js.get_button(2) + + def getFire2(self): + return self.js.get_button(1) + +class USBController(Controller): + + +# my USB Joystick +#up axis 0 -1 DOWN axis 0 1 left axis 1 1 right axis 1 -1 bouton gauche 10 bouton droite 9 + + def __init__(self, joystick): + super(USBController, self).__init__(joystick) + + + def getUp(self): + if self.js.get_axis(0) == -1: + return 1 + else: + return 0 + + def getDown(self): + if self.js.get_axis(0) > 0.9: + return 1 + else: + return 0 + + def getLeft(self): + if self.js.get_axis(1) == 1: + return 1 + else: + return 0 + + def getRight(self): + if self.js.get_axis(1) == -1: + return 1 + else: + return 0 + + def getLeftTrigger(self): + return self.js.get_button(10) + + def getRightTrigger(self): + return self.js.get_button(9) + + def getFire1(self): + if self.js.get_button(10) == 1: + print ("fire 1") + return self.js.get_button(10) + + def getFire2(self): + if self.js.get_button(9) == 1: + print ("fire 2") + return self.js.get_button(9) + + + + diff --git a/clients/planetarium/Readme.txt b/plugins/planetarium/Readme.txt similarity index 100% rename from clients/planetarium/Readme.txt rename to plugins/planetarium/Readme.txt diff --git a/plugins/planetarium/data/boundaries2.txt b/plugins/planetarium/data/boundaries2.txt new file mode 100644 index 0000000..f0c4fea --- /dev/null +++ b/plugins/planetarium/data/boundaries2.txt @@ -0,0 +1,89 @@ +AND coordinates [['343.0', '34.5'], ['343.0', '52.5'], ['350.0', '52.5'], ['350.0', '50.0'], ['353.75', '50.0'], ['353.75', '48.0'], ['2.5', '48.0'], ['2.5', '46.0'], ['13.0', '46.0'], ['13.0', '48.0'], ['16.75', '48.0'], ['16.75', '50.0'], ['20.5', '50.0'], ['25.0', '50.0'], ['25.0', '47.0'], ['30.625', '47.0'], ['30.625', '50.5'], ['37.75', '50.5'], ['37.75', '36.75'], ['30.0', '36.75'], ['30.0', '35.0'], ['21.125', '35.0'], ['21.125', '33.0'], ['10.75', '33.0'], ['10.75', '23.75'], ['12.75', '23.75'], ['12.75', '21.0'], ['2.125', '21.0'], ['2.125', '22.0'], ['1.0', '22.0'], ['1.0', '28.0'], ['0.0', '28.0'], ['0.0', '31.333333333333332'], ['356.25', '31.333333333333332'], ['356.25', '32.083333333333336'], ['352.5', '32.083333333333336'], ['352.5', '34.5']] +ANT coordinates [['140.5', '-24.0'], ['146.25', '-24.0'], ['146.25', '-25.5'], ['153.75', '-25.5'], ['153.75', '-28.833333333333332'], ['158.75', '-28.833333333333332'], ['158.75', '-30.833333333333332'], ['162.5', '-30.833333333333332'], ['162.5', '-35.0'], ['165.0', '-35.0'], ['165.0', '-38.25'], ['140.5', '-38.25'], ['140.5', '-35.25']] +APS coordinates [['205.0', '-81.5'], ['205.0', '-75.0'], ['205.0', '-70.0'], ['221.25', '-70.0'], ['255.0', '-70.0'], ['255.0', '-66.5'], ['262.5', '-66.5'], ['270.0', '-66.5'], ['270.0', '-75.0'], ['270.0', '-81.5']] +AQL coordinates [['278.75', '0.0'], ['278.75', '2.0'], ['283.0', '2.0'], ['283.0', '6.25'], ['279.93333333333334', '6.25'], ['279.93333333333334', '12.0'], ['283.0', '12.0'], ['283.0', '18.5'], ['285.0', '18.5'], ['285.0', '16.166666666666668'], ['297.5', '16.166666666666668'], ['297.5', '15.75'], ['302.125', '15.75'], ['302.125', '8.5'], ['304.5', '8.5'], ['304.5', '2.0'], ['308.0', '2.0'], ['308.0', '0.0'], ['308.0', '-9.0'], ['300.0', '-9.0'], ['300.0', '-11.966666666666667'], ['283.0', '-11.966666666666667'], ['283.0', '-4.0'], ['278.75', '-4.0']] +AQR coordinates [['308.0', '0.0'], ['308.0', '2.0'], ['312.5', '2.0'], ['320.0', '2.0'], ['322.0', '2.0'], ['322.0', '2.75'], ['325.0', '2.75'], ['325.0', '1.75'], ['330.0', '1.75'], ['330.0', '2.0'], ['341.25', '2.0'], ['341.25', '0.0'], ['341.25', '-4.0'], ['357.5', '-4.0'], ['357.5', '-7.0'], ['357.5', '-24.5'], ['345.0', '-24.5'], ['328.0', '-24.5'], ['328.0', '-9.0'], ['320.0', '-9.0'], ['320.0', '-15.0'], ['308.0', '-15.0'], ['308.0', '-9.0']] +ARA coordinates [['246.3125', '-60.0'], ['246.3125', '-44.5'], ['267.5', '-44.5'], ['270.0', '-44.5'], ['270.0', '-57.0'], ['262.5', '-57.0'], ['262.5', '-66.5'], ['255.0', '-66.5'], ['252.5', '-66.5'], ['252.5', '-65.0'], ['251.25', '-65.0'], ['251.25', '-62.416666666666664'], ['248.75', '-62.416666666666664'], ['248.75', '-61.0'], ['246.3125', '-61.0']] +ARI coordinates [['30.0', '9.916666666666666'], ['25.0', '9.916666666666666'], ['25.0', '25.0'], ['28.75', '25.0'], ['28.75', '27.25'], ['36.25', '27.25'], ['36.25', '30.666666666666668'], ['40.75', '30.666666666666668'], ['50.5', '30.666666666666668'], ['50.5', '19.0'], ['49.25', '19.0'], ['49.25', '9.916666666666666']] +AUR coordinates [['67.5', '30.666666666666668'], ['67.5', '36.0'], ['70.375', '36.0'], ['70.375', '52.5'], ['75.0', '52.5'], ['75.0', '56.0'], ['91.5', '56.0'], ['91.5', '54.0'], ['97.5', '54.0'], ['97.5', '50.0'], ['102.0', '50.0'], ['102.0', '44.5'], ['110.5', '44.5'], ['110.5', '35.5'], ['98.0', '35.5'], ['98.0', '28.0'], ['88.25', '28.0'], ['88.25', '28.5'], ['71.25', '28.5'], ['71.25', '30.0'], ['67.5', '30.0']] +BOO coordinates [['226.25', '8.0'], ['202.5', '8.0'], ['202.5', '15.0'], ['202.5', '28.5'], ['209.375', '28.5'], ['209.375', '30.75'], ['210.5', '30.75'], ['210.5', '48.5'], ['210.5', '55.5'], ['216.25', '55.5'], ['228.75', '55.5'], ['228.75', '53.0'], ['236.25', '53.0'], ['236.25', '51.5'], ['236.25', '40.0'], ['231.5', '40.0'], ['231.5', '33.0'], ['227.75', '33.0'], ['227.75', '26.0'], ['226.25', '26.0']] +CAE coordinates [['64.0', '-40.0'], ['64.0', '-37.0'], ['68.75', '-37.0'], ['68.75', '-30.0'], ['70.5', '-30.0'], ['70.5', '-26.75'], ['72.5', '-26.75'], ['75.0', '-26.75'], ['75.0', '-43.0'], ['72.5', '-43.0'], ['72.5', '-45.5'], ['67.5', '-45.5'], ['67.5', '-49.0'], ['64.0', '-49.0']] +CAM coordinates [['91.5', '56.0'], ['75.0', '56.0'], ['75.0', '52.5'], ['70.375', '52.5'], ['50.0', '52.5'], ['50.0', '55.0'], ['47.5', '55.0'], ['47.5', '57.0'], ['46.5', '57.0'], ['46.5', '68.0'], ['51.25', '68.0'], ['51.25', '77.0'], ['52.625', '77.0'], ['52.625', '80.0'], ['75.0', '80.0'], ['75.0', '85.0'], ['120.0', '85.0'], ['120.0', '86.5'], ['217.5', '86.5'], ['217.5', '80.0'], ['203.75', '80.0'], ['203.75', '77.0'], ['195.0', '77.0'], ['172.5', '77.0'], ['172.5', '80.0'], ['160.0', '80.0'], ['160.0', '82.0'], ['137.5', '82.0'], ['137.5', '73.5'], ['119.5', '73.5'], ['119.5', '60.0'], ['105.0', '60.0'], ['105.0', '62.0'], ['91.5', '62.0']] +CAP coordinates [['308.0', '-9.0'], ['308.0', '-15.0'], ['320.0', '-15.0'], ['320.0', '-9.0'], ['328.0', '-9.0'], ['328.0', '-24.5'], ['320.0', '-24.5'], ['320.0', '-28.0'], ['305.0', '-28.0'], ['300.0', '-28.0'], ['300.0', '-11.966666666666667'], ['300.0', '-9.0']] +CAR coordinates [['168.75', '-55.5'], ['168.75', '-64.0'], ['168.75', '-75.0'], ['135.5', '-75.0'], ['135.5', '-64.0'], ['102.5', '-64.0'], ['102.5', '-58.0'], ['97.5', '-58.0'], ['97.5', '-55.0'], ['92.5', '-55.0'], ['92.5', '-51.5'], ['90.0', '-51.5'], ['90.0', '-49.25'], ['120.0', '-49.25'], ['122.5', '-49.25'], ['122.5', '-53.0'], ['126.75', '-53.0'], ['126.75', '-53.5'], ['132.5', '-53.5'], ['132.5', '-55.5'], ['165.0', '-55.5']] +CAS coordinates [['343.0', '52.5'], ['343.0', '56.25'], ['343.0', '59.083333333333336'], ['347.5', '59.083333333333336'], ['347.5', '63.0'], ['353.75', '63.0'], ['353.75', '66.0'], ['5.0', '66.0'], ['5.0', '77.0'], ['51.25', '77.0'], ['51.25', '68.0'], ['46.5', '68.0'], ['46.5', '57.0'], ['36.5', '57.0'], ['36.5', '58.5'], ['28.625', '58.5'], ['28.625', '57.5'], ['25.5', '57.5'], ['25.5', '54.0'], ['20.5', '54.0'], ['20.5', '50.0'], ['16.75', '50.0'], ['16.75', '48.0'], ['13.0', '48.0'], ['13.0', '46.0'], ['2.5', '46.0'], ['2.5', '48.0'], ['353.75', '48.0'], ['353.75', '50.0'], ['350.0', '50.0'], ['350.0', '52.5']] +CEN coordinates [['165.0', '-35.0'], ['183.75', '-35.0'], ['183.75', '-33.0'], ['188.75', '-33.0'], ['188.75', '-28.5'], ['223.75', '-28.5'], ['223.75', '-42.0'], ['212.5', '-42.0'], ['212.5', '-55.0'], ['218.0', '-55.0'], ['218.0', '-64.0'], ['202.5', '-64.0'], ['192.5', '-64.0'], ['192.5', '-55.0'], ['177.5', '-55.0'], ['177.5', '-64.0'], ['168.75', '-64.0'], ['168.75', '-55.5'], ['165.0', '-55.5'], ['165.0', '-38.25']] +CEP coordinates [['300.0', '59.5'], ['300.0', '61.5'], ['306.25', '61.5'], ['306.25', '67.0'], ['310.0', '67.0'], ['310.0', '75.0'], ['302.5', '75.0'], ['302.5', '80.0'], ['315.0', '80.0'], ['315.0', '86.0'], ['315.0', '86.16666666666667'], ['345.0', '86.16666666666667'], ['345.0', '88.0'], ['120.0', '88.0'], ['120.0', '86.5'], ['120.0', '85.0'], ['75.0', '85.0'], ['75.0', '80.0'], ['52.625', '80.0'], ['52.625', '77.0'], ['51.25', '77.0'], ['5.0', '77.0'], ['5.0', '66.0'], ['353.75', '66.0'], ['353.75', '63.0'], ['347.5', '63.0'], ['347.5', '59.083333333333336'], ['343.0', '59.083333333333336'], ['343.0', '56.25'], ['334.75', '56.25'], ['334.75', '55.0'], ['332.0', '55.0'], ['332.0', '52.75'], ['329.5', '52.75'], ['329.5', '54.833333333333336'], ['309.0', '54.833333333333336'], ['309.0', '60.916666666666664'], ['308.05', '60.916666666666664'], ['308.05', '59.5']] +CET coordinates [['5.0', '0.0'], ['5.0', '2.0'], ['30.0', '2.0'], ['30.0', '9.916666666666666'], ['49.25', '9.916666666666666'], ['49.25', '0.0'], ['49.25', '-0.25'], ['39.75', '-0.25'], ['39.75', '-23.616666666666667'], ['25.0', '-23.616666666666667'], ['25.0', '-24.5'], ['357.5', '-24.5'], ['357.5', '-7.0'], ['5.0', '-7.0']] +CHA coordinates [['115.0', '-81.5'], ['115.0', '-75.0'], ['135.5', '-75.0'], ['168.75', '-75.0'], ['205.0', '-75.0'], ['205.0', '-81.5']] +CIR coordinates [['202.5', '-64.0'], ['218.0', '-64.0'], ['218.0', '-55.0'], ['225.75', '-55.0'], ['230.0', '-55.0'], ['230.0', '-60.0'], ['230.0', '-61.0'], ['227.5', '-61.0'], ['227.5', '-62.416666666666664'], ['223.75', '-62.416666666666664'], ['223.75', '-66.5'], ['221.25', '-66.5'], ['221.25', '-70.0'], ['205.0', '-70.0'], ['205.0', '-65.0'], ['202.5', '-65.0']] +CMA coordinates [['91.75', '-11.0'], ['110.5', '-11.0'], ['110.5', '-33.0'], ['98.75', '-33.0'], ['91.75', '-33.0'], ['91.75', '-26.75']] +CMI coordinates [['121.25', '0.0'], ['108.0', '0.0'], ['108.0', '1.5'], ['105.25', '1.5'], ['105.25', '5.5'], ['105.0', '5.5'], ['105.0', '10.0'], ['105.0', '12.5'], ['112.5', '12.5'], ['112.5', '13.5'], ['117.125', '13.5'], ['117.125', '10.0'], ['118.875', '10.0'], ['118.875', '7.0'], ['121.25', '7.0']] +CNC coordinates [['138.75', '7.0'], ['121.25', '7.0'], ['118.875', '7.0'], ['118.875', '10.0'], ['117.125', '10.0'], ['117.125', '13.5'], ['117.125', '20.0'], ['118.25', '20.0'], ['118.25', '28.0'], ['120.0', '28.0'], ['120.0', '33.5'], ['138.75', '33.5']] +COL coordinates [['75.0', '-43.0'], ['75.0', '-26.75'], ['91.75', '-26.75'], ['91.75', '-33.0'], ['98.75', '-33.0'], ['98.75', '-43.0'], ['90.0', '-43.0']] +COM coordinates [['178.0', '14.0'], ['178.0', '29.0'], ['180.0', '29.0'], ['180.0', '34.0'], ['185.0', '34.0'], ['185.0', '32.0'], ['198.75', '32.0'], ['198.75', '28.5'], ['202.5', '28.5'], ['202.5', '15.0'], ['192.5', '15.0'], ['192.5', '14.0']] +CRA coordinates [['267.5', '-37.0'], ['287.5', '-37.0'], ['287.5', '-44.5'], ['270.0', '-44.5'], ['267.5', '-44.5']] +CRB coordinates [['227.75', '26.0'], ['227.75', '33.0'], ['231.5', '33.0'], ['231.5', '40.0'], ['236.25', '40.0'], ['245.0', '40.0'], ['245.0', '27.0'], ['242.5', '27.0'], ['242.5', '26.0'], ['240.5', '26.0']] +CRT coordinates [['161.25', '-6.0'], ['172.75', '-6.0'], ['177.5', '-6.0'], ['177.5', '-11.0'], ['177.5', '-23.5'], ['162.5', '-23.5'], ['162.5', '-19.0'], ['161.25', '-19.0'], ['161.25', '-11.0']] +CRU coordinates [['177.5', '-55.0'], ['192.5', '-55.0'], ['192.5', '-64.0'], ['177.5', '-64.0']] +CRV coordinates [['192.5', '-11.0'], ['192.5', '-22.0'], ['188.75', '-22.0'], ['188.75', '-23.5'], ['177.5', '-23.5'], ['177.5', '-11.0']] +CVN coordinates [['180.0', '34.0'], ['180.0', '45.0'], ['181.25', '45.0'], ['181.25', '53.0'], ['202.5', '53.0'], ['202.5', '48.5'], ['210.5', '48.5'], ['210.5', '30.75'], ['209.375', '30.75'], ['209.375', '28.5'], ['202.5', '28.5'], ['198.75', '28.5'], ['198.75', '32.0'], ['185.0', '32.0'], ['185.0', '34.0']] +CYG coordinates [['288.875', '27.5'], ['288.875', '30.0'], ['290.375', '30.0'], ['290.375', '36.5'], ['291.0', '36.5'], ['291.0', '43.5'], ['287.5', '43.5'], ['287.5', '47.5'], ['286.25', '47.5'], ['286.25', '55.5'], ['291.25', '55.5'], ['291.25', '58.0'], ['296.5', '58.0'], ['296.5', '59.5'], ['300.0', '59.5'], ['308.05', '59.5'], ['308.05', '60.916666666666664'], ['309.0', '60.916666666666664'], ['309.0', '54.833333333333336'], ['329.5', '54.833333333333336'], ['329.5', '52.75'], ['329.5', '44.0'], ['328.625', '44.0'], ['328.625', '43.75'], ['328.125', '43.75'], ['328.125', '36.0'], ['326.0', '36.0'], ['326.0', '28.0'], ['321.25', '28.0'], ['313.75', '28.0'], ['313.75', '29.0'], ['295.0', '29.0'], ['295.0', '27.5']] +DEL coordinates [['308.0', '2.0'], ['304.5', '2.0'], ['304.5', '8.5'], ['302.125', '8.5'], ['302.125', '15.75'], ['303.75', '15.75'], ['303.75', '20.5'], ['308.5', '20.5'], ['308.5', '19.5'], ['315.75', '19.5'], ['315.75', '11.833333333333334'], ['313.125', '11.833333333333334'], ['313.125', '6.0'], ['312.5', '6.0'], ['312.5', '2.0']] +DOR coordinates [['57.5', '-52.833333333333336'], ['57.5', '-51.0'], ['61.25', '-51.0'], ['61.25', '-49.0'], ['64.0', '-49.0'], ['67.5', '-49.0'], ['67.5', '-54.0'], ['75.0', '-54.0'], ['75.0', '-56.5'], ['82.5', '-56.5'], ['82.5', '-61.0'], ['90.0', '-61.0'], ['90.0', '-64.0'], ['98.75', '-64.0'], ['98.75', '-70.0'], ['68.75', '-70.0'], ['68.75', '-66.5'], ['68.75', '-59.0'], ['65.0', '-59.0'], ['65.0', '-55.5'], ['60.0', '-55.5'], ['60.0', '-52.833333333333336']] +DRA coordinates [['137.5', '73.5'], ['137.5', '82.0'], ['160.0', '82.0'], ['160.0', '80.0'], ['172.5', '80.0'], ['172.5', '77.0'], ['195.0', '77.0'], ['195.0', '70.0'], ['210.0', '70.0'], ['210.0', '66.0'], ['235.0', '66.0'], ['235.0', '70.0'], ['248.0', '70.0'], ['248.0', '75.0'], ['262.5', '75.0'], ['262.5', '80.0'], ['270.0', '80.0'], ['270.0', '86.0'], ['315.0', '86.0'], ['315.0', '80.0'], ['302.5', '80.0'], ['302.5', '75.0'], ['310.0', '75.0'], ['310.0', '67.0'], ['306.25', '67.0'], ['306.25', '61.5'], ['300.0', '61.5'], ['300.0', '59.5'], ['296.5', '59.5'], ['296.5', '58.0'], ['291.25', '58.0'], ['291.25', '55.5'], ['286.25', '55.5'], ['286.25', '47.5'], ['273.5', '47.5'], ['273.5', '50.5'], ['255.0', '50.5'], ['255.0', '51.5'], ['236.25', '51.5'], ['236.25', '53.0'], ['228.75', '53.0'], ['228.75', '55.5'], ['216.25', '55.5'], ['216.25', '63.0'], ['202.5', '63.0'], ['202.5', '64.0'], ['180.0', '64.0'], ['180.0', '66.5'], ['170.0', '66.5'], ['170.0', '73.5']] +EQU coordinates [['312.5', '2.0'], ['312.5', '6.0'], ['313.125', '6.0'], ['313.125', '11.833333333333334'], ['315.75', '11.833333333333334'], ['316.75', '11.833333333333334'], ['316.75', '12.5'], ['320.0', '12.5'], ['320.0', '2.0']] +ERI coordinates [['53.75', '0.0'], ['69.25', '0.0'], ['70.0', '0.0'], ['70.0', '-4.0'], ['76.25', '-4.0'], ['76.25', '-11.0'], ['73.75', '-11.0'], ['73.75', '-13.5'], ['72.5', '-13.5'], ['72.5', '-26.75'], ['70.5', '-26.75'], ['70.5', '-30.0'], ['68.75', '-30.0'], ['68.75', '-37.0'], ['64.0', '-37.0'], ['64.0', '-40.0'], ['58.0', '-40.0'], ['58.0', '-44.0'], ['51.25', '-44.0'], ['51.25', '-46.0'], ['45.0', '-46.0'], ['45.0', '-49.0'], ['40.0', '-49.0'], ['40.0', '-51.0'], ['36.25', '-51.0'], ['36.25', '-54.0'], ['32.5', '-54.0'], ['32.5', '-57.5'], ['20.0', '-57.5'], ['20.0', '-52.5'], ['23.75', '-52.5'], ['23.75', '-50.5'], ['27.5', '-50.5'], ['27.5', '-47.833333333333336'], ['35.0', '-47.833333333333336'], ['35.0', '-40.0'], ['45.0', '-40.0'], ['45.0', '-38.416666666666664'], ['52.5', '-38.416666666666664'], ['52.5', '-36.0'], ['56.25', '-36.0'], ['56.25', '-23.616666666666667'], ['39.75', '-23.616666666666667'], ['39.75', '-0.25'], ['49.25', '-0.25'], ['53.75', '-0.25']] +FOR coordinates [['25.0', '-23.616666666666667'], ['39.75', '-23.616666666666667'], ['56.25', '-23.616666666666667'], ['56.25', '-36.0'], ['52.5', '-36.0'], ['52.5', '-38.416666666666664'], ['45.0', '-38.416666666666664'], ['45.0', '-40.0'], ['35.0', '-40.0'], ['25.0', '-40.0'], ['25.0', '-24.5']] +GEM coordinates [['94.625', '12.0'], ['94.625', '17.5'], ['93.25', '17.5'], ['93.25', '21.5'], ['88.25', '21.5'], ['88.25', '22.833333333333332'], ['88.25', '28.0'], ['98.0', '28.0'], ['98.0', '35.5'], ['110.5', '35.5'], ['116.25', '35.5'], ['116.25', '33.5'], ['120.0', '33.5'], ['120.0', '28.0'], ['118.25', '28.0'], ['118.25', '20.0'], ['117.125', '20.0'], ['117.125', '13.5'], ['112.5', '13.5'], ['112.5', '12.5'], ['105.0', '12.5'], ['105.0', '10.0'], ['104.0', '10.0'], ['104.0', '12.0']] +GRU coordinates [['320.0', '-37.0'], ['345.0', '-37.0'], ['350.0', '-37.0'], ['350.0', '-40.0'], ['350.0', '-57.0'], ['330.0', '-57.0'], ['330.0', '-50.0'], ['320.0', '-50.0'], ['320.0', '-44.5']] +HER coordinates [['244.0', '4.0'], ['241.25', '4.0'], ['241.25', '16.0'], ['238.75', '16.0'], ['238.75', '22.0'], ['240.5', '22.0'], ['240.5', '26.0'], ['242.5', '26.0'], ['242.5', '27.0'], ['245.0', '27.0'], ['245.0', '40.0'], ['236.25', '40.0'], ['236.25', '51.5'], ['255.0', '51.5'], ['255.0', '50.5'], ['273.5', '50.5'], ['273.5', '47.5'], ['272.625', '47.5'], ['272.625', '30.0'], ['275.5', '30.0'], ['275.5', '26.0'], ['283.0', '26.0'], ['283.0', '25.5'], ['283.0', '21.083333333333332'], ['283.0', '18.5'], ['283.0', '12.0'], ['279.93333333333334', '12.0'], ['273.75', '12.0'], ['273.75', '14.333333333333334'], ['258.75', '14.333333333333334'], ['258.75', '12.833333333333334'], ['251.25', '12.833333333333334'], ['251.25', '4.0']] +HOR coordinates [['64.0', '-40.0'], ['64.0', '-49.0'], ['61.25', '-49.0'], ['61.25', '-51.0'], ['57.5', '-51.0'], ['57.5', '-52.833333333333336'], ['52.5', '-52.833333333333336'], ['52.5', '-56.5'], ['48.0', '-56.5'], ['48.0', '-66.5'], ['32.5', '-66.5'], ['32.5', '-57.5'], ['32.5', '-54.0'], ['36.25', '-54.0'], ['36.25', '-51.0'], ['40.0', '-51.0'], ['40.0', '-49.0'], ['45.0', '-49.0'], ['45.0', '-46.0'], ['51.25', '-46.0'], ['51.25', '-44.0'], ['58.0', '-44.0'], ['58.0', '-40.0']] +HYA coordinates [['121.25', '0.0'], ['121.25', '7.0'], ['138.75', '7.0'], ['143.75', '7.0'], ['143.75', '0.0'], ['143.75', '-11.0'], ['161.25', '-11.0'], ['161.25', '-19.0'], ['162.5', '-19.0'], ['162.5', '-23.5'], ['177.5', '-23.5'], ['188.75', '-23.5'], ['188.75', '-22.0'], ['192.5', '-22.0'], ['213.75', '-22.0'], ['213.75', '-23.5'], ['223.75', '-23.5'], ['223.75', '-28.5'], ['188.75', '-28.5'], ['188.75', '-33.0'], ['183.75', '-33.0'], ['183.75', '-35.0'], ['165.0', '-35.0'], ['162.5', '-35.0'], ['162.5', '-30.833333333333332'], ['158.75', '-30.833333333333332'], ['158.75', '-28.833333333333332'], ['153.75', '-28.833333333333332'], ['153.75', '-25.5'], ['146.25', '-25.5'], ['146.25', '-24.0'], ['140.5', '-24.0'], ['136.25', '-24.0'], ['136.25', '-19.0'], ['128.75', '-19.0'], ['128.75', '-17.0'], ['125.5', '-17.0'], ['125.5', '-11.0'], ['121.25', '-11.0']] +HYI coordinates [['68.75', '-66.5'], ['68.75', '-70.0'], ['68.75', '-75.0'], ['52.5', '-75.0'], ['52.5', '-81.5'], ['0.0', '-81.5'], ['0.0', '-75.0'], ['11.25', '-75.0'], ['11.25', '-76.0'], ['20.0', '-76.0'], ['20.0', '-57.5'], ['32.5', '-57.5'], ['32.5', '-66.5'], ['48.0', '-66.5']] +IND coordinates [['320.0', '-75.0'], ['320.0', '-60.0'], ['305.0', '-60.0'], ['305.0', '-57.0'], ['305.0', '-44.5'], ['320.0', '-44.5'], ['320.0', '-50.0'], ['330.0', '-50.0'], ['330.0', '-57.0'], ['330.0', '-66.5'], ['350.0', '-66.5'], ['350.0', '-75.0']] +LAC coordinates [['328.125', '36.0'], ['328.125', '43.75'], ['328.625', '43.75'], ['328.625', '44.0'], ['329.5', '44.0'], ['329.5', '52.75'], ['332.0', '52.75'], ['332.0', '55.0'], ['334.75', '55.0'], ['334.75', '56.25'], ['343.0', '56.25'], ['343.0', '52.5'], ['343.0', '34.5'], ['342.25', '34.5'], ['342.25', '35.0'], ['330.0', '35.0'], ['330.0', '36.0']] +LEO coordinates [['161.25', '0.0'], ['161.25', '7.0'], ['143.75', '7.0'], ['138.75', '7.0'], ['138.75', '33.5'], ['148.25', '33.5'], ['148.25', '28.5'], ['157.5', '28.5'], ['157.5', '23.5'], ['161.25', '23.5'], ['161.25', '25.5'], ['165.0', '25.5'], ['165.0', '29.0'], ['178.0', '29.0'], ['178.0', '14.0'], ['178.0', '11.0'], ['172.75', '11.0'], ['172.75', '0.0'], ['172.75', '-6.0'], ['161.25', '-6.0']] +LEP coordinates [['72.5', '-26.75'], ['72.5', '-13.5'], ['73.75', '-13.5'], ['73.75', '-11.0'], ['76.25', '-11.0'], ['87.5', '-11.0'], ['91.75', '-11.0'], ['91.75', '-26.75'], ['75.0', '-26.75']] +LIB coordinates [['226.25', '0.0'], ['226.25', '-2.75'], ['238.75', '-2.75'], ['238.75', '-8.0'], ['238.75', '-20.0'], ['235.0', '-20.0'], ['235.0', '-28.5'], ['223.75', '-28.5'], ['223.75', '-23.5'], ['213.75', '-23.5'], ['213.75', '-22.0'], ['213.75', '-8.0'], ['220.0', '-8.0'], ['220.0', '0.0']] +LMI coordinates [['138.75', '33.5'], ['138.75', '39.75'], ['143.75', '39.75'], ['143.75', '42.0'], ['152.5', '42.0'], ['152.5', '40.0'], ['161.75', '40.0'], ['161.75', '34.0'], ['165.0', '34.0'], ['165.0', '29.0'], ['165.0', '25.5'], ['161.25', '25.5'], ['161.25', '23.5'], ['157.5', '23.5'], ['157.5', '28.5'], ['148.25', '28.5'], ['148.25', '33.5']] +LUP coordinates [['212.5', '-55.0'], ['212.5', '-42.0'], ['223.75', '-42.0'], ['223.75', '-28.5'], ['235.0', '-28.5'], ['240.0', '-28.5'], ['240.0', '-42.0'], ['235.0', '-42.0'], ['235.0', '-48.0'], ['230.0', '-48.0'], ['230.0', '-54.0'], ['225.75', '-54.0'], ['225.75', '-55.0'], ['218.0', '-55.0']] +LYN coordinates [['110.5', '35.5'], ['110.5', '44.5'], ['102.0', '44.5'], ['102.0', '50.0'], ['97.5', '50.0'], ['97.5', '54.0'], ['91.5', '54.0'], ['91.5', '56.0'], ['91.5', '62.0'], ['105.0', '62.0'], ['105.0', '60.0'], ['119.5', '60.0'], ['126.25', '60.0'], ['126.25', '47.0'], ['137.5', '47.0'], ['137.5', '42.0'], ['143.75', '42.0'], ['143.75', '39.75'], ['138.75', '39.75'], ['138.75', '33.5'], ['120.0', '33.5'], ['116.25', '33.5'], ['116.25', '35.5']] +LYR coordinates [['283.0', '25.5'], ['283.0', '26.0'], ['275.5', '26.0'], ['275.5', '30.0'], ['272.625', '30.0'], ['272.625', '47.5'], ['273.5', '47.5'], ['286.25', '47.5'], ['287.5', '47.5'], ['287.5', '43.5'], ['291.0', '43.5'], ['291.0', '36.5'], ['290.375', '36.5'], ['290.375', '30.0'], ['288.875', '30.0'], ['288.875', '27.5'], ['288.875', '25.5']] +MEN coordinates [['115.0', '-85.0'], ['52.5', '-85.0'], ['52.5', '-81.5'], ['52.5', '-75.0'], ['68.75', '-75.0'], ['68.75', '-70.0'], ['98.75', '-70.0'], ['98.75', '-75.0'], ['115.0', '-75.0'], ['115.0', '-81.5']] +MIC coordinates [['305.0', '-28.0'], ['320.0', '-28.0'], ['320.0', '-37.0'], ['320.0', '-44.5'], ['305.0', '-44.5']] +MON coordinates [['93.625', '0.0'], ['93.625', '10.0'], ['94.625', '10.0'], ['94.625', '12.0'], ['104.0', '12.0'], ['104.0', '10.0'], ['105.0', '10.0'], ['105.0', '5.5'], ['105.25', '5.5'], ['105.25', '1.5'], ['108.0', '1.5'], ['108.0', '0.0'], ['121.25', '0.0'], ['121.25', '-11.0'], ['110.5', '-11.0'], ['91.75', '-11.0'], ['87.5', '-11.0'], ['87.5', '-4.0'], ['93.625', '-4.0']] +MUS coordinates [['168.75', '-64.0'], ['177.5', '-64.0'], ['192.5', '-64.0'], ['202.5', '-64.0'], ['202.5', '-65.0'], ['205.0', '-65.0'], ['205.0', '-70.0'], ['205.0', '-75.0'], ['168.75', '-75.0']] +NOR coordinates [['230.0', '-60.0'], ['230.0', '-55.0'], ['225.75', '-55.0'], ['225.75', '-54.0'], ['230.0', '-54.0'], ['230.0', '-48.0'], ['235.0', '-48.0'], ['235.0', '-42.0'], ['240.0', '-42.0'], ['246.3125', '-42.0'], ['246.3125', '-44.5'], ['246.3125', '-60.0']] +OCT coordinates [['0.0', '-75.0'], ['0.0', '-81.5'], ['52.5', '-81.5'], ['52.5', '-85.0'], ['115.0', '-85.0'], ['115.0', '-81.5'], ['205.0', '-81.5'], ['270.0', '-81.5'], ['270.0', '-75.0'], ['320.0', '-75.0'], ['350.0', '-75.0']] +OPH coordinates [['244.0', '0.0'], ['244.0', '4.0'], ['251.25', '4.0'], ['251.25', '12.833333333333334'], ['258.75', '12.833333333333334'], ['258.75', '14.333333333333334'], ['273.75', '14.333333333333334'], ['273.75', '12.0'], ['279.93333333333334', '12.0'], ['279.93333333333334', '6.25'], ['273.75', '6.25'], ['273.75', '4.5'], ['276.375', '4.5'], ['276.375', '3.0'], ['273.75', '3.0'], ['273.75', '0.0'], ['267.5', '0.0'], ['267.5', '-4.0'], ['269.5', '-4.0'], ['269.5', '-10.0'], ['265.0', '-10.0'], ['265.0', '-10.333333333333334'], ['263.75', '-10.333333333333334'], ['263.75', '-10.0'], ['257.5', '-10.0'], ['257.5', '-16.0'], ['264.0', '-16.0'], ['264.0', '-30.0'], ['251.25', '-30.0'], ['251.25', '-23.416666666666668'], ['244.0', '-23.416666666666668'], ['244.0', '-18.75'], ['245.625', '-18.75'], ['245.625', '-17.75'], ['244.0', '-17.75'], ['244.0', '-8.0'], ['238.75', '-8.0'], ['238.75', '-2.75'], ['244.0', '-2.75']] +ORI coordinates [['69.25', '0.0'], ['69.25', '15.5'], ['74.5', '15.5'], ['74.5', '16.0'], ['80.0', '16.0'], ['80.0', '15.5'], ['84.0', '15.5'], ['84.0', '12.5'], ['86.5', '12.5'], ['86.5', '18.0'], ['85.5', '18.0'], ['85.5', '22.833333333333332'], ['88.25', '22.833333333333332'], ['88.25', '21.5'], ['93.25', '21.5'], ['93.25', '17.5'], ['94.625', '17.5'], ['94.625', '12.0'], ['94.625', '10.0'], ['93.625', '10.0'], ['93.625', '0.0'], ['93.625', '-4.0'], ['87.5', '-4.0'], ['87.5', '-11.0'], ['76.25', '-11.0'], ['76.25', '-4.0'], ['70.0', '-4.0'], ['70.0', '0.0']] +PAV coordinates [['270.0', '-75.0'], ['270.0', '-66.5'], ['262.5', '-66.5'], ['262.5', '-57.0'], ['270.0', '-57.0'], ['305.0', '-57.0'], ['305.0', '-60.0'], ['320.0', '-60.0'], ['320.0', '-75.0']] +PEG coordinates [['320.0', '2.0'], ['320.0', '12.5'], ['316.75', '12.5'], ['316.75', '11.833333333333334'], ['315.75', '11.833333333333334'], ['315.75', '19.5'], ['318.75', '19.5'], ['318.75', '23.5'], ['321.25', '23.5'], ['321.25', '28.0'], ['326.0', '28.0'], ['326.0', '36.0'], ['328.125', '36.0'], ['330.0', '36.0'], ['330.0', '35.0'], ['342.25', '35.0'], ['342.25', '34.5'], ['343.0', '34.5'], ['352.5', '34.5'], ['352.5', '32.083333333333336'], ['356.25', '32.083333333333336'], ['356.25', '31.333333333333332'], ['0.0', '31.333333333333332'], ['0.0', '28.0'], ['1.0', '28.0'], ['1.0', '22.0'], ['2.125', '22.0'], ['2.125', '21.0'], ['2.125', '12.5'], ['0.0', '12.5'], ['0.0', '10.0'], ['357.5', '10.0'], ['357.5', '7.5'], ['341.25', '7.5'], ['341.25', '2.0'], ['330.0', '2.0'], ['330.0', '1.75'], ['325.0', '1.75'], ['325.0', '2.75'], ['322.0', '2.75'], ['322.0', '2.0']] +PER coordinates [['40.75', '30.666666666666668'], ['40.75', '34.0'], ['38.5', '34.0'], ['38.5', '36.75'], ['37.75', '36.75'], ['37.75', '50.5'], ['30.625', '50.5'], ['30.625', '47.0'], ['25.0', '47.0'], ['25.0', '50.0'], ['20.5', '50.0'], ['20.5', '54.0'], ['25.5', '54.0'], ['25.5', '57.5'], ['28.625', '57.5'], ['28.625', '58.5'], ['36.5', '58.5'], ['36.5', '57.0'], ['46.5', '57.0'], ['47.5', '57.0'], ['47.5', '55.0'], ['50.0', '55.0'], ['50.0', '52.5'], ['70.375', '52.5'], ['70.375', '36.0'], ['67.5', '36.0'], ['67.5', '30.666666666666668'], ['50.5', '30.666666666666668']] +PHE coordinates [['350.0', '-40.0'], ['25.0', '-40.0'], ['35.0', '-40.0'], ['35.0', '-47.833333333333336'], ['27.5', '-47.833333333333336'], ['27.5', '-50.5'], ['23.75', '-50.5'], ['23.75', '-52.5'], ['20.0', '-52.5'], ['20.0', '-57.5'], ['350.0', '-57.5'], ['350.0', '-57.0']] +PIC coordinates [['90.0', '-43.0'], ['90.0', '-49.25'], ['90.0', '-51.5'], ['92.5', '-51.5'], ['92.5', '-55.0'], ['97.5', '-55.0'], ['97.5', '-58.0'], ['102.5', '-58.0'], ['102.5', '-64.0'], ['98.75', '-64.0'], ['90.0', '-64.0'], ['90.0', '-61.0'], ['82.5', '-61.0'], ['82.5', '-56.5'], ['75.0', '-56.5'], ['75.0', '-54.0'], ['67.5', '-54.0'], ['67.5', '-49.0'], ['67.5', '-45.5'], ['72.5', '-45.5'], ['72.5', '-43.0'], ['75.0', '-43.0']] +PSA coordinates [['345.0', '-24.5'], ['345.0', '-37.0'], ['320.0', '-37.0'], ['320.0', '-28.0'], ['320.0', '-24.5'], ['328.0', '-24.5']] +PSC coordinates [['341.25', '0.0'], ['341.25', '2.0'], ['341.25', '7.5'], ['357.5', '7.5'], ['357.5', '10.0'], ['0.0', '10.0'], ['0.0', '12.5'], ['2.125', '12.5'], ['2.125', '21.0'], ['12.75', '21.0'], ['12.75', '23.75'], ['10.75', '23.75'], ['10.75', '33.0'], ['21.125', '33.0'], ['21.125', '28.0'], ['25.0', '28.0'], ['25.0', '25.0'], ['25.0', '9.916666666666666'], ['30.0', '9.916666666666666'], ['30.0', '2.0'], ['5.0', '2.0'], ['5.0', '0.0'], ['5.0', '-7.0'], ['357.5', '-7.0'], ['357.5', '-4.0'], ['341.25', '-4.0']] +PUP coordinates [['110.5', '-11.0'], ['121.25', '-11.0'], ['125.5', '-11.0'], ['125.5', '-17.0'], ['125.5', '-35.25'], ['125.5', '-43.0'], ['120.0', '-43.0'], ['120.0', '-49.25'], ['90.0', '-49.25'], ['90.0', '-43.0'], ['98.75', '-43.0'], ['98.75', '-33.0'], ['110.5', '-33.0']] +PYX coordinates [['125.5', '-17.0'], ['128.75', '-17.0'], ['128.75', '-19.0'], ['136.25', '-19.0'], ['136.25', '-24.0'], ['140.5', '-24.0'], ['140.5', '-35.25'], ['125.5', '-35.25']] +RET coordinates [['48.0', '-66.5'], ['48.0', '-56.5'], ['52.5', '-56.5'], ['52.5', '-52.833333333333336'], ['57.5', '-52.833333333333336'], ['60.0', '-52.833333333333336'], ['60.0', '-55.5'], ['65.0', '-55.5'], ['65.0', '-59.0'], ['68.75', '-59.0'], ['68.75', '-66.5']] +SCL coordinates [['345.0', '-24.5'], ['357.5', '-24.5'], ['25.0', '-24.5'], ['25.0', '-40.0'], ['350.0', '-40.0'], ['350.0', '-37.0'], ['345.0', '-37.0']] +SCO coordinates [['238.75', '-8.0'], ['244.0', '-8.0'], ['244.0', '-17.75'], ['245.625', '-17.75'], ['245.625', '-18.75'], ['244.0', '-18.75'], ['244.0', '-23.416666666666668'], ['251.25', '-23.416666666666668'], ['251.25', '-30.0'], ['264.0', '-30.0'], ['267.5', '-30.0'], ['267.5', '-37.0'], ['267.5', '-44.5'], ['246.3125', '-44.5'], ['246.3125', '-42.0'], ['240.0', '-42.0'], ['240.0', '-28.5'], ['235.0', '-28.5'], ['235.0', '-20.0'], ['238.75', '-20.0']] +SCT coordinates [['273.75', '-16.0'], ['273.75', '-4.0'], ['278.75', '-4.0'], ['283.0', '-4.0'], ['283.0', '-11.966666666666667'], ['283.0', '-16.0']] +SER1 coordinates [['226.25', '0.0'], ['226.25', '8.0'], ['226.25', '26.0'], ['227.75', '26.0'], ['240.5', '26.0'], ['240.5', '22.0'], ['238.75', '22.0'], ['238.75', '16.0'], ['241.25', '16.0'], ['241.25', '4.0'], ['244.0', '4.0'], ['244.0', '0.0'], ['244.0', '-2.75'], ['238.75', '-2.75'], ['226.25', '-2.75']] +SER2 coordinates [['273.75', '0.0'], ['273.75', '3.0'], ['276.375', '3.0'], ['276.375', '4.5'], ['273.75', '4.5'], ['273.75', '6.25'], ['279.93333333333334', '6.25'], ['283.0', '6.25'], ['283.0', '2.0'], ['278.75', '2.0'], ['278.75', '0.0'], ['278.75', '-4.0'], ['273.75', '-4.0'], ['273.75', '-16.0'], ['264.0', '-16.0'], ['257.5', '-16.0'], ['257.5', '-10.0'], ['263.75', '-10.0'], ['263.75', '-10.333333333333334'], ['265.0', '-10.333333333333334'], ['265.0', '-10.0'], ['269.5', '-10.0'], ['269.5', '-4.0'], ['267.5', '-4.0'], ['267.5', '0.0']] +SEX coordinates [['143.75', '0.0'], ['143.75', '7.0'], ['161.25', '7.0'], ['161.25', '0.0'], ['161.25', '-6.0'], ['161.25', '-11.0'], ['143.75', '-11.0']] +SGE coordinates [['283.0', '18.5'], ['283.0', '21.083333333333332'], ['288.75', '21.083333333333332'], ['288.75', '19.166666666666668'], ['297.5', '19.166666666666668'], ['297.5', '21.25'], ['303.75', '21.25'], ['303.75', '20.5'], ['303.75', '15.75'], ['302.125', '15.75'], ['297.5', '15.75'], ['297.5', '16.166666666666668'], ['285.0', '16.166666666666668'], ['285.0', '18.5']] +SGR coordinates [['283.0', '-11.966666666666667'], ['300.0', '-11.966666666666667'], ['300.0', '-28.0'], ['305.0', '-28.0'], ['305.0', '-44.5'], ['287.5', '-44.5'], ['287.5', '-37.0'], ['267.5', '-37.0'], ['267.5', '-30.0'], ['264.0', '-30.0'], ['264.0', '-16.0'], ['273.75', '-16.0'], ['283.0', '-16.0']] +TAU coordinates [['49.25', '-0.25'], ['49.25', '0.0'], ['49.25', '9.916666666666666'], ['49.25', '19.0'], ['50.5', '19.0'], ['50.5', '30.666666666666668'], ['67.5', '30.666666666666668'], ['67.5', '30.0'], ['71.25', '30.0'], ['71.25', '28.5'], ['88.25', '28.5'], ['88.25', '28.0'], ['88.25', '22.833333333333332'], ['85.5', '22.833333333333332'], ['85.5', '18.0'], ['86.5', '18.0'], ['86.5', '12.5'], ['84.0', '12.5'], ['84.0', '15.5'], ['80.0', '15.5'], ['80.0', '16.0'], ['74.5', '16.0'], ['74.5', '15.5'], ['69.25', '15.5'], ['69.25', '0.0'], ['53.75', '0.0'], ['53.75', '-0.25']] +TEL coordinates [['305.0', '-57.0'], ['270.0', '-57.0'], ['270.0', '-44.5'], ['287.5', '-44.5'], ['305.0', '-44.5']] +TRA coordinates [['221.25', '-70.0'], ['221.25', '-66.5'], ['223.75', '-66.5'], ['223.75', '-62.416666666666664'], ['227.5', '-62.416666666666664'], ['227.5', '-61.0'], ['230.0', '-61.0'], ['230.0', '-60.0'], ['246.3125', '-60.0'], ['246.3125', '-61.0'], ['248.75', '-61.0'], ['248.75', '-62.416666666666664'], ['251.25', '-62.416666666666664'], ['251.25', '-65.0'], ['252.5', '-65.0'], ['252.5', '-66.5'], ['255.0', '-66.5'], ['255.0', '-70.0']] +TRI coordinates [['25.0', '25.0'], ['25.0', '28.0'], ['21.125', '28.0'], ['21.125', '33.0'], ['21.125', '35.0'], ['30.0', '35.0'], ['30.0', '36.75'], ['37.75', '36.75'], ['38.5', '36.75'], ['38.5', '34.0'], ['40.75', '34.0'], ['40.75', '30.666666666666668'], ['36.25', '30.666666666666668'], ['36.25', '27.25'], ['28.75', '27.25'], ['28.75', '25.0']] +TUC coordinates [['350.0', '-75.0'], ['350.0', '-66.5'], ['330.0', '-66.5'], ['330.0', '-57.0'], ['350.0', '-57.0'], ['350.0', '-57.5'], ['20.0', '-57.5'], ['20.0', '-76.0'], ['11.25', '-76.0'], ['11.25', '-75.0'], ['0.0', '-75.0']] +UMA coordinates [['143.75', '42.0'], ['137.5', '42.0'], ['137.5', '47.0'], ['126.25', '47.0'], ['126.25', '60.0'], ['119.5', '60.0'], ['119.5', '73.5'], ['137.5', '73.5'], ['170.0', '73.5'], ['170.0', '66.5'], ['180.0', '66.5'], ['180.0', '64.0'], ['202.5', '64.0'], ['202.5', '63.0'], ['216.25', '63.0'], ['216.25', '55.5'], ['210.5', '55.5'], ['210.5', '48.5'], ['202.5', '48.5'], ['202.5', '53.0'], ['181.25', '53.0'], ['181.25', '45.0'], ['180.0', '45.0'], ['180.0', '34.0'], ['180.0', '29.0'], ['178.0', '29.0'], ['165.0', '29.0'], ['165.0', '34.0'], ['161.75', '34.0'], ['161.75', '40.0'], ['152.5', '40.0'], ['152.5', '42.0']] +UMI coordinates [['195.0', '77.0'], ['203.75', '77.0'], ['203.75', '80.0'], ['217.5', '80.0'], ['217.5', '86.5'], ['120.0', '86.5'], ['120.0', '88.0'], ['345.0', '88.0'], ['345.0', '86.16666666666667'], ['315.0', '86.16666666666667'], ['315.0', '86.0'], ['270.0', '86.0'], ['270.0', '80.0'], ['262.5', '80.0'], ['262.5', '75.0'], ['248.0', '75.0'], ['248.0', '70.0'], ['235.0', '70.0'], ['235.0', '66.0'], ['210.0', '66.0'], ['210.0', '70.0'], ['195.0', '70.0']] +VEL coordinates [['165.0', '-55.5'], ['132.5', '-55.5'], ['132.5', '-53.5'], ['126.75', '-53.5'], ['126.75', '-53.0'], ['122.5', '-53.0'], ['122.5', '-49.25'], ['120.0', '-49.25'], ['120.0', '-43.0'], ['125.5', '-43.0'], ['125.5', '-35.25'], ['140.5', '-35.25'], ['140.5', '-38.25'], ['165.0', '-38.25']] +VIR coordinates [['172.75', '0.0'], ['172.75', '11.0'], ['178.0', '11.0'], ['178.0', '14.0'], ['192.5', '14.0'], ['192.5', '15.0'], ['202.5', '15.0'], ['202.5', '8.0'], ['226.25', '8.0'], ['226.25', '0.0'], ['220.0', '0.0'], ['220.0', '-8.0'], ['213.75', '-8.0'], ['213.75', '-22.0'], ['192.5', '-22.0'], ['192.5', '-11.0'], ['177.5', '-11.0'], ['177.5', '-6.0'], ['172.75', '-6.0']] +VOL coordinates [['98.75', '-64.0'], ['102.5', '-64.0'], ['135.5', '-64.0'], ['135.5', '-75.0'], ['115.0', '-75.0'], ['98.75', '-75.0'], ['98.75', '-70.0']] +VUL coordinates [['283.0', '21.083333333333332'], ['283.0', '25.5'], ['288.875', '25.5'], ['288.875', '27.5'], ['295.0', '27.5'], ['295.0', '29.0'], ['313.75', '29.0'], ['313.75', '28.0'], ['321.25', '28.0'], ['321.25', '23.5'], ['318.75', '23.5'], ['318.75', '19.5'], ['315.75', '19.5'], ['308.5', '19.5'], ['308.5', '20.5'], ['303.75', '20.5'], ['303.75', '21.25'], ['297.5', '21.25'], ['297.5', '19.166666666666668'], ['288.75', '19.166666666666668'], ['288.75', '21.083333333333332']] diff --git a/clients/planetarium/data/cities.json b/plugins/planetarium/data/cities.json similarity index 100% rename from clients/planetarium/data/cities.json rename to plugins/planetarium/data/cities.json diff --git a/clients/planetarium/go3.sh b/plugins/planetarium/go3.sh similarity index 100% rename from clients/planetarium/go3.sh rename to plugins/planetarium/go3.sh diff --git a/clients/planetarium/hipnames b/plugins/planetarium/hipnames similarity index 100% rename from clients/planetarium/hipnames rename to plugins/planetarium/hipnames diff --git a/clients/planetarium/lj3.py b/plugins/planetarium/lj3.py similarity index 100% rename from clients/planetarium/lj3.py rename to plugins/planetarium/lj3.py diff --git a/clients/planetarium/main.py b/plugins/planetarium/main.py similarity index 100% rename from clients/planetarium/main.py rename to plugins/planetarium/main.py diff --git a/plugins/simu.py b/plugins/simu.py new file mode 100755 index 0000000..0d28226 --- /dev/null +++ b/plugins/simu.py @@ -0,0 +1,245 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + +''' +LJ v0.8.0 + +Pygame Simulator plugin for LJ + +LICENCE : CC +Sam Neurohack, loloster, + +OSC server with : + +/simu/quit +/simu/newpl new pl number to draw +/simu/newclient new client number to draw + +''' +#from __future__ import print_function +import time +import math +import random +import itertools +import sys +import os +#import thread +import redis +import pygame +import pdb +import types, ast, argparse +from OSC import OSCServer, OSCClient, OSCMessage + +pl = [[],[],[],[]] + +print ("") +print ("LJ v0.8.0 : Pygame simulator") +print ("") +print ("Arguments parsing if needed...") + +# +# Arguments parsing +# + +argsparser = argparse.ArgumentParser(description="Available commands") +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) + +args = argsparser.parse_args() + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +# Laser choice +if args.laser: + simuPL = args.laser +else: + simuPL = 0 + +# Debug ? +if args.verbose: + debug = args.verbose +else: + debug = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + +r = redis.StrictRedis(host=redisIP, port=6379, db=0) + + +# +# OSC +# + +oscIPin = "127.0.0.1" +oscPORTin = 8008 + +ljIP = "127.0.0.1" +ljPort = 8002 + +print ("") +print ("Receiving on ", oscIPin, ":",str(oscPORTin)) +oscserver = OSCServer( (oscIPin, oscPORTin) ) +oscserver.timeout = 0 +OSCRunning = True + +def handle_timeout(self): + self.timed_out = True + +oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver) + + +def sendLJ(address, args): + + if debug >0: + print "Sending to LJ...", address, args + + osclientlj = OSCClient() + osclientlj.connect((ljIP, ljPort)) + + oscmsg = OSCMessage() + oscmsg.setAddress(address) + oscmsg.append(args) + + try: + osclientlj.sendto(oscmsg, (ljIP, ljPort)) + oscmsg.clearData() + return True + + except: + print 'Connection to LJ IP', ljIP,'port', ljPort, 'refused : died ?' + return False + + +# RAW OSC Frame available ? +def osc_frame(): + + # clear timed_out flag + oscserver.timed_out = False + # handle all pending requests then return + while not oscserver.timed_out: + oscserver.handle_request() + +# /quit +def quit(path, tags, args, source): + + pygame.quit() + print "pySimu Stopped by /quit." + sys.exit() + +# /start : 0 exit +def start(path, tags, args, source): + + print args, type(args) + if args[0] == 0: + pygame.quit() + print "pySimu stopped by /start 0" + sys.exit() + +# Answer to LJ pings +def ping(path, tags, args, source): + # Will receive message address, and message data flattened in s, x, y + print "Simu got /ping with value", args[0] + print "Simu replied with /pong simu" + sendLJ("/pong","simu") + + + +# /newPL pointlistnumber +def newPL(path, tags, args, source): + + user = ''.join(path.split("/")) + print "" + print user,path,args + print "Simulator got a new point list number :", args[0] + simuPL = args[0] + +# /newClient clientnumber +def newClient(path, tags, args, source): + + user = ''.join(path.split("/")) + print "" + print user,path,args + print "Simulator got a new client number : ", args[0] + ljclient = args[0] + +oscserver.addMsgHandler( "/quit", quit ) +oscserver.addMsgHandler( "/ping", ping ) +oscserver.addMsgHandler( "/pysimu/start", start ) +oscserver.addMsgHandler( "/pysimu/newpl", newPL ) +oscserver.addMsgHandler( "/pysimu/newclient", newClient ) + + +# +# Pygame screen +# + +def RenderScreen(surface): + + if len(pl[simuPL]): + + xyc_prev = pl[simuPL][0] + #pygame.draw.line(surface,self.black_hole_color,(x_bh_cur, y_bh_cur), (x_bh_next, y_bh_next)) + #pygame.draw.line(surface,self.spoke_color,(x_bh_cur, y_bh_cur), (x_area_cur, y_area_cur)) + for xyc in pl[simuPL]: + c = int(xyc[2]) + if c: pygame.draw.line(surface,c,xyc_prev[:2],xyc[:2],3) + xyc_prev = xyc + +screen_size = [700,700] +pygame.init() +screen = pygame.display.set_mode(screen_size) +pygame.display.set_caption("LJ Simulator") +clock = pygame.time.Clock() +update_screen = False + +print ("Simulator displays client", ljclient, "point list", str(simuPL)) + +# +# Main +# + +try: + + while True: + + # pending osc message ? + osc_frame() + + # Pygame events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + break + + screen.fill(0) + pl[simuPL] = ast.literal_eval(r.get("/pl/"+ str(ljclient) + "/" + str(simuPL))) + + if update_screen: + update_screen = False + RenderScreen(screen) + pygame.display.flip() + else: + update_screen = True + + clock.tick(30) + # time.sleep(0.001) + +except KeyboardInterrupt: + pass + +finally: + pygame.quit() + print "pySimu Stopped." + + + + diff --git a/plugins/textcycl.py b/plugins/textcycl.py new file mode 100644 index 0000000..deccef6 --- /dev/null +++ b/plugins/textcycl.py @@ -0,0 +1,130 @@ +# coding=UTF-8 + +''' +Cycling text on one LJ laser. +LICENCE : CC +''' + +import redis +import lj3 +import sys,time +import argparse + +from osc4py3.as_eventloop import * +from osc4py3 import oscbuildparse +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * + +OSCinPort = 8007 + +duration = 300 +lasertext = ["TEAMLASER","FANFAN","LOLOSTER","SAM"] + +''' +is_py2 = sys.version[0] == '2' +if is_py2: + from Queue import Queue +else: + from queue import Queue +''' +print ("") +print ("Arguments parsing if needed...") +argsparser = argparse.ArgumentParser(description="Text Cycling for LJ") +argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str) +argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int) +argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) + + +args = argsparser.parse_args() + + +if args.client: + ljclient = args.client +else: + ljclient = 0 + +if args.laser: + plnumber = args.laser +else: + plnumber = 0 + +if args.verbose: + debug = args.verbose +else: + debug = 0 + +# Redis Computer IP +if args.redisIP != None: + redisIP = args.redisIP +else: + redisIP = '127.0.0.1' + +lj3.Config(redisIP,ljclient) +#r = redis.StrictRedis(host=redisIP, port=6379, db=0) + + +# If you want to use rgb for color : +def rgb2int(r,g,b): + return int('0x%02x%02x%02x' % (r,g,b),0) + + +def WebStatus(message): + lj3.Send("/status",message) + +def OSCljclient(value): + # Will receive message address, and message data flattened in s, x, y + print("I got /cycl/ljclient with value", value) + ljclient = value + lj3.LjClient(ljclient) + + +osc_startup() +osc_udp_server("127.0.0.1", OSCinPort, "InPort") + +osc_method("/ping*", lj3.OSCping) +osc_method("/cycl/ljclient", OSCljclient) + + +WebStatus("Textcycl") + +def Run(): + + counter =0 + step = 0 + timing = -1 + color = rgb2int(255,255,255) + + try: + while 1: + + if timing == duration or timing == -1: + message = lasertext[step] + lj3.Text(message, color, PL = 0, xpos = 300, ypos = 300, resize = 1, rotx =0, roty =0 , rotz=0) + lj3.DrawPL(0) + timing = 0 + + else: + step += 1 + if step >3: + step =0 + timing += 1 + time.sleep(0.01) + except KeyboardInterrupt: + pass + + # Gently stop on CTRL C + + finally: + + WebStatus("Textcycl stop") + print("Stopping OSC...") + lj3.OSCstop() + + print ("Textcycl Stopped.") + + + +Run() + + diff --git a/settings.py b/settings.py index dd3441d..d444e66 100644 --- a/settings.py +++ b/settings.py @@ -24,6 +24,7 @@ def Write(): config.set('General', 'nozoscip', str(gstt.nozoscIP)) config.set('General', 'debug', str(gstt.debug)) + for i in range(gstt.LaserNumber): laser = 'laser' + str(i) config.set(laser, 'ip', str(gstt.lasersIPS[i])) @@ -49,7 +50,10 @@ def Read(): gstt.oscIPin = config.get('General', 'bhoroscip') gstt.nozoscip = config.get('General', 'nozoscip') gstt.debug = config.get('General', 'debug') + gstt.plugins = ast.literal_eval(config.get('plugins', 'plugins')) + + print "" for i in range(4): laser = 'laser' + str(i) gstt.lasersIPS[i]= config.get(laser, 'ip') diff --git a/visualiser-linux b/visualiser-linux deleted file mode 100755 index 6530ef0..0000000 Binary files a/visualiser-linux and /dev/null differ diff --git a/webui/LJ.js b/webui/LJ.js index 2769bba..e42f893 100644 --- a/webui/LJ.js +++ b/webui/LJ.js @@ -8,17 +8,13 @@ function noMenu() { // Set all central menu buttons with normal button style - var x = document.getElementById("align"); + var x = document.getElementById("align"); x.value = 0 ; var x = document.getElementById("run"); x.value = 0 ; var x = document.getElementById("simu"); x.value = 0 ; var x = document.getElementById("live"); - x.value = 0 ; - var x = document.getElementById("nozoid"); - x.value = 0 ; - var x = document.getElementById("planet"); x.value = 0 ; // Hide all possible main central grids. @@ -26,16 +22,11 @@ x.style.display = "none"; var x = document.getElementById("mgsimu"); x.style.display = "none"; - var x = document.getElementById("cnvbuttons"); - x.style.display = "none"; var x = document.getElementById("mgrun"); x.style.display = "none"; var x = document.getElementById("mglive"); x.style.display = "none"; - var x = document.getElementById("mgnozoid"); - x.style.display = "none"; - var x = document.getElementById("mgplanet"); - x.style.display = "none"; + } function showAlign() { @@ -58,7 +49,7 @@ noMenu(); var x = document.getElementById("mgsimu"); x.style.display = "grid"; - var x = document.getElementById("cnvbuttons"); + var x = document.getElementById("cnvbuttons"); x.style.display = "grid"; var x = document.getElementById("simu"); x.value = 1 ; @@ -72,24 +63,71 @@ x.value = 1 ; } - function showNozoid() { - noMenu(); - var x = document.getElementById("mgnozoid"); - x.style.display = "grid"; - var x = document.getElementById("nozoid"); - x.value = 1 ; - } - function showPlanet() { - noMenu(); - var x = document.getElementById("mgplanet"); +// +// SimuUIs +// + + function nosimuUI() { + // Hide all possible main central grids. + var x = document.getElementById("planetUI"); + x.style.display = "none"; + var x = document.getElementById("nozoidUI"); + x.style.display = "none"; + var x = document.getElementById("aiUI"); + x.style.display = "none"; + var x = document.getElementById("lissaUI"); + x.style.display = "none"; + var x = document.getElementById("vjUI"); + x.style.display = "none"; + var x = document.getElementById("wordsUI"); + x.style.display = "none"; + } + + function showplanetUI() { + nosimuUI(); + var x = document.getElementById("planetUI"); x.style.display = "grid"; - var x = document.getElementById("cnvbuttons"); - x.style.display = "grid"; - var x = document.getElementById("planet"); - x.value = 1 ; + _WS.send("/planet/ping"); } + function shownozoidUI() { + nosimuUI(); + var x = document.getElementById("nozoidUI"); + x.style.display = "grid"; + _WS.send("/nozoid/ping"); + } + + function showaiUI() { + nosimuUI(); + var x = document.getElementById("aiUI"); + x.style.display = "grid"; + } + + function showlissaUI() { + nosimuUI(); + var x = document.getElementById("lissaUI"); + x.style.display = "grid"; + } + + function showvjUI() { + nosimuUI(); + var x = document.getElementById("vjUI"); + x.style.display = "grid"; + _WS.send("/bank0/ping"); + } + + function showwordsUI() { + nosimuUI(); + var x = document.getElementById("wordsUI"); + x.style.display = "grid"; + _WS.send("/words/ping"); + } + +// +// Button clicked +// + function buttonClicked(clicked_id) { _WS.send("/" + clicked_id); @@ -108,61 +146,15 @@ showlissaUI(); } if (clicked_id === "vj/vjUI") { - showlissaUI(); + showvjUI(); + } + if (clicked_id === "words/wordsUI") { + showwordsUI(); } if (clicked_id === "nozoid/down 50") { var x = document.getElementById("nozoid/down 50"); x.value = 0 ; } - } - - -// -// SimuUIs -// - - function nosimuUI() { - // Hide all possible main central grids. - var x = document.getElementById("planetUI"); - x.style.display = "none"; - var x = document.getElementById("nozoidUI"); - x.style.display = "none"; - var x = document.getElementById("aiUI"); - x.style.display = "none"; - var x = document.getElementById("lissaUI"); - x.style.display = "none"; - var x = document.getElementById("vjUI"); - x.style.display = "none"; - } - - function showplanetUI() { - nosimuUI(); - var x = document.getElementById("planetUI"); - x.style.display = "grid"; - } - - function shownozoidUI() { - nosimuUI(); - var x = document.getElementById("nozoidUI"); - x.style.display = "grid"; - } - - function showaiUI() { - nosimuUI(); - var x = document.getElementById("aiUI"); - x.style.display = "grid"; - } - - function showlissaUI() { - nosimuUI(); - var x = document.getElementById("lissaUI"); - x.style.display = "grid"; - } - - function showvjUI() { - nosimuUI(); - var x = document.getElementById("vjUI"); - x.style.display = "grid"; } diff --git a/webui/LJgrid.css b/webui/LJgrid.css index 2f45c9e..624960f 100644 --- a/webui/LJgrid.css +++ b/webui/LJgrid.css @@ -1,4 +1,3 @@ - .maingrid { display: grid; grid-template-columns: 900px; @@ -21,7 +20,7 @@ } .mgstatus { display: grid; - grid-template-columns: 470px 80px 1fr; + grid-template-columns: 390px 150px 1fr; grid-template-raw: 30px; grid-column-gap: 1px; grid-row-gap: 1px; @@ -58,8 +57,8 @@ display: none; height: 400px; width: 400px; - grid-template-columns: 66px 66px 66px 66px; - grid-template-rows: 66px 17px 69px 17px; + grid-template-columns: 66px 66px 66px 66px 66px 66px; + grid-template-rows: 67px 67px 67px; background-color: #000; justify-items: center; align-items: center; @@ -338,6 +337,15 @@ font: normal normal normal 11px arial; text-decoration: none; } +.info { + background: #000; + color: #c0c0c0; + width: 160px; + text-align: center; + vertical-align: middle; + height: 21px; + border: 1px solid #445; +} .submit { background: #000; color: #c0c0c0; diff --git a/webui/index.html b/webui/index.html index 4dc23fa..fe4eeca 100644 --- a/webui/index.html +++ b/webui/index.html @@ -60,29 +60,29 @@
-
-
-
S
+
+
+
S
C
-
0
-
+
0
+
1
-
+
2
-
+
-
3
-
+
3
+
@@ -92,6 +92,7 @@
Emergy Black
+
@@ -141,54 +142,50 @@
- - - +
-
+
- Client - + - PL - - - Laser - - + PL + + + @@ -536,7 +533,18 @@
-
+
+
+ +
+ Virtual + +
@@ -658,14 +666,106 @@ -
- +
@@ -925,142 +1009,6 @@
- - - -
-
-
-
- MMO-3 - - -
-
- OCS-2 - -
-
-
-
- STOP/START -
-
- Color ? - -
-
- XCURVE LineIN - - - - XCURVE - -
- -
- Automodulation X ? - - Automodulation Y ? - -
-
-
- - - - -
- - -
- -
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - @@ -1077,6 +1025,7 @@ + -