geo_coder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+