gpx_reduce.py
changeset 15 cfb0607e5afc
parent 10 89108adbc468
equal deleted inserted replaced
14:f440529b9606 15:cfb0607e5afc
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python3
     2 # -*- coding: utf8 -*-
     2 # -*- coding: utf8 -*-
     3 
     3 
     4 '''
     4 '''
     5 gpx_reduce v1.8: removes points from gpx-files to reduce filesize and
     5 gpx_reduce v1.8: removes points from gpx-files to reduce filesize and
     6 tries to keep introduced distortions to the track at a minimum.
     6 tries to keep introduced distortions to the track at a minimum.
    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)