]> git.street.me.uk Git - andy/viking.git/blob - tools/gctrackbyarc.py
Some spelling fixes in a comment
[andy/viking.git] / tools / gctrackbyarc.py
1 #!/usr/bin/env python
2
3 # WARNING: I haven't thought much about the best way of doing
4 #          this. it may get lots of extra caches, or take a long
5 #          time if your path goes thru a city.
6 # there's probably a better algorithm.
7
8 # in meters.
9 maxdist = 2500.0
10
11 # get geocaches, circles of "radius", then go ahead advance_dist in the track and do it again.
12 #radius = maxdist * 2 * 0.707106 # sqrt(2)
13 radius = maxdist * 2
14 advance_dist = maxdist * 2
15
16
17 # TODO: shell escape in case mkdtemp has unsafe chars in (unlikely)
18
19 class Coord:
20   def __init__(self, lat=0.0, lon=0.0):
21     self.lat = lat
22     self.lon = lon
23
24   # diff between two coords in meters.
25   def diff(c1,c2):
26     from math import acos, sin, cos
27     PIOVER180 = 3.14159265358979 / 180.0
28     EquatorialRadius = 6378137 # WGS-84
29     lat1 = c1.lat * PIOVER180
30     lon1 = c1.lon * PIOVER180
31     lat2 = c2.lat * PIOVER180
32     lon2 = c2.lon * PIOVER180
33     return EquatorialRadius * acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2));
34
35 def load_track ( file ):
36   import re
37   latlonre = re.compile("lat=['\"]([0-9\\-\\.]*?)['\"].*lon=['\"]([0-9\\-\\.]*?)['\"]")
38   track = []
39   for line in file:
40     match = latlonre.search(line)
41     if match:
42       lat = float(match.group(1))
43       lon = float(match.group(2))
44       track.append ( Coord(lat,lon) )
45   return track
46
47 # position inside of a track = index of trackpoint + meters past this trackpoint
48 class TPos:
49   def __init__(self, track):
50     self.track = track
51     self.n_tps = len(self.track)
52     self.i_lasttp = 0 # index of tp before current position
53     self.dist_past = 0 # meters past this tp
54
55     self.coord = Coord()
56
57     if self.n_tps > 0:
58       self.coord.lat = track[0].lat
59       self.coord.lon = track[0].lon
60
61     if self.n_tps > 1:
62       self.finished = False
63     else:
64       self.finished = True # no tps in track, nothing to do
65
66   def recalculate_coord(self):
67     if self.i_lasttp >= self.n_tps - 1:
68       self.coord = self.track[self.n_tps - 1] # return last tp
69       return
70
71     c1 = self.track[self.i_lasttp]
72     c2 = self.track[self.i_lasttp+1]
73
74     # APPROXIMATE
75     percentage_past = self.dist_past / Coord.diff ( c1, c2 )
76     self.coord.lat = c1.lat + percentage_past * (c2.lat - c1.lat)
77     self.coord.lon = c1.lon + percentage_past * (c2.lon - c1.lon)
78
79   def advance(self, distance):
80     if self.i_lasttp >= (self.n_tps - 1):
81       self.finished = True
82     if self.finished:
83       return
84
85     # possibility one: we don't pass a TP
86     dist_to_next_tp = Coord.diff ( self.track[self.i_lasttp], self.track[self.i_lasttp+1] ) - self.dist_past
87     if dist_to_next_tp > distance:
88       self.dist_past += distance
89       self.recalculate_coord()
90     else:
91       # goto beginning of next tp and try again.
92       self.i_lasttp += 1
93       self.dist_past = 0
94
95       if self.i_lasttp >= (self.n_tps - 1):
96         self.recalculate_coord()
97       else:
98         self.advance ( distance - dist_to_next_tp )
99
100 #    dist_after_pos = dist_after_i
101 #    if self.track[i_lasttp
102 # TODO!
103
104   def end(self):
105     return self.finished
106
107   
108 def get_geocaches_for(coord,radius,tmpdir,i):
109   import os, sys
110   MAXGCS = 100
111   radiusinmiles = radius * 100 / 2.54 / 12 / 5280 # meters to miles
112   gcgetstr = "gcget %f,%f %d %f > %s/%d.loc" % (coord.lat, coord.lon, MAXGCS, radius, tmpdir, i)
113   sys.stderr.write("%s\n" % gcgetstr)
114   os.system(gcgetstr)
115   #print "type=\"trackpoint\" latitude=\"%f\" longitude=\"%f\"" % (coord.lat, coord.lon)
116
117
118 #------------
119
120
121 import sys, os
122 tr = load_track ( sys.stdin )
123 tpos = TPos(tr)
124
125 import tempfile
126 tmpdir = tempfile.mkdtemp()
127
128 i = 0
129 while not tpos.end():
130   get_geocaches_for ( tpos.coord, radius, tmpdir, i )
131   tpos.advance ( advance_dist )
132   i += 1
133 get_geocaches_for ( tpos.coord, radius, tmpdir, i )
134
135 ####### condense all #######
136 gb_input_args = ["-i geo -f %s/%d.loc" % (tmpdir,j) for j in range(i)]
137 gb_string = "gpsbabel %s -x duplicate,location -o gpx -F -" % (" ".join(gb_input_args))
138 sys.stderr.write("\n%s\n" % gb_string)
139 os.system(gb_string)
140
141 ####### delete temp files #######
142 for j in range(i):
143   os.sys.remove("%s/%d.loc" % (tmpdir,j))
144 os.sys.rmdir(tmpdir)