Planetarium alpha

This commit is contained in:
nrhck 2019-02-10 16:53:51 +01:00
parent 4e37cdaa46
commit 6ae38061a5
12 changed files with 706 additions and 257 deletions

20
LJ.conf
View File

@ -1,5 +1,5 @@
[General]
lasernumber = 1
lasernumber = 4
debug = 0
ljayserverip = 127.0.0.1
nozoscip = 127.0.0.1
@ -39,9 +39,9 @@ swapx = -1
swapy = -1
lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser2]
color = -1
@ -58,9 +58,9 @@ swapx = 1
swapy = 1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser3]
color = -1
@ -77,7 +77,7 @@ swapx = -1
swapy = -1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]

View File

@ -59,6 +59,8 @@ In webui/index.html change the ws ip adress to the server IP if needed.
Using the same idea check all ip address in LJ.conf.
There is a nice ws debug tool websocat.
#

View File

@ -2,39 +2,41 @@ Multi Laser planetarium in python3 for LJ.
v0.01
Sam Neurohack
User can define :
- Observer position using GPS coordinates or built in cities catalog on earth.
- Observer time. If you choose Now, the sky is updated live, so you can virtual sky photography :)
- Each laser starchart has a center direction like Azimuth : 63.86° & Altitude: 61.83° and a Field of view like 90°. For the all sky with 4 lasers, give 90° FOV per laser.
- What is displayed : Solar system objects, Stars, Compass letters.
-
Display all solar planets and hipparcos catalog objects below a given magnitude. Accuracy tested against apparent data and starchart at https://www.calsky.com/cs.cgi?cha=7&sec=3&sub=2
Some future features :
It's an alpha release so a little hardcoded :
- Constellations display
- 3D with anaglyph
- Time Speed setting
- What do you want ?
- set observer position (find SkyCity, SkyCountryCode) in main.py like 'Paris' and 'FR'
- set observer date.time in InitObserver() arguments (default is now in UTC)
- set what sky part you want to display for each laser in 'LaserSkies' variable : Define alitude and azimuth for top left and bottom right
User must understand Right Ascension/Declinaison and Azimuth/Altitude coordinates system. Some needed astronomy concepts online :
https://rhodesmill.org/skyfield/stars.html
https://in-the-sky.org//staratlas.php?ra=15.358411414&dec=73.47660962&limitmag=2
http://www.physics.csbsju.edu/astro/SF/SF.06.html
It needs more libraries than plan. Currently it relies on the awesome astropy, skyfield,...
Soon some pictures.
To Run :
Launch LJ first
python3 main.py
For debug options and more type : python3 --help
This project is on "OK" precision grade and definately not coding skills show off, I'm learning python coding it. To check accuracy, one can compare to :
https://www.calsky.com/cs.cgi?cha=7&sec=3&sub=2
To install :
go3.sh
NB :
- if you get an year error out of range : install the last skyfield "python-skyfield" in github.
- Read main.py
The author barely understand astronomy so please report if you find newbie errors sam (at) neurohack cc
This project uses the awesome Skyfield by Brandon Rhodes and Astropy.
Kernels for Sky objects positions references :
Acton, C.H.; "Ancillary Data Services of NASA's Navigation and Ancillary Information Facility;" Planetary and Space Science, Vol. 44, No. 1, pp. 65-70, 1996.
Charles Acton, Nathaniel Bachman, Boris Semenov, Edward Wright; A look toward the future in the handling of space science mission geometry; Planetary and Space Science (2017);
DOI 10.1016/j.pss.2017.02.013
https://doi.org/10.1016/j.pss.2017.02.013
LICENCE : CC
Remember : LJ will automatically warp geometry according to alignement data before sending to lasers. See webUI.
'''

View File

@ -0,0 +1,9 @@
sudo apt install python3-pip
pip3 install jplephem
pip3 install pyephem
pip3 install astropy
pip3 install skyfield
pip3 install pandas
pip3 install redis
pip3 install osc4py3
pip3 install --pre astroquery

View File

@ -22,7 +22,11 @@ Sam Neurohack
import math
import redis
#from OSC import OSCServer, OSCClient, OSCMessage
# 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)
@ -32,16 +36,23 @@ ClientNumber = 0
point_list = []
pl = [[],[],[],[]]
#
# OSC interaction with LJ
#
'''
LJIP = "127.0.0.1"
def OSCstart():
# Start the system.
osc_startup()
#osc_udp_client(redisIP, 8002, "LJ 8002")
def OSCframe():
osc_process()
# Properly close the system. Todo
def OSCstop():
osc_terminate()
osclientlj = OSCClient()
oscmsg = OSCMessage()
osclientlj.connect((redisIP, 8002))
'''
'''
def Send(oscaddress,oscargs=''):
oscmsg = OSCMessage()
@ -50,21 +61,35 @@ def Send(oscaddress,oscargs=''):
#print ("sending to bhorosc : ",oscmsg)
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
oscmsg.clearData()
msg = oscbuildparse.OSCMessage(oscaddress, None, [oscargs])
osc_send(msg, "LJ 8002")
except:
print ('Connection to LJ refused : died ?')
pass
#time.sleep(0.001
def WebStatus(message):
Send("/status",message)
'''
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 = [
#implementé
# caracteres corrects
[(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0
[(-20,30), (0,-30), (-20,30)], #1
@ -77,7 +102,7 @@ ASCII_GRAPHICS = [
[(-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
# A implementer
# 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)], #<
@ -86,7 +111,7 @@ ASCII_GRAPHICS = [
[(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é
# Caracteres corrects
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A
@ -163,6 +188,7 @@ def Config(redisIP,client):
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = client
osc_udp_client(redisIP, 8002, "LJ 8002")
def LineTo(xy, c, PL):
@ -296,10 +322,11 @@ def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
# 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_pl_list = ASCII_GRAPHICS[ord(ch) - 46 ]
char_draw = []
#dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0))
@ -309,6 +336,7 @@ def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
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)

301
clients/planetarium/main.py Normal file → Executable file
View File

@ -37,6 +37,11 @@ from astropy.time import Time
from skyfield.api import Star, load, Topos,Angle
from skyfield.data import hipparcos
from osc4py3.as_eventloop import *
from osc4py3 import oscbuildparse
from osc4py3 import oscmethod as osm
import json
'''
@ -53,6 +58,8 @@ else:
import argparse
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Planetarium for LJ")
@ -60,6 +67,7 @@ argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ
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("-d","--debug",help="Verbosity level (0 by default)",type=int)
argsparser.add_argument("-i","--input",help="inputs OSC Port (8005 by default)",type=int)
#argsparser.add_argument("-n","--name",help="City Name of the observer",type=str)
#argsparser.add_argument("-r","--redisIP",help="Country code of the observer ",type=str)
@ -81,6 +89,11 @@ if args.debug:
else:
debug = 0
if args.input:
OSCinPort = args.input
else:
OSCinPort = 8005
# Redis Computer IP
if args.redisIP != None:
redisIP = args.redisIP
@ -95,16 +108,12 @@ lj3.Config(redisIP,ljclient)
fov = 256
viewer_distance = 2.2
width = 450
height = 450
width = 750
height = 750
centerX = width / 2
centerY = height / 2
samparray = [0] * 100
# (x,y,color in integer) 65280 is color #00FF00
# Green rectangular shape :
pl0 = [(100,300,65280),(200,300,65280),(200,200,65280),(100,200,65280),(100,300,65280)]
# If you want to use rgb for color :
@ -154,7 +163,7 @@ def Proj(x,y,z,angleX,angleY,angleZ):
'''
To minize number of sky objects coordinates conversion : Change planetarium FOV in Ra Dec to select objects
(planets, hipparcos,..). Then get those objects in AltAz coordinates.
(planets, hipparcos,..). Then get only those objects in AltAz coordinates.
aa2radec use Astropy to compute Equatorial Right Ascension and Declinaison coordinates from given observator Altitude and Azimuth.
Example ra,dec = aa2radec( azimuth = 0, altitude = 90, lati = 48.85341, longi = 2.3488, elevation = 100, t =AstroPyNow )
with AstroPyNow = Time.now()
@ -211,36 +220,60 @@ def RadecSkies(LaserSkies, AstroSkyTime):
print()
print("Converting", lasernumber, "LaserSkies limits in Right Ascension & Declination (radec) coordinates ")
for laser in range(lasernumber):
if debug > 0:
print("Laser",laser)
# Left top point
LaserSkies[laser][4],LaserSkies[laser][6] = aa2radec(azimuth = LaserSkies[laser][0], altitude =LaserSkies[laser][2], t =AstroSkyTime)
if debug > 0:
print(LaserSkies[laser][4],LaserSkies[laser][6])
# Right Bottom point
LaserSkies[laser][5],LaserSkies[laser][7] = aa2radec(azimuth = LaserSkies[laser][1], altitude =LaserSkies[laser][3], t =AstroSkyTime)
if debug > 0:
print(LaserSkies[laser][5],LaserSkies[laser][7])
if debug > 0:
print(LaserSkies)
print ("Done.")
def azimuth2scrX(leftAzi,rightAzi,s):
a1, a2 = leftAzi, rightAzi
b1, b2 = -width/2, width/2
b1, b2 = 0, width
#if debug > 0:
# print(leftAzi, rightAzi, s, b1 + ((s - a1) * (b2 - b1) / (a2 - a1)))
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
def altitude2scrY(topAlti,botAlti,s):
a1, a2 = botAlti, topAlti
b1, b2 = -height/2, height/2
a1, a2 = topAlti, botAlti
b1, b2 = 0, height
#if debug > 0:
# print(topAlti,botAlti,s, b1 + ((s - a1) * (b2 - b1) / (a2 - a1)))
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
#
# Solar System
#
SolarObjectShape = [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)]
# Planets Radius in km
SolarObjectradius = [
('Sun', 695500.0),
('Mercury', 2440.0),
('Venus', 6051.8),
('Earth', 6371.01),
('Mars', 3389.9),
('Jupiter', 69911.0),
('Saturn', 58232.0),
('Uranus', 25362.0),
('Neptune', 24624.0),
('134340 Pluto', 1195.0),
]
def LoadSolar():
global planets, SolarObjects, earth
@ -257,7 +290,6 @@ def LoadSolar():
def UpdateSolar():
global SolarObjects
# Compute Alt Az coordinates for all solar objects for obsehttps://www.startpage.com/do/searchrver.
for number,object in enumerate(SolarObjects):
@ -300,56 +332,43 @@ def LoadHipparcos(ts):
hipparcosURL = 'data/hip_main.dat.gz'
with load.open(hipparcosURL) as f:
hipdata = hipparcos.load_dataframe(f)
print("Loaded.")
#print("Loaded.")
hipparcos_epoch = ts.tt(1991.25)
# CODE IMPORTED HERE FROM TESTS. NEEDS TO ADAPT
# Star selection
def StarSelect():
global StarsObjects, hipdatafilt
hipparcos_epoch = ts.tt(1991.25)
barnards_star = Star.from_dataframe(hipdata.loc[87937])
polaris = Star.from_dataframe(hipdata.loc[11767])
StarsObjects = [[]]
#hipparcos_epoch = ts.tt(1991.25)
#barnards_star = Star.from_dataframe(hipdata.loc[87937])
#polaris = Star.from_dataframe(hipdata.loc[11767])
print()
print ("Selecting sky portion")
print ("Stars selection...")
hipdatafilt = hipdata[hipdata['magnitude'] <= 2.5]
print(('After filtering, there are {} stars with magnitude <= 2.5'.format(len(hipdatafilt))))
bright_stars = Star.from_dataframe(hipdatafilt)
print (hipdatafilt)
#print (bright_stars)
hipdatafilt = hipdata[hipdata['magnitude'] <= 3.5]
print(('{} stars with magnitude <= 3.5'.format(len(hipdatafilt))))
Starnames = hipdatafilt.index
t = ts.utc(2018, 9, 3)
'''
Observer = earth + Topos(gpslat, gpslong)
ApparentPosition = Observer.at(t).observe(bright_stars).apparent()
alt, az, distance = ApparentPosition.altaz('standard')
print(('Now there are {} azimuth'.format(len(az))))
print(('and {} altitute'.format(len(alt))))
'''
astrometric = earth.at(t).observe(bright_stars)
ra, dec, distance = astrometric.radec()
print(('Now there are {} right ascensions'.format(len(ra.hours))))
print(('and {} declinations'.format(len(dec.degrees))))
Observer = earth + Topos(gpslat, gpslong)
AP = Observer.at(t).observe(bright_stars)
print ("AP",AP.apparent())
StarsObjects[0] = [Starnames[0],0,0]
for index in range(len(Starnames)-1):
StarsObjects.append([Starnames[index+1],0,0])
def UpdateStars():
def UpdateStars(ts):
global StarsObjects
hipparcos_epoch = ts.tt(1991.25)
# Compute Alt Az coordinates for all solar objects for obsehttps://www.startpage.com/do/searchrver.
for number,object in enumerate(StarsObjects):
#print(object[0],number)
StarsObjects[number][1], StarsObjects[number][2], distance = EarthObjPosition(planets[object[0]],SkyfieldTime)
StarsObjects[number][1], StarsObjects[number][2], distance = EarthObjPosition(Star.from_dataframe(hipdatafilt.loc[StarsObjects[number][0]]),SkyfieldTime)
if debug > 0:
PrintSolar()
PrintStars()
def PrintStars():
@ -360,10 +379,71 @@ def DrawStars(laser):
for number,object in enumerate(StarsObjects):
# Solar object is in given laser sky azimuth and altitude range ?
if LaserSkies[laser][0] < StarsObjects[number][2] < LaserSkies[laser][1] and LaserSkies[laser][3] < StarsObjects[number][1] < LaserSkies[laser][2]:
#print ("drawing",StarsObjects[number][0],StarsObjects[number][1],StarsObjects[number][2],"on laser",laser)
lj3.rPolyLineOneColor(StarsObjectshape, c = white, PL = laser, closed = False, xpos = azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],StarsObjects[number][2]), ypos = altitude2scrY(LaserSkies[laser][2],LaserSkies[laser][3],StarsObjects[number][1]), resize = 2, rotx =0, roty =0 , rotz=0)
# Star object is in given lasersky altitude range ?
if LaserSkies[laser][3] < StarsObjects[number][1] < LaserSkies[laser][2]:
# Star object is in given lasersky azimuth range ?
if LaserSkies[laser][0] < StarsObjects[number][2] < LaserSkies[laser][1] :
#print ("drawing",StarsObjects[number][0],StarsObjects[number][1],StarsObjects[number][2],"on laser",laser)
lj3.rPolyLineOneColor(StarsObjectShape, c = white, PL = laser, closed = False, xpos = azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],StarsObjects[number][2]), ypos = altitude2scrY(LaserSkies[laser][2],LaserSkies[laser][3],StarsObjects[number][1]), resize = 0.05, rotx =0, roty =0 , rotz=0)
# Star object is in given lasersky North azimuth ?
if LaserSkies[laser][0] > LaserSkies[laser][1] and StarsObjects[number][2] < LaserSkies[laser][1] :
#print ("drawing",StarsObjects[number][0],StarsObjects[number][1],StarsObjects[number][2],"on laser",laser)
lj3.rPolyLineOneColor(StarsObjectShape, c = white, PL = laser, closed = False, xpos = azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],StarsObjects[number][2]), ypos = altitude2scrY(LaserSkies[laser][2],LaserSkies[laser][3],StarsObjects[number][1]), resize = 0.05, rotx =0, roty =0 , rotz=0)
#
# Anything system. Say you want
#
AnythingObjectShape = [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)]
def LoadAnything():
global planets, AnythingObjects, earth
print("Loading Anything System...")
# de421.bps https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/a_old_versions/de421.bsp
# planets = load('data/de421.bsp')
earth = planets['earth']
print('Loaded.')
# [Object name, object altitude, object azimuth]
AnythingObjects = [['MERCURY',0.0, 0.0], ['VENUS', 0.0, 0.0], ['JUPITER BARYCENTER', 0.0, 0.0], ['SATURN BARYCENTER', 0.0, 0.0], ['URANUS BARYCENTER', 0.0, 0.0], ['NEPTUNE BARYCENTER', 0.0, 0.0], ['PLUTO BARYCENTER', 0.0, 0.0], ['SUN', 0.0, 0.0], ['MOON', 0.0, 0.0], ['MARS', 0.0, 0.0]]
def UpdateAnything():
global AnythingObjects
# Compute Alt Az coordinates for all Anything objects for obsehttps://www.startpage.com/do/searchrver.
for number,object in enumerate(AnythingObjects):
#print(object[0],number)
AnythingObjects[number][1], AnythingObjects[number][2], distance = EarthObjPosition(planets[object[0]],SkyfieldTime)
if debug > 0:
PrintAnything()
def PrintAnything():
for number,object in enumerate(AnythingObjects):
print (AnythingObjects[number][0],"is at (alt,az)",AnythingObjects[number][1],AnythingObjects[number][2])
# Draw the AnythingShapeObject for any Anything object is in the laser Sky
def DrawAnything(laser):
for number,object in enumerate(AnythingObjects):
# Anything object is in given laser sky azimuth and altitude range ?
if LaserSkies[laser][0] < AnythingObjects[number][2] < LaserSkies[laser][1] and LaserSkies[laser][3] < AnythingObjects[number][1] < LaserSkies[laser][2]:
#print ("drawing",AnythingObjects[number][0],AnythingObjects[number][1],AnythingObjects[number][2],"on laser",laser)
lj3.rPolyLineOneColor(AnythingObjectShape, c = white, PL = laser, closed = False, xpos = azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],AnythingObjects[number][2]), ypos = altitude2scrY(LaserSkies[laser][2],LaserSkies[laser][3],AnythingObjects[number][1]), resize = 2, rotx =0, roty =0 , rotz=0)
@ -379,7 +459,7 @@ def LoadCities():
f=open("data/cities.json","r")
s = f.read()
world = json.loads(s)
print("Loaded.")
#print("Loaded.")
# Get longitude and latitude of given City in given country. Need to better understand python dictionnaries.
@ -398,24 +478,31 @@ def CityPositiion(cityname, countrycode):
# Add Kompass letter to given laser point list if it is in laser sky at Y axis 300
# Add Kompass orientation to given laser point list if it is in laser sky at Y axis 300
# point lasers to
def DrawOrientation(laser):
#print("LaserSkies 0",LaserSkies[laser][0],"LaserSkies 1",LaserSkies[laser][1])
# North direction is in given laser sky azimuth range?
if LaserSkies[laser][0] < 0 < LaserSkies[laser][1]:
lj3.Text("N",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],0), 300)
if LaserSkies[laser][1] < LaserSkies[laser][0]:
#print ("N az",azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],0))
lj3.Text("NORTH",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],359), 770, resize = 0.5, rotx =0, roty =0 , rotz=0)
# East direction is in given laser sky azimuth range ?
if LaserSkies[laser][0] < 90 < LaserSkies[laser][1]:
lj3.Text("E",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],90), 300)
if LaserSkies[laser][0] <= 90 < LaserSkies[laser][1]:
#print ("E az",azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],0))
lj3.Text("EAST",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],90), 770, resize = 0.5, rotx =0, roty =0 , rotz=0)
# South direction is in given laser sky azimuth range ?
if LaserSkies[laser][0] < 180 < LaserSkies[laser][1]:
lj3.Text("S",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],180), 300)
if LaserSkies[laser][0] <= 180 < LaserSkies[laser][1]:
#print ("S az",azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],0))
lj3.Text("SOUTH",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],180), 770, resize = 0.5, rotx =0, roty =0 , rotz=0)
# West direction is in given laser sky azimuth range ?
if LaserSkies[laser][0] < 270 < LaserSkies[laser][1]:
lj3.Text("W",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],270), 300)
if LaserSkies[laser][0] <= 270 < LaserSkies[laser][1]:
#print ("W az",azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],0))
lj3.Text("WEST",white,laser,azimuth2scrX(LaserSkies[laser][0],LaserSkies[laser][1],270), 770, resize = 0.5, rotx =0, roty =0 , rotz=0)
@ -427,7 +514,7 @@ def InitObserver(SkyCity, SkyCountryCode, time,ts):
# Observer position i.e : Paris FR
#Skylat = 48.85341 # decimal degree
#Skylong = 2.3488 # decimal degree
print()
#print()
print("Observer GPS position and time...")
Skylat, Skylong = CityPositiion(SkyCity,SkyCountryCode)
print ("GPS Position of",SkyCity, "in", SkyCountryCode, ":",Skylat,Skylong)
@ -438,7 +525,7 @@ def InitObserver(SkyCity, SkyCountryCode, time,ts):
# Other time in Astropy style
# times = '1999-01-01T00:00:00.123456789'
# t = Time(times, format='isot', scale='utc')
print()
#print()
AstroSkyTime = time
print ("AstroPy time", AstroSkyTime)
SkyfieldTime = ts.from_astropy(AstroSkyTime)
@ -450,53 +537,86 @@ def InitObserver(SkyCity, SkyCountryCode, time,ts):
# Computer for all Laser "skies" their Right Ascension/Declinaison coordinates from their Altitude/azimuth Coordinates.
# to later select their visible objects in radec catalogs like hipparcos.
# LaserSky definition for one laser (in decimal degrees) : [LeftAzi, RightAzi, TopAlt, BotAlt, LeftRa, RightRa, TopDec, BottomDec]
# LaserSky definition for one laser (in decimal degrees) : [RightAzi, LeftAzi, TopAlt, BotAlt, LeftRa, RightRa, TopDec, BottomDec]
# With 4 lasers with each one a quarter of the 360 ° real sky, there is 4 LaserSky :
LaserSkies = [[0.0,90.0,90.0,0.0,0.0,0.0,0.0,0.0],[90,180,90,0,0,0,0,0],[180,270,90,0,0,0,0,0],[270,360,90,0,0,0,0,0]]
LaserSkies = [[45,135.0,90.0,0.0,0.0,0.0,0.0,0.0],[135,225,90,0,0,0,0,0],[225,315,90,0,0,0,0,0],[305,0,90,0,0,0,0,0]]
RadecSkies(LaserSkies, AstroSkyTime)
def NewTime(timeshift):
SkyfieldTime += timeshift
UpdateSolar()
UpdateStars()
if DisplaySolar:
UpdateSolar()
if DisplayStars:
UpdateStars()
if DisplayAnything:
UpdateAnything()
#def handlerfunction(s, x, y):
# Will receive message data unpacked in s, x, y
# pass
def OSChandler(address, s, x, y):
# Will receive message address, and message data flattened in s, x, y
print("Planetarium OSC server got address", address,"s",s,"x",x,"y",y)
pass
def WebStatus(message):
lj3.Send("/status",message)
#
# Main functions
# Main part
#
try:
def Planetarium():
lj3.OSCstart()
# Make server channels to receive packets.
#osc_udp_server("127.0.0.1", 3721, "localhost")
osc_udp_server("0.0.0.0", OSCinPort, "InPort")
# Associate Python functions with message address patterns, using default
# argument scheme OSCARG_DATAUNPACK.
#osc_method("/planet/*", handlerfunction)
# Too, but request the message address pattern before in argscheme
osc_method("/planet/*", OSChandler, argscheme=osm.OSCARG_ADDRESS + osm.OSCARG_DATAUNPACK)
ts = load.timescale()
LoadHipparcos(ts)
LoadSolar()
LoadCities()
SkyCity = 'Paris'
SkyCountryCode = 'FR'
LoadSolar()
InitObserver(SkyCity, SkyCountryCode, Time.now(),ts)
print()
print ("Updating Sky Objects for current observer...")
print()
LoadHipparcos(ts)
StarSelect()
#print()
#print ("Updating Sky Objects for current observer...")
#print()
print("Updating solar system (de421) objects position for observer at", Skylat, Skylong, "time", SkyfieldTime.utc_iso())
UpdateSolar()
print ("Done.")
print()
#print ("Done.")
#print()
print("Updating stars for observer at", Skylat, Skylong, "time", SkyfieldTime.utc_iso())
#UpdateStars()
UpdateStars(ts)
print ("Done.")
# UpdateStars() Todo
DisplayStars = False
DisplaySolar = True
DisplayStars = True
DisplaySolar = False
DisplayOrientation = True
DisplayAnything = False
while 1:
@ -507,14 +627,29 @@ def Planetarium():
if DisplaySolar:
DrawSolar(laser)
if DisplayStars:
pass
DrawStars(laser)
if DisplayAnything:
DrawAnything()
lj3.DrawPL(laser)
time.sleep(0.01)
lj3.OSCframe()
time.sleep(0.01)
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj3.OSCstop()
print ("Fin du planetarium.")
Planetarium()

83
clients/textcycl.py Normal file
View File

@ -0,0 +1,83 @@
# 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()

View File

@ -74,8 +74,11 @@ swapY = [1,1,1,-1]
# For glitch art : change position and number of points added by tracer.py
# shortline is for distance with next point, shorter than 4000 (in etherdream coordinates)
# i.e (0.25,3) means add 3 points at 25% on the line.
stepshortline = [(1.0, 8)]
stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)]
#stepshortline = [(1.0, 8)]
#stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)]
stepslongline = [(0.25,1), (0.75, 1), (1.0, 1)]
#stepshortline = [(1.0, 8)]
stepslongline = [(1.0, 1)]
point = [0,0,0]

View File

@ -8,6 +8,7 @@ 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
todo :
@ -417,7 +418,7 @@ finally:
r.set('/lstt/'+str(laserid),64)
r.set('/cap/'+str(laserid),0)
print "Fin des haricots"
print "Fin de LJ."
'''

View File

@ -14,16 +14,26 @@
x.className = "button";
var x = document.getElementById("showlive");
x.className = "button";
var x = document.getElementById("shownozoid");
x.className = "button";
var x = document.getElementById("showplanet");
x.className = "button";
// Hide all possible main central grids.
var x = document.getElementById("mgalign");
x.style.display = "none";
var x = document.getElementById("mgcanvas");
x.style.display = "none";
var x = document.getElementById("mgrun");
x.style.display = "none";
var x = document.getElementById("mglive");
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() {
@ -44,8 +54,10 @@
function showCanvas() {
noMenu();
var x = document.getElementById("mgcanvas");
x.style.display = "block";
var x = document.getElementById("mgsimu");
x.style.display = "grid";
var x = document.getElementById("cnvbuttons");
x.style.display = "grid";
var x = document.getElementById("showcanvas");
x.className = "button:checked";
}
@ -57,7 +69,21 @@
var x = document.getElementById("showlive");
x.className = "button:checked";
}
function showNozoid() {
noMenu();
var x = document.getElementById("mgnozoid");
x.style.display = "grid";
var x = document.getElementById("shownozoid");
x.className = "button:checked";
}
function showPlanet() {
noMenu();
var x = document.getElementById("mgplanet");
x.style.display = "grid";
var x = document.getElementById("showplanet");
x.className = "button:checked";
}
u
function buttonClicked(clicked_id) {
_WS.send("/" + clicked_id);
}

View File

@ -21,7 +21,7 @@
}
.mgstatus {
display: grid;
grid-template-columns: 250px 150px 1fr;
grid-template-columns: 300px 150px 1fr;
grid-template-raw: 30px;
grid-column-gap: 1px;
grid-row-gap: 1px;
@ -46,15 +46,30 @@
border-style: groove;
border-width: 1px;
}
.mgcanvas {
.mgsimu {
display: none;
height: 400px;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1Fr;
width: 900px;
grid-template-columns: 500px 400px;
grid-template-rows: 400px;
background-color: #151515;
}
.cnvbuttons {
display: none;
height: 400px;
width: 400px;
grid-template-columns: 66px 66px 66px 66px;
grid-template-rows: 66px 17px 69px 17px;
background-color: #000;
justify-items: center;
align-items: center;
border-color: #445;
border-style: groove;
border-width: 1px;
grid-gap: 1px;
transition: all .3s ease;
background-color: #151515;
}
.mglive {
display: none;
@ -66,6 +81,24 @@
border-style: groove;
border-width: 1px;
}
.mgnozoid {
display: none;
height: 400px;
grid-template-columns: 1Fr;
grid-template-rows: 1Fr;
background-color: #151515;
border-color: #445;
border-style: groove;
border-width: 1px;
}
.mgplanet {
display: none;
height: 400px;
width: 900px;
grid-template-columns: 500px 400px;
grid-template-rows: 400px;
background-color: #151515;
}
.mgrun {
display: none;
height: 400px;

View File

@ -5,7 +5,7 @@
<meta charset="utf-8">
<title>LJ</title>
<!-- Web audio defaults -->
<!-- Web audio buttons defaults -->
<script src="webcomponents-lite.js"></script>
<script>
WebAudioControlsOptions={
@ -18,18 +18,26 @@
}
</script>
<script src="webaudio-controls.js"></script>
<link rel="stylesheet" href="LJgrid.css" />
<script src="LJ.js"></script>
<link rel="stylesheet" href="LJgrid.css" />
<!-- Javascript for this webapp is a the end of this html page and in LJ.js -->
<script src="LJ.js"></script>
</head>
</head>
<body style="background-color:#222;">
<!-- mg : MainGrid Webpage one column, different raws displayed or hidden by menu button -->
<!--
MainGrid Webpage one column, different raws displayed or hidden by menu button
-->
<div class="maingrid">
<!-- mg : Title and laser state ()-->
<!--
Title and laser state
-->
<div class="mgtitle">
<!-- LJ Logo -->
@ -73,7 +81,7 @@
</div>
<div>
<!--
<!--
<div class="topgrid">
<div class="lasertext">Laser</div>
<div><webaudio-knob id="noteon" src="knobs/Prophetic5.png" diameter="70" min="16" max="20" value="0" sprites="5"></webaudio-knob></div>
@ -90,7 +98,11 @@
<div></div>
</div>
<!-- mg : Menu buttons and Status display -->
<!--
Menu buttons and Status display
-->
<div id="mgstatus" class="mgstatus">
<div>
<!-- <webaudio-switch id="align" height="10" width="99" value="0" src="knobs/align.png" type="toggle"></webaudio-switch>
@ -101,18 +113,23 @@
<button class="button" id="showcanvas" onclick="showCanvas()">Simu</button>
<button class="button" id="showrun" onclick="showRun()">Run</button>
<button class="button" id="showlive" onclick="showLive()">Live</button>
<button class="button" id="shownozoid" onclick="showNozoid()">Nozoid</button>
<button class="button" id="showplanet" onclick="showPlanet()">Planet</button>
</div>
<div><button class="button" id="showstatus">DISCONNECTED</button></div>
<div></div>
</div>
<!-- mg : Align -->
<!--
Align
-->
<div id="mgalign" class="mgalign">
<!-- Laserbox 0 -->
<!-- Laser 0 -->
<div class="laserbox">
<!-- IP 0 -->
<!-- IP laser 0 -->
<div>
<form onsubmit="onSubmit(); return false;">
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/0">
@ -160,24 +177,28 @@
</div>
</div>
<!-- Laserbox 1 -->
<!-- Laser 1 -->
<div class="laserbox">
<!-- IP 1 -->
<!-- IP laser 1 -->
<div>
<form onsubmit="onSubmit(); return false;">
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/1">
</form>
</div>
<div>
<!-- Align Icons -->
<webaudio-switch id="grid/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
<webaudio-switch id="mouse/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
<!-- Blackout icon -->
<webaudio-switch id="black/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
<!-- Swap Icons -->
<webaudio-switch id="swap/X/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
<webaudio-switch id="swap/Y/1" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
</div>
<!-- Lasergrid 1 -->
<div class="lasergrid" style="background-image: url(lasergrid1.png);">
<div><webaudio-param id="kpps/1" link="kpps/1"></webaudio-param></div>
@ -209,24 +230,28 @@
</div>
</div>
<!-- Laserbox 2 -->
<!-- Laser 2 -->
<div class="laserbox">
<!-- IP 2 -->
<!-- IP laser 2 -->
<div>
<form onsubmit="onSubmit(); return false;">
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/2">
</form>
</div>
<div>
<!-- Align Icons -->
<!-- Align Icons -->
<webaudio-switch id="grid/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
<webaudio-switch id="mouse/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
<!-- Blackout icon -->
<webaudio-switch id="black/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
<!-- Swap Icons -->
<webaudio-switch id="swap/X/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
<webaudio-switch id="swap/Y/2" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
</div>
<!-- Laser 2 grid -->
<div class="lasergrid" style="background-image: url(lasergrid2.png)">
<div><webaudio-param id="kpps/2" link="kpps/2"></webaudio-param></div>
@ -260,24 +285,28 @@
</div>
</div>
<!-- Laserbox 3 -->
<!-- Laser 3 -->
<div class="laserbox">
<!-- IP 3 -->
<!-- IP laser 3 -->
<div>
<form onsubmit="onSubmit(); return false;">
<input class = "submit" onchange = "onSubmit(this.id)" type="text" id="ip/3">
</form>
</div>
<div>
<!-- Align Icons -->
<!-- Align Icons -->
<webaudio-switch id="grid/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/grid.png"></webaudio-switch>
<webaudio-switch id="mouse/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/mouse.png"></webaudio-switch>
<!-- Blackout icon -->
<webaudio-switch id="black/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/blackout.png"></webaudio-switch>
<!-- Swap Icons -->
<webaudio-switch id="swap/X/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapx.png"></webaudio-switch>
<webaudio-switch id="swap/Y/3" value="0" height="25" width="21" tooltip="Switch-B" src="knobs/swapy.png"></webaudio-switch>
</div>
<!-- Laser 3 grid -->
<div class="lasergrid" style="background-image: url(lasergrid3.png)">
<div><webaudio-param id="kpps/3" link="kpps/3" ></webaudio-param></div>
@ -312,11 +341,14 @@
</div>
</div>
<!-- mg : Live -->
<!--
Live
-->
<div id="mglive" class="mglive">
<!-- with AI box -->
<!-- with AI Interface -->
<div class="withaibox">
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">With AI
</div>
@ -347,7 +379,7 @@
</div>
<!-- Lissabox -->
<!-- Lissa interface -->
<div class="lissabox">
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">LISSA
</div>
@ -378,7 +410,7 @@
</div>
</div>
<!-- 3D proj grid -->
<!-- 3D proj interface -->
<div class="projgrid">
<div></div>
<div class="lasertext" style="border-color:#334;border-style: groove;border-width:1px;">3D ROT</div>
@ -396,90 +428,181 @@
<div class="lasertext">Y</div>
<div class="lasertext">Z</div>
</div>
</div>
<!-- mg : canvas to display point list as laser simulator -->
<div id = "mgcanvas" class="mgcanvas">
<div>
<canvas id="canvas" width="500" height="500"></canvas>
</div>
<div></div>
<!--
Simulator to display point list
-->
<div id = "mgsimu" class="mgsimu">
<div>
<canvas id="canvas" width="500" height="400" style="border-color: #445;border-style:groove;border-width:1px;"></canvas>
</div>
<!-- Selection buttons grid -->
<div id="cnvbuttons" class="cnvbuttons">
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 0" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 1" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 2" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 3" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 24" onclick ="buttonClicked(this.id)" class="button:checked">PL 0</button></div>
<div><button id ="noteon 25" onclick ="buttonClicked(this.id)" class="button">PL 1</button></div>
<div><button id ="noteon 26" onclick ="buttonClicked(this.id)" class="button">PL 2</button></div>
<div><button id ="noteon 27" onclick ="buttonClicked(this.id)" class="button">PL 3</button></div>
</div>
</div>
<!-- mg run icons grid -->
<div id="mgrun"class="mgrun"> <!-- Laser Client selection grid -->
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 0" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 1" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 2" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 3" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div><button id ="noteon 4" onclick ="buttonClicked(this.id)" class="button">4</button></div>
<div><button id ="noteon 5" onclick ="buttonClicked(this.id)" class="button">5</button></div>
<div><button id ="noteon 6" onclick ="buttonClicked(this.id)" class="button">6</button></div>
<div><button id ="noteon 7" onclick ="buttonClicked(this.id)" class="button">7</button></div>
<!-- Simulator PL selection grid -->
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 24" onclick ="buttonClicked(this.id)" class="button:checked">PL 0</button></div>
<div><button id ="noteon 25" onclick ="buttonClicked(this.id)" class="button">PL 1</button></div>
<div><button id ="noteon 26" onclick ="buttonClicked(this.id)" class="button">PL 2</button></div>
<div><button id ="noteon 27" onclick ="buttonClicked(this.id)" class="button">PL 3</button></div>
<div></div>
<div></div>
<div></div>
<div></div>
<!-- Laser selection grid -->
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 16" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 17" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 18" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 19" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div></div>
<div></div>
<div></div>
<div></div>
<!-- Hidden grid -->
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<!-- mg : footer display events for debug -->
<!--
Run
-->
<div id="mgrun" class="mgrun">
<!-- Laser Client selection grid -->
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 0" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 1" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 2" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 3" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div><button id ="noteon 4" onclick ="buttonClicked(this.id)" class="button">4</button></div>
<div><button id ="noteon 5" onclick ="buttonClicked(this.id)" class="button">5</button></div>
<div><button id ="noteon 6" onclick ="buttonClicked(this.id)" class="button">6</button></div>
<div><button id ="noteon 7" onclick ="buttonClicked(this.id)" class="button">7</button></div>
<!-- Simulator PL selection grid -->
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 24" onclick ="buttonClicked(this.id)" class="button:checked">PL 0</button></div>
<div><button id ="noteon 25" onclick ="buttonClicked(this.id)" class="button">PL 1</button></div>
<div><button id ="noteon 26" onclick ="buttonClicked(this.id)" class="button">PL 2</button></div>
<div><button id ="noteon 27" onclick ="buttonClicked(this.id)" class="button">PL 3</button></div>
<div></div>
<div></div>
<div></div>
<div></div>
<!-- Laser selection grid -->
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconlaser.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 16" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 17" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 18" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 19" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div></div>
<div></div>
<div></div>
<div></div>
<!-- Hidden grid -->
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconblack.png" alt=" " class="icongrid" /></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<!--
Nozoid
-->
<div id = "mgnozoid" class="mgnozoid">
<div>
<span class="lasertext">X</span>
<select>
<option value="LFO1">LFO1</option>
<option value="LFO2">LFO2</option>
<option value="LFO3">LFO3</option>
<option value="LFO4">LFO4</option>
</select>
<span class="lasertext">Y</span>
<select>
<option value="LFO1">LFO1</option>
<option value="LFO2">LFO2</option>
<option value="LFO3">LFO3</option>
<option value="LFO4">LFO4</option>
</select>
</div>
</div>
<!--
Planetarium
-->
<div id = "mgplanet" class="mgplanet">
<!-- Simuator canvas -->
<div>
<canvas id="canvas" width="500" height="400" style="border-color: #445;border-style:groove;border-width:1px;"></canvas>
</div>
<!-- Selection buttons grid -->
<div id="cnvbuttons" class="cnvbuttons">
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/client.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 0" onclick ="buttonClicked(this.id)" class="button:checked">0</button></div>
<div><button id ="noteon 1" onclick ="buttonClicked(this.id)" class="button">1</button></div>
<div><button id ="noteon 2" onclick ="buttonClicked(this.id)" class="button">2</button></div>
<div><button id ="noteon 3" onclick ="buttonClicked(this.id)" class="button">3</button></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><img src="knobs/iconljay2.png" alt=" " class="icongrid" /></div>
<div><button id ="noteon 24" onclick ="buttonClicked(this.id)" class="button:checked">PL 0</button></div>
<div><button id ="noteon 25" onclick ="buttonClicked(this.id)" class="button">PL 1</button></div>
<div><button id ="noteon 26" onclick ="buttonClicked(this.id)" class="button">PL 2</button></div>
<div><button id ="noteon 27" onclick ="buttonClicked(this.id)" class="button">PL 3</button></div>
</div>
</div>
<!--
Footer display events for debug
-->
<div class="mgfooter">
<div id="showin"></div>
<div id="showout"></div>
@ -489,7 +612,9 @@
</div>
<!-- web audio animations -->
<!--
web audio buttons scripts
-->
<script type="text/javascript">
var message="";
var log=[];
@ -547,7 +672,9 @@
</script>
<!-- Point list draw -->
<!--
Simulator Point list drawing scripts
-->
<script type="text/javascript">
// Store Reference To The Canvas & Set Context
@ -655,7 +782,7 @@
</script>
</body>
<!-- non displayed items, for code reference
<!-- non displayed items, for code reference mainly for other type of webaudio buttons
<div>
<span class="lasertext">Swap X</span>
<span class="lasertext">Swap Y</span>