]>
Commit | Line | Data |
---|---|---|
06a509d2 EB |
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) |