diff options
| author | Tim Redfern <tim@eclectronics.org> | 2012-05-04 17:59:13 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2012-05-04 17:59:13 +0100 |
| commit | b5914dd492fa4716737bbe43f4abcad5258b6396 (patch) | |
| tree | d1d8ac3dac05fb7e99c6d7e08c955f105ab587a2 | |
| parent | 3209f698306ab0cf22ef0fe31a722bad22214691 (diff) | |
working with image maps
| -rw-r--r-- | gps.py | 313 | ||||
| -rw-r--r-- | gps_serial.py~ | 80 | ||||
| -rw-r--r-- | gpspoller.py | 88 | ||||
| -rw-r--r-- | gpspoller.pyc | bin | 0 -> 2696 bytes | |||
| -rw-r--r-- | gpstest.py | 14 | ||||
| -rw-r--r-- | indexmapV1.gif | bin | 0 -> 3235 bytes | |||
| -rw-r--r-- | latLng.pyc | bin | 0 -> 1095 bytes | |||
| -rw-r--r-- | layers.py | 29 | ||||
| -rw-r--r-- | layers.pyc | bin | 0 -> 3862 bytes | |||
| -rw-r--r-- | testreceive.pd | 18 | ||||
| -rwxr-xr-x | tomorrowtheground.py | 35 | ||||
| -rw-r--r-- | tomorrowthegroundGUI/data/indexmapV1.gif | bin | 0 -> 3233 bytes | |||
| -rw-r--r-- | tomorrowthegroundGUI/tomorrowthegroundGUI.pde | 24 | ||||
| -rw-r--r-- | ttg01.xml | 8 | ||||
| -rw-r--r-- | xml2obj.pyc | bin | 0 -> 3905 bytes |
15 files changed, 589 insertions, 20 deletions
@@ -0,0 +1,313 @@ +# ******!*********!*********!*********!*********!*********!*********!*********
+#
+# Copyright (c) IBM Corporation, 2006. All Rights Reserved.
+# Author: Simon Johnston (skjohn@us.ibm.com)
+#
+# Simple class which can interface to a serially connected GPS device that
+# implements the NMEA standard. The reference I used was found at:
+# http://www.gpsinformation.org/dale/nmea.htm
+# The class currently decodes the following sentences:
+# GLL, GSA, GSV, RMC
+#
+# Classes:
+# GPSError - exception for GPSDevice (also wraps serial errors).
+# GPSDevice - GPS device interface (serial) class.
+#
+# Functions:
+# format_date - convert date from NMEA to ISO format.
+# format_time - convert time from NMEA to ISO format.
+# format_latlong - convert date from NMEA to standard decimal format.
+#
+# ******!*********!*********!*********!*********!*********!*********!*********
+
+import datetime
+
+import serial
+
+class GPSError(Exception):
+ """ Signal errors in the GPS communication, both NMEA sentence errors
+ as well as wrapping up underlying serial I/O errors.
+ """
+ pass
+
+class GPSDevice(object):
+ """ General GPS Device interface for connecting to serial port GPS devices
+ using the default communication params specified by the National Marine
+ Electronics Association (NMEA) specifications.
+ """
+ def __init__(self, commport):
+ """ GPSDevice(port)
+ Connects to the serial port specified, as the port numbers are
+ zero-based on windows the actual device string would be "COM" +
+ port+1.
+ """
+ self.commport = commport
+ self.port = None
+
+ def open(self):
+ """ open()
+ open the GPS device port, the NMEA default serial I/O parameters are
+ defined as 4800,8,N,1.
+ """
+ nmea_params = {
+ 'port': self.commport,
+ 'baudrate': 4800,
+ 'bytesize': serial.EIGHTBITS,
+ 'parity': serial.PARITY_NONE,
+ 'stopbits': serial.STOPBITS_ONE
+ }
+ if self.port:
+ raise GPSError, 'Device port is already open'
+ try:
+ self.port = serial.Serial(**nmea_params)
+ self.port.open()
+ except serial.SerialException:
+ raise GPSError, 'Caught serial error opening port, is device connected?'
+
+ def read(self):
+ """ read() -> dict
+ rRad a single NMEA sentence from the device returning the data as a
+ dictionary. The 'sentence' key will identify the sentence type itself
+ with other parameters extracted and nicely formatted where possible.
+ """
+ sentence = 'error'
+ line = self._read_raw()
+ if line:
+ parsed = self._validate(line)
+ if parsed:
+ if _decode_func.has_key(parsed[0]):
+ return _decode_func[parsed[0]](parsed)
+ else:
+ sentence = parsed[0]
+ return {
+ 'sentence': sentence
+ }
+
+ def read_all(self):
+ """ read_all() -> dict
+ A generator allowing the user to read data from the device in a for loop
+ rather than having to craft their own looping method.
+ """
+ while 1:
+ try:
+ record = self.read()
+ except IOError:
+ raise StopIteration
+ yield record
+
+ def close(self):
+ """ close()
+ Close the port, note you can no longer read from the device until you
+ re-open it.
+ """
+ if not self.port:
+ raise GPSError, 'Device port not open, cannot close'
+ self.port.close()
+ self.port = None
+
+ def _read_raw(self):
+ """ _read_raw() -> str
+ Internal method which reads a line from the device (line ends in \r\n).
+ """
+ if not self.port:
+ raise GPSError, 'Device port not open, cannot read'
+ return self.port.readline()
+
+ def _checksum(self, data):
+ """ _checksum(data) -> str
+ Internal method which calculates the XOR checksum over the sentence (as
+ a string, not including the leading '$' or the final 3 characters, the
+ ',' and checksum itself).
+ """
+ checksum = 0
+ for character in data:
+ checksum = checksum ^ ord(character)
+ hex_checksum = "%02x" % checksum
+ return hex_checksum.upper()
+
+ def _validate(self, sentence):
+ """ _validate(sentence) -> str
+ Internal method.
+ """
+ sentence.strip()
+ if sentence.endswith('\r\n'):
+ sentence = sentence[:len(sentence)-2]
+ if not sentence.startswith('$GP'):
+ #
+ # Note that sentences that start with '$P' are proprietary
+ # formats and are described as $P<MID><SID> where MID is the
+ # manufacturer identified (Magellan is MGN etc.) and then the
+ # SID is the manufacturers sentence identifier.
+ #
+ return None
+ star = sentence.rfind('*')
+ if star >= 0:
+ check = sentence[star+1:]
+ sentence = sentence[1:star]
+ sum = self._checksum(sentence)
+ if sum <> check:
+ return None
+ sentence = sentence[2:]
+ return sentence.split(',')
+
+#
+# The internal decoder functions start here.
+#
+def format_date(datestr):
+ """ format_date(datestr) -> str
+ Internal function. Turn GPS DDMMYY into DD/MM/YY
+ """
+ year = int(datestr[4:])
+ now = datetime.date.today()
+ if year + 2000 > now.year:
+ year = year + 1900
+ else:
+ year = yeat + 2000
+ the_date = datetime.date(year, int(datestr[2:4]), int(datestr[:2]))
+ return the_date.isoformat()
+
+def format_time(timestr):
+ """ format_time(timestr) -> str
+ Internal function. Turn GPS HHMMSS into HH:MM:SS UTC
+ """
+ utc_str = '+00:00'
+ the_time = datetime.time(int(timestr[:2]), int(timestr[2:4]), int(timestr[4:]))
+ return the_time.strftime('%H:%M:%S') + utc_str
+
+def format_latlong(data, direction):
+ """ format_latlong(data, direction) -> str
+ Internal function. Turn GPS HHMM.nnnn into standard HH.ddddd
+ """
+ # Check to see if it's HMM.nnnn or HHMM.nnnn or HHHMM.nnnn
+ dot = data.find('.')
+ if (dot > 5) or (dot < 3):
+ raise ValueError, 'Incorrect formatting of "%s"' % data
+ hours = data[0:dot-2]
+ mins = float(data[dot-2:])
+ if hours[0] == '0':
+ hours = hours[1:]
+ if direction in ['S', 'W']:
+ hours = '-' + hours
+ decimal = mins / 60.0 * 100.0
+ decimal = decimal * 10000.0
+ return '%s.%06d' % (hours, decimal)
+
+def _convert(v, f, d):
+ """ convert(v, f, d) -> value
+ Internal function.
+ """
+ try:
+ return f(v)
+ except:
+ return d
+
+def _decode_gll(data):
+ """ decode_gll(date) -> dict
+ Internal function.
+ """
+ return {
+ 'sentence': data[0],
+ 'latitude': '%s' % format_latlong(data[1], data[2]),
+ 'longitude': '%s' % format_latlong(data[3], data[4]),
+ 'time': format_time(data[5]),
+ 'active': data[6]
+ }
+
+def _decode_gga(data):
+ """ decode_gga(date) -> dict
+ Internal function.
+ """
+ quality = ['invalid', 'GPS', 'DGPS', 'PPS', 'Real TIme', 'Float RTK',
+ 'Estimated', 'Manual', 'Simulation']
+ qindex = _convert(data[6], int, '')
+ if qindex >= len(quality):
+ qstring = str(qindex)
+ else:
+ qstring = quality[qindex]
+ return {
+ 'sentence': data[0],
+ 'time': format_time(data[1]),
+ 'latitude': '%s' % format_latlong(data[2], data[3]),
+ 'longitude': '%s' % format_latlong(data[4], data[5]),
+ 'quality': qstring,
+ 'tracked': _convert(data[7], int, ''),
+ 'dilution': _convert(data[8], float, ''),
+ 'altitude': '%s,%s' % (data[9], data[10]),
+ 'geoid_height': '%s,%s' % (data[11], data[12])
+ }
+
+def _decode_gsa(data):
+ """ decode_gsa(date) -> dict
+ Internal function.
+ """
+ return {
+ 'sentence': data[0],
+ 'selection': data[1],
+ '3dfix': _convert(data[2], int, ''),
+ 'prns': data[3:14],
+ 'pdop': convert(data[15], float, ''),
+ 'horizontal_dilution': _convert(data[16], float, ''),
+ 'vertical_dilution': _convert(data[17], float, ''),
+ }
+
+def _decode_gsv(data):
+ """ decode_gsv(date) -> dict
+ Internal function.
+ """
+ return {
+ 'sentence': data[0],
+ 'satelite': _convert(data[2], int, ''),
+ 'inuse': _convert(data[1], int, ''),
+ 'inview': _convert(data[3], int, ''),
+ 'prn': _convert(data[4], int, ''),
+ 'elevation': _convert(data[5], float, ''),
+ 'azimuth': _convert(data[6], float, ''),
+ 'snr': _convert(data[7], int, '')
+ }
+
+def _decode_rmc(data):
+ """ decode_rmc(date) -> dict
+ Internal function.
+ """
+ return {
+ 'sentence': data[0],
+ 'time': format_time(data[1]),
+ 'active': data[2],
+ 'latitude': '%s' % format_latlong(data[3], data[4]),
+ 'longitude': '%s' % format_latlong(data[5], data[6]),
+ 'speed': _convert(data[7], float, ''),
+ 'angle': _convert(data[8], float, ''),
+ 'date': format_date(data[9]),
+ 'variation': '%s,%s' % (data[10], data[11])
+ }
+
+#
+# Simple dictionary mapping the sentence types to their
+# corresponding decoder functions.
+#
+_decode_func = {
+ 'GLL': _decode_gll,
+ 'GSA': _decode_gsa,
+ 'GSV': _decode_gsv,
+ 'RMC': _decode_rmc,
+}
+
+#
+# Simple test case, this can be used to run indefinitely (formatting and printing
+# each record) or run until it gets a GLL response and print the machines location.
+#
+if __name__ == '__main__':
+ import sys
+ port = 4
+ gps = GPSDevice(port)
+ gps.open()
+ for record in gps.read_all():
+ if sys.argv[0] == 'forever':
+ print record
+ else:
+ if record['sentence'] == 'GLL':
+ print 'I was at long %s, lat %s at %s' % (
+ record['longitude'],
+ record['latitude'],
+ record['time'])
+ break
diff --git a/gps_serial.py~ b/gps_serial.py~ new file mode 100644 index 0000000..c25581b --- /dev/null +++ b/gps_serial.py~ @@ -0,0 +1,80 @@ +#!/usr/bin/python
+
+# Copyright (C) 2007 by Jaroslaw Zachwieja
+# Published under the terms of GNU General Public License v2 or later.
+# License text available at http://www.gnu.org/licenses/licenses.html#GPL
+
+import serial
+import string
+
+gps = serial.Serial('/dev/ttyUSB0', 4800, timeout=1)
+file = '/tmp/nmea.kml'
+
+print "Serving data"
+
+latitude = 0
+longitude = 0
+speed = 0
+heading = 0
+altitude = 0
+range = 1000
+tilt = 30
+
+while 1:
+ line = gps.readline()
+ datablock = line.split(',')
+
+ if line[0:6] == '$GPRMC':
+ latitude_in = string.atof(datablock[3])
+ longitude_in = string.atof(datablock[5])
+ altitude = string.atof(datablock[8])
+ speed_in = string.atof(datablock[7])
+ heading = string.atof(datablock[8])
+
+ if datablock[4] == 'S':
+ latitude_in = -latitude_in
+ if datablock[6] == 'W':
+ longitude_in = -longitude_in
+
+ latitude_degrees = int(latitude_in/100)
+ latitude_minutes = latitude_in - latitude_degrees*100
+
+ longitude_degrees = int(longitude_in/100)
+ longitude_minutes = longitude_in - longitude_degrees*100
+
+ latitude = latitude_degrees + (latitude_minutes/60)
+ longitude = longitude_degrees + (longitude_minutes/60)
+
+ speed = int(speed_in * 1.852)
+ range = ( ( speed / 100 ) * 350 ) + 650
+ tilt = ( ( speed / 120 ) * 43 ) + 30
+
+ if speed < 10:
+ range = 200
+ tilt = 30
+ heading = 0
+
+ output = """<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://earth.google.com/kml/2.0">
+ <Placemark>
+ <name>%s km/h</name>
+ <description>^</description>
+ <LookAt>
+ <longitude>%s</longitude>
+ <latitude>%s</latitude>
+ <range>%s</range>
+ <tilt>%s</tilt>
+ <heading>%s</heading>
+ </LookAt>
+ <Point>
+ <coordinates>%s,%s,%s</coordinates>
+ </Point>
+ </Placemark>
+</kml>""" % (speed,longitude,latitude,range,tilt,heading,longitude,latitude,altitude)
+
+ f=open(file, 'w')
+ f.write(output)
+ f.close()
+
+ser.close()
+
diff --git a/gpspoller.py b/gpspoller.py new file mode 100644 index 0000000..6f7c19c --- /dev/null +++ b/gpspoller.py @@ -0,0 +1,88 @@ +#!/usr/bin/python
+
+# Copyright (C) 2007 by Jaroslaw Zachwieja
+# Modified (C) 2012 by Tim Redfern
+# Published under the terms of GNU General Public License v2 or later.
+# License text available at http://www.gnu.org/licenses/licenses.html#GPL
+
+import serial,string,threading,time,sys,random
+
+class GpsPoller(threading.Thread):
+
+ latitude = 0
+ longitude = 0
+ changed = False
+
+ def __init__(self,port,test=False):
+ self.test=test
+ self.port=port
+ self.gps = serial.Serial(port, 9600, timeout=1)
+ threading.Thread.__init__(self)
+
+ def check(self):
+ if self.changed:
+ self.changed=False
+ return (self.latitude,self.longitude)
+ else:
+ return False
+
+ def run(self):
+ if self.test:
+ print "GpsPoller: serving random data"
+ else:
+ print "GpsPoller: serving data from",self.port
+ try:
+ while True:
+ if self.test:
+ self.latitude=random.random()*90
+ self.longitude=random.random()*90
+ self.changed=True
+ time.sleep(0.5)
+ else:
+ line = self.gps.read(1)
+ line = line+self.gps.readline()
+ datablock = line.split(',')
+
+ if line[0:6] == '$GPRMC':
+ latitude_in = string.atof(datablock[3])
+ longitude_in = string.atof(datablock[5])
+ altitude = string.atof(datablock[8])
+ speed_in = string.atof(datablock[7])
+ heading = string.atof(datablock[8])
+
+ if datablock[4] == 'S':
+ latitude_in = -latitude_in
+ if datablock[6] == 'W':
+ longitude_in = -longitude_in
+
+ latitude_degrees = int(latitude_in/100)
+ latitude_minutes = latitude_in - latitude_degrees*100
+
+ longitude_degrees = int(longitude_in/100)
+ longitude_minutes = longitude_in - longitude_degrees*100
+
+ latitude = latitude_degrees + (latitude_minutes/60)
+ longitude = longitude_degrees + (longitude_minutes/60)
+
+ if latitude!=self.latitude or longitude!=self.longitude:
+ self.latitude=latitude
+ self.longitude=longitude
+ self.changed=True
+
+
+ except StopIteration:
+ pass
+
+ def __del__():
+ self.gps.close()
+
+if __name__ == '__main__':
+
+ gpsp = GpsPoller(sys.argv[1])
+ gpsp.start()
+ while 1:
+ # In the main thread, every 5 seconds print the current value
+ time.sleep(0.1)
+ check=gpsp.check()
+ if check!=False:
+ print "changed:",check[0],check[1]
diff --git a/gpspoller.pyc b/gpspoller.pyc Binary files differnew file mode 100644 index 0000000..e8cda43 --- /dev/null +++ b/gpspoller.pyc diff --git a/gpstest.py b/gpstest.py new file mode 100644 index 0000000..88c5198 --- /dev/null +++ b/gpstest.py @@ -0,0 +1,14 @@ +import sys,gps
+port = 6
+gps = GPSDevice(port)
+gps.open()
+for record in gps.read_all():
+ if sys.argv[0] == 'forever':
+ print record
+ else:
+ if record['sentence'] == 'GLL':
+ print 'I am hanging out at long %s, lat %s at %s' % (
+ record['longitude'],
+ record['latitude'],
+ record['time'])
+ break
\ No newline at end of file diff --git a/indexmapV1.gif b/indexmapV1.gif Binary files differnew file mode 100644 index 0000000..63363bb --- /dev/null +++ b/indexmapV1.gif diff --git a/latLng.pyc b/latLng.pyc Binary files differnew file mode 100644 index 0000000..11ac9e8 --- /dev/null +++ b/latLng.pyc @@ -18,7 +18,7 @@ class layer: except: print "gps layer: failed to parse", file def findpixel(self,pos): - return latLng(int((pos.lng-self.tl.lng)/self.pixsize.lng),int((pos.lat-self.br.lat)/self.pixsize.lat)) + return (int((pos.lng-self.tl.lng)/self.pixsize.lng),int((pos.lat-self.br.lat)/self.pixsize.lat)) def checkcoord(self,pos): p=self.findpixel(pos) if p!=self.pixel: @@ -27,7 +27,10 @@ class layer: else: return None def setcoord(self,pos): - return str(1.0) + """constructs a list of messages when values change" + returns None otherwise""" + result=None + return r class trigger(): """a generic trigger - @@ -43,6 +46,26 @@ class trigger(): return None class indexlayer(layer): + """generates gps triggers from an index colour image + triggers when colour changes""" triggers=[] + colour=-1 def setcoord(self,pos): - return str(1)
\ No newline at end of file + result=None + #210 35 5 185 + c=self.image.getpixel(pos) + if c!=self.colour: + self.colour=c + print "indexlayer: new colour",c + for t in self.triggers: + if c==t.id: + result=t.command + return result + +class scalelayer(layer): + """generates a varying signal based on interpolating a greyscale image + uses sub pixel position""" + def findpixel(self,pos): + return (int((pos.lng-self.tl.lng)/self.pixsize.lng),int((pos.lat-self.br.lat)/self.pixsize.lat)) + def setcoord(self,pos): + result=None
\ No newline at end of file diff --git a/layers.pyc b/layers.pyc Binary files differnew file mode 100644 index 0000000..e95e372 --- /dev/null +++ b/layers.pyc diff --git a/testreceive.pd b/testreceive.pd index c375170..d53a273 100644 --- a/testreceive.pd +++ b/testreceive.pd @@ -1,4 +1,14 @@ -#N canvas 796 273 450 300 10; -#X obj 126 54 netreceive 5401 1; -#X obj 126 96 print udp; -#X connect 0 0 1 0; +#N canvas 915 509 450 300 10; +#X obj 169 92 print udp; +#X msg 29 61 /pd 1; +#X msg 82 26 /other 1; +#X obj 169 50 netreceive 5401 1; +#X obj 148 141 OSCroute /play; +#X obj 145 210 print play; +#X obj 230 204 print other; +#X connect 1 0 4 0; +#X connect 2 0 4 0; +#X connect 3 0 0 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 4 1 6 0; diff --git a/tomorrowtheground.py b/tomorrowtheground.py index 2ffdf7e..5553b42 100755 --- a/tomorrowtheground.py +++ b/tomorrowtheground.py @@ -1,6 +1,21 @@ #!/usr/bin/python #UDP listener +import signal,sys + +def signal_handler(signal, frame): + insock.close() + print "tomorrowtheground: interrupted" + sys.exit(0) + +signal.signal(signal.SIGINT, signal_handler) + +import gpspoller +gpsp="" +if len(sys.argv)>1: + gpsp = GpsPoller(sys.argv[1]) + gpsp.start() + from latLng import * from layers import * from xml2obj import * @@ -8,7 +23,7 @@ from xml2obj import * doc=xml2obj(open("ttg01.xml")) gpslayers=[] for i in doc.gps.index: - #should catch invalid xml + #catch invalid xml g=indexlayer(i.file,i.ll1,i.ll2) for t in i.trigger: g.triggers.append(trigger(int(t.id),t.command,t.param)) @@ -20,7 +35,7 @@ GUI_IP="127.0.0.1" GUI_PORT=5400 insock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) insock.bind( (GUI_IP,GUI_PORT) ) -insock.settimeout(0.01) +insock.settimeout(0.01) #non blocking PD_IP="127.0.0.1" PD_PORT=5401 outsock = socket.socket( socket.AF_INET,socket.SOCK_DGRAM ) @@ -35,11 +50,17 @@ while True: pos.parse(data) posChanged=True except: - nothing=None + nothing=None + if gpsp!="": + check=gpsp.check() + if check!=False: + pos=latLng(check[0],check[1]) + posChanged=True if posChanged: - print "received message:", data + posChanged=False for layer in gpslayers: - r=layer.checkcoord(pos) - if layer.checkcoord!=None: - outsock.sendto( r, (PD_IP, PD_PORT) ) + r=layer.checkcoord(pos) #returns a message or None + if r!=None: + #pd needs \n at end of message + outsock.sendto( str(r[0])+' '+str(r[1])+'\n', (PD_IP, PD_PORT) )
\ No newline at end of file diff --git a/tomorrowthegroundGUI/data/indexmapV1.gif b/tomorrowthegroundGUI/data/indexmapV1.gif Binary files differnew file mode 100644 index 0000000..3fcc16f --- /dev/null +++ b/tomorrowthegroundGUI/data/indexmapV1.gif diff --git a/tomorrowthegroundGUI/tomorrowthegroundGUI.pde b/tomorrowthegroundGUI/tomorrowthegroundGUI.pde index 0fe919e..b359409 100644 --- a/tomorrowthegroundGUI/tomorrowthegroundGUI.pde +++ b/tomorrowthegroundGUI/tomorrowthegroundGUI.pde @@ -1,15 +1,19 @@ import hypermedia.net.*; -PImage bgmap; +PImage[] bgmaps; +int usemap; UDP udp; int x,y; float lat1,lng1,lat2,lng2,fw,fh; void setup() { - bgmap = loadImage("gentmap.png"); + bgmaps=new PImage[2]; + bgmaps[0] = loadImage("gentmap.png"); + bgmaps[1] = loadImage("indexmapV1.gif"); + usemap=0; size(bgmap.width,bgmap.height); - frameRate(30); + frameRate(15); udp = new UDP(this); x=width/2; y=height/2; @@ -23,7 +27,7 @@ void setup() void draw() { - background(bgmap); + background(bgmaps[usemap]); fill(255); stroke(255,0,0); ellipse(x,y,5,5); @@ -39,3 +43,15 @@ void mouseDragged() udp.send(((fy*fh)+lat2)+","+((fx*fw)+lng1)+"\n","127.0.0.1",5400); } } + +void keyPressed() { + switch(key) { + case '0': + usemap=0; + break; + case '1': + usemap=1; + break; + } +} + @@ -1,10 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <tomorrowtheground> <gps> - <index file="x01.png" ll1="51.050608,3.724698" ll2="51.046878,3.732852"> + <index file="indexmapV1.gif" ll1="51.050608,3.724698" ll2="51.046878,3.732852"> <trigger id="01" command="play" param="b01.wav"> </trigger> - <trigger id="02" command="play" param="b02.wav"> + <trigger id="03" command="play" param="b02.wav"> + </trigger> + <trigger id="28" command="play" param="b03.wav"> + </trigger> + <trigger id="29" command="play" param="b04.wav"> </trigger> </index> <scale file="x02.png" ll1="51.050608,3.724698" ll2="51.046878,3.732852" freq="1.0" command="cc01"> diff --git a/xml2obj.pyc b/xml2obj.pyc Binary files differnew file mode 100644 index 0000000..180a0bb --- /dev/null +++ b/xml2obj.pyc |
