1 package net.sourceforge.jgeocoder.tiger;
2
3 import org.apache.commons.lang.builder.EqualsBuilder;
4 import org.apache.commons.lang.builder.HashCodeBuilder;
5 import org.apache.commons.lang.builder.ToStringBuilder;
6
7
8
9
10
11
12
13
14
15
16 class Geo{
17 public float lat, lon;
18 public int zip;
19 public long tlid;
20 public Geo(){}
21 public Geo(float lat, float lon, int zip, long tlid) {
22 this.lat = lat;
23 this.lon = lon;
24 this.zip = zip;
25 this.tlid = tlid;
26 }
27 @Override
28 public String toString() {
29 return ToStringBuilder.reflectionToString(this);
30 }
31 @Override
32 public int hashCode() {
33 return HashCodeBuilder.reflectionHashCode(this);
34 }
35 @Override
36 public boolean equals(Object obj) {
37 return EqualsBuilder.reflectionEquals(this, obj);
38 }
39 }
40
41 class Distance{
42 public float totalLat=0f, totalLon=0f;
43 }
44 /***
45 * TODO javadocs me
46 * @author jliang
47 *
48 */
49 class Geocoder {
50
51 static Geo geocodeFromHit(int streetnum, TigerLineHit hit){
52 return geocode(streetnum, hit.tlid, Integer.valueOf(hit.frAddR), Integer.valueOf(hit.frAddL),
53 Integer.valueOf(hit.toAddR), Integer.valueOf(hit.toAddL),
54 Integer.valueOf(hit.zipL), Integer.valueOf(hit.zipR), hit.toLat, hit.toLon, hit.frLon, hit.frLat,
55 hit.lon1, hit.lat1, hit.lon2, hit.lat2, hit.lon3, hit.lat3, hit.lon4, hit.lat4, hit.lon5, hit.lat5,
56 hit.lon6, hit.lat6, hit.lon7, hit.lat7, hit.lon8, hit.lat8, hit.lon9, hit.lat9, hit.lon10, hit.lat10);
57 }
58
59 static Geo geocode(int streetnum, long tlid, int fraddr, int fraddl, int toaddr, int toaddl,
60 int zipL, int zipR, float tolat, float tolong, float frlong, float frlat,
61 float long1, float lat1, float long2, float lat2, float long3, float lat3, float long4, float lat4,
62 float long5, float lat5, float long6, float lat6, float long7, float lat7, float long8, float lat8,
63 float long9, float lat9, float long10, float lat10 ){
64
65 Distance distance = getDistance(tolat, tolong, frlong, frlat, long1, lat1, long2, lat2, long3, lat3, long4, lat4, long5, lat5, long6, lat6, long7, lat7, long8, lat8, long9, lat9, long10, lat10);
66 int addrStart, addrEnd, zip;
67 if(!isLeft(streetnum, fraddr, fraddl, toaddr, toaddl) && (fraddr%2 == streetnum%2)){
68 addrStart = fraddr; addrEnd = toaddr; zip = zipR;
69 }else{
70 addrStart = fraddl; addrEnd = toaddl; zip = zipL;
71 }
72
73 int dec1 = addrEnd - streetnum, dec2 = addrEnd - addrStart;
74 float rel = dec1*1f / dec2;
75 if(rel == 1f){
76 return new Geo(frlat, frlong, zip, tlid);
77 }
78 if(rel == 0f){
79 return new Geo(tolat, tolong, zip, tlid);
80 }
81
82
83
84 float tempEndLat = frlat + distance.totalLat, tempEndLon = frlong + distance.totalLon;
85 float totalDist = getLineDistance(frlong, frlat, tempEndLon, tempEndLat);
86 Geo ret = pointFromChainRatio(totalDist, rel, tolat, tolong, frlong, frlat, long1, lat1, long2, lat2, long3, lat3, long4, lat4, long5, lat5, long6, lat6, long7, lat7, long8, lat8, long9, lat9, long10, lat10);
87 ret.zip = zip; ret.tlid = tlid;
88 return ret;
89 }
90
91 private static Geo pointFromChainRatio(float totalLength, float ratio,
92 float tolat, float tolong, float frlong, float frlat,
93 float long1, float lat1, float long2, float lat2, float long3, float lat3, float long4, float lat4,
94 float long5, float lat5, float long6, float lat6, float long7, float lat7, float long8, float lat8,
95 float long9, float lat9, float long10, float lat10
96 ){
97 float lastLat = frlat, lastLon = frlong;
98 boolean found = false;
99 float totalRatio=0f, totalTravel=0f, travelTarget=ratio*totalLength;
100
101
102
103
104 float thisLen, thisRatio, useStartLon=frlong, useStartLat=frlat, useEndLon=tolong, useEndLat=tolat, useRatio=ratio;
105
106
107 if(lat1 != 0 && !found){
108 thisLen = getLineDistance(long1, lat1, lastLon, lastLat);
109 thisRatio = thisLen / totalLength;
110 if(thisLen + totalTravel >= travelTarget){
111 useStartLat = lastLat; useStartLon = lastLon;
112 useEndLat = lat1; useEndLon = long1;
113 useRatio = thisRatio; found = true;
114 }else{
115 totalRatio = totalRatio + thisRatio;
116 lastLon = long1; lastLat = lat1;
117 totalTravel = totalTravel + thisLen;
118 }
119 }
120
121 if(lat2 != 0 && !found){
122 thisLen = getLineDistance(long2, lat2, lastLon, lastLat);
123 thisRatio = thisLen / totalLength;
124 if(thisLen + totalTravel >= travelTarget){
125 useStartLat = lastLat; useStartLon = lastLon;
126 useEndLat = lat2; useEndLon = long2;
127 useRatio = thisRatio; found = true;
128 }else{
129 totalRatio = totalRatio + thisRatio;
130 lastLon = long2; lastLat = lat2;
131 totalTravel = totalTravel + thisLen;
132 }
133 }
134
135 if(lat3 != 0 && !found){
136 thisLen = getLineDistance(long3, lat3, lastLon, lastLat);
137 thisRatio = thisLen / totalLength;
138 if(thisLen + totalTravel >= travelTarget){
139 useStartLat = lastLat; useStartLon = lastLon;
140 useEndLat = lat3; useEndLon = long3;
141 useRatio = thisRatio; found = true;
142 }else{
143 totalRatio = totalRatio + thisRatio;
144 lastLon = long3; lastLat = lat3;
145 totalTravel = totalTravel + thisLen;
146 }
147 }
148
149 if(lat4 != 0 && !found){
150 thisLen = getLineDistance(long4, lat4, lastLon, lastLat);
151 thisRatio = thisLen / totalLength;
152 if(thisLen + totalTravel >= travelTarget){
153 useStartLat = lastLat; useStartLon = lastLon;
154 useEndLat = lat4; useEndLon = long4;
155 useRatio = thisRatio; found = true;
156 }else{
157 totalRatio = totalRatio + thisRatio;
158 lastLon = long4; lastLat = lat4;
159 totalTravel = totalTravel + thisLen;
160 }
161 }
162
163 if(lat5 != 0 && !found){
164 thisLen = getLineDistance(long5, lat5, lastLon, lastLat);
165 thisRatio = thisLen / totalLength;
166 if(thisLen + totalTravel >= travelTarget){
167 useStartLat = lastLat; useStartLon = lastLon;
168 useEndLat = lat5; useEndLon = long5;
169 useRatio = thisRatio; found = true;
170 }else{
171 totalRatio = totalRatio + thisRatio;
172 lastLon = long5; lastLat = lat5;
173 totalTravel = totalTravel + thisLen;
174 }
175 }
176
177 if(lat6 != 0 && !found){
178 thisLen = getLineDistance(long6, lat6, lastLon, lastLat);
179 thisRatio = thisLen / totalLength;
180 if(thisLen + totalTravel >= travelTarget){
181 useStartLat = lastLat; useStartLon = lastLon;
182 useEndLat = lat6; useEndLon = long6;
183 useRatio = thisRatio; found = true;
184 }else{
185 totalRatio = totalRatio + thisRatio;
186 lastLon = long6; lastLat = lat6;
187 totalTravel = totalTravel + thisLen;
188 }
189 }
190
191 if(lat7 != 0 && !found){
192 thisLen = getLineDistance(long7, lat7, lastLon, lastLat);
193 thisRatio = thisLen / totalLength;
194 if(thisLen + totalTravel >= travelTarget){
195 useStartLat = lastLat; useStartLon = lastLon;
196 useEndLat = lat7; useEndLon = long7;
197 useRatio = thisRatio; found = true;
198 }else{
199 totalRatio = totalRatio + thisRatio;
200 lastLon = long7; lastLat = lat7;
201 totalTravel = totalTravel + thisLen;
202 }
203 }
204
205 if(lat8 != 0 && !found){
206 thisLen = getLineDistance(long8, lat8, lastLon, lastLat);
207 thisRatio = thisLen / totalLength;
208 if(thisLen + totalTravel >= travelTarget){
209 useStartLat = lastLat; useStartLon = lastLon;
210 useEndLat = lat8; useEndLon = long8;
211 useRatio = thisRatio; found = true;
212 }else{
213 totalRatio = totalRatio + thisRatio;
214 lastLon = long8; lastLat = lat8;
215 totalTravel = totalTravel + thisLen;
216 }
217 }
218
219 if(lat9 != 0 && !found){
220 thisLen = getLineDistance(long9, lat9, lastLon, lastLat);
221 thisRatio = thisLen / totalLength;
222 if(thisLen + totalTravel >= travelTarget){
223 useStartLat = lastLat; useStartLon = lastLon;
224 useEndLat = lat9; useEndLon = long9;
225 useRatio = thisRatio; found = true;
226 }else{
227 totalRatio = totalRatio + thisRatio;
228 lastLon = long9; lastLat = lat9;
229 totalTravel = totalTravel + thisLen;
230 }
231 }
232
233 if(lat10 != 0 && !found){
234 thisLen = getLineDistance(long10, lat10, lastLon, lastLat);
235 thisRatio = thisLen / totalLength;
236 if(thisLen + totalTravel >= travelTarget){
237 useStartLat = lastLat; useStartLon = lastLon;
238 useEndLat = lat10; useEndLon = long10;
239 useRatio = thisRatio; found = true;
240 }else{
241 totalRatio = totalRatio + thisRatio;
242 lastLon = long10; lastLat = lat10;
243 totalTravel = totalTravel + thisLen;
244 }
245 }
246 float rel = (ratio - totalRatio)/ useRatio;
247 float lonDist = useEndLon - useStartLon;
248 float latDist = useEndLat - useStartLat;
249 Geo ret = new Geo();
250 ret.lat = useEndLat - (rel * latDist);
251 ret.lon = useEndLon - (rel * lonDist);
252 return ret;
253 }
254
255 private static float getLineDistance(float x1, float y1, float x2, float y2){
256 double dx = x2 - x1, dy = y2-y1;
257 return (float)Math.sqrt(dx*dx + dy*dy);
258 }
259
260 private static boolean isLeft(int streetnum, int fraddr, int fraddl, int toaddr, int toaddl){
261 return fraddr == -1 || (!between(streetnum, fraddr, toaddr) && !between(streetnum, toaddr, fraddr));
262 }
263
264 private static boolean between(int num, int start, int end){
265 return num >= start && num <= end;
266 }
267
268 private static Distance getDistance(float tolat, float tolong, float frlong, float frlat,
269 float long1, float lat1, float long2, float lat2, float long3, float lat3, float long4, float lat4,
270 float long5, float lat5, float long6, float lat6, float long7, float lat7, float long8, float lat8,
271 float long9, float lat9, float long10, float lat10){
272 Distance ret = new Distance();
273 float lastLat = frlat, lastLon = frlong;
274 if(lat1 != 0f){
275 ret.totalLat += Math.abs(lat1 - lastLat);
276 ret.totalLon += Math.abs(long1 - lastLon);
277 lastLat = lat1;
278 lastLon = long1;
279 }
280 if(lat2 != 0f){
281 ret.totalLat += Math.abs(lat2 - lastLat);
282 ret.totalLon += Math.abs(long2 - lastLon);
283 lastLat = lat2;
284 lastLon = long2;
285 }
286
287 if(lat3 != 0f){
288 ret.totalLat += Math.abs(lat3 - lastLat);
289 ret.totalLon += Math.abs(long3 - lastLon);
290 lastLat = lat3;
291 lastLon = long3;
292 }
293
294 if(lat4 != 0f){
295 ret.totalLat += Math.abs(lat4 - lastLat);
296 ret.totalLon += Math.abs(long4 - lastLon);
297 lastLat = lat4;
298 lastLon = long4;
299 }
300
301 if(lat5 != 0f){
302 ret.totalLat += Math.abs(lat5 - lastLat);
303 ret.totalLon += Math.abs(long5 - lastLon);
304 lastLat = lat5;
305 lastLon = long5;
306 }
307
308 if(lat6 != 0f){
309 ret.totalLat += Math.abs(lat6 - lastLat);
310 ret.totalLon += Math.abs(long6 - lastLon);
311 lastLat = lat6;
312 lastLon = long6;
313 }
314
315 if(lat7 != 0f){
316 ret.totalLat += Math.abs(lat7 - lastLat);
317 ret.totalLon += Math.abs(long7 - lastLon);
318 lastLat = lat7;
319 lastLon = long7;
320 }
321
322 if(lat8 != 0f){
323 ret.totalLat += Math.abs(lat8 - lastLat);
324 ret.totalLon += Math.abs(long8 - lastLon);
325 lastLat = lat8;
326 lastLon = long8;
327 }
328
329 if(lat9 != 0f){
330 ret.totalLat += Math.abs(lat9 - lastLat);
331 ret.totalLon += Math.abs(long9 - lastLon);
332 lastLat = lat9;
333 lastLon = long9;
334 }
335
336 if(lat10 != 0f){
337 ret.totalLat += Math.abs(lat10 - lastLat);
338 ret.totalLon += Math.abs(long10 - lastLon);
339 lastLat = lat10;
340 lastLon = long10;
341 }
342
343 ret.totalLat += Math.abs(tolat - lastLat);
344 ret.totalLon += Math.abs(tolong - lastLon);
345
346 return ret;
347 }
348
349 }