geo_coder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +32 -0
  3. data/History.txt +6 -0
  4. data/Makefile +13 -0
  5. data/Manifest.txt +18 -0
  6. data/README.rdoc +197 -0
  7. data/Rakefile +53 -0
  8. data/TODO.txt +8 -0
  9. data/VERSION +1 -0
  10. data/bin/build_indexes +8 -0
  11. data/bin/rebuild_cluster +22 -0
  12. data/bin/rebuild_metaphones +23 -0
  13. data/bin/tiger_import +59 -0
  14. data/demos/demo/app/ext/geocodewrap.rb +84 -0
  15. data/demos/demo/app/views/index.builder +13 -0
  16. data/demos/demo/app/views/index.erb +71 -0
  17. data/demos/demo/config.ru +12 -0
  18. data/demos/demo/config/bootstraps.rb +130 -0
  19. data/demos/demo/config/geoenvironment.rb +25 -0
  20. data/demos/demo/geocoder_helper.rb +12 -0
  21. data/demos/demo/geocom_geocode.rb +10 -0
  22. data/demos/demo/main.rb +3 -0
  23. data/demos/demo/rakefile.rb +17 -0
  24. data/demos/demo/tmp/restart.txt +0 -0
  25. data/demos/simpledemo/views/index.builder +13 -0
  26. data/demos/simpledemo/views/index.erb +69 -0
  27. data/demos/simpledemo/ws.rb +83 -0
  28. data/doc/Makefile +7 -0
  29. data/doc/html4css1.css +279 -0
  30. data/doc/lookup.rst +193 -0
  31. data/doc/parsing.rst +125 -0
  32. data/doc/voidspace.css +147 -0
  33. data/geo_coder.gemspec +172 -0
  34. data/lib/geocoder/us.rb +21 -0
  35. data/lib/geocoder/us/address.rb +290 -0
  36. data/lib/geocoder/us/constants.rb +670 -0
  37. data/lib/geocoder/us/database.rb +745 -0
  38. data/lib/geocoder/us/import.rb +181 -0
  39. data/lib/geocoder/us/import/tiger.rb +13 -0
  40. data/lib/geocoder/us/numbers.rb +58 -0
  41. data/navteq/README +4 -0
  42. data/navteq/convert.sql +37 -0
  43. data/navteq/navteq_import +39 -0
  44. data/navteq/prepare.sql +92 -0
  45. data/sql/cluster.sql +16 -0
  46. data/sql/convert.sql +80 -0
  47. data/sql/create.sql +37 -0
  48. data/sql/index.sql +12 -0
  49. data/sql/place.csv +104944 -0
  50. data/sql/place.sql +104948 -0
  51. data/sql/setup.sql +78 -0
  52. data/src/Makefile +13 -0
  53. data/src/README +14 -0
  54. data/src/liblwgeom/Makefile +75 -0
  55. data/src/liblwgeom/box2d.c +54 -0
  56. data/src/liblwgeom/lex.yy.c +4799 -0
  57. data/src/liblwgeom/liblwgeom.h +1405 -0
  58. data/src/liblwgeom/lwalgorithm.c +946 -0
  59. data/src/liblwgeom/lwalgorithm.h +52 -0
  60. data/src/liblwgeom/lwcircstring.c +759 -0
  61. data/src/liblwgeom/lwcollection.c +541 -0
  62. data/src/liblwgeom/lwcompound.c +118 -0
  63. data/src/liblwgeom/lwcurvepoly.c +86 -0
  64. data/src/liblwgeom/lwgeom.c +886 -0
  65. data/src/liblwgeom/lwgeom_api.c +2201 -0
  66. data/src/liblwgeom/lwgparse.c +1219 -0
  67. data/src/liblwgeom/lwgunparse.c +1054 -0
  68. data/src/liblwgeom/lwline.c +525 -0
  69. data/src/liblwgeom/lwmcurve.c +125 -0
  70. data/src/liblwgeom/lwmline.c +137 -0
  71. data/src/liblwgeom/lwmpoint.c +138 -0
  72. data/src/liblwgeom/lwmpoly.c +141 -0
  73. data/src/liblwgeom/lwmsurface.c +129 -0
  74. data/src/liblwgeom/lwpoint.c +439 -0
  75. data/src/liblwgeom/lwpoly.c +579 -0
  76. data/src/liblwgeom/lwsegmentize.c +1047 -0
  77. data/src/liblwgeom/lwutil.c +369 -0
  78. data/src/liblwgeom/measures.c +861 -0
  79. data/src/liblwgeom/postgis_config.h +93 -0
  80. data/src/liblwgeom/ptarray.c +847 -0
  81. data/src/liblwgeom/vsprintf.c +179 -0
  82. data/src/liblwgeom/wktparse.h +126 -0
  83. data/src/liblwgeom/wktparse.lex +74 -0
  84. data/src/liblwgeom/wktparse.tab.c +2353 -0
  85. data/src/liblwgeom/wktparse.tab.h +145 -0
  86. data/src/liblwgeom/wktparse.y +385 -0
  87. data/src/libsqlite3_geocoder/Makefile +22 -0
  88. data/src/libsqlite3_geocoder/Makefile.nix +15 -0
  89. data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
  90. data/src/libsqlite3_geocoder/extension.c +121 -0
  91. data/src/libsqlite3_geocoder/extension.h +13 -0
  92. data/src/libsqlite3_geocoder/levenshtein.c +42 -0
  93. data/src/libsqlite3_geocoder/metaphon.c +278 -0
  94. data/src/libsqlite3_geocoder/util.c +37 -0
  95. data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
  96. data/src/metaphone/Makefile +7 -0
  97. data/src/metaphone/README +49 -0
  98. data/src/metaphone/extension.c +37 -0
  99. data/src/metaphone/metaphon.c +251 -0
  100. data/src/shp2sqlite/Makefile +37 -0
  101. data/src/shp2sqlite/Makefile.nix +36 -0
  102. data/src/shp2sqlite/Makefile.redhat +35 -0
  103. data/src/shp2sqlite/dbfopen.c +1595 -0
  104. data/src/shp2sqlite/getopt.c +695 -0
  105. data/src/shp2sqlite/getopt.h +127 -0
  106. data/src/shp2sqlite/shapefil.h +500 -0
  107. data/src/shp2sqlite/shp2sqlite.c +1974 -0
  108. data/src/shp2sqlite/shpopen.c +1894 -0
  109. data/tests/address.rb +236 -0
  110. data/tests/benchmark.rb +20 -0
  111. data/tests/constants.rb +57 -0
  112. data/tests/data/address-sample.csv +52 -0
  113. data/tests/data/db-test.csv +57 -0
  114. data/tests/data/locations.csv +4 -0
  115. data/tests/database.rb +137 -0
  116. data/tests/generate.rb +34 -0
  117. data/tests/numbers.rb +46 -0
  118. data/tests/run.rb +11 -0
  119. metadata +237 -0
@@ -0,0 +1,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
+ }