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,579 @@
1
+ /**********************************************************************
2
+ * $Id: lwpoly.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
+ /* basic LWPOLY manipulation */
14
+
15
+ #include <stdio.h>
16
+ #include <stdlib.h>
17
+ #include <string.h>
18
+ #include "liblwgeom.h"
19
+
20
+
21
+ #define CHECK_POLY_RINGS_ZM 1
22
+
23
+ /* construct a new LWPOLY. arrays (points/points per ring) will NOT be copied
24
+ * use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
25
+ */
26
+ LWPOLY *
27
+ lwpoly_construct(int SRID, BOX2DFLOAT4 *bbox, unsigned int nrings, POINTARRAY **points)
28
+ {
29
+ LWPOLY *result;
30
+ int hasz, hasm;
31
+ #ifdef CHECK_POLY_RINGS_ZM
32
+ char zm;
33
+ unsigned int i;
34
+ #endif
35
+
36
+ if ( nrings < 1 ) lwerror("lwpoly_construct: need at least 1 ring");
37
+
38
+ hasz = TYPE_HASZ(points[0]->dims);
39
+ hasm = TYPE_HASM(points[0]->dims);
40
+
41
+ #ifdef CHECK_POLY_RINGS_ZM
42
+ zm = TYPE_GETZM(points[0]->dims);
43
+ for (i=1; i<nrings; i++)
44
+ {
45
+ if ( zm != TYPE_GETZM(points[i]->dims) )
46
+ lwerror("lwpoly_construct: mixed dimensioned rings");
47
+ }
48
+ #endif
49
+
50
+ result = (LWPOLY*) lwalloc(sizeof(LWPOLY));
51
+ result->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1), POLYGONTYPE,
52
+ 0);
53
+ result->SRID = SRID;
54
+ result->nrings = nrings;
55
+ result->rings = points;
56
+ result->bbox = bbox;
57
+
58
+ return result;
59
+ }
60
+
61
+
62
+ /*
63
+ * given the LWPOLY serialized form (or a pointer into a muli* one)
64
+ * construct a proper LWPOLY.
65
+ * serialized_form should point to the 8bit type format (with type = 3)
66
+ * See serialized form doc
67
+ */
68
+ LWPOLY *
69
+ lwpoly_deserialize(uchar *serialized_form)
70
+ {
71
+
72
+ LWPOLY *result;
73
+ uint32 nrings;
74
+ int ndims, hasz, hasm;
75
+ uint32 npoints;
76
+ uchar type;
77
+ uchar *loc;
78
+ int t;
79
+
80
+ if (serialized_form == NULL)
81
+ {
82
+ lwerror("lwpoly_deserialize called with NULL arg");
83
+ return NULL;
84
+ }
85
+
86
+ result = (LWPOLY*) lwalloc(sizeof(LWPOLY));
87
+
88
+ type = serialized_form[0];
89
+ result->type = type;
90
+
91
+ ndims = TYPE_NDIMS(type);
92
+ hasz = TYPE_HASZ(type);
93
+ hasm = TYPE_HASM(type);
94
+ loc = serialized_form;
95
+
96
+ if ( TYPE_GETTYPE(type) != POLYGONTYPE)
97
+ {
98
+ lwerror("lwpoly_deserialize: attempt to deserialize a poly which is really a %s", lwgeom_typename(type));
99
+ return NULL;
100
+ }
101
+
102
+
103
+ loc = serialized_form+1;
104
+
105
+ if (lwgeom_hasBBOX(type)) {
106
+ LWDEBUG(3, "lwpoly_deserialize: input has bbox");
107
+
108
+ result->bbox = lwalloc(sizeof(BOX2DFLOAT4));
109
+ memcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));
110
+ loc += sizeof(BOX2DFLOAT4);
111
+ } else {
112
+ result->bbox = NULL;
113
+ }
114
+
115
+ if ( lwgeom_hasSRID(type))
116
+ {
117
+ result->SRID = lw_get_int32(loc);
118
+ loc +=4; /* type + SRID */
119
+ }
120
+ else
121
+ {
122
+ result->SRID = -1;
123
+ }
124
+
125
+ nrings = lw_get_uint32(loc);
126
+ result->nrings = nrings;
127
+ loc +=4;
128
+ result->rings = (POINTARRAY**) lwalloc(nrings* sizeof(POINTARRAY*));
129
+
130
+ for (t =0;t<nrings;t++)
131
+ {
132
+ /* read in a single ring and make a PA */
133
+ npoints = lw_get_uint32(loc);
134
+ loc +=4;
135
+
136
+ result->rings[t] = pointArray_construct(loc, hasz, hasm, npoints);
137
+ loc += sizeof(double)*ndims*npoints;
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ /*
144
+ * create the serialized form of the polygon
145
+ * result's first char will be the 8bit type. See serialized form doc
146
+ * points copied
147
+ */
148
+ uchar *
149
+ lwpoly_serialize(LWPOLY *poly)
150
+ {
151
+ size_t size, retsize;
152
+ uchar *result;
153
+
154
+ size = lwpoly_serialize_size(poly);
155
+ result = lwalloc(size);
156
+ lwpoly_serialize_buf(poly, result, &retsize);
157
+
158
+ if ( retsize != size )
159
+ {
160
+ lwerror("lwpoly_serialize_size returned %d, ..serialize_buf returned %d", size, retsize);
161
+ }
162
+
163
+ return result;
164
+ }
165
+
166
+ /*
167
+ * create the serialized form of the polygon writing it into the
168
+ * given buffer, and returning number of bytes written into
169
+ * the given int pointer.
170
+ * result's first char will be the 8bit type. See serialized form doc
171
+ * points copied
172
+ */
173
+ void
174
+ lwpoly_serialize_buf(LWPOLY *poly, uchar *buf, size_t *retsize)
175
+ {
176
+ size_t size=1; /* type byte */
177
+ char hasSRID;
178
+ int t;
179
+ uchar *loc;
180
+ int ptsize;
181
+
182
+ LWDEBUG(2, "lwpoly_serialize_buf called");
183
+
184
+ ptsize = sizeof(double)*TYPE_NDIMS(poly->type);
185
+
186
+ hasSRID = (poly->SRID != -1);
187
+
188
+ size += 4; /* nrings */
189
+ size += 4*poly->nrings; /* npoints/ring */
190
+
191
+ buf[0] = (uchar) lwgeom_makeType_full(
192
+ TYPE_HASZ(poly->type), TYPE_HASM(poly->type),
193
+ hasSRID, POLYGONTYPE, poly->bbox ? 1 : 0);
194
+ loc = buf+1;
195
+
196
+ if (poly->bbox)
197
+ {
198
+ memcpy(loc, poly->bbox, sizeof(BOX2DFLOAT4));
199
+ size += sizeof(BOX2DFLOAT4); /* bvol */
200
+ loc += sizeof(BOX2DFLOAT4);
201
+ }
202
+
203
+ if (hasSRID)
204
+ {
205
+ memcpy(loc, &poly->SRID, sizeof(int32));
206
+ loc += 4;
207
+ size +=4; /* 4 byte SRID */
208
+ }
209
+
210
+ memcpy(loc, &poly->nrings, sizeof(int32)); /* nrings */
211
+ loc+=4;
212
+
213
+ for (t=0;t<poly->nrings;t++)
214
+ {
215
+ POINTARRAY *pa = poly->rings[t];
216
+ size_t pasize;
217
+ uint32 npoints;
218
+
219
+ if ( TYPE_GETZM(poly->type) != TYPE_GETZM(pa->dims) )
220
+ lwerror("Dimensions mismatch in lwpoly");
221
+
222
+ npoints = pa->npoints;
223
+
224
+ memcpy(loc, &npoints, sizeof(uint32)); /* npoints this ring */
225
+ loc+=4;
226
+
227
+ pasize = npoints*ptsize;
228
+ size += pasize;
229
+
230
+ /* copy points */
231
+ memcpy(loc, getPoint_internal(pa, 0), pasize);
232
+ loc += pasize;
233
+
234
+ }
235
+
236
+ if (retsize) *retsize = size;
237
+ }
238
+
239
+
240
+ /* find bounding box (standard one) zmin=zmax=0 if 2d (might change to NaN) */
241
+ BOX3D *
242
+ lwpoly_compute_box3d(LWPOLY *poly)
243
+ {
244
+ BOX3D *result;
245
+
246
+ /* just need to check outer ring -- interior rings are inside */
247
+ POINTARRAY *pa = poly->rings[0];
248
+ result = ptarray_compute_box3d(pa);
249
+
250
+ return result;
251
+ }
252
+
253
+ /* find length of this serialized polygon */
254
+ size_t
255
+ lwgeom_size_poly(const uchar *serialized_poly)
256
+ {
257
+ uint32 result = 1; /* char type */
258
+ uint32 nrings;
259
+ int ndims;
260
+ int t;
261
+ uchar type;
262
+ uint32 npoints;
263
+ const uchar *loc;
264
+
265
+ if (serialized_poly == NULL)
266
+ return -9999;
267
+
268
+
269
+ type = (uchar) serialized_poly[0];
270
+ ndims = lwgeom_ndims(type);
271
+
272
+ if ( lwgeom_getType(type) != POLYGONTYPE)
273
+ return -9999;
274
+
275
+
276
+ loc = serialized_poly+1;
277
+
278
+ if (lwgeom_hasBBOX(type))
279
+ {
280
+ LWDEBUG(3, "lwgeom_size_poly: has bbox");
281
+
282
+ loc += sizeof(BOX2DFLOAT4);
283
+ result +=sizeof(BOX2DFLOAT4);
284
+ }
285
+
286
+
287
+ if ( lwgeom_hasSRID(type))
288
+ {
289
+ LWDEBUG(3, "lwgeom_size_poly: has srid");
290
+
291
+ loc +=4; /* type + SRID */
292
+ result += 4;
293
+ }
294
+
295
+
296
+ nrings = lw_get_uint32(loc);
297
+ loc +=4;
298
+ result +=4;
299
+
300
+ LWDEBUGF(3, "lwgeom_size_poly contains %d rings", nrings);
301
+
302
+ for (t =0;t<nrings;t++)
303
+ {
304
+ /* read in a single ring and make a PA */
305
+ npoints = lw_get_uint32(loc);
306
+ loc += 4;
307
+ result += 4;
308
+
309
+ if (ndims == 3)
310
+ {
311
+ loc += 24*npoints;
312
+ result += 24*npoints;
313
+ }
314
+ else if (ndims == 2)
315
+ {
316
+ loc += 16*npoints;
317
+ result += 16*npoints;
318
+ }
319
+ else if (ndims == 4)
320
+ {
321
+ loc += 32*npoints;
322
+ result += 32*npoints;
323
+ }
324
+ }
325
+
326
+ LWDEBUGF(3, "lwgeom_size_poly returning %d", result);
327
+
328
+ return result;
329
+ }
330
+
331
+ /* find length of this deserialized polygon */
332
+ size_t
333
+ lwpoly_serialize_size(LWPOLY *poly)
334
+ {
335
+ size_t size = 1; /* type */
336
+ uint32 i;
337
+
338
+ if ( poly->SRID != -1 ) size += 4; /* SRID */
339
+ if ( poly->bbox ) size += sizeof(BOX2DFLOAT4);
340
+
341
+ LWDEBUGF(2, "lwpoly_serialize_size called with poly[%p] (%d rings)",
342
+ poly, poly->nrings);
343
+
344
+ size += 4; /* nrings */
345
+
346
+ for (i=0; i<poly->nrings; i++)
347
+ {
348
+ size += 4; /* npoints */
349
+ size += poly->rings[i]->npoints*TYPE_NDIMS(poly->type)*sizeof(double);
350
+ }
351
+
352
+ LWDEBUGF(3, "lwpoly_serialize_size returning %d", size);
353
+
354
+ return size;
355
+ }
356
+
357
+ void lwpoly_free (LWPOLY *poly)
358
+ {
359
+ int t;
360
+
361
+ if ( poly->bbox )
362
+ lwfree(poly->bbox);
363
+
364
+ for (t=0;t<poly->nrings;t++)
365
+ {
366
+ if( poly->rings[t] )
367
+ ptarray_free(poly->rings[t]);
368
+ }
369
+
370
+ if ( poly->rings )
371
+ lwfree(poly->rings);
372
+
373
+ lwfree(poly);
374
+ }
375
+
376
+ void printLWPOLY(LWPOLY *poly)
377
+ {
378
+ int t;
379
+ lwnotice("LWPOLY {");
380
+ lwnotice(" ndims = %i", (int)TYPE_NDIMS(poly->type));
381
+ lwnotice(" SRID = %i", (int)poly->SRID);
382
+ lwnotice(" nrings = %i", (int)poly->nrings);
383
+ for (t=0;t<poly->nrings;t++)
384
+ {
385
+ lwnotice(" RING # %i :",t);
386
+ printPA(poly->rings[t]);
387
+ }
388
+ lwnotice("}");
389
+ }
390
+
391
+ int
392
+ lwpoly_compute_box2d_p(LWPOLY *poly, BOX2DFLOAT4 *box)
393
+ {
394
+ BOX2DFLOAT4 boxbuf;
395
+ uint32 i;
396
+
397
+ if ( ! poly->nrings ) return 0;
398
+ if ( ! ptarray_compute_box2d_p(poly->rings[0], box) ) return 0;
399
+ for (i=1; i<poly->nrings; i++)
400
+ {
401
+ if ( ! ptarray_compute_box2d_p(poly->rings[0], &boxbuf) )
402
+ return 0;
403
+ if ( ! box2d_union_p(box, &boxbuf, box) )
404
+ return 0;
405
+ }
406
+ return 1;
407
+ }
408
+
409
+ /* Clone LWLINE object. POINTARRAY are not copied, it's ring array is. */
410
+ LWPOLY *
411
+ lwpoly_clone(const LWPOLY *g)
412
+ {
413
+ LWPOLY *ret = lwalloc(sizeof(LWPOLY));
414
+ memcpy(ret, g, sizeof(LWPOLY));
415
+ ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings);
416
+ memcpy(ret->rings, g->rings, sizeof(POINTARRAY *)*g->nrings);
417
+ if ( g->bbox ) ret->bbox = box2d_clone(g->bbox);
418
+ return ret;
419
+ }
420
+
421
+ /*
422
+ * Add 'what' to this poly at position 'where'.
423
+ * where=0 == prepend
424
+ * where=-1 == append
425
+ * Returns a MULTIPOLYGON or a GEOMETRYCOLLECTION
426
+ */
427
+ LWGEOM *
428
+ lwpoly_add(const LWPOLY *to, uint32 where, const LWGEOM *what)
429
+ {
430
+ LWCOLLECTION *col;
431
+ LWGEOM **geoms;
432
+ int newtype;
433
+
434
+ if ( where != -1 && where != 0 )
435
+ {
436
+ lwerror("lwpoly_add only supports 0 or -1 as second argument, got %d", where);
437
+ return NULL;
438
+ }
439
+
440
+ /* dimensions compatibility are checked by caller */
441
+
442
+ /* Construct geoms array */
443
+ geoms = lwalloc(sizeof(LWGEOM *)*2);
444
+ if ( where == -1 ) /* append */
445
+ {
446
+ geoms[0] = lwgeom_clone((LWGEOM *)to);
447
+ geoms[1] = lwgeom_clone(what);
448
+ }
449
+ else /* prepend */
450
+ {
451
+ geoms[0] = lwgeom_clone(what);
452
+ geoms[1] = lwgeom_clone((LWGEOM *)to);
453
+ }
454
+
455
+ /* reset SRID and wantbbox flag from component types */
456
+ geoms[0]->SRID = geoms[1]->SRID = -1;
457
+ TYPE_SETHASSRID(geoms[0]->type, 0);
458
+ TYPE_SETHASSRID(geoms[1]->type, 0);
459
+ TYPE_SETHASBBOX(geoms[0]->type, 0);
460
+ TYPE_SETHASBBOX(geoms[1]->type, 0);
461
+
462
+ /* Find appropriate geom type */
463
+ if ( TYPE_GETTYPE(what->type) == POLYGONTYPE ) newtype = MULTIPOLYGONTYPE;
464
+ else newtype = COLLECTIONTYPE;
465
+
466
+ col = lwcollection_construct(newtype,
467
+ to->SRID, NULL,
468
+ 2, geoms);
469
+
470
+ return (LWGEOM *)col;
471
+ }
472
+
473
+ void
474
+ lwpoly_forceRHR(LWPOLY *poly)
475
+ {
476
+ int i;
477
+
478
+ if ( ptarray_isccw(poly->rings[0]) )
479
+ {
480
+ ptarray_reverse(poly->rings[0]);
481
+ }
482
+
483
+ for (i=1; i<poly->nrings; i++)
484
+ {
485
+ if ( ! ptarray_isccw(poly->rings[i]) )
486
+ {
487
+ ptarray_reverse(poly->rings[i]);
488
+ }
489
+ }
490
+ }
491
+
492
+ void
493
+ lwpoly_release(LWPOLY *lwpoly)
494
+ {
495
+ lwgeom_release(lwpoly_as_lwgeom(lwpoly));
496
+ }
497
+
498
+ void
499
+ lwpoly_reverse(LWPOLY *poly)
500
+ {
501
+ int i;
502
+
503
+ for (i=0; i<poly->nrings; i++)
504
+ ptarray_reverse(poly->rings[i]);
505
+ }
506
+
507
+ LWPOLY *
508
+ lwpoly_segmentize2d(LWPOLY *poly, double dist)
509
+ {
510
+ POINTARRAY **newrings;
511
+ unsigned int i;
512
+
513
+ newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
514
+ for (i=0; i<poly->nrings; i++)
515
+ {
516
+ newrings[i] = ptarray_segmentize2d(poly->rings[i], dist);
517
+ }
518
+ return lwpoly_construct(poly->SRID, NULL,
519
+ poly->nrings, newrings);
520
+ }
521
+
522
+ /*
523
+ * check coordinate equality
524
+ * ring and coordinate order is considered
525
+ */
526
+ char
527
+ lwpoly_same(const LWPOLY *p1, const LWPOLY *p2)
528
+ {
529
+ unsigned int i;
530
+
531
+ if ( p1->nrings != p2->nrings ) return 0;
532
+ for (i=0; i<p1->nrings; i++)
533
+ {
534
+ if ( ! ptarray_same(p1->rings[i], p2->rings[i]) )
535
+ return 0;
536
+ }
537
+ return 1;
538
+ }
539
+
540
+ /*
541
+ * Construct a polygon from a LWLINE being
542
+ * the shell and an array of LWLINE (possibly NULL) being holes.
543
+ * Pointarrays from intput geoms are cloned.
544
+ * SRID must be the same for each input line.
545
+ * Input lines must have at least 4 points, and be closed.
546
+ */
547
+ LWPOLY *
548
+ lwpoly_from_lwlines(const LWLINE *shell,
549
+ unsigned int nholes, const LWLINE **holes)
550
+ {
551
+ unsigned int nrings;
552
+ POINTARRAY **rings = lwalloc((nholes+1)*sizeof(POINTARRAY *));
553
+ int SRID = shell->SRID;
554
+ LWPOLY *ret;
555
+
556
+ if ( shell->points->npoints < 4 )
557
+ lwerror("lwpoly_from_lwlines: shell must have at least 4 points");
558
+ if ( ! ptarray_isclosed2d(shell->points) )
559
+ lwerror("lwpoly_from_lwlines: shell must be closed");
560
+ rings[0] = ptarray_clone(shell->points);
561
+
562
+ for (nrings=1; nrings<=nholes; nrings++)
563
+ {
564
+ const LWLINE *hole = holes[nrings-1];
565
+
566
+ if ( hole->SRID != SRID )
567
+ lwerror("lwpoly_from_lwlines: mixed SRIDs in input lines");
568
+
569
+ if ( hole->points->npoints < 4 )
570
+ lwerror("lwpoly_from_lwlines: holes must have at least 4 points");
571
+ if ( ! ptarray_isclosed2d(hole->points) )
572
+ lwerror("lwpoly_from_lwlines: holes must be closed");
573
+
574
+ rings[nrings] = ptarray_clone(hole->points);
575
+ }
576
+
577
+ ret = lwpoly_construct(SRID, NULL, nrings, rings);
578
+ return ret;
579
+ }