geo_coder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +12 -0
- data/Gemfile.lock +32 -0
- data/History.txt +6 -0
- data/Makefile +13 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +197 -0
- data/Rakefile +53 -0
- data/TODO.txt +8 -0
- data/VERSION +1 -0
- data/bin/build_indexes +8 -0
- data/bin/rebuild_cluster +22 -0
- data/bin/rebuild_metaphones +23 -0
- data/bin/tiger_import +59 -0
- data/demos/demo/app/ext/geocodewrap.rb +84 -0
- data/demos/demo/app/views/index.builder +13 -0
- data/demos/demo/app/views/index.erb +71 -0
- data/demos/demo/config.ru +12 -0
- data/demos/demo/config/bootstraps.rb +130 -0
- data/demos/demo/config/geoenvironment.rb +25 -0
- data/demos/demo/geocoder_helper.rb +12 -0
- data/demos/demo/geocom_geocode.rb +10 -0
- data/demos/demo/main.rb +3 -0
- data/demos/demo/rakefile.rb +17 -0
- data/demos/demo/tmp/restart.txt +0 -0
- data/demos/simpledemo/views/index.builder +13 -0
- data/demos/simpledemo/views/index.erb +69 -0
- data/demos/simpledemo/ws.rb +83 -0
- data/doc/Makefile +7 -0
- data/doc/html4css1.css +279 -0
- data/doc/lookup.rst +193 -0
- data/doc/parsing.rst +125 -0
- data/doc/voidspace.css +147 -0
- data/geo_coder.gemspec +172 -0
- data/lib/geocoder/us.rb +21 -0
- data/lib/geocoder/us/address.rb +290 -0
- data/lib/geocoder/us/constants.rb +670 -0
- data/lib/geocoder/us/database.rb +745 -0
- data/lib/geocoder/us/import.rb +181 -0
- data/lib/geocoder/us/import/tiger.rb +13 -0
- data/lib/geocoder/us/numbers.rb +58 -0
- data/navteq/README +4 -0
- data/navteq/convert.sql +37 -0
- data/navteq/navteq_import +39 -0
- data/navteq/prepare.sql +92 -0
- data/sql/cluster.sql +16 -0
- data/sql/convert.sql +80 -0
- data/sql/create.sql +37 -0
- data/sql/index.sql +12 -0
- data/sql/place.csv +104944 -0
- data/sql/place.sql +104948 -0
- data/sql/setup.sql +78 -0
- data/src/Makefile +13 -0
- data/src/README +14 -0
- data/src/liblwgeom/Makefile +75 -0
- data/src/liblwgeom/box2d.c +54 -0
- data/src/liblwgeom/lex.yy.c +4799 -0
- data/src/liblwgeom/liblwgeom.h +1405 -0
- data/src/liblwgeom/lwalgorithm.c +946 -0
- data/src/liblwgeom/lwalgorithm.h +52 -0
- data/src/liblwgeom/lwcircstring.c +759 -0
- data/src/liblwgeom/lwcollection.c +541 -0
- data/src/liblwgeom/lwcompound.c +118 -0
- data/src/liblwgeom/lwcurvepoly.c +86 -0
- data/src/liblwgeom/lwgeom.c +886 -0
- data/src/liblwgeom/lwgeom_api.c +2201 -0
- data/src/liblwgeom/lwgparse.c +1219 -0
- data/src/liblwgeom/lwgunparse.c +1054 -0
- data/src/liblwgeom/lwline.c +525 -0
- data/src/liblwgeom/lwmcurve.c +125 -0
- data/src/liblwgeom/lwmline.c +137 -0
- data/src/liblwgeom/lwmpoint.c +138 -0
- data/src/liblwgeom/lwmpoly.c +141 -0
- data/src/liblwgeom/lwmsurface.c +129 -0
- data/src/liblwgeom/lwpoint.c +439 -0
- data/src/liblwgeom/lwpoly.c +579 -0
- data/src/liblwgeom/lwsegmentize.c +1047 -0
- data/src/liblwgeom/lwutil.c +369 -0
- data/src/liblwgeom/measures.c +861 -0
- data/src/liblwgeom/postgis_config.h +93 -0
- data/src/liblwgeom/ptarray.c +847 -0
- data/src/liblwgeom/vsprintf.c +179 -0
- data/src/liblwgeom/wktparse.h +126 -0
- data/src/liblwgeom/wktparse.lex +74 -0
- data/src/liblwgeom/wktparse.tab.c +2353 -0
- data/src/liblwgeom/wktparse.tab.h +145 -0
- data/src/liblwgeom/wktparse.y +385 -0
- data/src/libsqlite3_geocoder/Makefile +22 -0
- data/src/libsqlite3_geocoder/Makefile.nix +15 -0
- data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
- data/src/libsqlite3_geocoder/extension.c +121 -0
- data/src/libsqlite3_geocoder/extension.h +13 -0
- data/src/libsqlite3_geocoder/levenshtein.c +42 -0
- data/src/libsqlite3_geocoder/metaphon.c +278 -0
- data/src/libsqlite3_geocoder/util.c +37 -0
- data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
- data/src/metaphone/Makefile +7 -0
- data/src/metaphone/README +49 -0
- data/src/metaphone/extension.c +37 -0
- data/src/metaphone/metaphon.c +251 -0
- data/src/shp2sqlite/Makefile +37 -0
- data/src/shp2sqlite/Makefile.nix +36 -0
- data/src/shp2sqlite/Makefile.redhat +35 -0
- data/src/shp2sqlite/dbfopen.c +1595 -0
- data/src/shp2sqlite/getopt.c +695 -0
- data/src/shp2sqlite/getopt.h +127 -0
- data/src/shp2sqlite/shapefil.h +500 -0
- data/src/shp2sqlite/shp2sqlite.c +1974 -0
- data/src/shp2sqlite/shpopen.c +1894 -0
- data/tests/address.rb +236 -0
- data/tests/benchmark.rb +20 -0
- data/tests/constants.rb +57 -0
- data/tests/data/address-sample.csv +52 -0
- data/tests/data/db-test.csv +57 -0
- data/tests/data/locations.csv +4 -0
- data/tests/database.rb +137 -0
- data/tests/generate.rb +34 -0
- data/tests/numbers.rb +46 -0
- data/tests/run.rb +11 -0
- 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
|
+
}
|