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,93 @@
1
+ /* postgis_config.h. Generated from postgis_config.h.in by configure. */
2
+ /* postgis_config.h.in. Generated from configure.ac by autoheader. */
3
+
4
+ /* Define to 1 if you have the <dlfcn.h> header file. */
5
+ #define HAVE_DLFCN_H 1
6
+
7
+ /* Defined if libiconv headers and library are present */
8
+ #define HAVE_ICONV 0
9
+
10
+ /* Define to 1 if you have the <inttypes.h> header file. */
11
+ #define HAVE_INTTYPES_H 1
12
+
13
+ /* Define to 1 if you have the `geos_c' library (-lgeos_c). */
14
+ #define HAVE_LIBGEOS_C 1
15
+
16
+ /* Define to 1 if you have the `pq' library (-lpq). */
17
+ #define HAVE_LIBPQ 0
18
+
19
+ /* Define to 1 if you have the `proj' library (-lproj). */
20
+ #define HAVE_LIBPROJ 0
21
+
22
+ /* Define to 1 if you have the <memory.h> header file. */
23
+ #define HAVE_MEMORY_H 1
24
+
25
+ /* Define to 1 if you have the <stdint.h> header file. */
26
+ #define HAVE_STDINT_H 1
27
+
28
+ /* Define to 1 if you have the <stdlib.h> header file. */
29
+ #define HAVE_STDLIB_H 1
30
+
31
+ /* Define to 1 if you have the <strings.h> header file. */
32
+ #define HAVE_STRINGS_H 1
33
+
34
+ /* Define to 1 if you have the <string.h> header file. */
35
+ #define HAVE_STRING_H 1
36
+
37
+ /* Define to 1 if you have the <sys/stat.h> header file. */
38
+ #define HAVE_SYS_STAT_H 1
39
+
40
+ /* Define to 1 if you have the <sys/types.h> header file. */
41
+ #define HAVE_SYS_TYPES_H 1
42
+
43
+ /* Define to 1 if you have the <unistd.h> header file. */
44
+ #define HAVE_UNISTD_H 1
45
+
46
+ /* Enable caching of bounding box within geometries */
47
+ #define POSTGIS_AUTOCACHE_BBOX 0
48
+
49
+ /* PostGIS build date */
50
+ #define POSTGIS_BUILD_DATE "2009-03-09 15:11:36"
51
+
52
+ /* PostGIS library debug level (0=disabled) */
53
+ #define POSTGIS_DEBUG_LEVEL 0
54
+
55
+ /* GEOS library version */
56
+ #define POSTGIS_GEOS_VERSION 30
57
+
58
+ /* PostGIS library version */
59
+ #define POSTGIS_LIB_VERSION "1.4.0SVN"
60
+
61
+ /* PostGIS major version */
62
+ #define POSTGIS_MAJOR_VERSION "1"
63
+
64
+ /* PostGIS micro version */
65
+ #define POSTGIS_MICRO_VERSION "0SVN"
66
+
67
+ /* PostGIS minor version */
68
+ #define POSTGIS_MINOR_VERSION "4"
69
+
70
+ /* PostgreSQL server version */
71
+ #define POSTGIS_PGSQL_VERSION 83
72
+
73
+ /* Enable GEOS profiling (0=disabled) */
74
+ #define POSTGIS_PROFILE 0
75
+
76
+ /* PROJ library version */
77
+ #define POSTGIS_PROJ_VERSION 46
78
+
79
+ /* PostGIS scripts version */
80
+ #define POSTGIS_SCRIPTS_VERSION "1.4.0SVN"
81
+
82
+ /* Enable use of ANALYZE statistics */
83
+ #define POSTGIS_USE_STATS 1
84
+
85
+ /* PostGIS version */
86
+ #define POSTGIS_VERSION "1.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1"
87
+
88
+ /* Define to 1 if you have the ANSI C header files. */
89
+ #define STDC_HEADERS 1
90
+
91
+ /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
92
+ `char[]'. */
93
+ #define YYTEXT_POINTER 1
@@ -0,0 +1,847 @@
1
+ /**********************************************************************
2
+ * $Id: ptarray.c 3639 2009-02-04 00:28:37Z pramsey $
3
+ *
4
+ * PostGIS - Spatial Types for PostgreSQL
5
+ * http://postgis.refractions.net
6
+ * Copyright 2001-2006 Refractions Research Inc.
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 <stdio.h>
14
+ #include <string.h>
15
+
16
+ #include "liblwgeom.h"
17
+
18
+
19
+ POINTARRAY *
20
+ ptarray_construct(char hasz, char hasm, unsigned int npoints)
21
+ {
22
+ uchar dims = 0;
23
+ size_t size;
24
+ uchar *ptlist;
25
+ POINTARRAY *pa;
26
+
27
+ TYPE_SETZM(dims, hasz?1:0, hasm?1:0);
28
+ size = TYPE_NDIMS(dims)*npoints*sizeof(double);
29
+
30
+ ptlist = (uchar *)lwalloc(size);
31
+ pa = lwalloc(sizeof(POINTARRAY));
32
+ pa->dims = dims;
33
+ pa->serialized_pointlist = ptlist;
34
+ pa->npoints = npoints;
35
+
36
+ return pa;
37
+
38
+ }
39
+
40
+ void ptarray_free(POINTARRAY *pa)
41
+ {
42
+ /* TODO
43
+ * Turn this on after retrofitting all calls to lwfree_ in /lwgeom
44
+ if( pa->serialized_pointlist )
45
+ lwfree(pa->serialized_pointlist);
46
+ */
47
+
48
+ lwfree(pa);
49
+ }
50
+
51
+ void
52
+ ptarray_reverse(POINTARRAY *pa)
53
+ {
54
+ POINT4D pbuf;
55
+ uint32 i;
56
+ int ptsize = pointArray_ptsize(pa);
57
+ int last = pa->npoints-1;
58
+ int mid = last/2;
59
+
60
+ for (i=0; i<=mid; i++)
61
+ {
62
+ uchar *from, *to;
63
+ from = getPoint_internal(pa, i);
64
+ to = getPoint_internal(pa, (last-i));
65
+ memcpy((uchar *)&pbuf, to, ptsize);
66
+ memcpy(to, from, ptsize);
67
+ memcpy(from, (uchar *)&pbuf, ptsize);
68
+ }
69
+
70
+ }
71
+
72
+ /*
73
+ * calculate the 2d bounding box of a set of points
74
+ * write result to the provided BOX2DFLOAT4
75
+ * Return 0 if bounding box is NULL (empty geom)
76
+ */
77
+ int
78
+ ptarray_compute_box2d_p(const POINTARRAY *pa, BOX2DFLOAT4 *result)
79
+ {
80
+ int t;
81
+ POINT2D pt;
82
+ BOX3D box;
83
+
84
+ if (pa->npoints == 0) return 0;
85
+
86
+ getPoint2d_p(pa, 0, &pt);
87
+
88
+ box.xmin = pt.x;
89
+ box.xmax = pt.x;
90
+ box.ymin = pt.y;
91
+ box.ymax = pt.y;
92
+
93
+ for (t=1; t<pa->npoints; t++)
94
+ {
95
+ getPoint2d_p(pa, t, &pt);
96
+ if (pt.x < box.xmin) box.xmin = pt.x;
97
+ if (pt.y < box.ymin) box.ymin = pt.y;
98
+ if (pt.x > box.xmax) box.xmax = pt.x;
99
+ if (pt.y > box.ymax) box.ymax = pt.y;
100
+ }
101
+
102
+ box3d_to_box2df_p(&box, result);
103
+
104
+ return 1;
105
+ }
106
+
107
+ /*
108
+ * Calculate the 2d bounding box of a set of points.
109
+ * Return allocated BOX2DFLOAT4 or NULL (for empty array).
110
+ */
111
+ BOX2DFLOAT4 *
112
+ ptarray_compute_box2d(const POINTARRAY *pa)
113
+ {
114
+ int t;
115
+ POINT2D pt;
116
+ BOX2DFLOAT4 *result;
117
+
118
+ if (pa->npoints == 0) return NULL;
119
+
120
+ result = lwalloc(sizeof(BOX2DFLOAT4));
121
+
122
+ getPoint2d_p(pa, 0, &pt);
123
+
124
+ result->xmin = pt.x;
125
+ result->xmax = pt.x;
126
+ result->ymin = pt.y;
127
+ result->ymax = pt.y;
128
+
129
+ for (t=1;t<pa->npoints;t++)
130
+ {
131
+ getPoint2d_p(pa, t, &pt);
132
+ if (pt.x < result->xmin) result->xmin = pt.x;
133
+ if (pt.y < result->ymin) result->ymin = pt.y;
134
+ if (pt.x > result->xmax) result->xmax = pt.x;
135
+ if (pt.y > result->ymax) result->ymax = pt.y;
136
+ }
137
+
138
+ return result;
139
+ }
140
+
141
+ /*
142
+ * Returns a modified POINTARRAY so that no segment is
143
+ * longer then the given distance (computed using 2d).
144
+ * Every input point is kept.
145
+ * Z and M values for added points (if needed) are set to 0.
146
+ */
147
+ POINTARRAY *
148
+ ptarray_segmentize2d(POINTARRAY *ipa, double dist)
149
+ {
150
+ double segdist;
151
+ POINT4D p1, p2;
152
+ void *ip, *op;
153
+ POINT4D pbuf;
154
+ POINTARRAY *opa;
155
+ int maxpoints = ipa->npoints;
156
+ int ptsize = pointArray_ptsize(ipa);
157
+ int ipoff=0; /* input point offset */
158
+
159
+ pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
160
+
161
+ /* Initial storage */
162
+ opa = (POINTARRAY *)lwalloc(ptsize * maxpoints);
163
+ opa->dims = ipa->dims;
164
+ opa->npoints = 0;
165
+ opa->serialized_pointlist = (uchar *)lwalloc(maxpoints*ptsize);
166
+
167
+ /* Add first point */
168
+ opa->npoints++;
169
+ getPoint4d_p(ipa, ipoff, &p1);
170
+ op = getPoint_internal(opa, opa->npoints-1);
171
+ memcpy(op, &p1, ptsize);
172
+ ipoff++;
173
+
174
+ while (ipoff<ipa->npoints)
175
+ {
176
+ /*
177
+ * We use these pointers to avoid
178
+ * "strict-aliasing rules break" warning raised
179
+ * by gcc (3.3 and up).
180
+ *
181
+ * It looks that casting a variable address (also
182
+ * referred to as "type-punned pointer")
183
+ * breaks those "strict" rules.
184
+ *
185
+ */
186
+ POINT4D *p1ptr=&p1, *p2ptr=&p2;
187
+
188
+ getPoint4d_p(ipa, ipoff, &p2);
189
+
190
+ segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
191
+
192
+ if (segdist > dist) /* add an intermediate point */
193
+ {
194
+ pbuf.x = p1.x + (p2.x-p1.x)/segdist * dist;
195
+ pbuf.y = p1.y + (p2.y-p1.y)/segdist * dist;
196
+ /* might also compute z and m if available... */
197
+ ip = &pbuf;
198
+ memcpy(&p1, ip, ptsize);
199
+ }
200
+ else /* copy second point */
201
+ {
202
+ ip = &p2;
203
+ p1 = p2;
204
+ ipoff++;
205
+ }
206
+
207
+ /* Add point */
208
+ if ( ++(opa->npoints) > maxpoints ) {
209
+ maxpoints *= 1.5;
210
+ opa->serialized_pointlist = (uchar *)lwrealloc(
211
+ opa->serialized_pointlist,
212
+ maxpoints*ptsize
213
+ );
214
+ }
215
+ op = getPoint_internal(opa, opa->npoints-1);
216
+ memcpy(op, ip, ptsize);
217
+ }
218
+
219
+ return opa;
220
+ }
221
+
222
+ char
223
+ ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
224
+ {
225
+ unsigned int i;
226
+ size_t ptsize;
227
+
228
+ if ( TYPE_GETZM(pa1->dims) != TYPE_GETZM(pa2->dims) ) return 0;
229
+
230
+ if ( pa1->npoints != pa2->npoints ) return 0;
231
+
232
+ ptsize = pointArray_ptsize(pa1);
233
+
234
+ for (i=0; i<pa1->npoints; i++)
235
+ {
236
+ if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), ptsize) )
237
+ return 0;
238
+ }
239
+
240
+ return 1;
241
+ }
242
+
243
+ /*
244
+ * Add a point in a pointarray.
245
+ * 'where' is the offset (starting at 0)
246
+ * if 'where' == -1 append is required.
247
+ */
248
+ POINTARRAY *
249
+ ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims, unsigned int where)
250
+ {
251
+ POINTARRAY *ret;
252
+ POINT4D pbuf;
253
+ size_t ptsize = pointArray_ptsize(pa);
254
+
255
+ LWDEBUGF(3, "pa %x p %x size %d where %d",
256
+ pa, p, pdims, where);
257
+
258
+ if ( pdims < 2 || pdims > 4 )
259
+ {
260
+ lwerror("ptarray_addPoint: point dimension out of range (%d)",
261
+ pdims);
262
+ return NULL;
263
+ }
264
+
265
+ if ( where > pa->npoints )
266
+ {
267
+ lwerror("ptarray_addPoint: offset out of range (%d)",
268
+ where);
269
+ return NULL;
270
+ }
271
+
272
+ LWDEBUG(3, "called with a %dD point");
273
+
274
+ pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;
275
+ memcpy((uchar *)&pbuf, p, pdims*sizeof(double));
276
+
277
+ LWDEBUG(3, "initialized point buffer");
278
+
279
+ ret = ptarray_construct(TYPE_HASZ(pa->dims),
280
+ TYPE_HASM(pa->dims), pa->npoints+1);
281
+
282
+ if ( where == -1 ) where = pa->npoints;
283
+
284
+ if ( where )
285
+ {
286
+ memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);
287
+ }
288
+
289
+ memcpy(getPoint_internal(ret, where), (uchar *)&pbuf, ptsize);
290
+
291
+ if ( where+1 != ret->npoints )
292
+ {
293
+ memcpy(getPoint_internal(ret, where+1),
294
+ getPoint_internal(pa, where),
295
+ ptsize*(pa->npoints-where));
296
+ }
297
+
298
+ return ret;
299
+ }
300
+
301
+ /*
302
+ * Remove a point from a pointarray.
303
+ * 'which' is the offset (starting at 0)
304
+ * Returned pointarray is newly allocated
305
+ */
306
+ POINTARRAY *
307
+ ptarray_removePoint(POINTARRAY *pa, unsigned int which)
308
+ {
309
+ POINTARRAY *ret;
310
+ size_t ptsize = pointArray_ptsize(pa);
311
+
312
+ LWDEBUGF(3, "pa %x which %d", pa, which);
313
+
314
+ #if PARANOIA_LEVEL > 0
315
+ if ( which > pa->npoints-1 )
316
+ {
317
+ lwerror("ptarray_removePoint: offset (%d) out of range (%d..%d)",
318
+ which, 0, pa->npoints-1);
319
+ return NULL;
320
+ }
321
+
322
+ if ( pa->npoints < 3 )
323
+ {
324
+ lwerror("ptarray_removePointe: can't remove a point from a 2-vertex POINTARRAY");
325
+ }
326
+ #endif
327
+
328
+ ret = ptarray_construct(TYPE_HASZ(pa->dims),
329
+ TYPE_HASM(pa->dims), pa->npoints-1);
330
+
331
+ /* copy initial part */
332
+ if ( which )
333
+ {
334
+ memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
335
+ }
336
+
337
+ /* copy final part */
338
+ if ( which < pa->npoints-1 )
339
+ {
340
+ memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
341
+ ptsize*(pa->npoints-which-1));
342
+ }
343
+
344
+ return ret;
345
+ }
346
+
347
+ /*
348
+ * Clone a pointarray
349
+ */
350
+ POINTARRAY *
351
+ ptarray_clone(const POINTARRAY *in)
352
+ {
353
+ POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
354
+ size_t size;
355
+
356
+ LWDEBUG(3, "ptarray_clone called.");
357
+
358
+ out->dims = in->dims;
359
+ out->npoints = in->npoints;
360
+
361
+ size = in->npoints*sizeof(double)*TYPE_NDIMS(in->dims);
362
+ out->serialized_pointlist = lwalloc(size);
363
+ memcpy(out->serialized_pointlist, in->serialized_pointlist, size);
364
+
365
+ return out;
366
+ }
367
+
368
+ int
369
+ ptarray_isclosed2d(const POINTARRAY *in)
370
+ {
371
+ if ( memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D)) ) return 0;
372
+ return 1;
373
+ }
374
+
375
+ /*
376
+ * calculate the BOX3D bounding box of a set of points
377
+ * returns a lwalloced BOX3D, or NULL on empty array.
378
+ * zmin/zmax values are set to NO_Z_VALUE if not available.
379
+ */
380
+ BOX3D *
381
+ ptarray_compute_box3d(const POINTARRAY *pa)
382
+ {
383
+ BOX3D *result = lwalloc(sizeof(BOX3D));
384
+
385
+ if ( ! ptarray_compute_box3d_p(pa, result) )
386
+ {
387
+ lwfree(result);
388
+ return NULL;
389
+ }
390
+
391
+ return result;
392
+ }
393
+
394
+ /*
395
+ * calculate the BOX3D bounding box of a set of points
396
+ * zmin/zmax values are set to NO_Z_VALUE if not available.
397
+ * write result to the provided BOX3D
398
+ * Return 0 if bounding box is NULL (empty geom)
399
+ */
400
+ int
401
+ ptarray_compute_box3d_p(const POINTARRAY *pa, BOX3D *result)
402
+ {
403
+ int t;
404
+ POINT3DZ pt;
405
+
406
+ LWDEBUGF(3, "ptarray_compute_box3d call (array has %d points)", pa->npoints);
407
+
408
+ if (pa->npoints == 0) return 0;
409
+
410
+ getPoint3dz_p(pa, 0, &pt);
411
+
412
+ LWDEBUG(3, "got point 0");
413
+
414
+ result->xmin = pt.x;
415
+ result->xmax = pt.x;
416
+ result->ymin = pt.y;
417
+ result->ymax = pt.y;
418
+
419
+ if ( TYPE_HASZ(pa->dims) ) {
420
+ result->zmin = pt.z;
421
+ result->zmax = pt.z;
422
+ } else {
423
+ result->zmin = NO_Z_VALUE;
424
+ result->zmax = NO_Z_VALUE;
425
+ }
426
+
427
+ LWDEBUGF(3, "scanning other %d points", pa->npoints);
428
+
429
+ for (t=1; t<pa->npoints; t++)
430
+ {
431
+ getPoint3dz_p(pa,t,&pt);
432
+ if (pt.x < result->xmin) result->xmin = pt.x;
433
+ if (pt.y < result->ymin) result->ymin = pt.y;
434
+ if (pt.x > result->xmax) result->xmax = pt.x;
435
+ if (pt.y > result->ymax) result->ymax = pt.y;
436
+
437
+ if ( TYPE_HASZ(pa->dims) ) {
438
+ if (pt.z > result->zmax) result->zmax = pt.z;
439
+ if (pt.z < result->zmin) result->zmin = pt.z;
440
+ }
441
+ }
442
+
443
+ LWDEBUG(3, "returning box");
444
+
445
+ return 1;
446
+ }
447
+
448
+ /*
449
+ * TODO: implement point interpolation
450
+ */
451
+ POINTARRAY *
452
+ ptarray_substring(POINTARRAY *ipa, double from, double to)
453
+ {
454
+ DYNPTARRAY *dpa;
455
+ POINTARRAY *opa;
456
+ POINT4D pt;
457
+ POINT4D p1, p2;
458
+ POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
459
+ POINT4D *p2ptr=&p2;
460
+ int nsegs, i;
461
+ double length, slength, tlength;
462
+ int state = 0; /* 0=before, 1=inside */
463
+
464
+ /*
465
+ * Create a dynamic pointarray with an initial capacity
466
+ * equal to full copy of input points
467
+ */
468
+ dpa = dynptarray_create(ipa->npoints, ipa->dims);
469
+
470
+ /* Compute total line length */
471
+ length = lwgeom_pointarray_length2d(ipa);
472
+
473
+
474
+ LWDEBUGF(3, "Total length: %g", length);
475
+
476
+
477
+ /* Get 'from' and 'to' lengths */
478
+ from = length*from;
479
+ to = length*to;
480
+
481
+
482
+ LWDEBUGF(3, "From/To: %g/%g", from, to);
483
+
484
+
485
+ tlength = 0;
486
+ getPoint4d_p(ipa, 0, &p1);
487
+ nsegs = ipa->npoints - 1;
488
+ for( i = 0; i < nsegs; i++ )
489
+ {
490
+ double dseg;
491
+
492
+ getPoint4d_p(ipa, i+1, &p2);
493
+
494
+
495
+ LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
496
+ i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);
497
+
498
+
499
+ /* Find the length of this segment */
500
+ slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
501
+
502
+ /*
503
+ * We are before requested start.
504
+ */
505
+ if ( state == 0 ) /* before */
506
+ {
507
+
508
+ LWDEBUG(3, " Before start");
509
+
510
+ /*
511
+ * Didn't reach the 'from' point,
512
+ * nothing to do
513
+ */
514
+ if ( from > tlength + slength ) goto END;
515
+
516
+ else if ( from == tlength + slength )
517
+ {
518
+
519
+ LWDEBUG(3, " Second point is our start");
520
+
521
+ /*
522
+ * Second point is our start
523
+ */
524
+ dynptarray_addPoint4d(dpa, &p2, 1);
525
+ state=1; /* we're inside now */
526
+ goto END;
527
+ }
528
+
529
+ else if ( from == tlength )
530
+ {
531
+
532
+ LWDEBUG(3, " First point is our start");
533
+
534
+ /*
535
+ * First point is our start
536
+ */
537
+ dynptarray_addPoint4d(dpa, &p1, 1);
538
+
539
+ /*
540
+ * We're inside now, but will check
541
+ * 'to' point as well
542
+ */
543
+ state=1;
544
+ }
545
+
546
+ else /* tlength < from < tlength+slength */
547
+ {
548
+
549
+ LWDEBUG(3, " Seg contains first point");
550
+
551
+ /*
552
+ * Our start is between first and
553
+ * second point
554
+ */
555
+ dseg = (from - tlength) / slength;
556
+ interpolate_point4d(&p1, &p2, &pt, dseg);
557
+
558
+ dynptarray_addPoint4d(dpa, &pt, 1);
559
+
560
+ /*
561
+ * We're inside now, but will check
562
+ * 'to' point as well
563
+ */
564
+ state=1;
565
+ }
566
+ }
567
+
568
+ if ( state == 1 ) /* inside */
569
+ {
570
+
571
+ LWDEBUG(3, " Inside");
572
+
573
+ /*
574
+ * Didn't reach the 'end' point,
575
+ * just copy second point
576
+ */
577
+ if ( to > tlength + slength )
578
+ {
579
+ dynptarray_addPoint4d(dpa, &p2, 0);
580
+ goto END;
581
+ }
582
+
583
+ /*
584
+ * 'to' point is our second point.
585
+ */
586
+ else if ( to == tlength + slength )
587
+ {
588
+
589
+ LWDEBUG(3, " Second point is our end");
590
+
591
+ dynptarray_addPoint4d(dpa, &p2, 0);
592
+ break; /* substring complete */
593
+ }
594
+
595
+ /*
596
+ * 'to' point is our first point.
597
+ * (should only happen if 'to' is 0)
598
+ */
599
+ else if ( to == tlength )
600
+ {
601
+
602
+ LWDEBUG(3, " First point is our end");
603
+
604
+ dynptarray_addPoint4d(dpa, &p1, 0);
605
+
606
+ break; /* substring complete */
607
+ }
608
+
609
+ /*
610
+ * 'to' point falls on this segment
611
+ * Interpolate and break.
612
+ */
613
+ else if ( to < tlength + slength )
614
+ {
615
+
616
+ LWDEBUG(3, " Seg contains our end");
617
+
618
+ dseg = (to - tlength) / slength;
619
+ interpolate_point4d(&p1, &p2, &pt, dseg);
620
+
621
+ dynptarray_addPoint4d(dpa, &pt, 0);
622
+
623
+ break;
624
+ }
625
+
626
+ else
627
+ {
628
+ LWDEBUG(3, "Unhandled case");
629
+ }
630
+ }
631
+
632
+
633
+ END:
634
+
635
+ tlength += slength;
636
+ memcpy(&p1, &p2, sizeof(POINT4D));
637
+ }
638
+
639
+ /* Get constructed pointarray and release memory associated
640
+ * with the dynamic pointarray
641
+ */
642
+ opa = dpa->pa;
643
+ lwfree(dpa);
644
+
645
+ LWDEBUGF(3, "Out of loop, ptarray has %d points", opa->npoints);
646
+
647
+ return opa;
648
+ }
649
+
650
+ /*
651
+ * Write into the *ret argument coordinates of the closes point on
652
+ * the given segment to the reference input point.
653
+ */
654
+ void
655
+ closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret)
656
+ {
657
+ double r;
658
+
659
+ if ( ( A->x == B->x) && (A->y == B->y) )
660
+ {
661
+ *ret = *A;
662
+ return;
663
+ }
664
+
665
+ /*
666
+ * We use comp.graphics.algorithms Frequently Asked Questions method
667
+ *
668
+ * (1) AC dot AB
669
+ * r = ----------
670
+ * ||AB||^2
671
+ * r has the following meaning:
672
+ * r=0 P = A
673
+ * r=1 P = B
674
+ * r<0 P is on the backward extension of AB
675
+ * r>1 P is on the forward extension of AB
676
+ * 0<r<1 P is interior to AB
677
+ *
678
+ */
679
+ r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
680
+
681
+ if (r<0) {
682
+ *ret = *A; return;
683
+ }
684
+ if (r>1) {
685
+ *ret = *B;
686
+ return;
687
+ }
688
+
689
+ ret->x = A->x + ( (B->x - A->x) * r );
690
+ ret->y = A->y + ( (B->y - A->y) * r );
691
+ }
692
+
693
+ /*
694
+ * Given a point, returns the location of closest point on pointarray
695
+ */
696
+ double
697
+ ptarray_locate_point(POINTARRAY *pa, POINT2D *p)
698
+ {
699
+ double mindist=-1;
700
+ double tlen, plen;
701
+ int t, seg=-1;
702
+ POINT2D start, end;
703
+ POINT2D proj;
704
+
705
+ getPoint2d_p(pa, 0, &start);
706
+ for (t=1; t<pa->npoints; t++)
707
+ {
708
+ double dist;
709
+ getPoint2d_p(pa, t, &end);
710
+ dist = distance2d_pt_seg(p, &start, &end);
711
+
712
+ if (t==1 || dist < mindist ) {
713
+ mindist = dist;
714
+ seg=t-1;
715
+ }
716
+
717
+ if ( mindist == 0 ) break;
718
+
719
+ start = end;
720
+ }
721
+
722
+ LWDEBUGF(3, "Closest segment: %d", seg);
723
+
724
+ /*
725
+ * If mindist is not 0 we need to project the
726
+ * point on the closest segment.
727
+ */
728
+ if ( mindist > 0 )
729
+ {
730
+ getPoint2d_p(pa, seg, &start);
731
+ getPoint2d_p(pa, seg+1, &end);
732
+ closest_point_on_segment(p, &start, &end, &proj);
733
+ } else {
734
+ proj = *p;
735
+ }
736
+
737
+ LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
738
+
739
+ tlen = lwgeom_pointarray_length2d(pa);
740
+
741
+ LWDEBUGF(3, "tlen %g", tlen);
742
+
743
+ plen=0;
744
+ getPoint2d_p(pa, 0, &start);
745
+ for (t=0; t<seg; t++, start=end)
746
+ {
747
+ getPoint2d_p(pa, t+1, &end);
748
+ plen += distance2d_pt_pt(&start, &end);
749
+
750
+ LWDEBUGF(4, "Segment %d made plen %g", t, plen);
751
+ }
752
+
753
+ plen+=distance2d_pt_pt(&proj, &start);
754
+
755
+ LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);
756
+ LWDEBUGF(3, "mindist: %g", mindist);
757
+
758
+ return plen/tlen;
759
+ }
760
+
761
+ /*
762
+ * Longitude shift for a pointarray.
763
+ * Y remains the same
764
+ * X is converted:
765
+ * from -180..180 to 0..360
766
+ * from 0..360 to -180..180
767
+ * X < 0 becomes X + 360
768
+ * X > 180 becomes X - 360
769
+ */
770
+ void
771
+ ptarray_longitude_shift(POINTARRAY *pa)
772
+ {
773
+ int i;
774
+ double x;
775
+
776
+ for (i=0; i<pa->npoints; i++) {
777
+ memcpy(&x, getPoint_internal(pa, i), sizeof(double));
778
+ if ( x < 0 ) x+= 360;
779
+ else if ( x > 180 ) x -= 360;
780
+ memcpy(getPoint_internal(pa, i), &x, sizeof(double));
781
+ }
782
+ }
783
+
784
+ DYNPTARRAY *
785
+ dynptarray_create(size_t initial_capacity, int dims)
786
+ {
787
+ DYNPTARRAY *ret=lwalloc(sizeof(DYNPTARRAY));
788
+
789
+ LWDEBUGF(3, "dynptarray_create called, dims=%d.", dims);
790
+
791
+ if ( initial_capacity < 1 ) initial_capacity=1;
792
+
793
+ ret->pa=lwalloc(sizeof(POINTARRAY));
794
+ ret->pa->dims=dims;
795
+ ret->ptsize=pointArray_ptsize(ret->pa);
796
+ ret->capacity=initial_capacity;
797
+ ret->pa->serialized_pointlist=lwalloc(ret->ptsize*ret->capacity);
798
+ ret->pa->npoints=0;
799
+
800
+ return ret;
801
+ }
802
+
803
+ /*
804
+ * Add a POINT4D to the dynamic pointarray.
805
+ *
806
+ * The dynamic pointarray may be of any dimension, only
807
+ * accepted dimensions will be copied.
808
+ *
809
+ * If allow_duplicates is set to 0 (false) a check
810
+ * is performed to see if last point in array is equal to the
811
+ * provided one. NOTE that the check is 4d based, with missing
812
+ * ordinates in the pointarray set to NO_Z_VALUE and NO_M_VALUE
813
+ * respectively.
814
+ */
815
+ int
816
+ dynptarray_addPoint4d(DYNPTARRAY *dpa, POINT4D *p4d, int allow_duplicates)
817
+ {
818
+ POINTARRAY *pa=dpa->pa;
819
+ POINT4D tmp;
820
+
821
+ LWDEBUG(3, "dynptarray_addPoint4d called.");
822
+
823
+ if ( ! allow_duplicates && pa->npoints > 0 )
824
+ {
825
+ getPoint4d_p(pa, pa->npoints-1, &tmp);
826
+
827
+ /*
828
+ * return 0 and do nothing else if previous point in list is
829
+ * equal to this one (4D equality)
830
+ */
831
+ if (tmp.x == p4d->x && tmp.y == p4d->y && tmp.z == p4d->z && tmp.m == p4d->m) return 0;
832
+ }
833
+
834
+ ++pa->npoints;
835
+ if ( pa->npoints > dpa->capacity )
836
+ {
837
+ dpa->capacity*=2;
838
+ pa->serialized_pointlist = lwrealloc(
839
+ pa->serialized_pointlist,
840
+ dpa->capacity*dpa->ptsize);
841
+ }
842
+
843
+ setPoint4d(pa, pa->npoints-1, p4d);
844
+
845
+ return 1;
846
+ }
847
+