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,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
+ }