geo_coder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +32 -0
  3. data/History.txt +6 -0
  4. data/Makefile +13 -0
  5. data/Manifest.txt +18 -0
  6. data/README.rdoc +197 -0
  7. data/Rakefile +53 -0
  8. data/TODO.txt +8 -0
  9. data/VERSION +1 -0
  10. data/bin/build_indexes +8 -0
  11. data/bin/rebuild_cluster +22 -0
  12. data/bin/rebuild_metaphones +23 -0
  13. data/bin/tiger_import +59 -0
  14. data/demos/demo/app/ext/geocodewrap.rb +84 -0
  15. data/demos/demo/app/views/index.builder +13 -0
  16. data/demos/demo/app/views/index.erb +71 -0
  17. data/demos/demo/config.ru +12 -0
  18. data/demos/demo/config/bootstraps.rb +130 -0
  19. data/demos/demo/config/geoenvironment.rb +25 -0
  20. data/demos/demo/geocoder_helper.rb +12 -0
  21. data/demos/demo/geocom_geocode.rb +10 -0
  22. data/demos/demo/main.rb +3 -0
  23. data/demos/demo/rakefile.rb +17 -0
  24. data/demos/demo/tmp/restart.txt +0 -0
  25. data/demos/simpledemo/views/index.builder +13 -0
  26. data/demos/simpledemo/views/index.erb +69 -0
  27. data/demos/simpledemo/ws.rb +83 -0
  28. data/doc/Makefile +7 -0
  29. data/doc/html4css1.css +279 -0
  30. data/doc/lookup.rst +193 -0
  31. data/doc/parsing.rst +125 -0
  32. data/doc/voidspace.css +147 -0
  33. data/geo_coder.gemspec +172 -0
  34. data/lib/geocoder/us.rb +21 -0
  35. data/lib/geocoder/us/address.rb +290 -0
  36. data/lib/geocoder/us/constants.rb +670 -0
  37. data/lib/geocoder/us/database.rb +745 -0
  38. data/lib/geocoder/us/import.rb +181 -0
  39. data/lib/geocoder/us/import/tiger.rb +13 -0
  40. data/lib/geocoder/us/numbers.rb +58 -0
  41. data/navteq/README +4 -0
  42. data/navteq/convert.sql +37 -0
  43. data/navteq/navteq_import +39 -0
  44. data/navteq/prepare.sql +92 -0
  45. data/sql/cluster.sql +16 -0
  46. data/sql/convert.sql +80 -0
  47. data/sql/create.sql +37 -0
  48. data/sql/index.sql +12 -0
  49. data/sql/place.csv +104944 -0
  50. data/sql/place.sql +104948 -0
  51. data/sql/setup.sql +78 -0
  52. data/src/Makefile +13 -0
  53. data/src/README +14 -0
  54. data/src/liblwgeom/Makefile +75 -0
  55. data/src/liblwgeom/box2d.c +54 -0
  56. data/src/liblwgeom/lex.yy.c +4799 -0
  57. data/src/liblwgeom/liblwgeom.h +1405 -0
  58. data/src/liblwgeom/lwalgorithm.c +946 -0
  59. data/src/liblwgeom/lwalgorithm.h +52 -0
  60. data/src/liblwgeom/lwcircstring.c +759 -0
  61. data/src/liblwgeom/lwcollection.c +541 -0
  62. data/src/liblwgeom/lwcompound.c +118 -0
  63. data/src/liblwgeom/lwcurvepoly.c +86 -0
  64. data/src/liblwgeom/lwgeom.c +886 -0
  65. data/src/liblwgeom/lwgeom_api.c +2201 -0
  66. data/src/liblwgeom/lwgparse.c +1219 -0
  67. data/src/liblwgeom/lwgunparse.c +1054 -0
  68. data/src/liblwgeom/lwline.c +525 -0
  69. data/src/liblwgeom/lwmcurve.c +125 -0
  70. data/src/liblwgeom/lwmline.c +137 -0
  71. data/src/liblwgeom/lwmpoint.c +138 -0
  72. data/src/liblwgeom/lwmpoly.c +141 -0
  73. data/src/liblwgeom/lwmsurface.c +129 -0
  74. data/src/liblwgeom/lwpoint.c +439 -0
  75. data/src/liblwgeom/lwpoly.c +579 -0
  76. data/src/liblwgeom/lwsegmentize.c +1047 -0
  77. data/src/liblwgeom/lwutil.c +369 -0
  78. data/src/liblwgeom/measures.c +861 -0
  79. data/src/liblwgeom/postgis_config.h +93 -0
  80. data/src/liblwgeom/ptarray.c +847 -0
  81. data/src/liblwgeom/vsprintf.c +179 -0
  82. data/src/liblwgeom/wktparse.h +126 -0
  83. data/src/liblwgeom/wktparse.lex +74 -0
  84. data/src/liblwgeom/wktparse.tab.c +2353 -0
  85. data/src/liblwgeom/wktparse.tab.h +145 -0
  86. data/src/liblwgeom/wktparse.y +385 -0
  87. data/src/libsqlite3_geocoder/Makefile +22 -0
  88. data/src/libsqlite3_geocoder/Makefile.nix +15 -0
  89. data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
  90. data/src/libsqlite3_geocoder/extension.c +121 -0
  91. data/src/libsqlite3_geocoder/extension.h +13 -0
  92. data/src/libsqlite3_geocoder/levenshtein.c +42 -0
  93. data/src/libsqlite3_geocoder/metaphon.c +278 -0
  94. data/src/libsqlite3_geocoder/util.c +37 -0
  95. data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
  96. data/src/metaphone/Makefile +7 -0
  97. data/src/metaphone/README +49 -0
  98. data/src/metaphone/extension.c +37 -0
  99. data/src/metaphone/metaphon.c +251 -0
  100. data/src/shp2sqlite/Makefile +37 -0
  101. data/src/shp2sqlite/Makefile.nix +36 -0
  102. data/src/shp2sqlite/Makefile.redhat +35 -0
  103. data/src/shp2sqlite/dbfopen.c +1595 -0
  104. data/src/shp2sqlite/getopt.c +695 -0
  105. data/src/shp2sqlite/getopt.h +127 -0
  106. data/src/shp2sqlite/shapefil.h +500 -0
  107. data/src/shp2sqlite/shp2sqlite.c +1974 -0
  108. data/src/shp2sqlite/shpopen.c +1894 -0
  109. data/tests/address.rb +236 -0
  110. data/tests/benchmark.rb +20 -0
  111. data/tests/constants.rb +57 -0
  112. data/tests/data/address-sample.csv +52 -0
  113. data/tests/data/db-test.csv +57 -0
  114. data/tests/data/locations.csv +4 -0
  115. data/tests/database.rb +137 -0
  116. data/tests/generate.rb +34 -0
  117. data/tests/numbers.rb +46 -0
  118. data/tests/run.rb +11 -0
  119. metadata +237 -0
@@ -0,0 +1,946 @@
1
+ /**********************************************************************
2
+ * $Id: lwalgorithm.c 3812 2009-03-09 14:36:15Z pramsey $
3
+ *
4
+ * PostGIS - Spatial Types for PostgreSQL
5
+ * http://postgis.refractions.net
6
+ * Copyright 2008 Paul Ramsey
7
+ *
8
+ * This is free software; you can redistribute and/or modify it under
9
+ * the terms of the GNU General Public Licence. See the COPYING file.
10
+ *
11
+ **********************************************************************/
12
+
13
+ #include "lwalgorithm.h"
14
+
15
+
16
+ /*
17
+ ** lw_segment_side()
18
+ **
19
+ ** Return < 0.0 if point Q is left of segment P
20
+ ** Return > 0.0 if point Q is right of segment P
21
+ ** Return = 0.0 if point Q in on segment P
22
+ */
23
+ double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q)
24
+ {
25
+ return ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) );
26
+ }
27
+
28
+ int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2)
29
+ {
30
+ double minq=LW_MIN(q1.x,q2.x);
31
+ double maxq=LW_MAX(q1.x,q2.x);
32
+ double minp=LW_MIN(p1.x,p2.x);
33
+ double maxp=LW_MAX(p1.x,p2.x);
34
+
35
+ if (minp>maxq || maxp<minq)
36
+ return LW_FALSE;
37
+
38
+ minq=LW_MIN(q1.y,q2.y);
39
+ maxq=LW_MAX(q1.y,q2.y);
40
+ minp=LW_MIN(p1.y,p2.y);
41
+ maxp=LW_MAX(p1.y,p2.y);
42
+
43
+ if (minp>maxq || maxp<minq)
44
+ return LW_FALSE;
45
+
46
+ return LW_TRUE;
47
+ }
48
+
49
+ /*
50
+ ** lw_segment_intersects()
51
+ **
52
+ ** Returns one of
53
+ ** SEG_ERROR = -1,
54
+ ** SEG_NO_INTERSECTION = 0,
55
+ ** SEG_COLINEAR = 1,
56
+ ** SEG_CROSS_LEFT = 2,
57
+ ** SEG_CROSS_RIGHT = 3,
58
+ ** SEG_TOUCH_LEFT = 4,
59
+ ** SEG_TOUCH_RIGHT = 5
60
+ */
61
+ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2)
62
+ {
63
+
64
+ double pq1, pq2, qp1, qp2;
65
+
66
+ /* No envelope interaction => we are done. */
67
+ if (!lw_segment_envelope_intersects(*p1, *p2, *q1, *p2))
68
+ {
69
+ return SEG_NO_INTERSECTION;
70
+ }
71
+
72
+ /* Are the start and end points of q on the same side of p? */
73
+ pq1=lw_segment_side(p1,p2,q1);
74
+ pq2=lw_segment_side(p1,p2,q2);
75
+ if ((pq1>0 && pq2>0) || (pq1<0 && pq2<0))
76
+ {
77
+ return SEG_NO_INTERSECTION;
78
+ }
79
+
80
+ /* Are the start and end points of p on the same side of q? */
81
+ qp1=lw_segment_side(q1,q2,p1);
82
+ qp2=lw_segment_side(q1,q2,p2);
83
+ if ((qp1>0 && qp2>0) || (qp1<0 && qp2<0))
84
+ {
85
+ return SEG_NO_INTERSECTION;
86
+ }
87
+
88
+ /* Nobody is on one side or another? Must be colinear. */
89
+ if (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0)
90
+ {
91
+ return SEG_COLINEAR;
92
+ }
93
+
94
+ /*
95
+ ** When one end-point touches, the sidedness is determined by the
96
+ ** location of the other end-point.
97
+ */
98
+ if ( pq2 == 0.0 )
99
+ {
100
+ if ( pq1 < 0.0 )
101
+ return SEG_TOUCH_LEFT;
102
+ else
103
+ return SEG_TOUCH_RIGHT;
104
+ }
105
+ if ( pq1 == 0.0 )
106
+ {
107
+ if ( pq2 < 0.0 )
108
+ return SEG_TOUCH_LEFT;
109
+ else
110
+ return SEG_TOUCH_RIGHT;
111
+ }
112
+
113
+ /* The segments cross, what direction is the crossing? */
114
+ if ( pq1 < pq2 )
115
+ return SEG_CROSS_RIGHT;
116
+ else
117
+ return SEG_CROSS_LEFT;
118
+
119
+ /* This should never happen! */
120
+ return SEG_ERROR;
121
+
122
+ }
123
+
124
+ /*
125
+ ** lwline_crossing_direction()
126
+ **
127
+ ** Returns one of
128
+ ** LINE_NO_CROSS = 0
129
+ ** LINE_CROSS_LEFT = -1
130
+ ** LINE_CROSS_RIGHT = 1
131
+ ** LINE_MULTICROSS_END_LEFT = -2
132
+ ** LINE_MULTICROSS_END_RIGHT = 2
133
+ ** LINE_MULTICROSS_END_SAME_FIRST_LEFT = -3
134
+ ** LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3
135
+ **
136
+ */
137
+ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2)
138
+ {
139
+
140
+ int i = 0, j = 0, rv = 0;
141
+ POINT2D *p1;
142
+ POINT2D *p2;
143
+ POINT2D *q1;
144
+ POINT2D *q2;
145
+ POINTARRAY *pa1;
146
+ POINTARRAY *pa2;
147
+ int cross_left = 0;
148
+ int cross_right = 0;
149
+ int first_cross = 0;
150
+ int final_cross = 0;
151
+ int this_cross = 0;
152
+ int vertex_touch = -1;
153
+ int vertex_touch_type = 0;
154
+
155
+ pa1 = (POINTARRAY*)l1->points;
156
+ pa2 = (POINTARRAY*)l2->points;
157
+
158
+ p1 = lwalloc(sizeof(POINT2D));
159
+ p2 = lwalloc(sizeof(POINT2D));
160
+ q1 = lwalloc(sizeof(POINT2D));
161
+ q2 = lwalloc(sizeof(POINT2D));
162
+
163
+ /* One-point lines can't intersect (and shouldn't exist). */
164
+ if ( pa1->npoints < 2 || pa2->npoints < 2 )
165
+ return LINE_NO_CROSS;
166
+
167
+ LWDEBUGF(4, "lineCrossingDirection: l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0));
168
+ LWDEBUGF(4, "lineCrossingDirection: l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0));
169
+
170
+ for ( i = 1; i < pa2->npoints; i++ )
171
+ {
172
+
173
+ rv = getPoint2d_p(pa2, i-1, q1);
174
+ rv = getPoint2d_p(pa2, i, q2);
175
+
176
+ for ( j = 1; j < pa1->npoints; j++ )
177
+ {
178
+
179
+ rv = getPoint2d_p(pa1, j-1, p1);
180
+ rv = getPoint2d_p(pa1, j, p2);
181
+
182
+ LWDEBUGF(4, "lineCrossingDirection: i=%d, j=%d", i, j);
183
+
184
+ this_cross = lw_segment_intersects(p1, p2, q1, q2);
185
+
186
+ if ( ! first_cross && this_cross )
187
+ first_cross = this_cross;
188
+ if ( this_cross )
189
+ final_cross = this_cross;
190
+
191
+ if ( this_cross == SEG_CROSS_LEFT )
192
+ {
193
+ cross_left++;
194
+ break;
195
+ }
196
+
197
+ if ( this_cross == SEG_CROSS_RIGHT )
198
+ {
199
+ cross_right++;
200
+ break;
201
+ }
202
+
203
+ /*
204
+ ** Crossing at a co-linearity can be turned into crossing at
205
+ ** a vertex by pulling the original touch point forward along
206
+ ** the co-linearity.
207
+ */
208
+ if ( this_cross == SEG_COLINEAR && vertex_touch == (i-1) )
209
+ {
210
+ vertex_touch = i;
211
+ break;
212
+ }
213
+
214
+ /*
215
+ ** Crossing-at-vertex will cause four segment touch interactions, two at
216
+ ** j-1 and two at j. We avoid incrementing our cross count by ignoring the
217
+ ** second pair.
218
+ */
219
+ if ( this_cross == SEG_TOUCH_LEFT )
220
+ {
221
+ if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_RIGHT )
222
+ {
223
+ cross_left++;
224
+ vertex_touch = -1;
225
+ vertex_touch_type = 0;
226
+ }
227
+ else
228
+ {
229
+ vertex_touch = i;
230
+ vertex_touch_type = this_cross;
231
+ }
232
+ break;
233
+ }
234
+ if ( this_cross == SEG_TOUCH_RIGHT )
235
+ {
236
+ if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_LEFT )
237
+ {
238
+ cross_right++;
239
+ vertex_touch = -1;
240
+ vertex_touch_type = 0;
241
+ }
242
+ else
243
+ {
244
+ vertex_touch = i;
245
+ vertex_touch_type = this_cross;
246
+ }
247
+ break;
248
+ }
249
+
250
+ /*
251
+ ** TODO Handle co-linear cases.
252
+ */
253
+
254
+ LWDEBUGF(4, "lineCrossingDirection: this_cross=%d, vertex_touch=%d, vertex_touch_type=%d", this_cross, vertex_touch, vertex_touch_type);
255
+
256
+ }
257
+
258
+ }
259
+
260
+ LWDEBUGF(4, "first_cross=%d, final_cross=%d, cross_left=%d, cross_right=%d", first_cross, final_cross, cross_left, cross_right);
261
+
262
+ lwfree(p1);
263
+ lwfree(p2);
264
+ lwfree(q1);
265
+ lwfree(q2);
266
+
267
+ if ( !cross_left && !cross_right )
268
+ return LINE_NO_CROSS;
269
+
270
+ if ( !cross_left && cross_right == 1 )
271
+ return LINE_CROSS_RIGHT;
272
+
273
+ if ( !cross_right && cross_left == 1 )
274
+ return LINE_CROSS_LEFT;
275
+
276
+ if ( cross_left - cross_right == 1 )
277
+ return LINE_MULTICROSS_END_LEFT;
278
+
279
+ if ( cross_left - cross_right == -1 )
280
+ return LINE_MULTICROSS_END_RIGHT;
281
+
282
+ if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT )
283
+ return LINE_MULTICROSS_END_SAME_FIRST_LEFT;
284
+
285
+ if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT )
286
+ return LINE_MULTICROSS_END_SAME_FIRST_RIGHT;
287
+
288
+ if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_LEFT )
289
+ return LINE_MULTICROSS_END_SAME_FIRST_RIGHT;
290
+
291
+ if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_RIGHT )
292
+ return LINE_MULTICROSS_END_SAME_FIRST_LEFT;
293
+
294
+ return LINE_NO_CROSS;
295
+
296
+ }
297
+
298
+ /*
299
+ ** lwpoint_get_ordinate(point, ordinate) => double
300
+ */
301
+ double lwpoint_get_ordinate(const POINT4D *p, int ordinate)
302
+ {
303
+ if ( ! p )
304
+ {
305
+ lwerror("Null input geometry.");
306
+ return 0.0;
307
+ }
308
+
309
+ if ( ordinate > 3 || ordinate < 0 )
310
+ {
311
+ lwerror("Cannot extract ordinate %d.", ordinate);
312
+ return 0.0;
313
+ }
314
+
315
+ if ( ordinate == 3 )
316
+ return p->m;
317
+ if ( ordinate == 2 )
318
+ return p->z;
319
+ if ( ordinate == 1 )
320
+ return p->y;
321
+
322
+ return p->x;
323
+
324
+ }
325
+ void lwpoint_set_ordinate(POINT4D *p, int ordinate, double value)
326
+ {
327
+ if ( ! p )
328
+ {
329
+ lwerror("Null input geometry.");
330
+ return;
331
+ }
332
+
333
+ if ( ordinate > 3 || ordinate < 0 )
334
+ {
335
+ lwerror("Cannot extract ordinate %d.", ordinate);
336
+ return;
337
+ }
338
+
339
+ LWDEBUGF(4, " setting ordinate %d to %g", ordinate, value);
340
+
341
+ switch ( ordinate )
342
+ {
343
+ case 3:
344
+ p->m = value;
345
+ return;
346
+ case 2:
347
+ p->z = value;
348
+ return;
349
+ case 1:
350
+ p->y = value;
351
+ return;
352
+ case 0:
353
+ p->x = value;
354
+ return;
355
+ }
356
+ }
357
+
358
+
359
+ int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value)
360
+ {
361
+ double p1_value = lwpoint_get_ordinate(p1, ordinate);
362
+ double p2_value = lwpoint_get_ordinate(p2, ordinate);
363
+ double proportion;
364
+ int i = 0;
365
+
366
+ if ( ordinate < 0 || ordinate >= ndims )
367
+ {
368
+ lwerror("Ordinate (%d) is not within ndims (%d).", ordinate, ndims);
369
+ return 0;
370
+ }
371
+
372
+ if ( FP_MIN(p1_value, p2_value) > interpolation_value ||
373
+ FP_MAX(p1_value, p2_value) < interpolation_value )
374
+ {
375
+ lwerror("Cannot interpolate to a value (%g) not between the input points (%g, %g).", interpolation_value, p1_value, p2_value);
376
+ return 0;
377
+ }
378
+
379
+ proportion = fabs((interpolation_value - p1_value) / (p2_value - p1_value));
380
+
381
+ for ( i = 0; i < ndims; i++ )
382
+ {
383
+ double newordinate = 0.0;
384
+ p1_value = lwpoint_get_ordinate(p1, i);
385
+ p2_value = lwpoint_get_ordinate(p2, i);
386
+ newordinate = p1_value + proportion * (p2_value - p1_value);
387
+ lwpoint_set_ordinate(p, i, newordinate);
388
+ LWDEBUGF(4, " clip ordinate(%d) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) ", i, p1_value, p2_value, proportion, newordinate );
389
+ }
390
+
391
+ return 1;
392
+ }
393
+
394
+ LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to)
395
+ {
396
+ LWCOLLECTION *lwgeom_out = NULL;
397
+
398
+ if ( ! mline )
399
+ {
400
+ lwerror("Null input geometry.");
401
+ return NULL;
402
+ }
403
+
404
+ if ( mline->ngeoms == 1)
405
+ {
406
+ lwgeom_out = lwline_clip_to_ordinate_range(mline->geoms[0], ordinate, from, to);
407
+ }
408
+ else
409
+ {
410
+ LWCOLLECTION *col;
411
+ char hasz = TYPE_HASZ(mline->type);
412
+ char hasm = TYPE_HASM(mline->type);
413
+ char hassrid = TYPE_HASSRID(mline->type);
414
+ int i, j;
415
+ char homogeneous = 1;
416
+ size_t geoms_size = 0;
417
+ lwgeom_out = lwcollection_construct_empty(mline->SRID, hasz, hasm);
418
+ lwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, MULTILINETYPE);
419
+ for ( i = 0; i < mline->ngeoms; i ++ )
420
+ {
421
+ col = lwline_clip_to_ordinate_range(mline->geoms[i], ordinate, from, to);
422
+ if ( col )
423
+ { /* Something was left after the clip. */
424
+ if ( lwgeom_out->ngeoms + col->ngeoms > geoms_size )
425
+ {
426
+ geoms_size += 16;
427
+ if ( lwgeom_out->geoms )
428
+ {
429
+ lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, geoms_size * sizeof(LWGEOM*));
430
+ }
431
+ else
432
+ {
433
+ lwgeom_out->geoms = lwalloc(geoms_size * sizeof(LWGEOM*));
434
+ }
435
+ }
436
+ for ( j = 0; j < col->ngeoms; j++ )
437
+ {
438
+ lwgeom_out->geoms[lwgeom_out->ngeoms] = col->geoms[j];
439
+ lwgeom_out->ngeoms++;
440
+ }
441
+ if ( TYPE_GETTYPE(col->type) != TYPE_GETTYPE(mline->type) )
442
+ {
443
+ homogeneous = 0;
444
+ }
445
+ /* Shallow free the struct, leaving the geoms behind. */
446
+ if ( col->bbox ) lwfree(col->bbox);
447
+ lwfree(col);
448
+ }
449
+ }
450
+ lwgeom_drop_bbox((LWGEOM*)lwgeom_out);
451
+ lwgeom_add_bbox((LWGEOM*)lwgeom_out);
452
+ if ( ! homogeneous )
453
+ {
454
+ lwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);
455
+ }
456
+ }
457
+
458
+ if ( ! lwgeom_out || lwgeom_out->ngeoms == 0 ) /* Nothing left after clip. */
459
+ {
460
+ return NULL;
461
+ }
462
+
463
+ return lwgeom_out;
464
+
465
+ }
466
+
467
+
468
+ /*
469
+ ** lwline_clip_to_ordinate_range(line, ordinate, from, to) => lwmline
470
+ **
471
+ ** Take in a LINESTRING and return a MULTILINESTRING of those portions of the
472
+ ** LINESTRING between the from/to range for the specified ordinate (XYZM)
473
+ */
474
+ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to)
475
+ {
476
+
477
+ POINTARRAY *pa_in = NULL;
478
+ LWCOLLECTION *lwgeom_out = NULL;
479
+ POINTARRAY *pa_out = NULL;
480
+ DYNPTARRAY *dp = NULL;
481
+ int i, rv;
482
+ int added_last_point = 0;
483
+ POINT4D *p = NULL, *q = NULL, *r = NULL;
484
+ double ordinate_value_p = 0.0, ordinate_value_q = 0.0;
485
+ char hasz = TYPE_HASZ(line->type);
486
+ char hasm = TYPE_HASM(line->type);
487
+ char dims = TYPE_NDIMS(line->type);
488
+ char hassrid = TYPE_HASSRID(line->type);
489
+
490
+ LWDEBUGF(4, "hassrid = %d", hassrid);
491
+
492
+ /* Null input, nothing we can do. */
493
+ if ( ! line )
494
+ {
495
+ lwerror("Null input geometry.");
496
+ return NULL;
497
+ }
498
+
499
+ /* Ensure 'from' is less than 'to'. */
500
+ if ( to < from )
501
+ {
502
+ double t = from;
503
+ from = to;
504
+ to = t;
505
+ }
506
+
507
+ LWDEBUGF(4, "from = %g, to = %g, ordinate = %d", from, to, ordinate);
508
+ LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line, PARSER_CHECK_NONE));
509
+
510
+ /* Asking for an ordinate we don't have. Error. */
511
+ if ( ordinate >= dims )
512
+ {
513
+ lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims);
514
+ return NULL;
515
+ }
516
+
517
+ /* Prepare our working point objects. */
518
+ p = lwalloc(sizeof(POINT4D));
519
+ q = lwalloc(sizeof(POINT4D));
520
+ r = lwalloc(sizeof(POINT4D));
521
+
522
+ /* Construct a collection to hold our outputs. */
523
+ lwgeom_out = lwalloc(sizeof(LWCOLLECTION));
524
+ lwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, MULTILINETYPE);
525
+ if (hassrid)
526
+ lwgeom_out->SRID = line->SRID;
527
+ else
528
+ lwgeom_out->SRID = -1;
529
+ lwgeom_out->bbox = NULL;
530
+ lwgeom_out->ngeoms = 0;
531
+ lwgeom_out->geoms = NULL;
532
+
533
+ pa_in = (POINTARRAY*)line->points;
534
+
535
+ for ( i = 0; i < pa_in->npoints; i++ )
536
+ {
537
+ LWDEBUGF(4, "Point #%d", i);
538
+ if ( i > 0 )
539
+ {
540
+ q->x = p->x;
541
+ q->y = p->y;
542
+ q->z = p->z;
543
+ q->m = p->m;
544
+ ordinate_value_q = ordinate_value_p;
545
+ }
546
+ rv = getPoint4d_p(pa_in, i, p);
547
+ ordinate_value_p = lwpoint_get_ordinate(p, ordinate);
548
+ LWDEBUGF(4, " ordinate_value_p %g (current)", ordinate_value_p);
549
+ LWDEBUGF(4, " ordinate_value_q %g (previous)", ordinate_value_q);
550
+
551
+ /* Is this point inside the ordinate range? Yes. */
552
+ if ( ordinate_value_p >= from && ordinate_value_p <= to )
553
+ {
554
+ LWDEBUGF(4, " inside ordinate range (%g, %g)", from, to);
555
+
556
+ if ( ! added_last_point )
557
+ {
558
+ LWDEBUG(4," new ptarray required");
559
+ /* We didn't add the previous point, so this is a new segment.
560
+ * Make a new point array. */
561
+ if ( dp ) lwfree(dp);
562
+ dp = dynptarray_create(64, line->type);
563
+
564
+ /* We're transiting into the range so add an interpolated
565
+ * point at the range boundary.
566
+ * If we're on a boundary and crossing from the far side,
567
+ * we also need an interpolated point. */
568
+ if ( i > 0 && ( /* Don't try to interpolate if this is the first point */
569
+ ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */
570
+ ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */
571
+ ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */
572
+ {
573
+ double interpolation_value;
574
+ (ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from);
575
+ rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);
576
+ rv = dynptarray_addPoint4d(dp, r, 0);
577
+ LWDEBUGF(4, " interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
578
+ }
579
+ }
580
+ /* Add the current vertex to the point array. */
581
+ rv = dynptarray_addPoint4d(dp, p, 0);
582
+ if ( ordinate_value_p == from || ordinate_value_p == to )
583
+ {
584
+ added_last_point = 2; /* Added on boundary. */
585
+ }
586
+ else
587
+ {
588
+ added_last_point = 1; /* Added inside range. */
589
+ }
590
+ }
591
+ /* Is this point inside the ordinate range? No. */
592
+ else
593
+ {
594
+ LWDEBUGF(4, " added_last_point (%d)", added_last_point);
595
+ if ( added_last_point == 1 )
596
+ {
597
+ /* We're transiting out of the range, so add an interpolated point
598
+ * to the point array at the range boundary. */
599
+ double interpolation_value;
600
+ (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);
601
+ rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);
602
+ rv = dynptarray_addPoint4d(dp, r, 0);
603
+ LWDEBUGF(4, " interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
604
+ }
605
+ else if ( added_last_point == 2 )
606
+ {
607
+ /* We're out and the last point was on the boundary.
608
+ * If the last point was the near boundary, nothing to do.
609
+ * If it was the far boundary, we need an interpolated point. */
610
+ if ( from != to && (
611
+ (ordinate_value_q == from && ordinate_value_p > from) ||
612
+ (ordinate_value_q == to && ordinate_value_p < to) ) )
613
+ {
614
+ double interpolation_value;
615
+ (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);
616
+ rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value);
617
+ rv = dynptarray_addPoint4d(dp, r, 0);
618
+ LWDEBUGF(4, " interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
619
+ }
620
+ }
621
+ else if ( i && ordinate_value_q < from && ordinate_value_p > to )
622
+ {
623
+ /* We just hopped over the whole range, from bottom to top,
624
+ * so we need to add *two* interpolated points! */
625
+ pa_out = ptarray_construct(hasz, hasm, 2);
626
+ /* Interpolate lower point. */
627
+ rv = lwpoint_interpolate(p, q, r, dims, ordinate, from);
628
+ setPoint4d(pa_out, 0, r);
629
+ /* Interpolate upper point. */
630
+ rv = lwpoint_interpolate(p, q, r, dims, ordinate, to);
631
+ setPoint4d(pa_out, 1, r);
632
+ }
633
+ else if ( i && ordinate_value_q > to && ordinate_value_p < from )
634
+ {
635
+ /* We just hopped over the whole range, from top to bottom,
636
+ * so we need to add *two* interpolated points! */
637
+ pa_out = ptarray_construct(hasz, hasm, 2);
638
+ /* Interpolate upper point. */
639
+ rv = lwpoint_interpolate(p, q, r, dims, ordinate, to);
640
+ setPoint4d(pa_out, 0, r);
641
+ /* Interpolate lower point. */
642
+ rv = lwpoint_interpolate(p, q, r, dims, ordinate, from);
643
+ setPoint4d(pa_out, 1, r);
644
+ }
645
+ /* We have an extant point-array, save it out to a multi-line. */
646
+ if ( dp || pa_out )
647
+ {
648
+ LWGEOM *oline;
649
+ LWDEBUG(4, "saving pointarray to multi-line (1)");
650
+ if ( dp )
651
+ {
652
+ /* Only one point, so we have to make an lwpoint to hold this
653
+ * and set the overall output type to a generic collection. */
654
+ if ( dp->pa->npoints == 1 )
655
+ {
656
+ oline = (LWGEOM*)lwpoint_construct(line->SRID, NULL, dp->pa);
657
+ oline->type = lwgeom_makeType(hasz, hasm, hassrid, POINTTYPE);
658
+ lwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);
659
+ }
660
+ else
661
+ {
662
+ oline = (LWGEOM*)lwline_construct(line->SRID, NULL, dp->pa);
663
+ oline->type = lwgeom_makeType(hasz, hasm, hassrid, LINETYPE);
664
+ }
665
+ }
666
+ else
667
+ {
668
+ oline = (LWGEOM*)lwline_construct(line->SRID, NULL, pa_out);
669
+ }
670
+ lwgeom_out->ngeoms++;
671
+ if ( lwgeom_out->geoms ) /* We can't just realloc, since repalloc chokes on a starting null ptr. */
672
+ {
673
+ lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, sizeof(LWGEOM*) * lwgeom_out->ngeoms);
674
+ }
675
+ else
676
+ {
677
+ lwgeom_out->geoms = lwalloc(sizeof(LWGEOM*) * lwgeom_out->ngeoms);
678
+ }
679
+ lwgeom_out->geoms[lwgeom_out->ngeoms - 1] = oline;
680
+ lwgeom_drop_bbox((LWGEOM*)lwgeom_out);
681
+ lwgeom_add_bbox((LWGEOM*)lwgeom_out);
682
+ if ( dp ) lwfree(dp);
683
+ dp = NULL;
684
+ if ( pa_out ) pa_out = NULL;
685
+ }
686
+ added_last_point = 0;
687
+
688
+ }
689
+ }
690
+
691
+ /* Still some points left to be saved out. */
692
+ if ( dp && dp->pa->npoints > 0 )
693
+ {
694
+ LWGEOM *oline;
695
+ LWDEBUG(4, "saving pointarray to multi-line (2)");
696
+ LWDEBUGF(4, "dp->pa->npoints == %d", dp->pa->npoints);
697
+ LWDEBUGF(4, "lwgeom_out->ngeoms == %d", lwgeom_out->ngeoms);
698
+
699
+ if ( dp->pa->npoints == 1 )
700
+ {
701
+ oline = (LWGEOM*)lwpoint_construct(line->SRID, NULL, dp->pa);
702
+ oline->type = lwgeom_makeType(hasz, hasm, hassrid, POINTTYPE);
703
+ lwgeom_out->type = lwgeom_makeType(hasz, hasm, hassrid, COLLECTIONTYPE);
704
+ }
705
+ else
706
+ {
707
+ oline = (LWGEOM*)lwline_construct(line->SRID, NULL, dp->pa);
708
+ oline->type = lwgeom_makeType(hasz, hasm, hassrid, LINETYPE);
709
+ }
710
+
711
+ lwgeom_out->ngeoms++;
712
+ if ( lwgeom_out->geoms ) /* We can't just realloc, since repalloc chokes on a starting null ptr. */
713
+ {
714
+ lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, sizeof(LWGEOM*) * lwgeom_out->ngeoms);
715
+ }
716
+ else
717
+ {
718
+ lwgeom_out->geoms = lwalloc(sizeof(LWGEOM*) * lwgeom_out->ngeoms);
719
+ }
720
+ lwgeom_out->geoms[lwgeom_out->ngeoms - 1] = oline;
721
+ lwgeom_drop_bbox((LWGEOM*)lwgeom_out);
722
+ lwgeom_add_bbox((LWGEOM*)lwgeom_out);
723
+ if ( dp ) lwfree(dp);
724
+ dp = NULL;
725
+ }
726
+
727
+ lwfree(p);
728
+ lwfree(q);
729
+ lwfree(r);
730
+
731
+ if ( lwgeom_out->ngeoms > 0 )
732
+ return lwgeom_out;
733
+
734
+ return NULL;
735
+
736
+ }
737
+
738
+ static char *base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
739
+
740
+ /*
741
+ ** Calculate the geohash, iterating downwards and gaining precision.
742
+ ** From geohash-native.c, (c) 2008 David Troy <dave@roundhousetech.com>
743
+ ** Released under the MIT License.
744
+ */
745
+ char *geohash_point(double longitude, double latitude, int precision)
746
+ {
747
+ int is_even=1, i=0;
748
+ double lat[2], lon[2], mid;
749
+ char bits[] = {16,8,4,2,1};
750
+ int bit=0, ch=0;
751
+ char *geohash = NULL;
752
+
753
+ geohash = lwalloc(precision + 1);
754
+
755
+ lat[0] = -90.0; lat[1] = 90.0;
756
+ lon[0] = -180.0; lon[1] = 180.0;
757
+
758
+ while (i < precision)
759
+ {
760
+ if (is_even)
761
+ {
762
+ mid = (lon[0] + lon[1]) / 2;
763
+ if (longitude > mid)
764
+ {
765
+ ch |= bits[bit];
766
+ lon[0] = mid;
767
+ }
768
+ else
769
+ {
770
+ lon[1] = mid;
771
+ }
772
+ }
773
+ else
774
+ {
775
+ mid = (lat[0] + lat[1]) / 2;
776
+ if (latitude > mid)
777
+ {
778
+ ch |= bits[bit];
779
+ lat[0] = mid;
780
+ }
781
+ else
782
+ {
783
+ lat[1] = mid;
784
+ }
785
+ }
786
+
787
+ is_even = !is_even;
788
+ if (bit < 4)
789
+ {
790
+ bit++;
791
+ }
792
+ else
793
+ {
794
+ geohash[i++] = base32[ch];
795
+ bit = 0;
796
+ ch = 0;
797
+ }
798
+ }
799
+ geohash[i] = 0;
800
+ return geohash;
801
+ }
802
+
803
+ int lwgeom_geohash_precision(BOX3D bbox, BOX3D *bounds)
804
+ {
805
+ double minx, miny, maxx, maxy;
806
+ double latmax, latmin, lonmax, lonmin;
807
+ double lonwidth, latwidth;
808
+ double latmaxadjust, lonmaxadjust, latminadjust, lonminadjust;
809
+ int precision = 0;
810
+
811
+ /* Get the bounding box, return error if things don't work out. */
812
+ minx = bbox.xmin;
813
+ miny = bbox.ymin;
814
+ maxx = bbox.xmax;
815
+ maxy = bbox.ymax;
816
+
817
+ if( minx == maxx && miny == maxy )
818
+ {
819
+ /* It's a point. Doubles have 51 bits of precision.
820
+ ** 2 * 51 / 5 == 20 */
821
+ return 20;
822
+ }
823
+
824
+ lonmin = -180.0;
825
+ latmin = -90.0;
826
+ lonmax = 180.0;
827
+ latmax = 90.0;
828
+
829
+ /* Shrink a world bounding box until one of the edges interferes with the
830
+ ** bounds of our rectangle. */
831
+ while( 1 )
832
+ {
833
+ lonwidth = lonmax - lonmin;
834
+ latwidth = latmax - latmin;
835
+ latmaxadjust = lonmaxadjust = latminadjust = lonminadjust = 0.0;
836
+
837
+ if( minx > lonmin + lonwidth / 2.0 )
838
+ {
839
+ lonminadjust = lonwidth / 2.0;
840
+ }
841
+ else if ( maxx < lonmax - lonwidth / 2.0 )
842
+ {
843
+ lonmaxadjust = -1 * lonwidth / 2.0;
844
+ }
845
+ if( miny > latmin + latwidth / 2.0 )
846
+ {
847
+ latminadjust = latwidth / 2.0;
848
+ }
849
+ else if (maxy < latmax - latwidth / 2.0 )
850
+ {
851
+ latmaxadjust = -1 * latwidth / 2.0;
852
+ }
853
+ /* Only adjust if adjustments are legal (we haven't crossed any edges). */
854
+ if ( (lonminadjust || lonmaxadjust) && (latminadjust || latmaxadjust ) )
855
+ {
856
+ latmin += latminadjust;
857
+ lonmin += lonminadjust;
858
+ latmax += latmaxadjust;
859
+ lonmax += lonmaxadjust;
860
+ /* Each adjustment cycle corresponds to 2 bits of storage in the
861
+ ** geohash. */
862
+ precision += 2;
863
+ }
864
+ else
865
+ {
866
+ break;
867
+ }
868
+ }
869
+
870
+ /* Save the edges of our bounds, in case someone cares later. */
871
+ bounds->xmin = lonmin;
872
+ bounds->xmax = lonmax;
873
+ bounds->ymin = latmin;
874
+ bounds->ymax = latmax;
875
+
876
+ /* Each geohash character (base32) can contain 5 bits of information.
877
+ ** We are returning the precision in characters, so here we divide. */
878
+ return precision / 5;
879
+ }
880
+
881
+
882
+ /*
883
+ ** Return a geohash string for the geometry. <http://geohash.org>
884
+ ** Where the precision is non-positive, calculate a precision based on the
885
+ ** bounds of the feature. Big features have loose precision.
886
+ ** Small features have tight precision.
887
+ */
888
+ char *lwgeom_geohash(const LWGEOM *lwgeom, int precision)
889
+ {
890
+ BOX3D *bbox = NULL;
891
+ BOX3D precision_bounds;
892
+ double lat, lon;
893
+
894
+ bbox = lwgeom_compute_box3d(lwgeom);
895
+ if( ! bbox ) return NULL;
896
+
897
+ /* Return error if we are being fed something outside our working bounds */
898
+ if ( bbox->xmin < -180 || bbox->ymin < -90 || bbox->xmax > 180 || bbox->ymax > 90 )
899
+ {
900
+ lwerror("Geohash requires inputs in decimal degrees.");
901
+ lwfree(bbox);
902
+ return NULL;
903
+ }
904
+
905
+ /* What is the center of our geometry bounds? We'll use that to
906
+ ** approximate location. */
907
+ lon = bbox->xmin + (bbox->xmax - bbox->xmin) / 2;
908
+ lat = bbox->ymin + (bbox->ymax - bbox->ymin) / 2;
909
+
910
+ if ( precision <= 0 )
911
+ {
912
+ precision = lwgeom_geohash_precision(*bbox, &precision_bounds);
913
+ }
914
+
915
+ lwfree(bbox);
916
+
917
+ /*
918
+ ** Return the geohash of the center, with a precision determined by the
919
+ ** extent of the bounds.
920
+ ** Possible change: return the point at the center of the precision bounds?
921
+ */
922
+ return geohash_point(lon, lat, precision);
923
+ }
924
+
925
+
926
+
927
+
928
+
929
+
930
+
931
+
932
+
933
+
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+
943
+
944
+
945
+
946
+