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