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,2201 @@
|
|
|
1
|
+
|
|
2
|
+
#include <math.h>
|
|
3
|
+
#include <float.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include <stdio.h>
|
|
6
|
+
#include <errno.h>
|
|
7
|
+
|
|
8
|
+
#include "liblwgeom.h"
|
|
9
|
+
#include "wktparse.h"
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Lower this to reduce integrity checks
|
|
13
|
+
*/
|
|
14
|
+
#define PARANOIA_LEVEL 1
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**********************************************************************
|
|
19
|
+
* BOX routines
|
|
20
|
+
*
|
|
21
|
+
* returns the float thats very close to the input, but <=
|
|
22
|
+
* handles the funny differences in float4 and float8 reps.
|
|
23
|
+
**********************************************************************/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* These are taken from glibc
|
|
28
|
+
* some machines do *not* have these functions defined, so we give
|
|
29
|
+
* an implementation of them here.
|
|
30
|
+
*/
|
|
31
|
+
typedef int int32_tt;
|
|
32
|
+
typedef unsigned int u_int32_tt;
|
|
33
|
+
|
|
34
|
+
typedef union
|
|
35
|
+
{
|
|
36
|
+
float value;
|
|
37
|
+
u_int32_tt word;
|
|
38
|
+
} ieee_float_shape_type;
|
|
39
|
+
|
|
40
|
+
#define GET_FLOAT_WORD(i,d) \
|
|
41
|
+
do { \
|
|
42
|
+
ieee_float_shape_type gf_u; \
|
|
43
|
+
gf_u.value = (d); \
|
|
44
|
+
(i) = gf_u.word; \
|
|
45
|
+
} while (0)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
#define SET_FLOAT_WORD(d,i) \
|
|
49
|
+
do { \
|
|
50
|
+
ieee_float_shape_type sf_u; \
|
|
51
|
+
sf_u.word = (i); \
|
|
52
|
+
(d) = sf_u.value; \
|
|
53
|
+
} while (0)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Returns the next smaller or next larger float
|
|
58
|
+
* from x (in direction of y).
|
|
59
|
+
*/
|
|
60
|
+
float
|
|
61
|
+
nextafterf_custom(float x, float y)
|
|
62
|
+
{
|
|
63
|
+
int32_tt hx,hy,ix,iy;
|
|
64
|
+
|
|
65
|
+
GET_FLOAT_WORD(hx,x);
|
|
66
|
+
GET_FLOAT_WORD(hy,y);
|
|
67
|
+
ix = hx&0x7fffffff; /* |x| */
|
|
68
|
+
iy = hy&0x7fffffff; /* |y| */
|
|
69
|
+
|
|
70
|
+
if((ix>0x7f800000) || /* x is nan */
|
|
71
|
+
(iy>0x7f800000)) /* y is nan */
|
|
72
|
+
return x+y;
|
|
73
|
+
if(x==y) return y; /* x=y, return y */
|
|
74
|
+
if(ix==0) { /* x == 0 */
|
|
75
|
+
SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */
|
|
76
|
+
y = x*x;
|
|
77
|
+
if(y==x) return y; else return x; /* raise underflow flag */
|
|
78
|
+
}
|
|
79
|
+
if(hx>=0) { /* x > 0 */
|
|
80
|
+
if(hx>hy) { /* x > y, x -= ulp */
|
|
81
|
+
hx -= 1;
|
|
82
|
+
} else { /* x < y, x += ulp */
|
|
83
|
+
hx += 1;
|
|
84
|
+
}
|
|
85
|
+
} else { /* x < 0 */
|
|
86
|
+
if(hy>=0||hx>hy){ /* x < y, x -= ulp */
|
|
87
|
+
hx -= 1;
|
|
88
|
+
} else { /* x > y, x += ulp */
|
|
89
|
+
hx += 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
hy = hx&0x7f800000;
|
|
93
|
+
if(hy>=0x7f800000) return x+x; /* overflow */
|
|
94
|
+
if(hy<0x00800000) { /* underflow */
|
|
95
|
+
y = x*x;
|
|
96
|
+
if(y!=x) { /* raise underflow flag */
|
|
97
|
+
SET_FLOAT_WORD(y,hx);
|
|
98
|
+
return y;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
SET_FLOAT_WORD(x,hx);
|
|
102
|
+
return x;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
float nextDown_f(double d)
|
|
107
|
+
{
|
|
108
|
+
float result = d;
|
|
109
|
+
|
|
110
|
+
if ( ((double) result) <=d)
|
|
111
|
+
return result;
|
|
112
|
+
|
|
113
|
+
return nextafterf_custom(result, result - 1000000);
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* Returns the float thats very close to the input, but >=.
|
|
119
|
+
* handles the funny differences in float4 and float8 reps.
|
|
120
|
+
*/
|
|
121
|
+
float
|
|
122
|
+
nextUp_f(double d)
|
|
123
|
+
{
|
|
124
|
+
float result = d;
|
|
125
|
+
|
|
126
|
+
if ( ((double) result) >=d)
|
|
127
|
+
return result;
|
|
128
|
+
|
|
129
|
+
return nextafterf_custom(result, result + 1000000);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* Returns the double thats very close to the input, but <.
|
|
135
|
+
* handles the funny differences in float4 and float8 reps.
|
|
136
|
+
*/
|
|
137
|
+
double
|
|
138
|
+
nextDown_d(float d)
|
|
139
|
+
{
|
|
140
|
+
double result = d;
|
|
141
|
+
|
|
142
|
+
if ( result < d)
|
|
143
|
+
return result;
|
|
144
|
+
|
|
145
|
+
return nextafterf_custom(result, result - 1000000);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
* Returns the double thats very close to the input, but >
|
|
150
|
+
* handles the funny differences in float4 and float8 reps.
|
|
151
|
+
*/
|
|
152
|
+
double
|
|
153
|
+
nextUp_d(float d)
|
|
154
|
+
{
|
|
155
|
+
double result = d;
|
|
156
|
+
|
|
157
|
+
if ( result > d)
|
|
158
|
+
return result;
|
|
159
|
+
|
|
160
|
+
return nextafterf_custom(result, result + 1000000);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* Convert BOX3D to BOX2D
|
|
167
|
+
* returned box2d is allocated with 'lwalloc'
|
|
168
|
+
*/
|
|
169
|
+
BOX2DFLOAT4 *
|
|
170
|
+
box3d_to_box2df(BOX3D *box)
|
|
171
|
+
{
|
|
172
|
+
BOX2DFLOAT4 *result = (BOX2DFLOAT4*) lwalloc(sizeof(BOX2DFLOAT4));
|
|
173
|
+
|
|
174
|
+
#if PARANOIA_LEVEL > 0
|
|
175
|
+
if (box == NULL)
|
|
176
|
+
{
|
|
177
|
+
lwerror("box3d_to_box2df got NUL box");
|
|
178
|
+
return NULL;
|
|
179
|
+
}
|
|
180
|
+
#endif
|
|
181
|
+
|
|
182
|
+
result->xmin = nextDown_f(box->xmin);
|
|
183
|
+
result->ymin = nextDown_f(box->ymin);
|
|
184
|
+
|
|
185
|
+
result->xmax = nextUp_f(box->xmax);
|
|
186
|
+
result->ymax = nextUp_f(box->ymax);
|
|
187
|
+
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* Convert BOX3D to BOX2D using pre-allocated BOX2D
|
|
193
|
+
* returned box2d is allocated with 'lwalloc'
|
|
194
|
+
* return 0 on error (NULL input box)
|
|
195
|
+
*/
|
|
196
|
+
int
|
|
197
|
+
box3d_to_box2df_p(BOX3D *box, BOX2DFLOAT4 *result)
|
|
198
|
+
{
|
|
199
|
+
#if PARANOIA_LEVEL > 0
|
|
200
|
+
if (box == NULL)
|
|
201
|
+
{
|
|
202
|
+
lwerror("box3d_to_box2df got NUL box");
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
#endif
|
|
206
|
+
|
|
207
|
+
result->xmin = nextDown_f(box->xmin);
|
|
208
|
+
result->ymin = nextDown_f(box->ymin);
|
|
209
|
+
|
|
210
|
+
result->xmax = nextUp_f(box->xmax);
|
|
211
|
+
result->ymax = nextUp_f(box->ymax);
|
|
212
|
+
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
* Convert BOX2D to BOX3D
|
|
220
|
+
* zmin and zmax are set to NO_Z_VALUE
|
|
221
|
+
*/
|
|
222
|
+
BOX3D
|
|
223
|
+
box2df_to_box3d(BOX2DFLOAT4 *box)
|
|
224
|
+
{
|
|
225
|
+
BOX3D result;
|
|
226
|
+
|
|
227
|
+
#if PARANOIA_LEVEL > 0
|
|
228
|
+
if (box == NULL)
|
|
229
|
+
lwerror("box2df_to_box3d got NULL box");
|
|
230
|
+
#endif
|
|
231
|
+
|
|
232
|
+
result.xmin = box->xmin;
|
|
233
|
+
result.ymin = box->ymin;
|
|
234
|
+
|
|
235
|
+
result.xmax = box->xmax;
|
|
236
|
+
result.ymax = box->ymax;
|
|
237
|
+
|
|
238
|
+
result.zmin = result.zmax = NO_Z_VALUE;
|
|
239
|
+
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/*
|
|
244
|
+
* Convert BOX2D to BOX3D, using pre-allocated BOX3D as output
|
|
245
|
+
* Z values are set to NO_Z_VALUE.
|
|
246
|
+
*/
|
|
247
|
+
void
|
|
248
|
+
box2df_to_box3d_p(BOX2DFLOAT4 *box, BOX3D *out)
|
|
249
|
+
{
|
|
250
|
+
if (box == NULL) return;
|
|
251
|
+
|
|
252
|
+
out->xmin = box->xmin;
|
|
253
|
+
out->ymin = box->ymin;
|
|
254
|
+
|
|
255
|
+
out->xmax = box->xmax;
|
|
256
|
+
out->ymax = box->ymax;
|
|
257
|
+
|
|
258
|
+
out->zmin = out->zmax = NO_Z_VALUE;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* Returns a BOX3D that encloses b1 and b2
|
|
265
|
+
* box3d_union(NULL,A) --> A
|
|
266
|
+
* box3d_union(A,NULL) --> A
|
|
267
|
+
* box3d_union(A,B) --> A union B
|
|
268
|
+
*/
|
|
269
|
+
BOX3D *
|
|
270
|
+
box3d_union(BOX3D *b1, BOX3D *b2)
|
|
271
|
+
{
|
|
272
|
+
BOX3D *result;
|
|
273
|
+
|
|
274
|
+
result = lwalloc(sizeof(BOX3D));
|
|
275
|
+
|
|
276
|
+
if ( (b1 == NULL) && (b2 == NULL) )
|
|
277
|
+
{
|
|
278
|
+
return NULL;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (b1 == NULL)
|
|
282
|
+
{
|
|
283
|
+
/*return b2 */
|
|
284
|
+
memcpy(result, b2, sizeof(BOX3D));
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
if (b2 == NULL)
|
|
288
|
+
{
|
|
289
|
+
/*return b1 */
|
|
290
|
+
memcpy(result, b1, sizeof(BOX3D));
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (b1->xmin < b2->xmin)
|
|
295
|
+
result->xmin = b1->xmin;
|
|
296
|
+
else
|
|
297
|
+
result->xmin = b2->xmin;
|
|
298
|
+
|
|
299
|
+
if (b1->ymin < b2->ymin)
|
|
300
|
+
result->ymin = b1->ymin;
|
|
301
|
+
else
|
|
302
|
+
result->ymin = b2->ymin;
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
if (b1->xmax > b2->xmax)
|
|
306
|
+
result->xmax = b1->xmax;
|
|
307
|
+
else
|
|
308
|
+
result->xmax = b2->xmax;
|
|
309
|
+
|
|
310
|
+
if (b1->ymax > b2->ymax)
|
|
311
|
+
result->ymax = b1->ymax;
|
|
312
|
+
else
|
|
313
|
+
result->ymax = b2->ymax;
|
|
314
|
+
|
|
315
|
+
if (b1->zmax > b2->zmax)
|
|
316
|
+
result->zmax = b1->zmax;
|
|
317
|
+
else
|
|
318
|
+
result->zmax = b2->zmax;
|
|
319
|
+
|
|
320
|
+
if (b1->zmin > b2->zmin)
|
|
321
|
+
result->zmin = b1->zmin;
|
|
322
|
+
else
|
|
323
|
+
result->zmin = b2->zmin;
|
|
324
|
+
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* Make given ubox a union of b1 and b2 */
|
|
329
|
+
int
|
|
330
|
+
box3d_union_p(BOX3D *b1, BOX3D *b2, BOX3D *ubox)
|
|
331
|
+
{
|
|
332
|
+
|
|
333
|
+
LWDEBUG(2, "box3d_union_p called: (xmin, xmax), (ymin, ymax), (zmin, zmax)");
|
|
334
|
+
LWDEBUGF(4, "b1: (%.16f, %.16f),(%.16f, %.16f),(%.16f, %.16f)", b1->xmin, b1->xmax, b1->ymin, b1->ymax, b1->zmin, b1->zmax);
|
|
335
|
+
LWDEBUGF(4, "b2: (%.16f, %.16f),(%.16f, %.16f),(%.16f, %.16f)", b2->xmin, b2->xmax, b2->ymin, b2->ymax, b2->zmin, b2->zmax);
|
|
336
|
+
|
|
337
|
+
if ( (b1 == NULL) && (b2 == NULL) )
|
|
338
|
+
{
|
|
339
|
+
return 0;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (b1 == NULL)
|
|
343
|
+
{
|
|
344
|
+
memcpy(ubox, b2, sizeof(BOX3D));
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
if (b2 == NULL)
|
|
348
|
+
{
|
|
349
|
+
memcpy(ubox, b1, sizeof(BOX3D));
|
|
350
|
+
return 1;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (b1->xmin < b2->xmin)
|
|
354
|
+
ubox->xmin = b1->xmin;
|
|
355
|
+
else
|
|
356
|
+
ubox->xmin = b2->xmin;
|
|
357
|
+
|
|
358
|
+
if (b1->ymin < b2->ymin)
|
|
359
|
+
ubox->ymin = b1->ymin;
|
|
360
|
+
else
|
|
361
|
+
ubox->ymin = b2->ymin;
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
if (b1->xmax > b2->xmax)
|
|
365
|
+
ubox->xmax = b1->xmax;
|
|
366
|
+
else
|
|
367
|
+
ubox->xmax = b2->xmax;
|
|
368
|
+
|
|
369
|
+
if (b1->ymax > b2->ymax)
|
|
370
|
+
ubox->ymax = b1->ymax;
|
|
371
|
+
else
|
|
372
|
+
ubox->ymax = b2->ymax;
|
|
373
|
+
|
|
374
|
+
if (b1->zmax > b2->zmax)
|
|
375
|
+
ubox->zmax = b1->zmax;
|
|
376
|
+
else
|
|
377
|
+
ubox->zmax = b2->zmax;
|
|
378
|
+
|
|
379
|
+
if (b1->zmin < b2->zmin)
|
|
380
|
+
ubox->zmin = b1->zmin;
|
|
381
|
+
else
|
|
382
|
+
ubox->zmin = b2->zmin;
|
|
383
|
+
|
|
384
|
+
return 1;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
#if 0 /* UNUSED */
|
|
388
|
+
/*
|
|
389
|
+
* Returns a pointer to internal storage, or NULL
|
|
390
|
+
* if the serialized form does not have a BBOX.
|
|
391
|
+
*/
|
|
392
|
+
BOX2DFLOAT4 *
|
|
393
|
+
getbox2d_internal(uchar *srl)
|
|
394
|
+
{
|
|
395
|
+
if (TYPE_HASBBOX(srl[0])) return (BOX2DFLOAT4 *)(srl+1);
|
|
396
|
+
else return NULL;
|
|
397
|
+
}
|
|
398
|
+
#endif /* UNUSED */
|
|
399
|
+
|
|
400
|
+
/*
|
|
401
|
+
* Same as getbox2d, but modifies box instead of returning result on the stack
|
|
402
|
+
*/
|
|
403
|
+
int
|
|
404
|
+
getbox2d_p(uchar *srl, BOX2DFLOAT4 *box)
|
|
405
|
+
{
|
|
406
|
+
uchar type = srl[0];
|
|
407
|
+
uchar *loc;
|
|
408
|
+
BOX3D box3d;
|
|
409
|
+
|
|
410
|
+
LWDEBUG(2, "getbox2d_p call");
|
|
411
|
+
|
|
412
|
+
loc = srl+1;
|
|
413
|
+
|
|
414
|
+
if (lwgeom_hasBBOX(type))
|
|
415
|
+
{
|
|
416
|
+
/*woot - this is easy */
|
|
417
|
+
LWDEBUG(4, "getbox2d_p: has box");
|
|
418
|
+
memcpy(box, loc, sizeof(BOX2DFLOAT4));
|
|
419
|
+
return 1;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
LWDEBUG(4, "getbox2d_p: has no box - computing");
|
|
423
|
+
|
|
424
|
+
/* We have to actually compute it! */
|
|
425
|
+
if ( ! compute_serialized_box3d_p(srl, &box3d) ) return 0;
|
|
426
|
+
|
|
427
|
+
LWDEBUGF(4, "getbox2d_p: compute_serialized_box3d returned %p", box3d);
|
|
428
|
+
|
|
429
|
+
if ( ! box3d_to_box2df_p(&box3d, box) ) return 0;
|
|
430
|
+
|
|
431
|
+
LWDEBUG(4, "getbox2d_p: box3d converted to box2d");
|
|
432
|
+
|
|
433
|
+
return 1;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/************************************************************************
|
|
437
|
+
* POINTARRAY support functions
|
|
438
|
+
*
|
|
439
|
+
* TODO: should be moved to ptarray.c probably
|
|
440
|
+
*
|
|
441
|
+
************************************************************************/
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
* Copies a point from the point array into the parameter point
|
|
445
|
+
* will set point's z=NO_Z_VALUE if pa is 2d
|
|
446
|
+
* will set point's m=NO_M_VALUE if pa is 3d or 2d
|
|
447
|
+
*
|
|
448
|
+
* NOTE: point is a real POINT3D *not* a pointer
|
|
449
|
+
*/
|
|
450
|
+
POINT4D
|
|
451
|
+
getPoint4d(const POINTARRAY *pa, int n)
|
|
452
|
+
{
|
|
453
|
+
POINT4D result;
|
|
454
|
+
getPoint4d_p(pa, n, &result);
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/*
|
|
459
|
+
* Copies a point from the point array into the parameter point
|
|
460
|
+
* will set point's z=NO_Z_VALUE if pa is 2d
|
|
461
|
+
* will set point's m=NO_M_VALUE if pa is 3d or 2d
|
|
462
|
+
*
|
|
463
|
+
* NOTE: this will modify the point4d pointed to by 'point'.
|
|
464
|
+
*/
|
|
465
|
+
int
|
|
466
|
+
getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *op)
|
|
467
|
+
{
|
|
468
|
+
uchar *ptr;
|
|
469
|
+
int zmflag;
|
|
470
|
+
|
|
471
|
+
#if PARANOIA_LEVEL > 0
|
|
472
|
+
if ( ! pa ) lwerror("getPoint4d_p: NULL pointarray");
|
|
473
|
+
|
|
474
|
+
if ( (n<0) || (n>=pa->npoints))
|
|
475
|
+
{
|
|
476
|
+
lwerror("getPoint4d_p: point offset out of range");
|
|
477
|
+
}
|
|
478
|
+
#endif
|
|
479
|
+
|
|
480
|
+
LWDEBUG(4, "getPoint4d_p called.");
|
|
481
|
+
|
|
482
|
+
/* Get a pointer to nth point offset and zmflag */
|
|
483
|
+
ptr=getPoint_internal(pa, n);
|
|
484
|
+
zmflag=TYPE_GETZM(pa->dims);
|
|
485
|
+
|
|
486
|
+
LWDEBUGF(4, "ptr %p, zmflag %d", ptr, zmflag);
|
|
487
|
+
|
|
488
|
+
switch (zmflag)
|
|
489
|
+
{
|
|
490
|
+
case 0: /* 2d */
|
|
491
|
+
memcpy(op, ptr, sizeof(POINT2D));
|
|
492
|
+
op->m=NO_M_VALUE;
|
|
493
|
+
op->z=NO_Z_VALUE;
|
|
494
|
+
break;
|
|
495
|
+
|
|
496
|
+
case 3: /* ZM */
|
|
497
|
+
memcpy(op, ptr, sizeof(POINT4D));
|
|
498
|
+
break;
|
|
499
|
+
|
|
500
|
+
case 2: /* Z */
|
|
501
|
+
memcpy(op, ptr, sizeof(POINT3DZ));
|
|
502
|
+
op->m=NO_M_VALUE;
|
|
503
|
+
break;
|
|
504
|
+
|
|
505
|
+
case 1: /* M */
|
|
506
|
+
memcpy(op, ptr, sizeof(POINT3DM));
|
|
507
|
+
op->m=op->z; /* we use Z as temporary storage */
|
|
508
|
+
op->z=NO_Z_VALUE;
|
|
509
|
+
break;
|
|
510
|
+
|
|
511
|
+
default:
|
|
512
|
+
lwerror("Unknown ZM flag ??");
|
|
513
|
+
}
|
|
514
|
+
return 1;
|
|
515
|
+
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
/*
|
|
521
|
+
* Copy a point from the point array into the parameter point
|
|
522
|
+
* will set point's z=NO_Z_VALUE if pa is 2d
|
|
523
|
+
* NOTE: point is a real POINT3DZ *not* a pointer
|
|
524
|
+
*/
|
|
525
|
+
POINT3DZ
|
|
526
|
+
getPoint3dz(const POINTARRAY *pa, int n)
|
|
527
|
+
{
|
|
528
|
+
POINT3DZ result;
|
|
529
|
+
getPoint3dz_p(pa, n, &result);
|
|
530
|
+
return result;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/*
|
|
534
|
+
* Copy a point from the point array into the parameter point
|
|
535
|
+
* will set point's z=NO_Z_VALUE if pa is 2d
|
|
536
|
+
*
|
|
537
|
+
* NOTE: point is a real POINT3DZ *not* a pointer
|
|
538
|
+
*/
|
|
539
|
+
POINT3DM
|
|
540
|
+
getPoint3dm(const POINTARRAY *pa, int n)
|
|
541
|
+
{
|
|
542
|
+
POINT3DM result;
|
|
543
|
+
getPoint3dm_p(pa, n, &result);
|
|
544
|
+
return result;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/*
|
|
548
|
+
* Copy a point from the point array into the parameter point
|
|
549
|
+
* will set point's z=NO_Z_VALUE if pa is 2d
|
|
550
|
+
*
|
|
551
|
+
* NOTE: this will modify the point3dz pointed to by 'point'.
|
|
552
|
+
*/
|
|
553
|
+
int
|
|
554
|
+
getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *op)
|
|
555
|
+
{
|
|
556
|
+
uchar *ptr;
|
|
557
|
+
|
|
558
|
+
#if PARANOIA_LEVEL > 0
|
|
559
|
+
if ( ! pa ) return 0;
|
|
560
|
+
|
|
561
|
+
if ( (n<0) || (n>=pa->npoints))
|
|
562
|
+
{
|
|
563
|
+
LWDEBUGF(4, "%d out of numpoint range (%d)", n, pa->npoints);
|
|
564
|
+
return 0; /*error */
|
|
565
|
+
}
|
|
566
|
+
#endif
|
|
567
|
+
|
|
568
|
+
LWDEBUGF(2, "getPoint3dz_p called on array of %d-dimensions / %u pts",
|
|
569
|
+
TYPE_NDIMS(pa->dims), pa->npoints);
|
|
570
|
+
|
|
571
|
+
/* Get a pointer to nth point offset */
|
|
572
|
+
ptr=getPoint_internal(pa, n);
|
|
573
|
+
|
|
574
|
+
/*
|
|
575
|
+
* if input POINTARRAY has the Z, it is always
|
|
576
|
+
* at third position so make a single copy
|
|
577
|
+
*/
|
|
578
|
+
if ( TYPE_HASZ(pa->dims) )
|
|
579
|
+
{
|
|
580
|
+
memcpy(op, ptr, sizeof(POINT3DZ));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/*
|
|
584
|
+
* Otherwise copy the 2d part and initialize
|
|
585
|
+
* Z to NO_Z_VALUE
|
|
586
|
+
*/
|
|
587
|
+
else
|
|
588
|
+
{
|
|
589
|
+
memcpy(op, ptr, sizeof(POINT2D));
|
|
590
|
+
op->z=NO_Z_VALUE;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return 1;
|
|
594
|
+
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/*
|
|
598
|
+
* Copy a point from the point array into the parameter point
|
|
599
|
+
* will set point's m=NO_Z_VALUE if pa has no M
|
|
600
|
+
*
|
|
601
|
+
* NOTE: this will modify the point3dm pointed to by 'point'.
|
|
602
|
+
*/
|
|
603
|
+
int
|
|
604
|
+
getPoint3dm_p(const POINTARRAY *pa, int n, POINT3DM *op)
|
|
605
|
+
{
|
|
606
|
+
uchar *ptr;
|
|
607
|
+
int zmflag;
|
|
608
|
+
|
|
609
|
+
#if PARANOIA_LEVEL > 0
|
|
610
|
+
if ( ! pa ) return 0;
|
|
611
|
+
|
|
612
|
+
if ( (n<0) || (n>=pa->npoints))
|
|
613
|
+
{
|
|
614
|
+
lwerror("%d out of numpoint range (%d)", n, pa->npoints);
|
|
615
|
+
return 0; /*error */
|
|
616
|
+
}
|
|
617
|
+
#endif
|
|
618
|
+
|
|
619
|
+
LWDEBUGF(2, "getPoint3dm_p(%d) called on array of %d-dimensions / %u pts",
|
|
620
|
+
n, TYPE_NDIMS(pa->dims), pa->npoints);
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
/* Get a pointer to nth point offset and zmflag */
|
|
624
|
+
ptr=getPoint_internal(pa, n);
|
|
625
|
+
zmflag=TYPE_GETZM(pa->dims);
|
|
626
|
+
|
|
627
|
+
/*
|
|
628
|
+
* if input POINTARRAY has the M and NO Z,
|
|
629
|
+
* we can issue a single memcpy
|
|
630
|
+
*/
|
|
631
|
+
if ( zmflag == 1 )
|
|
632
|
+
{
|
|
633
|
+
memcpy(op, ptr, sizeof(POINT3DM));
|
|
634
|
+
return 1;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/*
|
|
638
|
+
* Otherwise copy the 2d part and
|
|
639
|
+
* initialize M to NO_M_VALUE
|
|
640
|
+
*/
|
|
641
|
+
memcpy(op, ptr, sizeof(POINT2D));
|
|
642
|
+
|
|
643
|
+
/*
|
|
644
|
+
* Then, if input has Z skip it and
|
|
645
|
+
* copy next double, otherwise initialize
|
|
646
|
+
* M to NO_M_VALUE
|
|
647
|
+
*/
|
|
648
|
+
if ( zmflag == 3 )
|
|
649
|
+
{
|
|
650
|
+
ptr+=sizeof(POINT3DZ);
|
|
651
|
+
memcpy(&(op->m), ptr, sizeof(double));
|
|
652
|
+
}
|
|
653
|
+
else
|
|
654
|
+
{
|
|
655
|
+
op->m=NO_M_VALUE;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return 1;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
/*
|
|
663
|
+
* Copy a point from the point array into the parameter point
|
|
664
|
+
* z value (if present) is not returned.
|
|
665
|
+
*
|
|
666
|
+
* NOTE: point is a real POINT2D *not* a pointer
|
|
667
|
+
*/
|
|
668
|
+
POINT2D
|
|
669
|
+
getPoint2d(const POINTARRAY *pa, int n)
|
|
670
|
+
{
|
|
671
|
+
POINT2D result;
|
|
672
|
+
getPoint2d_p(pa, n, &result);
|
|
673
|
+
return result;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/*
|
|
677
|
+
* Copy a point from the point array into the parameter point
|
|
678
|
+
* z value (if present) is not returned.
|
|
679
|
+
*
|
|
680
|
+
* NOTE: this will modify the point2d pointed to by 'point'.
|
|
681
|
+
*/
|
|
682
|
+
int
|
|
683
|
+
getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
|
|
684
|
+
{
|
|
685
|
+
#if PARANOIA_LEVEL > 0
|
|
686
|
+
if ( ! pa ) return 0;
|
|
687
|
+
|
|
688
|
+
if ( (n<0) || (n>=pa->npoints))
|
|
689
|
+
{
|
|
690
|
+
lwerror("getPoint2d_p: point offset out of range");
|
|
691
|
+
return 0; /*error */
|
|
692
|
+
}
|
|
693
|
+
#endif
|
|
694
|
+
|
|
695
|
+
/* this does x,y */
|
|
696
|
+
memcpy(point, getPoint_internal(pa, n), sizeof(POINT2D));
|
|
697
|
+
return 1;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/*
|
|
701
|
+
* set point N to the given value
|
|
702
|
+
* NOTE that the pointarray can be of any
|
|
703
|
+
* dimension, the appropriate ordinate values
|
|
704
|
+
* will be extracted from it
|
|
705
|
+
*
|
|
706
|
+
*/
|
|
707
|
+
void
|
|
708
|
+
setPoint4d(POINTARRAY *pa, int n, POINT4D *p4d)
|
|
709
|
+
{
|
|
710
|
+
uchar *ptr=getPoint_internal(pa, n);
|
|
711
|
+
switch ( TYPE_GETZM(pa->dims) )
|
|
712
|
+
{
|
|
713
|
+
case 3:
|
|
714
|
+
memcpy(ptr, p4d, sizeof(POINT4D));
|
|
715
|
+
break;
|
|
716
|
+
case 2:
|
|
717
|
+
memcpy(ptr, p4d, sizeof(POINT3DZ));
|
|
718
|
+
break;
|
|
719
|
+
case 1:
|
|
720
|
+
memcpy(ptr, p4d, sizeof(POINT2D));
|
|
721
|
+
ptr+=sizeof(POINT2D);
|
|
722
|
+
memcpy(ptr, &(p4d->m), sizeof(double));
|
|
723
|
+
break;
|
|
724
|
+
case 0:
|
|
725
|
+
memcpy(ptr, p4d, sizeof(POINT2D));
|
|
726
|
+
break;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
/*
|
|
732
|
+
* Get a pointer to nth point of a POINTARRAY.
|
|
733
|
+
* You cannot safely cast this to a real POINT, due to memory alignment
|
|
734
|
+
* constraints. Use getPoint*_p for that.
|
|
735
|
+
*/
|
|
736
|
+
uchar *
|
|
737
|
+
getPoint_internal(const POINTARRAY *pa, int n)
|
|
738
|
+
{
|
|
739
|
+
int size;
|
|
740
|
+
|
|
741
|
+
#if PARANOIA_LEVEL > 0
|
|
742
|
+
if ( pa == NULL ) {
|
|
743
|
+
lwerror("getPoint got NULL pointarray");
|
|
744
|
+
return NULL;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if ( (n<0) || (n>=pa->npoints))
|
|
748
|
+
{
|
|
749
|
+
return NULL; /*error */
|
|
750
|
+
}
|
|
751
|
+
#endif
|
|
752
|
+
|
|
753
|
+
size = pointArray_ptsize(pa);
|
|
754
|
+
|
|
755
|
+
return &(pa->serialized_pointlist[size*n]);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
/*
|
|
761
|
+
* Constructs a POINTARRAY.
|
|
762
|
+
*
|
|
763
|
+
* NOTE: points is *not* copied, so be careful about modification
|
|
764
|
+
* (can be aligned/missaligned).
|
|
765
|
+
*
|
|
766
|
+
* NOTE: ndims is descriptive - it describes what type of data 'points'
|
|
767
|
+
* points to. No data conversion is done.
|
|
768
|
+
*/
|
|
769
|
+
POINTARRAY *
|
|
770
|
+
pointArray_construct(uchar *points, char hasz, char hasm, uint32 npoints)
|
|
771
|
+
{
|
|
772
|
+
POINTARRAY *pa;
|
|
773
|
+
|
|
774
|
+
LWDEBUG(2, "pointArray_construct called.");
|
|
775
|
+
|
|
776
|
+
pa = (POINTARRAY*)lwalloc(sizeof(POINTARRAY));
|
|
777
|
+
|
|
778
|
+
pa->dims = 0;
|
|
779
|
+
TYPE_SETZM(pa->dims, hasz?1:0, hasm?1:0);
|
|
780
|
+
pa->npoints = npoints;
|
|
781
|
+
|
|
782
|
+
pa->serialized_pointlist = points;
|
|
783
|
+
|
|
784
|
+
LWDEBUGF(4, "pointArray_construct returning %p", pa);
|
|
785
|
+
|
|
786
|
+
return pa;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
/*
|
|
791
|
+
* Size of point represeneted in the POINTARRAY
|
|
792
|
+
* 16 for 2d, 24 for 3d, 32 for 4d
|
|
793
|
+
*/
|
|
794
|
+
int
|
|
795
|
+
pointArray_ptsize(const POINTARRAY *pa)
|
|
796
|
+
{
|
|
797
|
+
LWDEBUGF(2, "pointArray_ptsize: TYPE_NDIMS(pa->dims)=%x",TYPE_NDIMS(pa->dims));
|
|
798
|
+
|
|
799
|
+
return sizeof(double)*TYPE_NDIMS(pa->dims);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
/***************************************************************************
|
|
804
|
+
* Basic type handling
|
|
805
|
+
***************************************************************************/
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
/* Returns true if this type says it has an SRID (S bit set) */
|
|
809
|
+
char
|
|
810
|
+
lwgeom_hasSRID(uchar type)
|
|
811
|
+
{
|
|
812
|
+
return TYPE_HASSRID(type);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/* Returns either 2,3, or 4 -- 2=2D, 3=3D, 4=4D */
|
|
816
|
+
int
|
|
817
|
+
lwgeom_ndims(uchar type)
|
|
818
|
+
{
|
|
819
|
+
return TYPE_NDIMS(type);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/* has M ? */
|
|
823
|
+
int lwgeom_hasM(uchar type)
|
|
824
|
+
{
|
|
825
|
+
return ( (type & 0x10) >>4);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* has Z ? */
|
|
829
|
+
int lwgeom_hasZ(uchar type)
|
|
830
|
+
{
|
|
831
|
+
return ( (type & 0x20) >>5);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
/* get base type (ie. POLYGONTYPE) */
|
|
836
|
+
int
|
|
837
|
+
lwgeom_getType(uchar type)
|
|
838
|
+
{
|
|
839
|
+
LWDEBUGF(2, "lwgeom_getType %d", type);
|
|
840
|
+
|
|
841
|
+
return (type & 0x0F);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
/* Construct a type (hasBOX=false) */
|
|
846
|
+
uchar
|
|
847
|
+
lwgeom_makeType(char hasz, char hasm, char hasSRID, int type)
|
|
848
|
+
{
|
|
849
|
+
return lwgeom_makeType_full(hasz, hasm, hasSRID, type, 0);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/*
|
|
853
|
+
* Construct a type
|
|
854
|
+
* TODO: needs to be expanded to accept explicit MZ type
|
|
855
|
+
*/
|
|
856
|
+
uchar
|
|
857
|
+
lwgeom_makeType_full(char hasz, char hasm, char hasSRID, int type, char hasBBOX)
|
|
858
|
+
{
|
|
859
|
+
uchar result = (char)type;
|
|
860
|
+
|
|
861
|
+
TYPE_SETZM(result, hasz, hasm);
|
|
862
|
+
TYPE_SETHASSRID(result, hasSRID);
|
|
863
|
+
TYPE_SETHASBBOX(result, hasBBOX);
|
|
864
|
+
|
|
865
|
+
return result;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/* Returns true if there's a bbox in this LWGEOM (B bit set) */
|
|
869
|
+
char
|
|
870
|
+
lwgeom_hasBBOX(uchar type)
|
|
871
|
+
{
|
|
872
|
+
return TYPE_HASBBOX(type);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/*****************************************************************************
|
|
876
|
+
* Basic sub-geometry types
|
|
877
|
+
*****************************************************************************/
|
|
878
|
+
|
|
879
|
+
/* handle missaligned unsigned int32 data */
|
|
880
|
+
uint32
|
|
881
|
+
lw_get_uint32(const uchar *loc)
|
|
882
|
+
{
|
|
883
|
+
uint32 result;
|
|
884
|
+
|
|
885
|
+
memcpy(&result, loc, sizeof(uint32));
|
|
886
|
+
return result;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/* handle missaligned signed int32 data */
|
|
890
|
+
int32
|
|
891
|
+
lw_get_int32(const uchar *loc)
|
|
892
|
+
{
|
|
893
|
+
int32 result;
|
|
894
|
+
|
|
895
|
+
memcpy(&result,loc, sizeof(int32));
|
|
896
|
+
return result;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
/*************************************************************************
|
|
901
|
+
*
|
|
902
|
+
* Multi-geometry support
|
|
903
|
+
*
|
|
904
|
+
* Note - for a simple type (ie. point), this will have
|
|
905
|
+
* sub_geom[0] = serialized_form.
|
|
906
|
+
*
|
|
907
|
+
* For multi-geomtries sub_geom[0] will be a few bytes
|
|
908
|
+
* into the serialized form.
|
|
909
|
+
*
|
|
910
|
+
* This function just computes the length of each sub-object and
|
|
911
|
+
* pre-caches this info.
|
|
912
|
+
*
|
|
913
|
+
* For a geometry collection of multi* geometries, you can inspect
|
|
914
|
+
* the sub-components
|
|
915
|
+
* as well.
|
|
916
|
+
*/
|
|
917
|
+
LWGEOM_INSPECTED *
|
|
918
|
+
lwgeom_inspect(const uchar *serialized_form)
|
|
919
|
+
{
|
|
920
|
+
LWGEOM_INSPECTED *result = lwalloc(sizeof(LWGEOM_INSPECTED));
|
|
921
|
+
uchar typefl = (uchar)serialized_form[0];
|
|
922
|
+
uchar type;
|
|
923
|
+
uchar **sub_geoms;
|
|
924
|
+
const uchar *loc;
|
|
925
|
+
int t;
|
|
926
|
+
|
|
927
|
+
LWDEBUGF(2, "lwgeom_inspect: serialized@%p", serialized_form);
|
|
928
|
+
|
|
929
|
+
if (serialized_form == NULL)
|
|
930
|
+
return NULL;
|
|
931
|
+
|
|
932
|
+
result->serialized_form = serialized_form;
|
|
933
|
+
result->type = (uchar) serialized_form[0];
|
|
934
|
+
result->SRID = -1; /* assume */
|
|
935
|
+
|
|
936
|
+
type = lwgeom_getType(typefl);
|
|
937
|
+
|
|
938
|
+
loc = serialized_form+1;
|
|
939
|
+
|
|
940
|
+
if ( lwgeom_hasBBOX(typefl) )
|
|
941
|
+
{
|
|
942
|
+
loc += sizeof(BOX2DFLOAT4);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
if ( lwgeom_hasSRID(typefl) )
|
|
946
|
+
{
|
|
947
|
+
result->SRID = lw_get_int32(loc);
|
|
948
|
+
loc += 4;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
if ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) || (type == CIRCSTRINGTYPE))
|
|
952
|
+
{
|
|
953
|
+
/* simple geometry (point/line/polygon/circstring)-- not multi! */
|
|
954
|
+
result->ngeometries = 1;
|
|
955
|
+
sub_geoms = (uchar**) lwalloc(sizeof(char*));
|
|
956
|
+
sub_geoms[0] = (uchar *)serialized_form;
|
|
957
|
+
result->sub_geoms = (uchar **)sub_geoms;
|
|
958
|
+
return result;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/* its a GeometryCollection or multi* geometry */
|
|
962
|
+
|
|
963
|
+
result->ngeometries = lw_get_uint32(loc);
|
|
964
|
+
loc +=4;
|
|
965
|
+
|
|
966
|
+
LWDEBUGF(3, "lwgeom_inspect: geometry is a collection of %d elements",
|
|
967
|
+
result->ngeometries);
|
|
968
|
+
|
|
969
|
+
if ( ! result->ngeometries ) return result;
|
|
970
|
+
|
|
971
|
+
sub_geoms = lwalloc(sizeof(uchar*) * result->ngeometries );
|
|
972
|
+
result->sub_geoms = sub_geoms;
|
|
973
|
+
sub_geoms[0] = (uchar *)loc;
|
|
974
|
+
|
|
975
|
+
LWDEBUGF(3, "subgeom[0] @ %p (+%d)", sub_geoms[0], sub_geoms[0]-serialized_form);
|
|
976
|
+
|
|
977
|
+
for (t=1;t<result->ngeometries; t++)
|
|
978
|
+
{
|
|
979
|
+
/* -1 = entire object */
|
|
980
|
+
int sub_length = lwgeom_size_subgeom(sub_geoms[t-1], -1);
|
|
981
|
+
sub_geoms[t] = sub_geoms[t-1] + sub_length;
|
|
982
|
+
|
|
983
|
+
LWDEBUGF(3, "subgeom[%d] @ %p (+%d)",
|
|
984
|
+
t, sub_geoms[t], sub_geoms[0]-serialized_form);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
return result;
|
|
988
|
+
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
/*
|
|
993
|
+
* 1st geometry has geom_number = 0
|
|
994
|
+
* if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).
|
|
995
|
+
* if there arent enough geometries, return null.
|
|
996
|
+
* this is fine to call on a point (with geom_num=0),
|
|
997
|
+
* multipoint or geometrycollection
|
|
998
|
+
*/
|
|
999
|
+
LWPOINT *
|
|
1000
|
+
lwgeom_getpoint(uchar *serialized_form, int geom_number)
|
|
1001
|
+
{
|
|
1002
|
+
int type = lwgeom_getType((uchar)serialized_form[0]);
|
|
1003
|
+
uchar *sub_geom;
|
|
1004
|
+
|
|
1005
|
+
if ((type == POINTTYPE) && (geom_number == 0))
|
|
1006
|
+
{
|
|
1007
|
+
/* Be nice and do as they want instead of what they say */
|
|
1008
|
+
return lwpoint_deserialize(serialized_form);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
if ((type != MULTIPOINTTYPE) && (type != COLLECTIONTYPE) )
|
|
1012
|
+
return NULL;
|
|
1013
|
+
|
|
1014
|
+
sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
|
|
1015
|
+
if (sub_geom == NULL)
|
|
1016
|
+
return NULL;
|
|
1017
|
+
|
|
1018
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1019
|
+
if (type != POINTTYPE)
|
|
1020
|
+
return NULL;
|
|
1021
|
+
|
|
1022
|
+
return lwpoint_deserialize(sub_geom);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/*
|
|
1026
|
+
* 1st geometry has geom_number = 0
|
|
1027
|
+
* if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).
|
|
1028
|
+
* if there arent enough geometries, return null.
|
|
1029
|
+
* this is fine to call on a point (with geom_num=0), multipoint
|
|
1030
|
+
* or geometrycollection
|
|
1031
|
+
*/
|
|
1032
|
+
LWPOINT *lwgeom_getpoint_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1033
|
+
{
|
|
1034
|
+
uchar *sub_geom;
|
|
1035
|
+
uchar type;
|
|
1036
|
+
|
|
1037
|
+
sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1038
|
+
|
|
1039
|
+
if (sub_geom == NULL) return NULL;
|
|
1040
|
+
|
|
1041
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1042
|
+
if (type != POINTTYPE) return NULL;
|
|
1043
|
+
|
|
1044
|
+
return lwpoint_deserialize(sub_geom);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
/*
|
|
1049
|
+
* 1st geometry has geom_number = 0
|
|
1050
|
+
* if the actual geometry isnt a LINE, null is returned (see _gettype()).
|
|
1051
|
+
* if there arent enough geometries, return null.
|
|
1052
|
+
* this is fine to call on a line, multiline or geometrycollection
|
|
1053
|
+
*/
|
|
1054
|
+
LWLINE *
|
|
1055
|
+
lwgeom_getline(uchar *serialized_form, int geom_number)
|
|
1056
|
+
{
|
|
1057
|
+
uchar type = lwgeom_getType( (uchar) serialized_form[0]);
|
|
1058
|
+
uchar *sub_geom;
|
|
1059
|
+
|
|
1060
|
+
if ((type == LINETYPE) && (geom_number == 0))
|
|
1061
|
+
{
|
|
1062
|
+
/* be nice and do as they want instead of what they say */
|
|
1063
|
+
return lwline_deserialize(serialized_form);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
if ((type != MULTILINETYPE) && (type != COLLECTIONTYPE) )
|
|
1067
|
+
return NULL;
|
|
1068
|
+
|
|
1069
|
+
sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
|
|
1070
|
+
if (sub_geom == NULL) return NULL;
|
|
1071
|
+
|
|
1072
|
+
type = lwgeom_getType((uchar) sub_geom[0]);
|
|
1073
|
+
if (type != LINETYPE) return NULL;
|
|
1074
|
+
|
|
1075
|
+
return lwline_deserialize(sub_geom);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/*
|
|
1079
|
+
* 1st geometry has geom_number = 0
|
|
1080
|
+
* if the actual geometry isnt a LINE, null is returned (see _gettype()).
|
|
1081
|
+
* if there arent enough geometries, return null.
|
|
1082
|
+
* this is fine to call on a line, multiline or geometrycollection
|
|
1083
|
+
*/
|
|
1084
|
+
LWLINE *
|
|
1085
|
+
lwgeom_getline_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1086
|
+
{
|
|
1087
|
+
uchar *sub_geom;
|
|
1088
|
+
uchar type;
|
|
1089
|
+
|
|
1090
|
+
sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1091
|
+
|
|
1092
|
+
if (sub_geom == NULL) return NULL;
|
|
1093
|
+
|
|
1094
|
+
type = lwgeom_getType((uchar) sub_geom[0]);
|
|
1095
|
+
if (type != LINETYPE) return NULL;
|
|
1096
|
+
|
|
1097
|
+
return lwline_deserialize(sub_geom);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/*
|
|
1101
|
+
* 1st geometry has geom_number = 0
|
|
1102
|
+
* if the actual geometry isnt a POLYGON, null is returned (see _gettype()).
|
|
1103
|
+
* if there arent enough geometries, return null.
|
|
1104
|
+
* this is fine to call on a polygon, multipolygon or geometrycollection
|
|
1105
|
+
*/
|
|
1106
|
+
LWPOLY *
|
|
1107
|
+
lwgeom_getpoly(uchar *serialized_form, int geom_number)
|
|
1108
|
+
{
|
|
1109
|
+
uchar type = lwgeom_getType((uchar)serialized_form[0]);
|
|
1110
|
+
uchar *sub_geom;
|
|
1111
|
+
|
|
1112
|
+
if ((type == POLYGONTYPE) && (geom_number == 0))
|
|
1113
|
+
{
|
|
1114
|
+
/* Be nice and do as they want instead of what they say */
|
|
1115
|
+
return lwpoly_deserialize(serialized_form);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if ((type != MULTIPOLYGONTYPE) && (type != COLLECTIONTYPE) )
|
|
1119
|
+
return NULL;
|
|
1120
|
+
|
|
1121
|
+
sub_geom = lwgeom_getsubgeometry(serialized_form, geom_number);
|
|
1122
|
+
if (sub_geom == NULL) return NULL;
|
|
1123
|
+
|
|
1124
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1125
|
+
if (type != POLYGONTYPE) return NULL;
|
|
1126
|
+
|
|
1127
|
+
return lwpoly_deserialize(sub_geom);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
/*
|
|
1131
|
+
* 1st geometry has geom_number = 0
|
|
1132
|
+
* if the actual geometry isnt a POLYGON, null is returned (see _gettype()).
|
|
1133
|
+
* if there arent enough geometries, return null.
|
|
1134
|
+
* this is fine to call on a polygon, multipolygon or geometrycollection
|
|
1135
|
+
*/
|
|
1136
|
+
LWPOLY *
|
|
1137
|
+
lwgeom_getpoly_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1138
|
+
{
|
|
1139
|
+
uchar *sub_geom;
|
|
1140
|
+
uchar type;
|
|
1141
|
+
|
|
1142
|
+
sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1143
|
+
|
|
1144
|
+
if (sub_geom == NULL) return NULL;
|
|
1145
|
+
|
|
1146
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1147
|
+
if (type != POLYGONTYPE) return NULL;
|
|
1148
|
+
|
|
1149
|
+
return lwpoly_deserialize(sub_geom);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/*
|
|
1153
|
+
* 1st geometry has geom_number = 0
|
|
1154
|
+
* if the actual geometry isnt a CIRCULARSTRING, null is returned (see _gettype()).
|
|
1155
|
+
* if there arent enough geometries, return null.
|
|
1156
|
+
* this is fine to call on a circularstring
|
|
1157
|
+
*/
|
|
1158
|
+
LWCIRCSTRING *
|
|
1159
|
+
lwgeom_getcircstring_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1160
|
+
{
|
|
1161
|
+
uchar *sub_geom;
|
|
1162
|
+
uchar type;
|
|
1163
|
+
|
|
1164
|
+
sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1165
|
+
|
|
1166
|
+
if (sub_geom == NULL) return NULL;
|
|
1167
|
+
|
|
1168
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1169
|
+
if (type != CIRCSTRINGTYPE) return NULL;
|
|
1170
|
+
|
|
1171
|
+
return lwcircstring_deserialize(sub_geom);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/*
|
|
1175
|
+
* 1st geometry has geom_number = 0
|
|
1176
|
+
* if there arent enough geometries, return null.
|
|
1177
|
+
*/
|
|
1178
|
+
LWGEOM *lwgeom_getgeom_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1179
|
+
{
|
|
1180
|
+
uchar *sub_geom;
|
|
1181
|
+
uchar type;
|
|
1182
|
+
|
|
1183
|
+
sub_geom = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1184
|
+
|
|
1185
|
+
if (sub_geom == NULL) return NULL;
|
|
1186
|
+
|
|
1187
|
+
type = lwgeom_getType(sub_geom[0]);
|
|
1188
|
+
|
|
1189
|
+
return lwgeom_deserialize(sub_geom);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
/*
|
|
1194
|
+
* This gets the serialized form of a sub-geometry
|
|
1195
|
+
*
|
|
1196
|
+
* 1st geometry has geom_number = 0
|
|
1197
|
+
* if this isnt a multi* geometry, and geom_number ==0 then it returns
|
|
1198
|
+
* itself.
|
|
1199
|
+
*
|
|
1200
|
+
* Returns null on problems.
|
|
1201
|
+
*
|
|
1202
|
+
* In the future this is how you would access a muli* portion of a
|
|
1203
|
+
* geometry collection.
|
|
1204
|
+
* GEOMETRYCOLLECTION(MULTIPOINT(0 0, 1 1), LINESTRING(0 0, 1 1))
|
|
1205
|
+
* ie. lwgeom_getpoint( lwgeom_getsubgeometry( serialized, 0), 1)
|
|
1206
|
+
* --> POINT(1 1)
|
|
1207
|
+
*
|
|
1208
|
+
* You can inspect the sub-geometry as well if you wish.
|
|
1209
|
+
*
|
|
1210
|
+
*/
|
|
1211
|
+
uchar *
|
|
1212
|
+
lwgeom_getsubgeometry(const uchar *serialized_form, int geom_number)
|
|
1213
|
+
{
|
|
1214
|
+
uchar *result;
|
|
1215
|
+
/*major cheat!! */
|
|
1216
|
+
LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);
|
|
1217
|
+
|
|
1218
|
+
result = lwgeom_getsubgeometry_inspected(inspected, geom_number);
|
|
1219
|
+
lwinspected_release(inspected);
|
|
1220
|
+
return result;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
uchar *
|
|
1224
|
+
lwgeom_getsubgeometry_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1225
|
+
{
|
|
1226
|
+
if ((geom_number <0) || (geom_number >= inspected->ngeometries) )
|
|
1227
|
+
{
|
|
1228
|
+
lwerror("lwgeom_getsubgeometry_inspected: geom_number out of range");
|
|
1229
|
+
return NULL;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
return inspected->sub_geoms[geom_number];
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
/*
|
|
1237
|
+
* 1st geometry has geom_number = 0
|
|
1238
|
+
* use geom_number = -1 to find the actual type of the serialized form.
|
|
1239
|
+
* ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
|
|
1240
|
+
* --> multipoint
|
|
1241
|
+
* ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
|
|
1242
|
+
* --> point
|
|
1243
|
+
* gets the 8bit type of the geometry at location geom_number
|
|
1244
|
+
*/
|
|
1245
|
+
uchar
|
|
1246
|
+
lwgeom_getsubtype(uchar *serialized_form, int geom_number)
|
|
1247
|
+
{
|
|
1248
|
+
char result;
|
|
1249
|
+
/*major cheat!! */
|
|
1250
|
+
LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized_form);
|
|
1251
|
+
|
|
1252
|
+
result = lwgeom_getsubtype_inspected(inspected, geom_number);
|
|
1253
|
+
lwinspected_release(inspected);
|
|
1254
|
+
return result;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
uchar
|
|
1258
|
+
lwgeom_getsubtype_inspected(LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1259
|
+
{
|
|
1260
|
+
if ((geom_number <0) || (geom_number >= inspected->ngeometries) )
|
|
1261
|
+
return 99;
|
|
1262
|
+
|
|
1263
|
+
return inspected->sub_geoms[geom_number][0]; /* 1st byte is type */
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
/*
|
|
1268
|
+
* How many sub-geometries are there?
|
|
1269
|
+
* for point,line,polygon will return 1.
|
|
1270
|
+
*/
|
|
1271
|
+
int
|
|
1272
|
+
lwgeom_getnumgeometries(uchar *serialized_form)
|
|
1273
|
+
{
|
|
1274
|
+
uchar type = lwgeom_getType((uchar)serialized_form[0]);
|
|
1275
|
+
uchar *loc;
|
|
1276
|
+
|
|
1277
|
+
if ( (type==POINTTYPE) || (type==LINETYPE) || (type==POLYGONTYPE) ||
|
|
1278
|
+
(type==CIRCSTRINGTYPE) || (type==COMPOUNDTYPE) || (type==CURVEPOLYTYPE) )
|
|
1279
|
+
{
|
|
1280
|
+
return 1;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
loc = serialized_form+1;
|
|
1284
|
+
|
|
1285
|
+
if (lwgeom_hasBBOX((uchar) serialized_form[0]))
|
|
1286
|
+
{
|
|
1287
|
+
loc += sizeof(BOX2DFLOAT4);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (lwgeom_hasSRID((uchar) serialized_form[0]) )
|
|
1291
|
+
{
|
|
1292
|
+
loc += 4;
|
|
1293
|
+
}
|
|
1294
|
+
/* its a GeometryCollection or multi* geometry */
|
|
1295
|
+
return lw_get_uint32(loc);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/*
|
|
1299
|
+
* How many sub-geometries are there?
|
|
1300
|
+
* for point,line,polygon will return 1.
|
|
1301
|
+
*/
|
|
1302
|
+
int
|
|
1303
|
+
lwgeom_getnumgeometries_inspected(LWGEOM_INSPECTED *inspected)
|
|
1304
|
+
{
|
|
1305
|
+
return inspected->ngeometries;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
/*
|
|
1310
|
+
* Set finalType to COLLECTIONTYPE or 0 (0 means choose a best type)
|
|
1311
|
+
* (ie. give it 2 points and ask it to be a multipoint)
|
|
1312
|
+
* use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
|
|
1313
|
+
* all subgeometries must have the same SRID
|
|
1314
|
+
* if you want to construct an inspected, call this then inspect the result...
|
|
1315
|
+
*/
|
|
1316
|
+
uchar *
|
|
1317
|
+
lwgeom_serialized_construct(int SRID, int finalType, char hasz, char hasm,
|
|
1318
|
+
int nsubgeometries, uchar **serialized_subs)
|
|
1319
|
+
{
|
|
1320
|
+
uint32 *lengths;
|
|
1321
|
+
int t;
|
|
1322
|
+
int total_length = 0;
|
|
1323
|
+
char type = (char)-1;
|
|
1324
|
+
char this_type = -1;
|
|
1325
|
+
uchar *result;
|
|
1326
|
+
uchar *loc;
|
|
1327
|
+
|
|
1328
|
+
if (nsubgeometries == 0)
|
|
1329
|
+
return lwgeom_constructempty(SRID, hasz, hasm);
|
|
1330
|
+
|
|
1331
|
+
lengths = lwalloc(sizeof(int32) * nsubgeometries);
|
|
1332
|
+
|
|
1333
|
+
for (t=0;t<nsubgeometries;t++)
|
|
1334
|
+
{
|
|
1335
|
+
lengths[t] = lwgeom_size_subgeom(serialized_subs[t],-1);
|
|
1336
|
+
total_length += lengths[t];
|
|
1337
|
+
this_type = lwgeom_getType((uchar) (serialized_subs[t][0]));
|
|
1338
|
+
if (type == (char)-1)
|
|
1339
|
+
{
|
|
1340
|
+
type = this_type;
|
|
1341
|
+
}
|
|
1342
|
+
else if (type == COLLECTIONTYPE)
|
|
1343
|
+
{
|
|
1344
|
+
/* still a collection type... */
|
|
1345
|
+
}
|
|
1346
|
+
else
|
|
1347
|
+
{
|
|
1348
|
+
if ( (this_type == MULTIPOINTTYPE) || (this_type == MULTILINETYPE) || (this_type == MULTIPOLYGONTYPE) || (this_type == COLLECTIONTYPE) )
|
|
1349
|
+
{
|
|
1350
|
+
type = COLLECTIONTYPE;
|
|
1351
|
+
}
|
|
1352
|
+
else
|
|
1353
|
+
{
|
|
1354
|
+
if ( (this_type == POINTTYPE) && (type==POINTTYPE) )
|
|
1355
|
+
type=MULTIPOINTTYPE;
|
|
1356
|
+
else if ( (this_type == LINETYPE) && (type==LINETYPE) )
|
|
1357
|
+
type=MULTILINETYPE;
|
|
1358
|
+
else if ( (this_type == POLYGONTYPE) && (type==POLYGONTYPE) )
|
|
1359
|
+
type=MULTIPOLYGONTYPE;
|
|
1360
|
+
else if ( (this_type == POLYGONTYPE) && (type==MULTIPOLYGONTYPE) )
|
|
1361
|
+
; /* nop */
|
|
1362
|
+
else if ( (this_type == LINETYPE) && (type==MULTILINETYPE) )
|
|
1363
|
+
; /* nop */
|
|
1364
|
+
else if ( (this_type == POINTTYPE) && (type==MULTIPOINTTYPE) )
|
|
1365
|
+
; /* nop */
|
|
1366
|
+
else
|
|
1367
|
+
type = COLLECTIONTYPE;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
if (type == POINTTYPE)
|
|
1373
|
+
type = MULTIPOINTTYPE;
|
|
1374
|
+
if (type == LINETYPE)
|
|
1375
|
+
type = MULTILINETYPE;
|
|
1376
|
+
if (type == POINTTYPE)
|
|
1377
|
+
type = MULTIPOINTTYPE;
|
|
1378
|
+
|
|
1379
|
+
if (finalType == COLLECTIONTYPE)
|
|
1380
|
+
type = COLLECTIONTYPE;
|
|
1381
|
+
|
|
1382
|
+
/* now we have a multi* or GEOMETRYCOLLECTION, let's serialize it */
|
|
1383
|
+
|
|
1384
|
+
if (SRID != -1)
|
|
1385
|
+
total_length +=4; /* space for SRID */
|
|
1386
|
+
|
|
1387
|
+
total_length +=1 ; /* main type; */
|
|
1388
|
+
total_length +=4 ; /* nsubgeometries */
|
|
1389
|
+
|
|
1390
|
+
result = lwalloc(total_length);
|
|
1391
|
+
result[0] = (uchar) lwgeom_makeType(hasz, hasm, SRID != -1, type);
|
|
1392
|
+
if (SRID != -1)
|
|
1393
|
+
{
|
|
1394
|
+
memcpy(&result[1],&SRID,4);
|
|
1395
|
+
loc = result+5;
|
|
1396
|
+
}
|
|
1397
|
+
else
|
|
1398
|
+
loc = result+1;
|
|
1399
|
+
|
|
1400
|
+
memcpy(loc,&nsubgeometries,4);
|
|
1401
|
+
loc +=4;
|
|
1402
|
+
|
|
1403
|
+
for (t=0;t<nsubgeometries;t++)
|
|
1404
|
+
{
|
|
1405
|
+
memcpy(loc, serialized_subs[t], lengths[t] );
|
|
1406
|
+
loc += lengths[t] ;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
lwfree(lengths);
|
|
1410
|
+
return result;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
/*
|
|
1415
|
+
* Construct the empty geometry (GEOMETRYCOLLECTION(EMPTY)).
|
|
1416
|
+
*
|
|
1417
|
+
* Returns serialized form
|
|
1418
|
+
*/
|
|
1419
|
+
uchar *
|
|
1420
|
+
lwgeom_constructempty(int SRID, char hasz, char hasm)
|
|
1421
|
+
{
|
|
1422
|
+
int size = 0;
|
|
1423
|
+
uchar *result;
|
|
1424
|
+
int ngeoms = 0;
|
|
1425
|
+
uchar *loc;
|
|
1426
|
+
|
|
1427
|
+
if (SRID != -1)
|
|
1428
|
+
size +=4;
|
|
1429
|
+
|
|
1430
|
+
size += 5;
|
|
1431
|
+
|
|
1432
|
+
result = lwalloc(size);
|
|
1433
|
+
|
|
1434
|
+
result[0] = lwgeom_makeType(hasz, hasm, SRID != -1, COLLECTIONTYPE);
|
|
1435
|
+
if (SRID != -1)
|
|
1436
|
+
{
|
|
1437
|
+
memcpy(&result[1],&SRID,4);
|
|
1438
|
+
loc = result+5;
|
|
1439
|
+
}
|
|
1440
|
+
else
|
|
1441
|
+
loc = result+1;
|
|
1442
|
+
|
|
1443
|
+
memcpy(loc,&ngeoms,4);
|
|
1444
|
+
return result;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
size_t
|
|
1448
|
+
lwgeom_empty_length(int SRID)
|
|
1449
|
+
{
|
|
1450
|
+
int size = 5;
|
|
1451
|
+
if ( SRID != 1 ) size += 4;
|
|
1452
|
+
return size;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/*
|
|
1456
|
+
* Construct the empty geometry (GEOMETRYCOLLECTION(EMPTY))
|
|
1457
|
+
* writing it into the provided buffer.
|
|
1458
|
+
*/
|
|
1459
|
+
void
|
|
1460
|
+
lwgeom_constructempty_buf(int SRID, char hasz, char hasm,
|
|
1461
|
+
uchar *buf, size_t *retsize)
|
|
1462
|
+
{
|
|
1463
|
+
int ngeoms = 0;
|
|
1464
|
+
|
|
1465
|
+
buf[0] =(uchar) lwgeom_makeType( hasz, hasm, SRID != -1, COLLECTIONTYPE);
|
|
1466
|
+
if (SRID != -1)
|
|
1467
|
+
{
|
|
1468
|
+
memcpy(&buf[1],&SRID,4);
|
|
1469
|
+
buf += 5;
|
|
1470
|
+
}
|
|
1471
|
+
else
|
|
1472
|
+
buf += 1;
|
|
1473
|
+
|
|
1474
|
+
memcpy(buf, &ngeoms, 4);
|
|
1475
|
+
|
|
1476
|
+
if (retsize) *retsize = lwgeom_empty_length(SRID);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/*
|
|
1480
|
+
* helper function (not for general use)
|
|
1481
|
+
* find the size a geometry (or a sub-geometry)
|
|
1482
|
+
* 1st geometry has geom_number = 0
|
|
1483
|
+
* use geom_number = -1 to find the actual type of the serialized form.
|
|
1484
|
+
* ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
|
|
1485
|
+
* --> size of the multipoint
|
|
1486
|
+
* ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
|
|
1487
|
+
* --> size of the point
|
|
1488
|
+
* take a geometry, and find its length
|
|
1489
|
+
*/
|
|
1490
|
+
size_t
|
|
1491
|
+
lwgeom_size(const uchar *serialized_form)
|
|
1492
|
+
{
|
|
1493
|
+
uchar type = lwgeom_getType((uchar) serialized_form[0]);
|
|
1494
|
+
int t;
|
|
1495
|
+
const uchar *loc;
|
|
1496
|
+
uint32 ngeoms;
|
|
1497
|
+
int sub_size;
|
|
1498
|
+
int result = 1; /* type */
|
|
1499
|
+
|
|
1500
|
+
LWDEBUG(2, "lwgeom_size called");
|
|
1501
|
+
|
|
1502
|
+
if (type == POINTTYPE)
|
|
1503
|
+
{
|
|
1504
|
+
LWDEBUG(3, "lwgeom_size: is a point");
|
|
1505
|
+
|
|
1506
|
+
return lwgeom_size_point(serialized_form);
|
|
1507
|
+
}
|
|
1508
|
+
else if (type == LINETYPE)
|
|
1509
|
+
{
|
|
1510
|
+
LWDEBUG(3, "lwgeom_size: is a line");
|
|
1511
|
+
|
|
1512
|
+
return lwgeom_size_line(serialized_form);
|
|
1513
|
+
}
|
|
1514
|
+
else if(type == CIRCSTRINGTYPE)
|
|
1515
|
+
{
|
|
1516
|
+
LWDEBUG(3, "lwgeom_size: is a circularstring");
|
|
1517
|
+
|
|
1518
|
+
return lwgeom_size_circstring(serialized_form);
|
|
1519
|
+
}
|
|
1520
|
+
else if (type == POLYGONTYPE)
|
|
1521
|
+
{
|
|
1522
|
+
LWDEBUG(3, "lwgeom_size: is a polygon");
|
|
1523
|
+
|
|
1524
|
+
return lwgeom_size_poly(serialized_form);
|
|
1525
|
+
}
|
|
1526
|
+
else if (type == COMPOUNDTYPE)
|
|
1527
|
+
{
|
|
1528
|
+
LWDEBUG(3, "lwgeom_size: is a compound curve");
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
if ( type == 0 )
|
|
1532
|
+
{
|
|
1533
|
+
lwerror("lwgeom_size called with unknown-typed serialized geometry");
|
|
1534
|
+
return 0;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
/*
|
|
1538
|
+
* Handle all the multi* and geometrycollections the same
|
|
1539
|
+
*
|
|
1540
|
+
* NOTE: for a geometry collection of GC of GC of GC we will
|
|
1541
|
+
* be recursing...
|
|
1542
|
+
*/
|
|
1543
|
+
|
|
1544
|
+
LWDEBUGF(3, "lwgeom_size called on a geoemtry with type %d", type);
|
|
1545
|
+
|
|
1546
|
+
loc = serialized_form+1;
|
|
1547
|
+
|
|
1548
|
+
if (lwgeom_hasBBOX((uchar) serialized_form[0]))
|
|
1549
|
+
{
|
|
1550
|
+
LWDEBUG(3, "lwgeom_size: has bbox");
|
|
1551
|
+
|
|
1552
|
+
loc += sizeof(BOX2DFLOAT4);
|
|
1553
|
+
result +=sizeof(BOX2DFLOAT4);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
if (lwgeom_hasSRID( (uchar) serialized_form[0]) )
|
|
1557
|
+
{
|
|
1558
|
+
LWDEBUG(3, "lwgeom_size: has srid");
|
|
1559
|
+
|
|
1560
|
+
result +=4;
|
|
1561
|
+
loc +=4;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
ngeoms = lw_get_uint32(loc);
|
|
1566
|
+
loc +=4;
|
|
1567
|
+
result += 4; /* numgeoms */
|
|
1568
|
+
|
|
1569
|
+
LWDEBUGF(3, "lwgeom_size called on a geoemtry with %d elems (result so far: %d)", ngeoms, result);
|
|
1570
|
+
|
|
1571
|
+
for (t=0;t<ngeoms;t++)
|
|
1572
|
+
{
|
|
1573
|
+
sub_size = lwgeom_size(loc);
|
|
1574
|
+
|
|
1575
|
+
LWDEBUGF(3, " subsize %d", sub_size);
|
|
1576
|
+
|
|
1577
|
+
loc += sub_size;
|
|
1578
|
+
result += sub_size;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
LWDEBUGF(3, "lwgeom_size returning %d", result);
|
|
1582
|
+
|
|
1583
|
+
return result;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
size_t
|
|
1587
|
+
lwgeom_size_subgeom(const uchar *serialized_form, int geom_number)
|
|
1588
|
+
{
|
|
1589
|
+
if (geom_number == -1)
|
|
1590
|
+
{
|
|
1591
|
+
return lwgeom_size(serialized_form);
|
|
1592
|
+
}
|
|
1593
|
+
return lwgeom_size( lwgeom_getsubgeometry(serialized_form,geom_number));
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
|
|
1597
|
+
|
|
1598
|
+
int
|
|
1599
|
+
lwgeom_size_inspected(const LWGEOM_INSPECTED *inspected, int geom_number)
|
|
1600
|
+
{
|
|
1601
|
+
return lwgeom_size(inspected->sub_geoms[geom_number]);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
int
|
|
1605
|
+
compute_serialized_box3d_p(uchar *srl, BOX3D *out)
|
|
1606
|
+
{
|
|
1607
|
+
BOX3D *box = compute_serialized_box3d(srl);
|
|
1608
|
+
if ( ! box ) return 0;
|
|
1609
|
+
out->xmin = box->xmin;
|
|
1610
|
+
out->ymin = box->ymin;
|
|
1611
|
+
out->zmin = box->zmin;
|
|
1612
|
+
out->xmax = box->xmax;
|
|
1613
|
+
out->ymax = box->ymax;
|
|
1614
|
+
out->zmax = box->zmax;
|
|
1615
|
+
lwfree(box);
|
|
1616
|
+
|
|
1617
|
+
return 1;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
/*
|
|
1621
|
+
* Compute bounding box of a serialized LWGEOM, even if it is
|
|
1622
|
+
* already cached. The computed BOX2DFLOAT4 is stored at
|
|
1623
|
+
* the given location, the function returns 0 is the geometry
|
|
1624
|
+
* does not have a bounding box (EMPTY GEOM)
|
|
1625
|
+
*/
|
|
1626
|
+
int
|
|
1627
|
+
compute_serialized_box2d_p(uchar *srl, BOX2DFLOAT4 *out)
|
|
1628
|
+
{
|
|
1629
|
+
BOX3D *result = compute_serialized_box3d(srl);
|
|
1630
|
+
if ( ! result ) return 0;
|
|
1631
|
+
out->xmin = result->xmin;
|
|
1632
|
+
out->xmax = result->xmax;
|
|
1633
|
+
out->ymin = result->ymin;
|
|
1634
|
+
out->ymax = result->ymax;
|
|
1635
|
+
lwfree(result);
|
|
1636
|
+
|
|
1637
|
+
return 1;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
/*
|
|
1641
|
+
* Don't forget to lwfree() result !
|
|
1642
|
+
*/
|
|
1643
|
+
BOX3D *
|
|
1644
|
+
compute_serialized_box3d(uchar *srl)
|
|
1645
|
+
{
|
|
1646
|
+
int type = lwgeom_getType(srl[0]);
|
|
1647
|
+
int t;
|
|
1648
|
+
uchar *loc = srl;
|
|
1649
|
+
uint32 nelems;
|
|
1650
|
+
BOX3D *result;
|
|
1651
|
+
BOX3D b1;
|
|
1652
|
+
int sub_size;
|
|
1653
|
+
char nboxes=0;
|
|
1654
|
+
|
|
1655
|
+
LWDEBUGF(2, "compute_serialized_box3d called on type %d", type);
|
|
1656
|
+
|
|
1657
|
+
loc += 1; /* Move past the 'type' byte. */
|
|
1658
|
+
|
|
1659
|
+
if (lwgeom_hasBBOX(srl[0]))
|
|
1660
|
+
{
|
|
1661
|
+
loc += sizeof(BOX2DFLOAT4); /* Move past the bbox */
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
if (lwgeom_hasSRID(srl[0]) )
|
|
1665
|
+
{
|
|
1666
|
+
loc +=4; /* Move past the SRID */
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
if (type == POINTTYPE)
|
|
1670
|
+
{
|
|
1671
|
+
LWPOINT *pt = lwpoint_deserialize(srl);
|
|
1672
|
+
|
|
1673
|
+
LWDEBUG(3, "compute_serialized_box3d: lwpoint deserialized");
|
|
1674
|
+
|
|
1675
|
+
result = lwpoint_compute_box3d(pt);
|
|
1676
|
+
|
|
1677
|
+
LWDEBUG(3, "compute_serialized_box3d: bbox found");
|
|
1678
|
+
|
|
1679
|
+
lwpoint_free(pt);
|
|
1680
|
+
return result;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/*
|
|
1684
|
+
** For items that have elements (everything except points),
|
|
1685
|
+
** nelems == 0 => EMPTY geometry
|
|
1686
|
+
*/
|
|
1687
|
+
nelems = lw_get_uint32(loc);
|
|
1688
|
+
if ( nelems == 0 ) return NULL;
|
|
1689
|
+
|
|
1690
|
+
if (type == LINETYPE)
|
|
1691
|
+
{
|
|
1692
|
+
LWLINE *line = lwline_deserialize(srl);
|
|
1693
|
+
result = lwline_compute_box3d(line);
|
|
1694
|
+
lwline_free(line);
|
|
1695
|
+
return result;
|
|
1696
|
+
|
|
1697
|
+
}
|
|
1698
|
+
else if (type == CIRCSTRINGTYPE)
|
|
1699
|
+
{
|
|
1700
|
+
LWCIRCSTRING *curve = lwcircstring_deserialize(srl);
|
|
1701
|
+
result = lwcircstring_compute_box3d(curve);
|
|
1702
|
+
lwcircstring_free(curve);
|
|
1703
|
+
return result;
|
|
1704
|
+
}
|
|
1705
|
+
else if (type == POLYGONTYPE)
|
|
1706
|
+
{
|
|
1707
|
+
LWPOLY *poly = lwpoly_deserialize(srl);
|
|
1708
|
+
result = lwpoly_compute_box3d(poly);
|
|
1709
|
+
lwpoly_free(poly);
|
|
1710
|
+
return result;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
if ( ! ( type == MULTIPOINTTYPE || type == MULTILINETYPE ||
|
|
1714
|
+
type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ||
|
|
1715
|
+
type == COMPOUNDTYPE || type == CURVEPOLYTYPE ||
|
|
1716
|
+
type == MULTICURVETYPE || type == MULTISURFACETYPE) )
|
|
1717
|
+
{
|
|
1718
|
+
lwnotice("compute_serialized_box3d called on unknown type %d", type);
|
|
1719
|
+
return NULL;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
loc += 4;
|
|
1723
|
+
|
|
1724
|
+
/* each sub-type */
|
|
1725
|
+
result = NULL;
|
|
1726
|
+
for (t=0; t<nelems; t++)
|
|
1727
|
+
{
|
|
1728
|
+
if ( compute_serialized_box3d_p(loc, &b1) )
|
|
1729
|
+
{
|
|
1730
|
+
LWDEBUG(3, "Geom %d have box:");
|
|
1731
|
+
#if POSTGIS_DEBUG_LEVEL >= 3
|
|
1732
|
+
printBOX3D(&b1);
|
|
1733
|
+
#endif
|
|
1734
|
+
|
|
1735
|
+
if (result)
|
|
1736
|
+
{
|
|
1737
|
+
nboxes += box3d_union_p(result, &b1, result);
|
|
1738
|
+
}
|
|
1739
|
+
else
|
|
1740
|
+
{
|
|
1741
|
+
result = lwalloc(sizeof(BOX3D));
|
|
1742
|
+
memcpy(result, &b1, sizeof(BOX3D));
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
sub_size = lwgeom_size(loc);
|
|
1747
|
+
loc += sub_size;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
return result;
|
|
1751
|
+
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
/****************************************************************
|
|
1755
|
+
* memory management
|
|
1756
|
+
*
|
|
1757
|
+
* these only delete the memory associated
|
|
1758
|
+
* directly with the structure - NOT the stuff pointing into
|
|
1759
|
+
* the original de-serialized info
|
|
1760
|
+
*
|
|
1761
|
+
****************************************************************/
|
|
1762
|
+
|
|
1763
|
+
void
|
|
1764
|
+
lwinspected_release(LWGEOM_INSPECTED *inspected)
|
|
1765
|
+
{
|
|
1766
|
+
if ( inspected->ngeometries )
|
|
1767
|
+
lwfree(inspected->sub_geoms);
|
|
1768
|
+
lwfree(inspected);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
|
|
1772
|
+
|
|
1773
|
+
|
|
1774
|
+
|
|
1775
|
+
|
|
1776
|
+
/************************************************
|
|
1777
|
+
* debugging routines
|
|
1778
|
+
************************************************/
|
|
1779
|
+
|
|
1780
|
+
|
|
1781
|
+
void printBOX3D(BOX3D *box)
|
|
1782
|
+
{
|
|
1783
|
+
lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
|
|
1784
|
+
box->xmax, box->ymax);
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
void printPA(POINTARRAY *pa)
|
|
1788
|
+
{
|
|
1789
|
+
int t;
|
|
1790
|
+
POINT4D pt;
|
|
1791
|
+
char *mflag;
|
|
1792
|
+
|
|
1793
|
+
|
|
1794
|
+
if ( TYPE_HASM(pa->dims) ) mflag = "M";
|
|
1795
|
+
else mflag = "";
|
|
1796
|
+
|
|
1797
|
+
lwnotice(" POINTARRAY%s{", mflag);
|
|
1798
|
+
lwnotice(" ndims=%i, ptsize=%i",
|
|
1799
|
+
TYPE_NDIMS(pa->dims), pointArray_ptsize(pa));
|
|
1800
|
+
lwnotice(" npoints = %i", pa->npoints);
|
|
1801
|
+
|
|
1802
|
+
for (t =0; t<pa->npoints;t++)
|
|
1803
|
+
{
|
|
1804
|
+
getPoint4d_p(pa, t, &pt);
|
|
1805
|
+
if (TYPE_NDIMS(pa->dims) == 2)
|
|
1806
|
+
{
|
|
1807
|
+
lwnotice(" %i : %lf,%lf",t,pt.x,pt.y);
|
|
1808
|
+
}
|
|
1809
|
+
if (TYPE_NDIMS(pa->dims) == 3)
|
|
1810
|
+
{
|
|
1811
|
+
lwnotice(" %i : %lf,%lf,%lf",t,pt.x,pt.y,pt.z);
|
|
1812
|
+
}
|
|
1813
|
+
if (TYPE_NDIMS(pa->dims) == 4)
|
|
1814
|
+
{
|
|
1815
|
+
lwnotice(" %i : %lf,%lf,%lf,%lf",t,pt.x,pt.y,pt.z,pt.m);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
lwnotice(" }");
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
void printBYTES(uchar *a, int n)
|
|
1823
|
+
{
|
|
1824
|
+
int t;
|
|
1825
|
+
char buff[3];
|
|
1826
|
+
|
|
1827
|
+
buff[2] = 0; /* null terminate */
|
|
1828
|
+
|
|
1829
|
+
lwnotice(" BYTE ARRAY (n=%i) IN HEX: {", n);
|
|
1830
|
+
for (t=0;t<n;t++)
|
|
1831
|
+
{
|
|
1832
|
+
deparse_hex(a[t], buff);
|
|
1833
|
+
lwnotice(" %i : %s", t,buff );
|
|
1834
|
+
}
|
|
1835
|
+
lwnotice(" }");
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
|
|
1839
|
+
void
|
|
1840
|
+
printMULTI(uchar *serialized)
|
|
1841
|
+
{
|
|
1842
|
+
LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized);
|
|
1843
|
+
LWLINE *line;
|
|
1844
|
+
LWPOINT *point;
|
|
1845
|
+
LWPOLY *poly;
|
|
1846
|
+
int t;
|
|
1847
|
+
|
|
1848
|
+
lwnotice("MULTI* geometry (type = %i), with %i sub-geoms",lwgeom_getType((uchar)serialized[0]), inspected->ngeometries);
|
|
1849
|
+
|
|
1850
|
+
for (t=0;t<inspected->ngeometries;t++)
|
|
1851
|
+
{
|
|
1852
|
+
lwnotice(" sub-geometry %i:", t);
|
|
1853
|
+
line = NULL; point = NULL; poly = NULL;
|
|
1854
|
+
|
|
1855
|
+
line = lwgeom_getline_inspected(inspected,t);
|
|
1856
|
+
if (line !=NULL)
|
|
1857
|
+
{
|
|
1858
|
+
printLWLINE(line);
|
|
1859
|
+
}
|
|
1860
|
+
poly = lwgeom_getpoly_inspected(inspected,t);
|
|
1861
|
+
if (poly !=NULL)
|
|
1862
|
+
{
|
|
1863
|
+
printLWPOLY(poly);
|
|
1864
|
+
}
|
|
1865
|
+
point = lwgeom_getpoint_inspected(inspected,t);
|
|
1866
|
+
if (point !=NULL)
|
|
1867
|
+
{
|
|
1868
|
+
printPA(point->point);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
lwnotice("end multi*");
|
|
1873
|
+
|
|
1874
|
+
lwinspected_release(inspected);
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
void
|
|
1878
|
+
printType(uchar type)
|
|
1879
|
+
{
|
|
1880
|
+
lwnotice("type 0x%x ==> hasBBOX=%i, hasSRID=%i, ndims=%i, type=%i",(unsigned int) type, lwgeom_hasBBOX(type), lwgeom_hasSRID(type),lwgeom_ndims(type), lwgeom_getType(type));
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/*
|
|
1884
|
+
* Get the SRID from the LWGEOM.
|
|
1885
|
+
* None present => -1
|
|
1886
|
+
*/
|
|
1887
|
+
int
|
|
1888
|
+
lwgeom_getsrid(uchar *serialized)
|
|
1889
|
+
{
|
|
1890
|
+
uchar type = serialized[0];
|
|
1891
|
+
uchar *loc = serialized+1;
|
|
1892
|
+
|
|
1893
|
+
if ( ! lwgeom_hasSRID(type)) return -1;
|
|
1894
|
+
|
|
1895
|
+
if (lwgeom_hasBBOX(type))
|
|
1896
|
+
{
|
|
1897
|
+
loc += sizeof(BOX2DFLOAT4);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
return lw_get_int32(loc);
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
char
|
|
1904
|
+
ptarray_isccw(const POINTARRAY *pa)
|
|
1905
|
+
{
|
|
1906
|
+
int i;
|
|
1907
|
+
double area = 0;
|
|
1908
|
+
POINT2D p1, p2;
|
|
1909
|
+
|
|
1910
|
+
for (i=0; i<pa->npoints-1; i++)
|
|
1911
|
+
{
|
|
1912
|
+
getPoint2d_p(pa, i, &p1);
|
|
1913
|
+
getPoint2d_p(pa, i+1, &p2);
|
|
1914
|
+
area += (p1.y * p2.x) - (p1.x * p2.y);
|
|
1915
|
+
}
|
|
1916
|
+
if ( area > 0 ) return 0;
|
|
1917
|
+
else return 1;
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
/*
|
|
1921
|
+
* Returns a BOX2DFLOAT4 that encloses b1 and b2
|
|
1922
|
+
*
|
|
1923
|
+
* box2d_union(NULL,A) --> A
|
|
1924
|
+
* box2d_union(A,NULL) --> A
|
|
1925
|
+
* box2d_union(A,B) --> A union B
|
|
1926
|
+
*/
|
|
1927
|
+
BOX2DFLOAT4 *
|
|
1928
|
+
box2d_union(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2)
|
|
1929
|
+
{
|
|
1930
|
+
BOX2DFLOAT4 *result;
|
|
1931
|
+
|
|
1932
|
+
if ( (b1 == NULL) && (b2 == NULL) )
|
|
1933
|
+
{
|
|
1934
|
+
return NULL;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
result = lwalloc(sizeof(BOX2DFLOAT4));
|
|
1938
|
+
|
|
1939
|
+
if (b1 == NULL)
|
|
1940
|
+
{
|
|
1941
|
+
memcpy(result, b2, sizeof(BOX2DFLOAT4));
|
|
1942
|
+
return result;
|
|
1943
|
+
}
|
|
1944
|
+
if (b2 == NULL)
|
|
1945
|
+
{
|
|
1946
|
+
memcpy(result, b1, sizeof(BOX2DFLOAT4));
|
|
1947
|
+
return result;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
if (b1->xmin < b2->xmin) result->xmin = b1->xmin;
|
|
1951
|
+
else result->xmin = b2->xmin;
|
|
1952
|
+
|
|
1953
|
+
if (b1->ymin < b2->ymin) result->ymin = b1->ymin;
|
|
1954
|
+
else result->ymin = b2->ymin;
|
|
1955
|
+
|
|
1956
|
+
if (b1->xmax > b2->xmax) result->xmax = b1->xmax;
|
|
1957
|
+
else result->xmax = b2->xmax;
|
|
1958
|
+
|
|
1959
|
+
if (b1->ymax > b2->ymax) result->ymax = b1->ymax;
|
|
1960
|
+
else result->ymax = b2->ymax;
|
|
1961
|
+
|
|
1962
|
+
return result;
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
/*
|
|
1966
|
+
* ubox may be one of the two args...
|
|
1967
|
+
* return 1 if done something to ubox, 0 otherwise.
|
|
1968
|
+
*/
|
|
1969
|
+
int
|
|
1970
|
+
box2d_union_p(BOX2DFLOAT4 *b1, BOX2DFLOAT4 *b2, BOX2DFLOAT4 *ubox)
|
|
1971
|
+
{
|
|
1972
|
+
if ( (b1 == NULL) && (b2 == NULL) )
|
|
1973
|
+
{
|
|
1974
|
+
return 0;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
if (b1 == NULL)
|
|
1978
|
+
{
|
|
1979
|
+
memcpy(ubox, b2, sizeof(BOX2DFLOAT4));
|
|
1980
|
+
return 1;
|
|
1981
|
+
}
|
|
1982
|
+
if (b2 == NULL)
|
|
1983
|
+
{
|
|
1984
|
+
memcpy(ubox, b1, sizeof(BOX2DFLOAT4));
|
|
1985
|
+
return 1;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
if (b1->xmin < b2->xmin) ubox->xmin = b1->xmin;
|
|
1989
|
+
else ubox->xmin = b2->xmin;
|
|
1990
|
+
|
|
1991
|
+
if (b1->ymin < b2->ymin) ubox->ymin = b1->ymin;
|
|
1992
|
+
else ubox->ymin = b2->ymin;
|
|
1993
|
+
|
|
1994
|
+
if (b1->xmax > b2->xmax) ubox->xmax = b1->xmax;
|
|
1995
|
+
else ubox->xmax = b2->xmax;
|
|
1996
|
+
|
|
1997
|
+
if (b1->ymax > b2->ymax) ubox->ymax = b1->ymax;
|
|
1998
|
+
else ubox->ymax = b2->ymax;
|
|
1999
|
+
|
|
2000
|
+
return 1;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
const char *
|
|
2004
|
+
lwgeom_typeflags(uchar type)
|
|
2005
|
+
{
|
|
2006
|
+
static char flags[5];
|
|
2007
|
+
int flagno=0;
|
|
2008
|
+
if ( TYPE_HASZ(type) ) flags[flagno++] = 'Z';
|
|
2009
|
+
if ( TYPE_HASM(type) ) flags[flagno++] = 'M';
|
|
2010
|
+
if ( TYPE_HASBBOX(type) ) flags[flagno++] = 'B';
|
|
2011
|
+
if ( TYPE_HASSRID(type) ) flags[flagno++] = 'S';
|
|
2012
|
+
flags[flagno] = '\0';
|
|
2013
|
+
|
|
2014
|
+
LWDEBUGF(4, "Flags: %s - returning %p", flags, flags);
|
|
2015
|
+
|
|
2016
|
+
return flags;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
/*
|
|
2020
|
+
* Given a string with at least 2 chars in it, convert them to
|
|
2021
|
+
* a byte value. No error checking done!
|
|
2022
|
+
*/
|
|
2023
|
+
uchar
|
|
2024
|
+
parse_hex(char *str)
|
|
2025
|
+
{
|
|
2026
|
+
/* do this a little brute force to make it faster */
|
|
2027
|
+
|
|
2028
|
+
uchar result_high = 0;
|
|
2029
|
+
uchar result_low = 0;
|
|
2030
|
+
|
|
2031
|
+
switch (str[0])
|
|
2032
|
+
{
|
|
2033
|
+
case '0' :
|
|
2034
|
+
result_high = 0;
|
|
2035
|
+
break;
|
|
2036
|
+
case '1' :
|
|
2037
|
+
result_high = 1;
|
|
2038
|
+
break;
|
|
2039
|
+
case '2' :
|
|
2040
|
+
result_high = 2;
|
|
2041
|
+
break;
|
|
2042
|
+
case '3' :
|
|
2043
|
+
result_high = 3;
|
|
2044
|
+
break;
|
|
2045
|
+
case '4' :
|
|
2046
|
+
result_high = 4;
|
|
2047
|
+
break;
|
|
2048
|
+
case '5' :
|
|
2049
|
+
result_high = 5;
|
|
2050
|
+
break;
|
|
2051
|
+
case '6' :
|
|
2052
|
+
result_high = 6;
|
|
2053
|
+
break;
|
|
2054
|
+
case '7' :
|
|
2055
|
+
result_high = 7;
|
|
2056
|
+
break;
|
|
2057
|
+
case '8' :
|
|
2058
|
+
result_high = 8;
|
|
2059
|
+
break;
|
|
2060
|
+
case '9' :
|
|
2061
|
+
result_high = 9;
|
|
2062
|
+
break;
|
|
2063
|
+
case 'A' :
|
|
2064
|
+
case 'a' :
|
|
2065
|
+
result_high = 10;
|
|
2066
|
+
break;
|
|
2067
|
+
case 'B' :
|
|
2068
|
+
case 'b' :
|
|
2069
|
+
result_high = 11;
|
|
2070
|
+
break;
|
|
2071
|
+
case 'C' :
|
|
2072
|
+
case 'c' :
|
|
2073
|
+
result_high = 12;
|
|
2074
|
+
break;
|
|
2075
|
+
case 'D' :
|
|
2076
|
+
case 'd' :
|
|
2077
|
+
result_high = 13;
|
|
2078
|
+
break;
|
|
2079
|
+
case 'E' :
|
|
2080
|
+
case 'e' :
|
|
2081
|
+
result_high = 14;
|
|
2082
|
+
break;
|
|
2083
|
+
case 'F' :
|
|
2084
|
+
case 'f' :
|
|
2085
|
+
result_high = 15;
|
|
2086
|
+
break;
|
|
2087
|
+
}
|
|
2088
|
+
switch (str[1])
|
|
2089
|
+
{
|
|
2090
|
+
case '0' :
|
|
2091
|
+
result_low = 0;
|
|
2092
|
+
break;
|
|
2093
|
+
case '1' :
|
|
2094
|
+
result_low = 1;
|
|
2095
|
+
break;
|
|
2096
|
+
case '2' :
|
|
2097
|
+
result_low = 2;
|
|
2098
|
+
break;
|
|
2099
|
+
case '3' :
|
|
2100
|
+
result_low = 3;
|
|
2101
|
+
break;
|
|
2102
|
+
case '4' :
|
|
2103
|
+
result_low = 4;
|
|
2104
|
+
break;
|
|
2105
|
+
case '5' :
|
|
2106
|
+
result_low = 5;
|
|
2107
|
+
break;
|
|
2108
|
+
case '6' :
|
|
2109
|
+
result_low = 6;
|
|
2110
|
+
break;
|
|
2111
|
+
case '7' :
|
|
2112
|
+
result_low = 7;
|
|
2113
|
+
break;
|
|
2114
|
+
case '8' :
|
|
2115
|
+
result_low = 8;
|
|
2116
|
+
break;
|
|
2117
|
+
case '9' :
|
|
2118
|
+
result_low = 9;
|
|
2119
|
+
break;
|
|
2120
|
+
case 'A' :
|
|
2121
|
+
case 'a' :
|
|
2122
|
+
result_low = 10;
|
|
2123
|
+
break;
|
|
2124
|
+
case 'B' :
|
|
2125
|
+
case 'b' :
|
|
2126
|
+
result_low = 11;
|
|
2127
|
+
break;
|
|
2128
|
+
case 'C' :
|
|
2129
|
+
case 'c' :
|
|
2130
|
+
result_low = 12;
|
|
2131
|
+
break;
|
|
2132
|
+
case 'D' :
|
|
2133
|
+
case 'd' :
|
|
2134
|
+
result_low = 13;
|
|
2135
|
+
break;
|
|
2136
|
+
case 'E' :
|
|
2137
|
+
case 'e' :
|
|
2138
|
+
result_low = 14;
|
|
2139
|
+
break;
|
|
2140
|
+
case 'F' :
|
|
2141
|
+
case 'f' :
|
|
2142
|
+
result_low = 15;
|
|
2143
|
+
break;
|
|
2144
|
+
}
|
|
2145
|
+
return (uchar) ((result_high<<4) + result_low);
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
|
|
2149
|
+
/*
|
|
2150
|
+
* Given one byte, populate result with two byte representing
|
|
2151
|
+
* the hex number.
|
|
2152
|
+
*
|
|
2153
|
+
* Ie. deparse_hex( 255, mystr)
|
|
2154
|
+
* -> mystr[0] = 'F' and mystr[1] = 'F'
|
|
2155
|
+
*
|
|
2156
|
+
* No error checking done
|
|
2157
|
+
*/
|
|
2158
|
+
void
|
|
2159
|
+
deparse_hex(uchar str, char *result)
|
|
2160
|
+
{
|
|
2161
|
+
int input_high;
|
|
2162
|
+
int input_low;
|
|
2163
|
+
static char outchr[]={"0123456789ABCDEF" };
|
|
2164
|
+
|
|
2165
|
+
input_high = (str>>4);
|
|
2166
|
+
input_low = (str & 0x0F);
|
|
2167
|
+
|
|
2168
|
+
result[0] = outchr[input_high];
|
|
2169
|
+
result[1] = outchr[input_low];
|
|
2170
|
+
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
|
|
2174
|
+
/*
|
|
2175
|
+
* Find interpolation point I
|
|
2176
|
+
* between point A and point B
|
|
2177
|
+
* so that the len(AI) == len(AB)*F
|
|
2178
|
+
* and I falls on AB segment.
|
|
2179
|
+
*
|
|
2180
|
+
* Example:
|
|
2181
|
+
*
|
|
2182
|
+
* F=0.5 : A----I----B
|
|
2183
|
+
* F=1 : A---------B==I
|
|
2184
|
+
* F=0 : A==I---------B
|
|
2185
|
+
* F=.2 : A-I-------B
|
|
2186
|
+
*/
|
|
2187
|
+
void
|
|
2188
|
+
interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F)
|
|
2189
|
+
{
|
|
2190
|
+
#if PARANOIA_LEVEL > 0
|
|
2191
|
+
double absF=fabs(F);
|
|
2192
|
+
if ( absF < 0 || absF > 1 )
|
|
2193
|
+
{
|
|
2194
|
+
lwerror("interpolate_point4d: invalid F (%g)", F);
|
|
2195
|
+
}
|
|
2196
|
+
#endif
|
|
2197
|
+
I->x=A->x+((B->x-A->x)*F);
|
|
2198
|
+
I->y=A->y+((B->y-A->y)*F);
|
|
2199
|
+
I->z=A->z+((B->z-A->z)*F);
|
|
2200
|
+
I->m=A->m+((B->m-A->m)*F);
|
|
2201
|
+
}
|