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