31 |
31 |
32 import datetime, sys, time, operator |
32 import datetime, sys, time, operator |
33 from math import * |
33 from math import * |
34 import xml.etree.ElementTree as etree |
34 import xml.etree.ElementTree as etree |
35 from optparse import OptionParser |
35 from optparse import OptionParser |
|
36 from functools import reduce |
36 |
37 |
37 |
38 |
38 parser = OptionParser('usage: %prog [options] input-file.gpx') |
39 parser = OptionParser('usage: %prog [options] input-file.gpx') |
39 parser.add_option('-v', '--verbose', action='store', type='int', |
40 parser.add_option('-v', '--verbose', action='store', type='int', |
40 dest='verbose', default=1, help='verbose=[0,1]') |
41 dest='verbose', default=1, help='verbose=[0,1]') |
140 points[-1]['weight'] += 1 |
141 points[-1]['weight'] += 1 |
141 n = len(points) |
142 n = len(points) |
142 |
143 |
143 # progress printing initialisations |
144 # progress printing initialisations |
144 progress_printed = False |
145 progress_printed = False |
145 progress = None |
146 progress = 0 |
146 tprint = time.time() |
147 tprint = time.time() |
147 |
148 |
148 # execute Dijkstra-like algorithm on points |
149 # execute Dijkstra-like algorithm on points |
149 points[0]['cost'] = 1.0 |
150 points[0]['cost'] = 1.0 |
150 points[0]['prev'] = -1 |
151 points[0]['prev'] = -1 |
240 penalties[i1] += options.bend * kink |
241 penalties[i1] += options.bend * kink |
241 |
242 |
242 # find best predecessor |
243 # find best predecessor |
243 imin = None |
244 imin = None |
244 costmin = float('inf') |
245 costmin = float('inf') |
245 for prev, penalty in penalties.iteritems(): |
246 for prev, penalty in penalties.items(): |
246 # cost function is sum of points used (1.0) plus penalties |
247 # cost function is sum of points used (1.0) plus penalties |
247 cost = points[prev]['cost'] + 1.0 + penalty |
248 cost = points[prev]['cost'] + 1.0 + penalty |
248 if cost < costmin: |
249 if cost < costmin: |
249 imin = prev |
250 imin = prev |
250 costmin = cost |
251 costmin = cost |
253 |
254 |
254 # print progess |
255 # print progess |
255 if options.verbose == 1 and (100 * i2) / n > progress and time.time() >= tprint + 1: |
256 if options.verbose == 1 and (100 * i2) / n > progress and time.time() >= tprint + 1: |
256 tprint = time.time() |
257 tprint = time.time() |
257 progress = (100 * i2) / n |
258 progress = (100 * i2) / n |
258 print '\r', progress, '%', |
259 print ('\r', progress, '%', end=' ') |
259 sys.stdout.flush() |
260 sys.stdout.flush() |
260 progress_printed = True |
261 progress_printed = True |
261 |
262 |
262 if progress_printed: |
263 if progress_printed: |
263 print '\r', |
264 print ('\r', end=' ') |
264 |
265 |
265 # trace route backwards to collect final points |
266 # trace route backwards to collect final points |
266 final_pnums = [] |
267 final_pnums = [] |
267 i = n-1 |
268 i = n-1 |
268 while i >= 0: |
269 while i >= 0: |
278 # initialisations |
279 # initialisations |
279 ntot = 0 # total number of trackpoints (sum of segments) |
280 ntot = 0 # total number of trackpoints (sum of segments) |
280 newtot = 0 # total number of trackpoints after removal |
281 newtot = 0 # total number of trackpoints after removal |
281 |
282 |
282 # import xml data from files |
283 # import xml data from files |
283 print 'opening file', fname |
284 print ('opening file', fname) |
284 infile = open(fname) |
285 infile = open(fname) |
285 tree = etree.parse(infile) |
286 tree = etree.parse(infile) |
286 infile.close() |
287 infile.close() |
287 |
288 |
288 gpx = tree.getroot() |
289 gpx = tree.getroot() |
301 eles = [float(trkpt.find(nsmap + 'ele').text) for trkpt in trkpts] |
302 eles = [float(trkpt.find(nsmap + 'ele').text) for trkpt in trkpts] |
302 try: |
303 try: |
303 times = [datetime.datetime.strptime(trkpt.find(nsmap + 'time' |
304 times = [datetime.datetime.strptime(trkpt.find(nsmap + 'time' |
304 ).text, timeformat) for trkpt in trkpts] |
305 ).text, timeformat) for trkpt in trkpts] |
305 except Exception as e: |
306 except Exception as e: |
306 print '-- trackpoint without time' |
307 print ('-- trackpoint without time') |
307 times = None |
308 times = None |
308 |
309 |
309 # calculate projected points to work on |
310 # calculate projected points to work on |
310 coords = [] |
311 coords = [] |
311 for i in range(n): |
312 for i in range(n): |
314 |
315 |
315 # execute the reduction algorithm |
316 # execute the reduction algorithm |
316 final_pnums = reduced_track_indices(coords, times) |
317 final_pnums = reduced_track_indices(coords, times) |
317 |
318 |
318 n_new = len (final_pnums) |
319 n_new = len (final_pnums) |
319 print 'segment %d, with %d - %d = %d points' % (si, n, n - n_new, n_new) |
320 print ('segment %d, with %d - %d = %d points' % (si, n, n - n_new, n_new)) |
320 ntot += n |
321 ntot += n |
321 newtot += n_new |
322 newtot += n_new |
322 |
323 |
323 # delete certain points from original data |
324 # delete certain points from original data |
324 delete_pnums = [i for i in range(n) if i not in final_pnums] |
325 delete_pnums = [i for i in range(n) if i not in final_pnums] |
327 del trkpts [i] # also remove from the list |
328 del trkpts [i] # also remove from the list |
328 |
329 |
329 # remove certain sub-elements from remaining points |
330 # remove certain sub-elements from remaining points |
330 options.remove = options.remove.replace ('+','extensions,hdop,') |
331 options.remove = options.remove.replace ('+','extensions,hdop,') |
331 taglist = options.remove.split (',') |
332 taglist = options.remove.split (',') |
332 if taglist: print 'remove %s subelements from points' % ', '.join (taglist) |
333 if taglist: print ('remove %s subelements from points' % ', '.join (taglist)) |
333 for trkpnt in trkpts: |
334 for trkpnt in trkpts: |
334 for tag in taglist: |
335 for tag in taglist: |
335 e = trkpnt.find (nsmap + tag) |
336 e = trkpnt.find (nsmap + tag) |
336 if e != None: trkpnt.remove (e) |
337 if e != None: trkpnt.remove (e) |
337 |
338 |
338 print 'total number of points: %d - %d = %d' % (ntot, ntot - newtot, newtot) |
339 print ('total number of points: %d - %d = %d' % (ntot, ntot - newtot, newtot)) |
339 |
340 |
340 # export data to file |
341 # export data to file |
341 if options.ofname != None: |
342 if options.ofname != None: |
342 ofname = options.ofname |
343 ofname = options.ofname |
343 elif fname.endswith('.gpx'): |
344 elif fname.endswith('.gpx'): |
344 ofname = fname[:-4] + '_reduced.gpx' |
345 ofname = fname[:-4] + '_reduced.gpx' |
345 else: |
346 else: |
346 ofname = fname + '_reduced.gpx' |
347 ofname = fname + '_reduced.gpx' |
347 outfile = open(ofname, 'w') |
348 outfile = open(ofname, 'wb') |
348 tree.write (outfile, encoding="utf-8", xml_declaration=True, default_namespace=None, method="xml") |
349 tree.write (outfile, encoding="utf-8", xml_declaration=True, default_namespace=None, method="xml") |
349 outfile.close() |
350 outfile.close() |
350 print 'modified copy written to', ofname |
351 print ('modified copy written to', ofname) |