1 /*
2
3 gg_wkb.c -- Gaia common support for WKB encoded geometries
4
5 version 5.0, 2020 August 1
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29
30 Contributor(s):
31
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43
44 */
45
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <float.h>
50 #include <string.h>
51
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57
58 #include <spatialite/sqlite.h>
59
60 #include <spatialite/gaiageo.h>
61 #include <spatialite/geopackage.h>
62
63 static void
ParseWkbPoint(gaiaGeomCollPtr geo)64 ParseWkbPoint (gaiaGeomCollPtr geo)
65 {
66 /* decodes a POINT from WKB */
67 double x;
68 double y;
69 if (geo->size < geo->offset + 16)
70 return;
71 x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
72 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
73 geo->endian_arch);
74 geo->offset += 16;
75 gaiaAddPointToGeomColl (geo, x, y);
76 }
77
78 static void
ParseWkbPointZ(gaiaGeomCollPtr geo)79 ParseWkbPointZ (gaiaGeomCollPtr geo)
80 {
81 /* decodes a POINTZ from WKB */
82 double x;
83 double y;
84 double z;
85 if (geo->size < geo->offset + 24)
86 return;
87 x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
88 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
89 geo->endian_arch);
90 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
91 geo->endian_arch);
92 geo->offset += 24;
93 gaiaAddPointToGeomCollXYZ (geo, x, y, z);
94 }
95
96 static void
ParseWkbPointM(gaiaGeomCollPtr geo)97 ParseWkbPointM (gaiaGeomCollPtr geo)
98 {
99 /* decodes a POINTM from WKB */
100 double x;
101 double y;
102 double m;
103 if (geo->size < geo->offset + 24)
104 return;
105 x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
106 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
107 geo->endian_arch);
108 m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
109 geo->endian_arch);
110 geo->offset += 24;
111 gaiaAddPointToGeomCollXYM (geo, x, y, m);
112 }
113
114 static void
ParseWkbPointZM(gaiaGeomCollPtr geo)115 ParseWkbPointZM (gaiaGeomCollPtr geo)
116 {
117 /* decodes a POINTZM from WKB */
118 double x;
119 double y;
120 double z;
121 double m;
122 if (geo->size < geo->offset + 32)
123 return;
124 x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
125 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
126 geo->endian_arch);
127 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
128 geo->endian_arch);
129 m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
130 geo->endian_arch);
131 geo->offset += 32;
132 gaiaAddPointToGeomCollXYZM (geo, x, y, z, m);
133 }
134
135 static void
ParseWkbLine(gaiaGeomCollPtr geo)136 ParseWkbLine (gaiaGeomCollPtr geo)
137 {
138 /* decodes a LINESTRING from WKB */
139 int points;
140 int iv;
141 double x;
142 double y;
143 gaiaLinestringPtr line;
144 if (geo->size < geo->offset + 4)
145 return;
146 points =
147 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
148 geo->offset += 4;
149 if (geo->size < geo->offset + (16 * points))
150 return;
151 line = gaiaAddLinestringToGeomColl (geo, points);
152 for (iv = 0; iv < points; iv++)
153 {
154 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
155 geo->endian_arch);
156 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
157 geo->endian_arch);
158 gaiaSetPoint (line->Coords, iv, x, y);
159 geo->offset += 16;
160 }
161 }
162
163 static void
ParseWkbLineZ(gaiaGeomCollPtr geo)164 ParseWkbLineZ (gaiaGeomCollPtr geo)
165 {
166 /* decodes a LINESTRINGZ from WKB */
167 int points;
168 int iv;
169 double x;
170 double y;
171 double z;
172 gaiaLinestringPtr line;
173 if (geo->size < geo->offset + 4)
174 return;
175 points =
176 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
177 geo->offset += 4;
178 if (geo->size < geo->offset + (24 * points))
179 return;
180 line = gaiaAddLinestringToGeomColl (geo, points);
181 for (iv = 0; iv < points; iv++)
182 {
183 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
184 geo->endian_arch);
185 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
186 geo->endian_arch);
187 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
188 geo->endian_arch);
189 gaiaSetPointXYZ (line->Coords, iv, x, y, z);
190 geo->offset += 24;
191 }
192 }
193
194 static void
ParseWkbLineM(gaiaGeomCollPtr geo)195 ParseWkbLineM (gaiaGeomCollPtr geo)
196 {
197 /* decodes a LINESTRINGM from WKB */
198 int points;
199 int iv;
200 double x;
201 double y;
202 double m;
203 gaiaLinestringPtr line;
204 if (geo->size < geo->offset + 4)
205 return;
206 points =
207 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
208 geo->offset += 4;
209 if (geo->size < geo->offset + (24 * points))
210 return;
211 line = gaiaAddLinestringToGeomColl (geo, points);
212 for (iv = 0; iv < points; iv++)
213 {
214 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
215 geo->endian_arch);
216 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
217 geo->endian_arch);
218 m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
219 geo->endian_arch);
220 gaiaSetPointXYM (line->Coords, iv, x, y, m);
221 geo->offset += 24;
222 }
223 }
224
225 static void
ParseWkbLineZM(gaiaGeomCollPtr geo)226 ParseWkbLineZM (gaiaGeomCollPtr geo)
227 {
228 /* decodes a LINESTRINGZM from WKB */
229 int points;
230 int iv;
231 double x;
232 double y;
233 double z;
234 double m;
235 gaiaLinestringPtr line;
236 if (geo->size < geo->offset + 4)
237 return;
238 points =
239 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
240 geo->offset += 4;
241 if (geo->size < geo->offset + (32 * points))
242 return;
243 line = gaiaAddLinestringToGeomColl (geo, points);
244 for (iv = 0; iv < points; iv++)
245 {
246 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
247 geo->endian_arch);
248 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
249 geo->endian_arch);
250 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
251 geo->endian_arch);
252 m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
253 geo->endian_arch);
254 gaiaSetPointXYZM (line->Coords, iv, x, y, z, m);
255 geo->offset += 32;
256 }
257 }
258
259 static void
ParseWkbPolygon(gaiaGeomCollPtr geo)260 ParseWkbPolygon (gaiaGeomCollPtr geo)
261 {
262 /* decodes a POLYGON from WKB */
263 int rings;
264 int nverts;
265 int iv;
266 int ib;
267 double x;
268 double y;
269 gaiaPolygonPtr polyg = NULL;
270 gaiaRingPtr ring;
271 if (geo->size < geo->offset + 4)
272 return;
273 rings =
274 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
275 geo->offset += 4;
276 for (ib = 0; ib < rings; ib++)
277 {
278 if (geo->size < geo->offset + 4)
279 return;
280 nverts =
281 gaiaImport32 (geo->blob + geo->offset, geo->endian,
282 geo->endian_arch);
283 geo->offset += 4;
284 if (geo->size < geo->offset + (16 * nverts))
285 return;
286 if (ib == 0)
287 {
288 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
289 ring = polyg->Exterior;
290 }
291 else
292 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
293 for (iv = 0; iv < nverts; iv++)
294 {
295 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
296 geo->endian_arch);
297 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
298 geo->endian_arch);
299 geo->offset += 16;
300 gaiaSetPoint (ring->Coords, iv, x, y);
301 }
302 }
303 }
304
305 static void
ParseWkbPolygonZ(gaiaGeomCollPtr geo)306 ParseWkbPolygonZ (gaiaGeomCollPtr geo)
307 {
308 /* decodes a POLYGONZ from WKB */
309 int rings;
310 int nverts;
311 int iv;
312 int ib;
313 double x;
314 double y;
315 double z;
316 gaiaPolygonPtr polyg = NULL;
317 gaiaRingPtr ring;
318 if (geo->size < geo->offset + 4)
319 return;
320 rings =
321 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
322 geo->offset += 4;
323 for (ib = 0; ib < rings; ib++)
324 {
325 if (geo->size < geo->offset + 4)
326 return;
327 nverts =
328 gaiaImport32 (geo->blob + geo->offset, geo->endian,
329 geo->endian_arch);
330 geo->offset += 4;
331 if (geo->size < geo->offset + (24 * nverts))
332 return;
333 if (ib == 0)
334 {
335 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
336 ring = polyg->Exterior;
337 }
338 else
339 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
340 for (iv = 0; iv < nverts; iv++)
341 {
342 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
343 geo->endian_arch);
344 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
345 geo->endian_arch);
346 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
347 geo->endian_arch);
348 geo->offset += 24;
349 gaiaSetPointXYZ (ring->Coords, iv, x, y, z);
350 }
351 }
352 }
353
354 static void
ParseWkbPolygonM(gaiaGeomCollPtr geo)355 ParseWkbPolygonM (gaiaGeomCollPtr geo)
356 {
357 /* decodes a POLYGONM from WKB */
358 int rings;
359 int nverts;
360 int iv;
361 int ib;
362 double x;
363 double y;
364 double m;
365 gaiaPolygonPtr polyg = NULL;
366 gaiaRingPtr ring;
367 if (geo->size < geo->offset + 4)
368 return;
369 rings =
370 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
371 geo->offset += 4;
372 for (ib = 0; ib < rings; ib++)
373 {
374 if (geo->size < geo->offset + 4)
375 return;
376 nverts =
377 gaiaImport32 (geo->blob + geo->offset, geo->endian,
378 geo->endian_arch);
379 geo->offset += 4;
380 if (geo->size < geo->offset + (24 * nverts))
381 return;
382 if (ib == 0)
383 {
384 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
385 ring = polyg->Exterior;
386 }
387 else
388 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
389 for (iv = 0; iv < nverts; iv++)
390 {
391 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
392 geo->endian_arch);
393 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
394 geo->endian_arch);
395 m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
396 geo->endian_arch);
397 geo->offset += 24;
398 gaiaSetPointXYM (ring->Coords, iv, x, y, m);
399 }
400 }
401 }
402
403 static void
ParseWkbPolygonZM(gaiaGeomCollPtr geo)404 ParseWkbPolygonZM (gaiaGeomCollPtr geo)
405 {
406 /* decodes a POLYGONZM from WKB */
407 int rings;
408 int nverts;
409 int iv;
410 int ib;
411 double x;
412 double y;
413 double z;
414 double m;
415 gaiaPolygonPtr polyg = NULL;
416 gaiaRingPtr ring;
417 if (geo->size < geo->offset + 4)
418 return;
419 rings =
420 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
421 geo->offset += 4;
422 for (ib = 0; ib < rings; ib++)
423 {
424 if (geo->size < geo->offset + 4)
425 return;
426 nverts =
427 gaiaImport32 (geo->blob + geo->offset, geo->endian,
428 geo->endian_arch);
429 geo->offset += 4;
430 if (geo->size < geo->offset + (32 * nverts))
431 return;
432 if (ib == 0)
433 {
434 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
435 ring = polyg->Exterior;
436 }
437 else
438 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
439 for (iv = 0; iv < nverts; iv++)
440 {
441 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
442 geo->endian_arch);
443 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
444 geo->endian_arch);
445 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
446 geo->endian_arch);
447 m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
448 geo->endian_arch);
449 geo->offset += 32;
450 gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m);
451 }
452 }
453 }
454
455 static void
ParseCompressedWkbLine(gaiaGeomCollPtr geo)456 ParseCompressedWkbLine (gaiaGeomCollPtr geo)
457 {
458 /* decodes a COMPRESSED LINESTRING from WKB */
459 int points;
460 int iv;
461 double x;
462 double y;
463 double last_x = 0.0;
464 double last_y = 0.0;
465 float fx;
466 float fy;
467 gaiaLinestringPtr line;
468 if (geo->size < geo->offset + 4)
469 return;
470 points =
471 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
472 geo->offset += 4;
473 if (geo->size < geo->offset + (8 * points) + 16)
474 return;
475 line = gaiaAddLinestringToGeomColl (geo, points);
476 for (iv = 0; iv < points; iv++)
477 {
478 if (iv == 0 || iv == (points - 1))
479 {
480 /* first and last vertices are uncompressed */
481 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
482 geo->endian_arch);
483 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
484 geo->endian_arch);
485 geo->offset += 16;
486 }
487 else
488 {
489 /* any other intermediate vertex is compressed */
490 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
491 geo->endian_arch);
492 fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
493 geo->endian_arch);
494 x = last_x + fx;
495 y = last_y + fy;
496 geo->offset += 8;
497 }
498 gaiaSetPoint (line->Coords, iv, x, y);
499 last_x = x;
500 last_y = y;
501 }
502 }
503
504 static void
ParseCompressedWkbLineZ(gaiaGeomCollPtr geo)505 ParseCompressedWkbLineZ (gaiaGeomCollPtr geo)
506 {
507 /* decodes a COMPRESSED LINESTRINGZ from WKB */
508 int points;
509 int iv;
510 double x;
511 double y;
512 double z;
513 double last_x = 0.0;
514 double last_y = 0.0;
515 double last_z = 0.0;
516 float fx;
517 float fy;
518 float fz;
519 gaiaLinestringPtr line;
520 if (geo->size < geo->offset + 4)
521 return;
522 points =
523 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
524 geo->offset += 4;
525 if (geo->size < geo->offset + (12 * points) + 24)
526 return;
527 line = gaiaAddLinestringToGeomColl (geo, points);
528 for (iv = 0; iv < points; iv++)
529 {
530 if (iv == 0 || iv == (points - 1))
531 {
532 /* first and last vertices are uncompressed */
533 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
534 geo->endian_arch);
535 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
536 geo->endian_arch);
537 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
538 geo->endian_arch);
539 geo->offset += 24;
540 }
541 else
542 {
543 /* any other intermediate vertex is compressed */
544 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
545 geo->endian_arch);
546 fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
547 geo->endian_arch);
548 fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian,
549 geo->endian_arch);
550 x = last_x + fx;
551 y = last_y + fy;
552 z = last_z + fz;
553 geo->offset += 12;
554 }
555 gaiaSetPointXYZ (line->Coords, iv, x, y, z);
556 last_x = x;
557 last_y = y;
558 last_z = z;
559 }
560 }
561
562 static void
ParseCompressedWkbLineM(gaiaGeomCollPtr geo)563 ParseCompressedWkbLineM (gaiaGeomCollPtr geo)
564 {
565 /* decodes a COMPRESSED LINESTRINGM from WKB */
566 int points;
567 int iv;
568 double x;
569 double y;
570 double m;
571 double last_x = 0.0;
572 double last_y = 0.0;
573 float fx;
574 float fy;
575 gaiaLinestringPtr line;
576 if (geo->size < geo->offset + 4)
577 return;
578 points =
579 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
580 geo->offset += 4;
581 if (geo->size < geo->offset + (16 * points) + 16)
582 return;
583 line = gaiaAddLinestringToGeomColl (geo, points);
584 for (iv = 0; iv < points; iv++)
585 {
586 if (iv == 0 || iv == (points - 1))
587 {
588 /* first and last vertices are uncompressed */
589 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
590 geo->endian_arch);
591 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
592 geo->endian_arch);
593 m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
594 geo->endian_arch);
595 geo->offset += 24;
596 }
597 else
598 {
599 /* any other intermediate vertex is compressed */
600 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
601 geo->endian_arch);
602 fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
603 geo->endian_arch);
604 m = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
605 geo->endian_arch);
606 x = last_x + fx;
607 y = last_y + fy;
608 geo->offset += 16;
609 }
610 gaiaSetPointXYM (line->Coords, iv, x, y, m);
611 last_x = x;
612 last_y = y;
613 }
614 }
615
616 static void
ParseCompressedWkbLineZM(gaiaGeomCollPtr geo)617 ParseCompressedWkbLineZM (gaiaGeomCollPtr geo)
618 {
619 /* decodes a COMPRESSED LINESTRINGZM from WKB */
620 int points;
621 int iv;
622 double x;
623 double y;
624 double z;
625 double m;
626 double last_x = 0.0;
627 double last_y = 0.0;
628 double last_z = 0.0;
629 float fx;
630 float fy;
631 float fz;
632 gaiaLinestringPtr line;
633 if (geo->size < geo->offset + 4)
634 return;
635 points =
636 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
637 geo->offset += 4;
638 if (geo->size < geo->offset + (20 * points) + 24)
639 return;
640 line = gaiaAddLinestringToGeomColl (geo, points);
641 for (iv = 0; iv < points; iv++)
642 {
643 if (iv == 0 || iv == (points - 1))
644 {
645 /* first and last vertices are uncompressed */
646 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
647 geo->endian_arch);
648 y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
649 geo->endian_arch);
650 z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
651 geo->endian_arch);
652 m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
653 geo->endian_arch);
654 geo->offset += 32;
655 }
656 else
657 {
658 /* any other intermediate vertex is compressed */
659 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
660 geo->endian_arch);
661 fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
662 geo->endian_arch);
663 fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian,
664 geo->endian_arch);
665 m = gaiaImport64 (geo->blob + (geo->offset + 12), geo->endian,
666 geo->endian_arch);
667 x = last_x + fx;
668 y = last_y + fy;
669 z = last_z + fz;
670 geo->offset += 20;
671 }
672 gaiaSetPointXYZM (line->Coords, iv, x, y, z, m);
673 last_x = x;
674 last_y = y;
675 last_z = z;
676 }
677 }
678
679 static void
ParseCompressedWkbPolygon(gaiaGeomCollPtr geo)680 ParseCompressedWkbPolygon (gaiaGeomCollPtr geo)
681 {
682 /* decodes a COMPRESSED POLYGON from WKB */
683 int rings;
684 int nverts;
685 int iv;
686 int ib;
687 double x;
688 double y;
689 double last_x = 0.0;
690 double last_y = 0.0;
691 float fx;
692 float fy;
693 gaiaPolygonPtr polyg = NULL;
694 gaiaRingPtr ring;
695 if (geo->size < geo->offset + 4)
696 return;
697 rings =
698 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
699 geo->offset += 4;
700 for (ib = 0; ib < rings; ib++)
701 {
702 if (geo->size < geo->offset + 4)
703 return;
704 nverts =
705 gaiaImport32 (geo->blob + geo->offset, geo->endian,
706 geo->endian_arch);
707 geo->offset += 4;
708 if (geo->size < geo->offset + (8 * nverts) + 16)
709 return;
710 if (ib == 0)
711 {
712 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
713 ring = polyg->Exterior;
714 }
715 else
716 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
717 for (iv = 0; iv < nverts; iv++)
718 {
719 if (iv == 0 || iv == (nverts - 1))
720 {
721 /* first and last vertices are uncompressed */
722 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
723 geo->endian_arch);
724 y = gaiaImport64 (geo->blob + (geo->offset + 8),
725 geo->endian, geo->endian_arch);
726 geo->offset += 16;
727 }
728 else
729 {
730 /* any other intermediate vertex is compressed */
731 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
732 geo->endian_arch);
733 fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
734 geo->endian, geo->endian_arch);
735 x = last_x + fx;
736 y = last_y + fy;
737 geo->offset += 8;
738 }
739 gaiaSetPoint (ring->Coords, iv, x, y);
740 last_x = x;
741 last_y = y;
742 }
743 }
744 }
745
746 static void
ParseCompressedWkbPolygonZ(gaiaGeomCollPtr geo)747 ParseCompressedWkbPolygonZ (gaiaGeomCollPtr geo)
748 {
749 /* decodes a COMPRESSED POLYGONZ from WKB */
750 int rings;
751 int nverts;
752 int iv;
753 int ib;
754 double x;
755 double y;
756 double z;
757 double last_x = 0.0;
758 double last_y = 0.0;
759 double last_z = 0.0;
760 float fx;
761 float fy;
762 float fz;
763 gaiaPolygonPtr polyg = NULL;
764 gaiaRingPtr ring;
765 if (geo->size < geo->offset + 4)
766 return;
767 rings =
768 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
769 geo->offset += 4;
770 for (ib = 0; ib < rings; ib++)
771 {
772 if (geo->size < geo->offset + 4)
773 return;
774 nverts =
775 gaiaImport32 (geo->blob + geo->offset, geo->endian,
776 geo->endian_arch);
777 geo->offset += 4;
778 if (geo->size < geo->offset + (12 * nverts) + 24)
779 return;
780 if (ib == 0)
781 {
782 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
783 ring = polyg->Exterior;
784 }
785 else
786 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
787 for (iv = 0; iv < nverts; iv++)
788 {
789 if (iv == 0 || iv == (nverts - 1))
790 {
791 /* first and last vertices are uncompressed */
792 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
793 geo->endian_arch);
794 y = gaiaImport64 (geo->blob + (geo->offset + 8),
795 geo->endian, geo->endian_arch);
796 z = gaiaImport64 (geo->blob + (geo->offset + 16),
797 geo->endian, geo->endian_arch);
798 geo->offset += 24;
799 }
800 else
801 {
802 /* any other intermediate vertex is compressed */
803 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
804 geo->endian_arch);
805 fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
806 geo->endian, geo->endian_arch);
807 fz = gaiaImportF32 (geo->blob + (geo->offset + 8),
808 geo->endian, geo->endian_arch);
809 x = last_x + fx;
810 y = last_y + fy;
811 z = last_z + fz;
812 geo->offset += 12;
813 }
814 gaiaSetPointXYZ (ring->Coords, iv, x, y, z);
815 last_x = x;
816 last_y = y;
817 last_z = z;
818 }
819 }
820 }
821
822 static void
ParseCompressedWkbPolygonM(gaiaGeomCollPtr geo)823 ParseCompressedWkbPolygonM (gaiaGeomCollPtr geo)
824 {
825 /* decodes a COMPRESSED POLYGONM from WKB */
826 int rings;
827 int nverts;
828 int iv;
829 int ib;
830 double x;
831 double y;
832 double m;
833 double last_x = 0.0;
834 double last_y = 0.0;
835 float fx;
836 float fy;
837 gaiaPolygonPtr polyg = NULL;
838 gaiaRingPtr ring;
839 if (geo->size < geo->offset + 4)
840 return;
841 rings =
842 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
843 geo->offset += 4;
844 for (ib = 0; ib < rings; ib++)
845 {
846 if (geo->size < geo->offset + 4)
847 return;
848 nverts =
849 gaiaImport32 (geo->blob + geo->offset, geo->endian,
850 geo->endian_arch);
851 geo->offset += 4;
852 if (geo->size < geo->offset + (16 * nverts) + 16)
853 return;
854 if (ib == 0)
855 {
856 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
857 ring = polyg->Exterior;
858 }
859 else
860 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
861 for (iv = 0; iv < nverts; iv++)
862 {
863 if (iv == 0 || iv == (nverts - 1))
864 {
865 /* first and last vertices are uncompressed */
866 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
867 geo->endian_arch);
868 y = gaiaImport64 (geo->blob + (geo->offset + 8),
869 geo->endian, geo->endian_arch);
870 m = gaiaImport64 (geo->blob + (geo->offset + 16),
871 geo->endian, geo->endian_arch);
872 geo->offset += 24;
873 }
874 else
875 {
876 /* any other intermediate vertex is compressed */
877 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
878 geo->endian_arch);
879 fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
880 geo->endian, geo->endian_arch);
881 m = gaiaImport64 (geo->blob + (geo->offset + 8),
882 geo->endian, geo->endian_arch);
883 x = last_x + fx;
884 y = last_y + fy;
885 geo->offset += 16;
886 }
887 gaiaSetPointXYM (ring->Coords, iv, x, y, m);
888 last_x = x;
889 last_y = y;
890 }
891 }
892 }
893
894 static void
ParseCompressedWkbPolygonZM(gaiaGeomCollPtr geo)895 ParseCompressedWkbPolygonZM (gaiaGeomCollPtr geo)
896 {
897 /* decodes a COMPRESSED POLYGONZM from WKB */
898 int rings;
899 int nverts;
900 int iv;
901 int ib;
902 double x;
903 double y;
904 double z;
905 double m;
906 double last_x = 0.0;
907 double last_y = 0.0;
908 double last_z = 0.0;
909 float fx;
910 float fy;
911 float fz;
912 gaiaPolygonPtr polyg = NULL;
913 gaiaRingPtr ring;
914 if (geo->size < geo->offset + 4)
915 return;
916 rings =
917 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
918 geo->offset += 4;
919 for (ib = 0; ib < rings; ib++)
920 {
921 if (geo->size < geo->offset + 4)
922 return;
923 nverts =
924 gaiaImport32 (geo->blob + geo->offset, geo->endian,
925 geo->endian_arch);
926 geo->offset += 4;
927 if (geo->size < geo->offset + (20 * nverts) + 24)
928 return;
929 if (ib == 0)
930 {
931 polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
932 ring = polyg->Exterior;
933 }
934 else
935 ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
936 for (iv = 0; iv < nverts; iv++)
937 {
938 if (iv == 0 || iv == (nverts - 1))
939 {
940 /* first and last vertices are uncompressed */
941 x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
942 geo->endian_arch);
943 y = gaiaImport64 (geo->blob + (geo->offset + 8),
944 geo->endian, geo->endian_arch);
945 z = gaiaImport64 (geo->blob + (geo->offset + 16),
946 geo->endian, geo->endian_arch);
947 m = gaiaImport64 (geo->blob + (geo->offset + 24),
948 geo->endian, geo->endian_arch);
949 geo->offset += 32;
950 }
951 else
952 {
953 /* any other intermediate vertex is compressed */
954 fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
955 geo->endian_arch);
956 fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
957 geo->endian, geo->endian_arch);
958 fz = gaiaImportF32 (geo->blob + (geo->offset + 8),
959 geo->endian, geo->endian_arch);
960 m = gaiaImport64 (geo->blob + (geo->offset + 12),
961 geo->endian, geo->endian_arch);
962 x = last_x + fx;
963 y = last_y + fy;
964 z = last_z + fz;
965 geo->offset += 20;
966 }
967 gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m);
968 last_x = x;
969 last_y = y;
970 last_z = z;
971 }
972 }
973 }
974
975 static void
ParseWkbGeometry(gaiaGeomCollPtr geo,int isWKB)976 ParseWkbGeometry (gaiaGeomCollPtr geo, int isWKB)
977 {
978 /* decodes a MULTIxx or GEOMETRYCOLLECTION from SpatiaLite BLOB */
979 int entities;
980 int type;
981 int ie;
982 if (geo->size < geo->offset + 4)
983 return;
984 entities =
985 gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
986 geo->offset += 4;
987 for (ie = 0; ie < entities; ie++)
988 {
989 if (geo->size < geo->offset + 5)
990 return;
991 if (isWKB)
992 {
993 /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */
994 if (*(geo->blob + geo->offset) == 0x01)
995 geo->endian = GAIA_LITTLE_ENDIAN;
996 else
997 geo->endian = GAIA_BIG_ENDIAN;
998 }
999 type =
1000 gaiaImport32 (geo->blob + geo->offset + 1, geo->endian,
1001 geo->endian_arch);
1002 geo->offset += 5;
1003 switch (type)
1004 {
1005 case GAIA_POINT:
1006 ParseWkbPoint (geo);
1007 break;
1008 case GAIA_POINTZ:
1009 case GAIA_GEOSWKB_POINTZ:
1010 ParseWkbPointZ (geo);
1011 break;
1012 case GAIA_POINTM:
1013 ParseWkbPointM (geo);
1014 break;
1015 case GAIA_POINTZM:
1016 ParseWkbPointZM (geo);
1017 break;
1018 case GAIA_LINESTRING:
1019 ParseWkbLine (geo);
1020 break;
1021 case GAIA_LINESTRINGZ:
1022 case GAIA_GEOSWKB_LINESTRINGZ:
1023 ParseWkbLineZ (geo);
1024 break;
1025 case GAIA_LINESTRINGM:
1026 ParseWkbLineM (geo);
1027 break;
1028 case GAIA_LINESTRINGZM:
1029 ParseWkbLineZM (geo);
1030 break;
1031 case GAIA_POLYGON:
1032 ParseWkbPolygon (geo);
1033 break;
1034 case GAIA_POLYGONZ:
1035 case GAIA_GEOSWKB_POLYGONZ:
1036 ParseWkbPolygonZ (geo);
1037 break;
1038 case GAIA_POLYGONM:
1039 ParseWkbPolygonM (geo);
1040 break;
1041 case GAIA_POLYGONZM:
1042 ParseWkbPolygonZM (geo);
1043 break;
1044 case GAIA_COMPRESSED_LINESTRING:
1045 ParseCompressedWkbLine (geo);
1046 break;
1047 case GAIA_COMPRESSED_LINESTRINGZ:
1048 ParseCompressedWkbLineZ (geo);
1049 break;
1050 case GAIA_COMPRESSED_LINESTRINGM:
1051 ParseCompressedWkbLineM (geo);
1052 break;
1053 case GAIA_COMPRESSED_LINESTRINGZM:
1054 ParseCompressedWkbLineZM (geo);
1055 break;
1056 case GAIA_COMPRESSED_POLYGON:
1057 ParseCompressedWkbPolygon (geo);
1058 break;
1059 case GAIA_COMPRESSED_POLYGONZ:
1060 ParseCompressedWkbPolygonZ (geo);
1061 break;
1062 case GAIA_COMPRESSED_POLYGONM:
1063 ParseCompressedWkbPolygonM (geo);
1064 break;
1065 case GAIA_COMPRESSED_POLYGONZM:
1066 ParseCompressedWkbPolygonZM (geo);
1067 break;
1068 default:
1069 break;
1070 };
1071 }
1072 }
1073
1074 static gaiaGeomCollPtr
doParseTinyPointBlob(const unsigned char * blob,unsigned int size)1075 doParseTinyPointBlob (const unsigned char *blob, unsigned int size)
1076 {
1077 /* decoding from SpatiaLite TinyPoint BLOB to GEOMETRY */
1078 unsigned char pointType;
1079 int type;
1080 int little_endian;
1081 int endian_arch = gaiaEndianArch ();
1082 gaiaGeomCollPtr geo = NULL;
1083
1084 if (size < 24)
1085 return NULL; /* cannot be an internal BLOB TinyPoint geometry */
1086 if (*(blob + 0) != GAIA_MARK_START)
1087 return NULL; /* failed to recognize START signature */
1088 if (*(blob + (size - 1)) != GAIA_MARK_END)
1089 return NULL; /* failed to recognize END signature */
1090 if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
1091 little_endian = 1;
1092 else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1093 little_endian = 0;
1094 else
1095 return NULL; /* unknown encoding; nor little-endian neither big-endian */
1096
1097 pointType = *(blob + 6);
1098 geo = gaiaAllocGeomColl ();
1099 geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch);
1100 geo->endian_arch = (char) endian_arch;
1101 geo->endian = (char) little_endian;
1102 geo->blob = blob;
1103 geo->size = size;
1104 geo->offset = 7;
1105 switch (pointType)
1106 {
1107 /* setting up DimensionModel */
1108 case GAIA_TINYPOINT_XYZ:
1109 type = GAIA_POINTZ;
1110 geo->DimensionModel = GAIA_XY_Z;
1111 break;
1112 case GAIA_TINYPOINT_XYM:
1113 type = GAIA_POINTM;
1114 geo->DimensionModel = GAIA_XY_M;
1115 break;
1116 case GAIA_TINYPOINT_XYZM:
1117 type = GAIA_POINTZM;
1118 geo->DimensionModel = GAIA_XY_Z_M;
1119 break;
1120 default:
1121 type = GAIA_POINT;
1122 geo->DimensionModel = GAIA_XY;
1123 break;
1124 };
1125 switch (type)
1126 {
1127 /* parsing elementary geometries */
1128 case GAIA_POINT:
1129 ParseWkbPoint (geo);
1130 break;
1131 case GAIA_POINTZ:
1132 ParseWkbPointZ (geo);
1133 break;
1134 case GAIA_POINTM:
1135 ParseWkbPointM (geo);
1136 break;
1137 case GAIA_POINTZM:
1138 ParseWkbPointZM (geo);
1139 break;
1140 default:
1141 break;
1142 };
1143 geo->MinX = geo->FirstPoint->X;
1144 geo->MinY = geo->FirstPoint->Y;
1145 geo->MaxX = geo->FirstPoint->X;
1146 geo->MaxY = geo->FirstPoint->Y;
1147 geo->DeclaredType = GAIA_POINT;
1148 return geo;
1149 }
1150
1151 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobWkbEx(const unsigned char * blob,unsigned int size,int gpkg_mode,int gpkg_amphibious)1152 gaiaFromSpatiaLiteBlobWkbEx (const unsigned char *blob, unsigned int size,
1153 int gpkg_mode, int gpkg_amphibious)
1154 {
1155 /* decoding from SpatiaLite BLOB to GEOMETRY */
1156 int type;
1157 int little_endian;
1158 int endian_arch = gaiaEndianArch ();
1159 gaiaGeomCollPtr geo = NULL;
1160
1161 if (gpkg_amphibious || gpkg_mode)
1162 {
1163 #ifdef ENABLE_GEOPACKAGE /* GEOPACKAGE enabled: supporting GPKG geometries */
1164 if (gaiaIsValidGPB (blob, size))
1165 {
1166 geo = gaiaFromGeoPackageGeometryBlob (blob, size);
1167 if (geo != NULL)
1168 return geo;
1169 }
1170 if (gpkg_mode)
1171 return NULL; /* must accept only GPKG geometries */
1172 #else
1173 ;
1174 #endif /* end GEOPACKAGE: supporting GPKG geometries */
1175 }
1176
1177 if (size == 24 || size == 32 || size == 40)
1178 {
1179 /* testing for a possible TinyPoint BLOB */
1180 if (*(blob + 0) == GAIA_MARK_START &&
1181 (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
1182 || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1183 && *(blob + (size - 1)) == GAIA_MARK_END)
1184 return doParseTinyPointBlob (blob, size);
1185 }
1186
1187 if (size < 45)
1188 return NULL; /* cannot be an internal BLOB WKB geometry */
1189 if (*(blob + 0) != GAIA_MARK_START)
1190 return NULL; /* failed to recognize START signature */
1191 if (*(blob + (size - 1)) != GAIA_MARK_END)
1192 return NULL; /* failed to recognize END signature */
1193 if (*(blob + 38) != GAIA_MARK_MBR)
1194 return NULL; /* failed to recognize MBR signature */
1195 if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
1196 little_endian = 1;
1197 else if (*(blob + 1) == GAIA_BIG_ENDIAN)
1198 little_endian = 0;
1199 else
1200 return NULL; /* unknown encoding; nor little-endian neither big-endian */
1201 type = gaiaImport32 (blob + 39, little_endian, endian_arch);
1202 geo = gaiaAllocGeomColl ();
1203 geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch);
1204 geo->endian_arch = (char) endian_arch;
1205 geo->endian = (char) little_endian;
1206 geo->blob = blob;
1207 geo->size = size;
1208 geo->offset = 43;
1209 switch (type)
1210 {
1211 /* setting up DimensionModel */
1212 case GAIA_POINTZ:
1213 case GAIA_LINESTRINGZ:
1214 case GAIA_POLYGONZ:
1215 case GAIA_MULTIPOINTZ:
1216 case GAIA_MULTILINESTRINGZ:
1217 case GAIA_MULTIPOLYGONZ:
1218 case GAIA_GEOMETRYCOLLECTIONZ:
1219 case GAIA_COMPRESSED_LINESTRINGZ:
1220 case GAIA_COMPRESSED_POLYGONZ:
1221 geo->DimensionModel = GAIA_XY_Z;
1222 break;
1223 case GAIA_POINTM:
1224 case GAIA_LINESTRINGM:
1225 case GAIA_POLYGONM:
1226 case GAIA_MULTIPOINTM:
1227 case GAIA_MULTILINESTRINGM:
1228 case GAIA_MULTIPOLYGONM:
1229 case GAIA_GEOMETRYCOLLECTIONM:
1230 case GAIA_COMPRESSED_LINESTRINGM:
1231 case GAIA_COMPRESSED_POLYGONM:
1232 geo->DimensionModel = GAIA_XY_M;
1233 break;
1234 case GAIA_POINTZM:
1235 case GAIA_LINESTRINGZM:
1236 case GAIA_POLYGONZM:
1237 case GAIA_MULTIPOINTZM:
1238 case GAIA_MULTILINESTRINGZM:
1239 case GAIA_MULTIPOLYGONZM:
1240 case GAIA_GEOMETRYCOLLECTIONZM:
1241 case GAIA_COMPRESSED_LINESTRINGZM:
1242 case GAIA_COMPRESSED_POLYGONZM:
1243 geo->DimensionModel = GAIA_XY_Z_M;
1244 break;
1245 default:
1246 geo->DimensionModel = GAIA_XY;
1247 break;
1248 };
1249 switch (type)
1250 {
1251 /* parsing elementary geometries */
1252 case GAIA_POINT:
1253 ParseWkbPoint (geo);
1254 break;
1255 case GAIA_POINTZ:
1256 ParseWkbPointZ (geo);
1257 break;
1258 case GAIA_POINTM:
1259 ParseWkbPointM (geo);
1260 break;
1261 case GAIA_POINTZM:
1262 ParseWkbPointZM (geo);
1263 break;
1264 case GAIA_LINESTRING:
1265 ParseWkbLine (geo);
1266 break;
1267 case GAIA_LINESTRINGZ:
1268 ParseWkbLineZ (geo);
1269 break;
1270 case GAIA_LINESTRINGM:
1271 ParseWkbLineM (geo);
1272 break;
1273 case GAIA_LINESTRINGZM:
1274 ParseWkbLineZM (geo);
1275 break;
1276 case GAIA_POLYGON:
1277 ParseWkbPolygon (geo);
1278 break;
1279 case GAIA_POLYGONZ:
1280 ParseWkbPolygonZ (geo);
1281 break;
1282 case GAIA_POLYGONM:
1283 ParseWkbPolygonM (geo);
1284 break;
1285 case GAIA_POLYGONZM:
1286 ParseWkbPolygonZM (geo);
1287 break;
1288 case GAIA_COMPRESSED_LINESTRING:
1289 ParseCompressedWkbLine (geo);
1290 break;
1291 case GAIA_COMPRESSED_LINESTRINGZ:
1292 ParseCompressedWkbLineZ (geo);
1293 break;
1294 case GAIA_COMPRESSED_LINESTRINGM:
1295 ParseCompressedWkbLineM (geo);
1296 break;
1297 case GAIA_COMPRESSED_LINESTRINGZM:
1298 ParseCompressedWkbLineZM (geo);
1299 break;
1300 case GAIA_COMPRESSED_POLYGON:
1301 ParseCompressedWkbPolygon (geo);
1302 break;
1303 case GAIA_COMPRESSED_POLYGONZ:
1304 ParseCompressedWkbPolygonZ (geo);
1305 break;
1306 case GAIA_COMPRESSED_POLYGONM:
1307 ParseCompressedWkbPolygonM (geo);
1308 break;
1309 case GAIA_COMPRESSED_POLYGONZM:
1310 ParseCompressedWkbPolygonZM (geo);
1311 break;
1312 case GAIA_MULTIPOINT:
1313 case GAIA_MULTIPOINTZ:
1314 case GAIA_MULTIPOINTM:
1315 case GAIA_MULTIPOINTZM:
1316 case GAIA_MULTILINESTRING:
1317 case GAIA_MULTILINESTRINGZ:
1318 case GAIA_MULTILINESTRINGM:
1319 case GAIA_MULTILINESTRINGZM:
1320 case GAIA_MULTIPOLYGON:
1321 case GAIA_MULTIPOLYGONZ:
1322 case GAIA_MULTIPOLYGONM:
1323 case GAIA_MULTIPOLYGONZM:
1324 case GAIA_GEOMETRYCOLLECTION:
1325 case GAIA_GEOMETRYCOLLECTIONZ:
1326 case GAIA_GEOMETRYCOLLECTIONM:
1327 case GAIA_GEOMETRYCOLLECTIONZM:
1328 ParseWkbGeometry (geo, 0);
1329 break;
1330 default:
1331 break;
1332 };
1333 geo->MinX = gaiaImport64 (blob + 6, little_endian, endian_arch);
1334 geo->MinY = gaiaImport64 (blob + 14, little_endian, endian_arch);
1335 geo->MaxX = gaiaImport64 (blob + 22, little_endian, endian_arch);
1336 geo->MaxY = gaiaImport64 (blob + 30, little_endian, endian_arch);
1337 switch (type)
1338 {
1339 /* setting up DeclaredType */
1340 case GAIA_POINT:
1341 case GAIA_POINTZ:
1342 case GAIA_POINTM:
1343 case GAIA_POINTZM:
1344 geo->DeclaredType = GAIA_POINT;
1345 break;
1346 case GAIA_LINESTRING:
1347 case GAIA_LINESTRINGZ:
1348 case GAIA_LINESTRINGM:
1349 case GAIA_LINESTRINGZM:
1350 case GAIA_COMPRESSED_LINESTRING:
1351 case GAIA_COMPRESSED_LINESTRINGZ:
1352 case GAIA_COMPRESSED_LINESTRINGM:
1353 case GAIA_COMPRESSED_LINESTRINGZM:
1354 geo->DeclaredType = GAIA_LINESTRING;
1355 break;
1356 case GAIA_POLYGON:
1357 case GAIA_POLYGONZ:
1358 case GAIA_POLYGONM:
1359 case GAIA_POLYGONZM:
1360 case GAIA_COMPRESSED_POLYGON:
1361 case GAIA_COMPRESSED_POLYGONZ:
1362 case GAIA_COMPRESSED_POLYGONM:
1363 case GAIA_COMPRESSED_POLYGONZM:
1364 geo->DeclaredType = GAIA_POLYGON;
1365 break;
1366 case GAIA_MULTIPOINT:
1367 case GAIA_MULTIPOINTZ:
1368 case GAIA_MULTIPOINTM:
1369 case GAIA_MULTIPOINTZM:
1370 geo->DeclaredType = GAIA_MULTIPOINT;
1371 break;
1372 case GAIA_MULTILINESTRING:
1373 case GAIA_MULTILINESTRINGZ:
1374 case GAIA_MULTILINESTRINGM:
1375 case GAIA_MULTILINESTRINGZM:
1376 geo->DeclaredType = GAIA_MULTILINESTRING;
1377 break;
1378 case GAIA_MULTIPOLYGON:
1379 case GAIA_MULTIPOLYGONZ:
1380 case GAIA_MULTIPOLYGONM:
1381 case GAIA_MULTIPOLYGONZM:
1382 geo->DeclaredType = GAIA_MULTIPOLYGON;
1383 break;
1384 case GAIA_GEOMETRYCOLLECTION:
1385 case GAIA_GEOMETRYCOLLECTIONZ:
1386 case GAIA_GEOMETRYCOLLECTIONM:
1387 case GAIA_GEOMETRYCOLLECTIONZM:
1388 geo->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1389 break;
1390 default:
1391 geo->DeclaredType = GAIA_UNKNOWN;
1392 break;
1393 };
1394 return geo;
1395 }
1396
1397 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobWkb(const unsigned char * blob,unsigned int size)1398 gaiaFromSpatiaLiteBlobWkb (const unsigned char *blob, unsigned int size)
1399 {
1400 /*
1401 * decoding from SpatiaLite BLOB to GEOMETRY
1402 * convenience method - always disabling GPKG compatibility Modes
1403 */
1404 return gaiaFromSpatiaLiteBlobWkbEx (blob, size, 0, 0);
1405 }
1406
1407 static gaiaGeomCollPtr
doParseTinyPointBlobMbr(const unsigned char * blob,unsigned int size)1408 doParseTinyPointBlobMbr (const unsigned char *blob, unsigned int size)
1409 {
1410 /* decoding from SpatiaLite TinyPoint BLOB (MBR only) */
1411 int little_endian;
1412 int endian_arch = gaiaEndianArch ();
1413 double x;
1414 double y;
1415 gaiaGeomCollPtr geo = NULL;
1416 gaiaPolygonPtr polyg;
1417 gaiaRingPtr ring;
1418
1419 if (size < 24)
1420 return NULL; /* cannot be an internal BLOB TinyPoint geometry */
1421 if (*(blob + 0) != GAIA_MARK_START)
1422 return NULL; /* failed to recognize START signature */
1423 if (*(blob + (size - 1)) != GAIA_MARK_END)
1424 return NULL; /* failed to recognize END signature */
1425 if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
1426 little_endian = 1;
1427 else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1428 little_endian = 0;
1429 else
1430 return NULL; /* unknown encoding; nor little-endian neither big-endian */
1431
1432 x = gaiaImport64 (blob + 7, little_endian, endian_arch);
1433 y = gaiaImport64 (blob + 15, little_endian, endian_arch);
1434
1435 geo = gaiaAllocGeomColl ();
1436 polyg = gaiaAddPolygonToGeomColl (geo, 5, 0);
1437 ring = polyg->Exterior;
1438 gaiaSetPoint (ring->Coords, 0, x, y); /* vertex # 1 */
1439 gaiaSetPoint (ring->Coords, 1, x, y); /* vertex # 2 */
1440 gaiaSetPoint (ring->Coords, 2, x, y); /* vertex # 3 */
1441 gaiaSetPoint (ring->Coords, 3, x, y); /* vertex # 4 */
1442 gaiaSetPoint (ring->Coords, 4, x, y); /* vertex # 5 [same as vertex # 1 to close the polygon] */
1443 return geo;
1444 }
1445
1446 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobMbr(const unsigned char * blob,unsigned int size)1447 gaiaFromSpatiaLiteBlobMbr (const unsigned char *blob, unsigned int size)
1448 {
1449 /* decoding from SpatiaLite BLOB to GEOMETRY [MBR only] */
1450 int little_endian;
1451 int endian_arch = gaiaEndianArch ();
1452 double minx;
1453 double miny;
1454 double maxx;
1455 double maxy;
1456 gaiaGeomCollPtr geo = NULL;
1457 gaiaPolygonPtr polyg;
1458 gaiaRingPtr ring;
1459
1460 if (size == 24 || size == 32 || size == 40)
1461 {
1462 /* testing for a possible TinyPoint BLOB */
1463 if (*(blob + 0) == GAIA_MARK_START &&
1464 (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
1465 || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1466 && *(blob + (size - 1)) == GAIA_MARK_END)
1467 return doParseTinyPointBlobMbr (blob, size);
1468 }
1469 if (size < 45)
1470 return NULL; /* cannot be an internal BLOB WKB geometry */
1471 if (*(blob + 0) != GAIA_MARK_START)
1472 return NULL; /* failed to recognize START signature */
1473 if (*(blob + (size - 1)) != GAIA_MARK_END)
1474 return NULL; /* failed to recognize END signature */
1475 if (*(blob + 38) != GAIA_MARK_MBR)
1476 return NULL; /* failed to recognize MBR signature */
1477 if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
1478 little_endian = 1;
1479 else if (*(blob + 1) == GAIA_BIG_ENDIAN)
1480 little_endian = 0;
1481 else
1482 return NULL; /* unknown encoding; nor litte-endian neither big-endian */
1483 geo = gaiaAllocGeomColl ();
1484 polyg = gaiaAddPolygonToGeomColl (geo, 5, 0);
1485 ring = polyg->Exterior;
1486 minx = gaiaImport64 (blob + 6, little_endian, endian_arch);
1487 miny = gaiaImport64 (blob + 14, little_endian, endian_arch);
1488 maxx = gaiaImport64 (blob + 22, little_endian, endian_arch);
1489 maxy = gaiaImport64 (blob + 30, little_endian, endian_arch);
1490 gaiaSetPoint (ring->Coords, 0, minx, miny); /* vertex # 1 */
1491 gaiaSetPoint (ring->Coords, 1, maxx, miny); /* vertex # 2 */
1492 gaiaSetPoint (ring->Coords, 2, maxx, maxy); /* vertex # 3 */
1493 gaiaSetPoint (ring->Coords, 3, minx, maxy); /* vertex # 4 */
1494 gaiaSetPoint (ring->Coords, 4, minx, miny); /* vertex # 5 [same as vertex # 1 to close the polygon] */
1495 return geo;
1496 }
1497
1498 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkbEx(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int gpkg_mode)1499 gaiaToSpatiaLiteBlobWkbEx (gaiaGeomCollPtr geom, unsigned char **result,
1500 int *size, int gpkg_mode)
1501 {
1502 /* simply defaults to gaiaToSpatiaLiteBlobWkbEx2 tiny_point=FALSE */
1503 gaiaToSpatiaLiteBlobWkbEx2 (geom, result, size, gpkg_mode, 0);
1504 }
1505
1506 static void
doEncodeTinyPointBlob(gaiaGeomCollPtr geom,unsigned char ** result,int * size)1507 doEncodeTinyPointBlob (gaiaGeomCollPtr geom, unsigned char **result, int *size)
1508 {
1509 /* encoding a TinyPoint BLOB */
1510 int sz;
1511 unsigned char *blob;
1512 unsigned char *ptr;
1513 int endian_arch = gaiaEndianArch ();
1514 gaiaPointPtr point = geom->FirstPoint;
1515
1516 /* compunting the BLOB size */
1517 if (geom->DimensionModel == GAIA_XY_Z)
1518 sz = 32;
1519 else if (geom->DimensionModel == GAIA_XY_M)
1520 sz = 32;
1521 else if (geom->DimensionModel == GAIA_XY_Z_M)
1522 sz = 40;
1523 else
1524 sz = 24;
1525 /* allocating the BLOB */
1526 blob = malloc (sz);
1527 ptr = blob;
1528 /* and finally we build the BLOB */
1529 *ptr = GAIA_MARK_START; /* START signature */
1530 ptr++;
1531 *(ptr) = GAIA_TINYPOINT_LITTLE_ENDIAN; /* byte ordering */
1532 ptr++;
1533 gaiaExport32 (ptr, geom->Srid, 1, endian_arch); /* the SRID */
1534 ptr += 4;
1535 if (geom->DimensionModel == GAIA_XY_Z)
1536 *ptr = GAIA_TINYPOINT_XYZ;
1537 else if (geom->DimensionModel == GAIA_XY_M)
1538 *ptr = GAIA_TINYPOINT_XYM;
1539 else if (geom->DimensionModel == GAIA_XY_Z_M)
1540 *ptr = GAIA_TINYPOINT_XYZM;
1541 else
1542 *ptr = GAIA_TINYPOINT_XY;
1543 ptr++;
1544 gaiaExport64 (ptr, point->X, 1, endian_arch); /* X */
1545 ptr += 8;
1546 gaiaExport64 (ptr, point->Y, 1, endian_arch); /* Y */
1547 ptr += 8;
1548 if (geom->DimensionModel == GAIA_XY_Z)
1549 {
1550 gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */
1551 ptr += 8;
1552 }
1553 else if (geom->DimensionModel == GAIA_XY_M)
1554 {
1555 gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */
1556 ptr += 8;
1557 }
1558 else if (geom->DimensionModel == GAIA_XY_Z_M)
1559 {
1560 gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */
1561 ptr += 8;
1562 gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */
1563 ptr += 8;
1564 }
1565 *ptr = GAIA_MARK_END; /* END signature */
1566
1567 *result = blob;
1568 *size = sz;
1569 }
1570
1571 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkbEx2(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int gpkg_mode,int tiny_point)1572 gaiaToSpatiaLiteBlobWkbEx2 (gaiaGeomCollPtr geom, unsigned char **result,
1573 int *size, int gpkg_mode, int tiny_point)
1574 {
1575 /* builds the SpatiaLite BLOB representation for this GEOMETRY */
1576 int ib;
1577 int iv;
1578 double x;
1579 double y;
1580 double z = 0.0;
1581 double m = 0.0;
1582 int entities = 0;
1583 int n_points = 0;
1584 int n_linestrings = 0;
1585 int n_polygons = 0;
1586 int type;
1587 unsigned char *ptr;
1588 gaiaPointPtr pt;
1589 gaiaLinestringPtr ln;
1590 gaiaPolygonPtr pg;
1591 gaiaRingPtr rng;
1592 gaiaPointPtr point = NULL;
1593 gaiaLinestringPtr line = NULL;
1594 gaiaPolygonPtr polyg = NULL;
1595 int endian_arch = gaiaEndianArch ();
1596 gaiaMbrGeometry (geom);
1597
1598 if (gpkg_mode)
1599 {
1600 #ifdef ENABLE_GEOPACKAGE /* only if GeoPackage support is enabled */
1601 /* GeoPackage Mode enabled */
1602 gaiaToGPB (geom, result, size);
1603 #endif /* end GEOPACKAGE conditional */
1604 return;
1605 }
1606
1607 /* how many entities, and of what kind, do we have ? */
1608 pt = geom->FirstPoint;
1609 while (pt)
1610 {
1611 point = pt;
1612 entities++;
1613 n_points++;
1614 pt = pt->Next;
1615 }
1616 ln = geom->FirstLinestring;
1617 while (ln)
1618 {
1619 line = ln;
1620 entities++;
1621 n_linestrings++;
1622 ln = ln->Next;
1623 }
1624 pg = geom->FirstPolygon;
1625 while (pg)
1626 {
1627 polyg = pg;
1628 entities++;
1629 n_polygons++;
1630 pg = pg->Next;
1631 }
1632
1633 *size = 0;
1634 *result = NULL;
1635 if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
1636 return;
1637 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0 && entities == 1
1638 && geom->DeclaredType != GAIA_MULTIPOINT
1639 && geom->DeclaredType != GAIA_GEOMETRYCOLLECTION && tiny_point)
1640 {
1641 /* using the TinyPoint BLOB encoding */
1642 doEncodeTinyPointBlob (geom, result, size);
1643 return;
1644 }
1645
1646 /* ok, we can determine the geometry class */
1647 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
1648 {
1649 if (geom->DeclaredType == GAIA_MULTIPOINT)
1650 {
1651 if (geom->DimensionModel == GAIA_XY_Z)
1652 type = GAIA_MULTIPOINTZ;
1653 else if (geom->DimensionModel == GAIA_XY_M)
1654 type = GAIA_MULTIPOINTM;
1655 else if (geom->DimensionModel == GAIA_XY_Z_M)
1656 type = GAIA_MULTIPOINTZM;
1657 else
1658 type = GAIA_MULTIPOINT;
1659 }
1660 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1661 {
1662 if (geom->DimensionModel == GAIA_XY_Z)
1663 type = GAIA_GEOMETRYCOLLECTIONZ;
1664 else if (geom->DimensionModel == GAIA_XY_M)
1665 type = GAIA_GEOMETRYCOLLECTIONM;
1666 else if (geom->DimensionModel == GAIA_XY_Z_M)
1667 type = GAIA_GEOMETRYCOLLECTIONZM;
1668 else
1669 type = GAIA_GEOMETRYCOLLECTION;
1670 }
1671 else
1672 {
1673 if (geom->DimensionModel == GAIA_XY_Z)
1674 type = GAIA_POINTZ;
1675 else if (geom->DimensionModel == GAIA_XY_M)
1676 type = GAIA_POINTM;
1677 else if (geom->DimensionModel == GAIA_XY_Z_M)
1678 type = GAIA_POINTZM;
1679 else
1680 type = GAIA_POINT;
1681 }
1682 }
1683 else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
1684 {
1685 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1686 {
1687 if (geom->DimensionModel == GAIA_XY_Z)
1688 type = GAIA_GEOMETRYCOLLECTIONZ;
1689 else if (geom->DimensionModel == GAIA_XY_M)
1690 type = GAIA_GEOMETRYCOLLECTIONM;
1691 else if (geom->DimensionModel == GAIA_XY_Z_M)
1692 type = GAIA_GEOMETRYCOLLECTIONZM;
1693 else
1694 type = GAIA_GEOMETRYCOLLECTION;
1695 }
1696 else
1697 {
1698 if (geom->DimensionModel == GAIA_XY_Z)
1699 type = GAIA_MULTIPOINTZ;
1700 else if (geom->DimensionModel == GAIA_XY_M)
1701 type = GAIA_MULTIPOINTM;
1702 else if (geom->DimensionModel == GAIA_XY_Z_M)
1703 type = GAIA_MULTIPOINTZM;
1704 else
1705 type = GAIA_MULTIPOINT;
1706 }
1707 }
1708 else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
1709 {
1710 if (geom->DeclaredType == GAIA_MULTILINESTRING)
1711 {
1712 if (geom->DimensionModel == GAIA_XY_Z)
1713 type = GAIA_MULTILINESTRINGZ;
1714 else if (geom->DimensionModel == GAIA_XY_M)
1715 type = GAIA_MULTILINESTRINGM;
1716 else if (geom->DimensionModel == GAIA_XY_Z_M)
1717 type = GAIA_MULTILINESTRINGZM;
1718 else
1719 type = GAIA_MULTILINESTRING;
1720 }
1721 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1722 {
1723 if (geom->DimensionModel == GAIA_XY_Z)
1724 type = GAIA_GEOMETRYCOLLECTIONZ;
1725 else if (geom->DimensionModel == GAIA_XY_M)
1726 type = GAIA_GEOMETRYCOLLECTIONM;
1727 else if (geom->DimensionModel == GAIA_XY_Z_M)
1728 type = GAIA_GEOMETRYCOLLECTIONZM;
1729 else
1730 type = GAIA_GEOMETRYCOLLECTION;
1731 }
1732 else
1733 {
1734 if (geom->DimensionModel == GAIA_XY_Z)
1735 type = GAIA_LINESTRINGZ;
1736 else if (geom->DimensionModel == GAIA_XY_M)
1737 type = GAIA_LINESTRINGM;
1738 else if (geom->DimensionModel == GAIA_XY_Z_M)
1739 type = GAIA_LINESTRINGZM;
1740 else
1741 type = GAIA_LINESTRING;
1742 }
1743 }
1744 else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
1745 {
1746 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1747 {
1748 if (geom->DimensionModel == GAIA_XY_Z)
1749 type = GAIA_GEOMETRYCOLLECTIONZ;
1750 else if (geom->DimensionModel == GAIA_XY_M)
1751 type = GAIA_GEOMETRYCOLLECTIONM;
1752 else if (geom->DimensionModel == GAIA_XY_Z_M)
1753 type = GAIA_GEOMETRYCOLLECTIONZM;
1754 else
1755 type = GAIA_GEOMETRYCOLLECTION;
1756 }
1757 else
1758 {
1759 if (geom->DimensionModel == GAIA_XY_Z)
1760 type = GAIA_MULTILINESTRINGZ;
1761 else if (geom->DimensionModel == GAIA_XY_M)
1762 type = GAIA_MULTILINESTRINGM;
1763 else if (geom->DimensionModel == GAIA_XY_Z_M)
1764 type = GAIA_MULTILINESTRINGZM;
1765 else
1766 type = GAIA_MULTILINESTRING;
1767 }
1768 }
1769 else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
1770 {
1771 if (geom->DeclaredType == GAIA_MULTIPOLYGON)
1772 {
1773 if (geom->DimensionModel == GAIA_XY_Z)
1774 type = GAIA_MULTIPOLYGONZ;
1775 else if (geom->DimensionModel == GAIA_XY_M)
1776 type = GAIA_MULTIPOLYGONM;
1777 else if (geom->DimensionModel == GAIA_XY_Z_M)
1778 type = GAIA_MULTIPOLYGONZM;
1779 else
1780 type = GAIA_MULTIPOLYGON;
1781 }
1782 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1783 {
1784 if (geom->DimensionModel == GAIA_XY_Z)
1785 type = GAIA_GEOMETRYCOLLECTIONZ;
1786 else if (geom->DimensionModel == GAIA_XY_M)
1787 type = GAIA_GEOMETRYCOLLECTIONM;
1788 else if (geom->DimensionModel == GAIA_XY_Z_M)
1789 type = GAIA_GEOMETRYCOLLECTIONZM;
1790 else
1791 type = GAIA_GEOMETRYCOLLECTION;
1792 }
1793 else
1794 {
1795 if (geom->DimensionModel == GAIA_XY_Z)
1796 type = GAIA_POLYGONZ;
1797 else if (geom->DimensionModel == GAIA_XY_M)
1798 type = GAIA_POLYGONM;
1799 else if (geom->DimensionModel == GAIA_XY_Z_M)
1800 type = GAIA_POLYGONZM;
1801 else
1802 type = GAIA_POLYGON;
1803 }
1804 }
1805 else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
1806 {
1807 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1808 {
1809 if (geom->DimensionModel == GAIA_XY_Z)
1810 type = GAIA_GEOMETRYCOLLECTIONZ;
1811 else if (geom->DimensionModel == GAIA_XY_M)
1812 type = GAIA_GEOMETRYCOLLECTIONM;
1813 else if (geom->DimensionModel == GAIA_XY_Z_M)
1814 type = GAIA_GEOMETRYCOLLECTIONZM;
1815 else
1816 type = GAIA_GEOMETRYCOLLECTION;
1817 }
1818 else
1819 {
1820 if (geom->DimensionModel == GAIA_XY_Z)
1821 type = GAIA_MULTIPOLYGONZ;
1822 else if (geom->DimensionModel == GAIA_XY_M)
1823 type = GAIA_MULTIPOLYGONM;
1824 else if (geom->DimensionModel == GAIA_XY_Z_M)
1825 type = GAIA_MULTIPOLYGONZM;
1826 else
1827 type = GAIA_MULTIPOLYGON;
1828 }
1829 }
1830 else
1831 {
1832 if (geom->DimensionModel == GAIA_XY_Z)
1833 type = GAIA_GEOMETRYCOLLECTIONZ;
1834 else if (geom->DimensionModel == GAIA_XY_M)
1835 type = GAIA_GEOMETRYCOLLECTIONM;
1836 else if (geom->DimensionModel == GAIA_XY_Z_M)
1837 type = GAIA_GEOMETRYCOLLECTIONZM;
1838 else
1839 type = GAIA_GEOMETRYCOLLECTION;
1840 }
1841 /* and now we compute the size of BLOB */
1842 *size = 44; /* header size */
1843 switch (type)
1844 {
1845 case GAIA_POINT:
1846 *size += (sizeof (double) * 2); /* [x,y] coords */
1847 break;
1848 case GAIA_POINTZ:
1849 *size += (sizeof (double) * 3); /* [x,y,z] coords */
1850 break;
1851 case GAIA_POINTM:
1852 *size += (sizeof (double) * 3); /* [x,y,m] coords */
1853 break;
1854 case GAIA_POINTZM:
1855 *size += (sizeof (double) * 4); /* [x,y,z,m] coords */
1856 break;
1857 case GAIA_LINESTRING:
1858 *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */
1859 break;
1860 case GAIA_LINESTRINGZ:
1861 *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */
1862 break;
1863 case GAIA_LINESTRINGM:
1864 *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,m] for each vertex */
1865 break;
1866 case GAIA_LINESTRINGZM:
1867 *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */
1868 break;
1869 case GAIA_POLYGON:
1870 rng = polyg->Exterior;
1871 *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x.y] array - exterior ring */
1872 for (ib = 0; ib < polyg->NumInteriors; ib++)
1873 {
1874 rng = polyg->Interiors + ib;
1875 *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */
1876 }
1877 break;
1878 case GAIA_POLYGONZ:
1879 rng = polyg->Exterior;
1880 *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */
1881 for (ib = 0; ib < polyg->NumInteriors; ib++)
1882 {
1883 rng = polyg->Interiors + ib;
1884 *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */
1885 }
1886 break;
1887 case GAIA_POLYGONM:
1888 rng = polyg->Exterior;
1889 *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,m] array - exterior ring */
1890 for (ib = 0; ib < polyg->NumInteriors; ib++)
1891 {
1892 rng = polyg->Interiors + ib;
1893 *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,m] array - interior ring */
1894 }
1895 break;
1896 case GAIA_POLYGONZM:
1897 rng = polyg->Exterior;
1898 *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */
1899 for (ib = 0; ib < polyg->NumInteriors; ib++)
1900 {
1901 rng = polyg->Interiors + ib;
1902 *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */
1903 }
1904 break;
1905 default:
1906 /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */
1907 *size += 4; /* # entities */
1908 point = geom->FirstPoint;
1909 while (point)
1910 {
1911 *size += 5; /* entity header */
1912 if (geom->DimensionModel == GAIA_XY_Z
1913 || geom->DimensionModel == GAIA_XY_M)
1914 *size += (sizeof (double) * 3); /* three doubles for each POINT */
1915 else if (geom->DimensionModel == GAIA_XY_Z_M)
1916 *size += (sizeof (double) * 4); /* four doubles for each POINT */
1917 else
1918 *size += (sizeof (double) * 2); /* two doubles for each POINT */
1919 point = point->Next;
1920 }
1921 line = geom->FirstLinestring;
1922 while (line)
1923 {
1924 *size += 5; /* entity header */
1925 if (geom->DimensionModel == GAIA_XY_Z
1926 || geom->DimensionModel == GAIA_XY_M)
1927 *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */
1928 else if (geom->DimensionModel == GAIA_XY_Z_M)
1929 *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */
1930 else
1931 *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */
1932 line = line->Next;
1933 }
1934 polyg = geom->FirstPolygon;
1935 while (polyg)
1936 {
1937 *size += 5; /* entity header */
1938 rng = polyg->Exterior;
1939 if (geom->DimensionModel == GAIA_XY_Z
1940 || geom->DimensionModel == GAIA_XY_M)
1941 *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */
1942 else if (geom->DimensionModel == GAIA_XY_Z_M)
1943 *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */
1944 else
1945 *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x,y] array - exterior ring */
1946 for (ib = 0; ib < polyg->NumInteriors; ib++)
1947 {
1948 rng = polyg->Interiors + ib;
1949 if (geom->DimensionModel == GAIA_XY_Z
1950 || geom->DimensionModel == GAIA_XY_M)
1951 *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */
1952 else if (geom->DimensionModel == GAIA_XY_Z_M)
1953 *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */
1954 else
1955 *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */
1956 }
1957 polyg = polyg->Next;
1958 }
1959 };
1960 *result = malloc (*size);
1961 ptr = *result;
1962 /* and finally we build the BLOB */
1963 switch (type)
1964 {
1965 case GAIA_POINT:
1966 *ptr = GAIA_MARK_START; /* START signature */
1967 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
1968 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
1969 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
1970 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
1971 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
1972 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
1973 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
1974 gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch); /* class POINT */
1975 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
1976 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
1977 *(ptr + 59) = GAIA_MARK_END; /* END signature */
1978 break;
1979 case GAIA_POINTZ:
1980 *ptr = GAIA_MARK_START; /* START signature */
1981 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
1982 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
1983 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
1984 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
1985 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
1986 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
1987 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
1988 gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */
1989 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
1990 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
1991 gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* Z */
1992 *(ptr + 67) = GAIA_MARK_END; /* END signature */
1993 break;
1994 case GAIA_POINTM:
1995 *ptr = GAIA_MARK_START; /* START signature */
1996 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
1997 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
1998 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
1999 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2000 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2001 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2002 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2003 gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */
2004 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2005 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2006 gaiaExport64 (ptr + 59, point->M, 1, endian_arch); /* M */
2007 *(ptr + 67) = GAIA_MARK_END; /* END signature */
2008 break;
2009 case GAIA_POINTZM:
2010 *ptr = GAIA_MARK_START; /* START signature */
2011 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2012 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2013 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2014 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2015 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2016 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2017 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2018 gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */
2019 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2020 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2021 gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* M */
2022 gaiaExport64 (ptr + 67, point->M, 1, endian_arch); /* Z */
2023 *(ptr + 75) = GAIA_MARK_END; /* END signature */
2024 break;
2025 case GAIA_LINESTRING:
2026 *ptr = GAIA_MARK_START; /* START signature */
2027 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2028 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2029 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2030 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2031 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2032 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2033 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2034 gaiaExport32 (ptr + 39, GAIA_LINESTRING, 1, endian_arch); /* class LINESTRING */
2035 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2036 ptr += 47;
2037 for (iv = 0; iv < line->Points; iv++)
2038 {
2039 gaiaGetPoint (line->Coords, iv, &x, &y);
2040 gaiaExport64 (ptr, x, 1, endian_arch);
2041 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2042 ptr += 16;
2043 }
2044 *ptr = GAIA_MARK_END; /* END signature */
2045 break;
2046 case GAIA_LINESTRINGZ:
2047 *ptr = GAIA_MARK_START; /* START signature */
2048 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2049 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2050 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2051 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2052 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2053 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2054 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2055 gaiaExport32 (ptr + 39, GAIA_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */
2056 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2057 ptr += 47;
2058 for (iv = 0; iv < line->Points; iv++)
2059 {
2060 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2061 gaiaExport64 (ptr, x, 1, endian_arch);
2062 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2063 gaiaExport64 (ptr + 16, z, 1, endian_arch);
2064 ptr += 24;
2065 }
2066 *ptr = GAIA_MARK_END; /* END signature */
2067 break;
2068 case GAIA_LINESTRINGM:
2069 *ptr = GAIA_MARK_START; /* START signature */
2070 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2071 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2072 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2073 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2074 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2075 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2076 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2077 gaiaExport32 (ptr + 39, GAIA_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */
2078 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2079 ptr += 47;
2080 for (iv = 0; iv < line->Points; iv++)
2081 {
2082 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2083 gaiaExport64 (ptr, x, 1, endian_arch);
2084 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2085 gaiaExport64 (ptr + 16, m, 1, endian_arch);
2086 ptr += 24;
2087 }
2088 *ptr = GAIA_MARK_END; /* END signature */
2089 break;
2090 case GAIA_LINESTRINGZM:
2091 *ptr = GAIA_MARK_START; /* START signature */
2092 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2093 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2094 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2095 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2096 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2097 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2098 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2099 gaiaExport32 (ptr + 39, GAIA_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */
2100 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2101 ptr += 47;
2102 for (iv = 0; iv < line->Points; iv++)
2103 {
2104 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2105 gaiaExport64 (ptr, x, 1, endian_arch);
2106 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2107 gaiaExport64 (ptr + 16, z, 1, endian_arch);
2108 gaiaExport64 (ptr + 24, m, 1, endian_arch);
2109 ptr += 32;
2110 }
2111 *ptr = GAIA_MARK_END; /* END signature */
2112 break;
2113 case GAIA_POLYGON:
2114 *ptr = GAIA_MARK_START; /* START signature */
2115 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2116 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2117 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2118 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2119 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2120 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2121 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2122 gaiaExport32 (ptr + 39, GAIA_POLYGON, 1, endian_arch); /* class POLYGON */
2123 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
2124 rng = polyg->Exterior;
2125 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
2126 ptr += 51;
2127 for (iv = 0; iv < rng->Points; iv++)
2128 {
2129 gaiaGetPoint (rng->Coords, iv, &x, &y);
2130 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
2131 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
2132 ptr += 16;
2133 }
2134 for (ib = 0; ib < polyg->NumInteriors; ib++)
2135 {
2136 rng = polyg->Interiors + ib;
2137 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
2138 ptr += 4;
2139 for (iv = 0; iv < rng->Points; iv++)
2140 {
2141 gaiaGetPoint (rng->Coords, iv, &x, &y);
2142 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
2143 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
2144 ptr += 16;
2145 }
2146 }
2147 *ptr = GAIA_MARK_END; /* END signature */
2148 break;
2149 case GAIA_POLYGONZ:
2150 *ptr = GAIA_MARK_START; /* START signature */
2151 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2152 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2153 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2154 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2155 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2156 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2157 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2158 gaiaExport32 (ptr + 39, GAIA_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */
2159 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
2160 rng = polyg->Exterior;
2161 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
2162 ptr += 51;
2163 for (iv = 0; iv < rng->Points; iv++)
2164 {
2165 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2166 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
2167 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
2168 gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */
2169 ptr += 24;
2170 }
2171 for (ib = 0; ib < polyg->NumInteriors; ib++)
2172 {
2173 rng = polyg->Interiors + ib;
2174 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
2175 ptr += 4;
2176 for (iv = 0; iv < rng->Points; iv++)
2177 {
2178 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2179 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
2180 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
2181 gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - interior ring */
2182 ptr += 24;
2183 }
2184 }
2185 *ptr = GAIA_MARK_END; /* END signature */
2186 break;
2187 case GAIA_POLYGONM:
2188 *ptr = GAIA_MARK_START; /* START signature */
2189 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2190 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2191 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2192 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2193 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2194 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2195 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2196 gaiaExport32 (ptr + 39, GAIA_POLYGONM, 1, endian_arch); /* class POLYGON XYM */
2197 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
2198 rng = polyg->Exterior;
2199 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
2200 ptr += 51;
2201 for (iv = 0; iv < rng->Points; iv++)
2202 {
2203 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2204 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
2205 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
2206 gaiaExport64 (ptr + 16, m, 1, endian_arch); /* M - exterior ring */
2207 ptr += 24;
2208 }
2209 for (ib = 0; ib < polyg->NumInteriors; ib++)
2210 {
2211 rng = polyg->Interiors + ib;
2212 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
2213 ptr += 4;
2214 for (iv = 0; iv < rng->Points; iv++)
2215 {
2216 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2217 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
2218 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
2219 gaiaExport64 (ptr + 16, m, 1, endian_arch); /* M - interior ring */
2220 ptr += 24;
2221 }
2222 }
2223 *ptr = GAIA_MARK_END; /* END signature */
2224 break;
2225 case GAIA_POLYGONZM:
2226 *ptr = GAIA_MARK_START; /* START signature */
2227 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2228 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2229 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2230 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2231 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2232 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2233 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2234 gaiaExport32 (ptr + 39, GAIA_POLYGONZM, 1, endian_arch); /* class POLYGON */
2235 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
2236 rng = polyg->Exterior;
2237 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
2238 ptr += 51;
2239 for (iv = 0; iv < rng->Points; iv++)
2240 {
2241 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2242 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
2243 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
2244 gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */
2245 gaiaExport64 (ptr + 24, m, 1, endian_arch); /* M - exterior ring */
2246 ptr += 32;
2247 }
2248 for (ib = 0; ib < polyg->NumInteriors; ib++)
2249 {
2250 rng = polyg->Interiors + ib;
2251 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
2252 ptr += 4;
2253 for (iv = 0; iv < rng->Points; iv++)
2254 {
2255 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2256 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
2257 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
2258 gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */
2259 gaiaExport64 (ptr + 24, m, 1, endian_arch); /* M - exterior ring */
2260 ptr += 32;
2261 }
2262 }
2263 *ptr = GAIA_MARK_END; /* END signature */
2264 break;
2265 default:
2266 /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */
2267 *ptr = GAIA_MARK_START; /* START signature */
2268 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2269 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2270 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2271 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2272 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2273 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2274 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2275 gaiaExport32 (ptr + 39, type, 1, endian_arch); /* geometric class */
2276 gaiaExport32 (ptr + 43, entities, 1, endian_arch); /* # entities */
2277 ptr += 47;
2278 point = geom->FirstPoint;
2279 while (point)
2280 {
2281 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
2282 if (geom->DimensionModel == GAIA_XY_Z)
2283 {
2284 gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */
2285 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
2286 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
2287 gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */
2288 ptr += 29;
2289 }
2290 else if (geom->DimensionModel == GAIA_XY_M)
2291 {
2292 gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */
2293 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
2294 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
2295 gaiaExport64 (ptr + 21, point->M, 1, endian_arch); /* M */
2296 ptr += 29;
2297 }
2298 else if (geom->DimensionModel == GAIA_XY_Z_M)
2299 {
2300 gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */
2301 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
2302 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
2303 gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */
2304 gaiaExport64 (ptr + 29, point->M, 1, endian_arch); /* M */
2305 ptr += 37;
2306 }
2307 else
2308 {
2309 gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch); /* class POINT */
2310 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
2311 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
2312 ptr += 21;
2313 }
2314 point = point->Next;
2315 }
2316 line = geom->FirstLinestring;
2317 while (line)
2318 {
2319 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
2320 if (geom->DimensionModel == GAIA_XY_Z)
2321 gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */
2322 else if (geom->DimensionModel == GAIA_XY_M)
2323 gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */
2324 else if (geom->DimensionModel == GAIA_XY_Z_M)
2325 gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */
2326 else
2327 gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch); /* class LINESTRING */
2328 gaiaExport32 (ptr + 5, line->Points, 1, endian_arch); /* # points */
2329 ptr += 9;
2330 for (iv = 0; iv < line->Points; iv++)
2331 {
2332 if (geom->DimensionModel == GAIA_XY_Z)
2333 {
2334 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2335 }
2336 else if (geom->DimensionModel == GAIA_XY_M)
2337 {
2338 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2339 }
2340 else if (geom->DimensionModel == GAIA_XY_Z_M)
2341 {
2342 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2343 }
2344 else
2345 {
2346 gaiaGetPoint (line->Coords, iv, &x, &y);
2347 }
2348 gaiaExport64 (ptr, x, 1, endian_arch); /* X */
2349 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */
2350 ptr += 16;
2351 if (geom->DimensionModel == GAIA_XY_Z)
2352 {
2353 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2354 ptr += 8;
2355 }
2356 if (geom->DimensionModel == GAIA_XY_M)
2357 {
2358 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
2359 ptr += 8;
2360 }
2361 if (geom->DimensionModel == GAIA_XY_Z_M)
2362 {
2363 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2364 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */
2365 ptr += 16;
2366 }
2367 }
2368 line = line->Next;
2369 }
2370 polyg = geom->FirstPolygon;
2371 while (polyg)
2372 {
2373 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
2374 if (geom->DimensionModel == GAIA_XY_Z)
2375 gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */
2376 else if (geom->DimensionModel == GAIA_XY_M)
2377 gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch); /* class POLYGON XYM */
2378 else if (geom->DimensionModel == GAIA_XY_Z_M)
2379 gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch); /* class POLYGON XYZM */
2380 else
2381 gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch); /* class POLYGON */
2382 gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
2383 rng = polyg->Exterior;
2384 gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch); /* # points - exterior ring */
2385 ptr += 13;
2386 for (iv = 0; iv < rng->Points; iv++)
2387 {
2388 if (geom->DimensionModel == GAIA_XY_Z)
2389 {
2390 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2391 }
2392 else if (geom->DimensionModel == GAIA_XY_M)
2393 {
2394 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2395 }
2396 else if (geom->DimensionModel == GAIA_XY_Z_M)
2397 {
2398 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2399 }
2400 else
2401 {
2402 gaiaGetPoint (rng->Coords, iv, &x, &y);
2403 }
2404 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
2405 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
2406 ptr += 16;
2407 if (geom->DimensionModel == GAIA_XY_Z)
2408 {
2409 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2410 ptr += 8;
2411 }
2412 if (geom->DimensionModel == GAIA_XY_M)
2413 {
2414 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
2415 ptr += 8;
2416 }
2417 if (geom->DimensionModel == GAIA_XY_Z_M)
2418 {
2419 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2420 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */
2421 ptr += 16;
2422 }
2423 }
2424 for (ib = 0; ib < polyg->NumInteriors; ib++)
2425 {
2426 rng = polyg->Interiors + ib;
2427 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
2428 ptr += 4;
2429 for (iv = 0; iv < rng->Points; iv++)
2430 {
2431 if (geom->DimensionModel == GAIA_XY_Z)
2432 {
2433 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2434 }
2435 else if (geom->DimensionModel == GAIA_XY_M)
2436 {
2437 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2438 }
2439 else if (geom->DimensionModel == GAIA_XY_Z_M)
2440 {
2441 gaiaGetPointXYZM (rng->Coords, iv, &x, &y,
2442 &z, &m);
2443 }
2444 else
2445 {
2446 gaiaGetPoint (rng->Coords, iv, &x, &y);
2447 }
2448 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
2449 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
2450 ptr += 16;
2451 if (geom->DimensionModel == GAIA_XY_Z)
2452 {
2453 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2454 ptr += 8;
2455 }
2456 if (geom->DimensionModel == GAIA_XY_M)
2457 {
2458 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
2459 ptr += 8;
2460 }
2461 if (geom->DimensionModel == GAIA_XY_Z_M)
2462 {
2463 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
2464 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */
2465 ptr += 16;
2466 }
2467 }
2468 }
2469 polyg = polyg->Next;
2470 }
2471 *ptr = GAIA_MARK_END; /* END signature */
2472 };
2473 }
2474
2475 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)2476 gaiaToSpatiaLiteBlobWkb (gaiaGeomCollPtr geom, unsigned char **result,
2477 int *size)
2478 {
2479 /*
2480 * builds the SpatiaLite BLOB representation for this GEOMETRY
2481 * convenience method - always disabling GPKG compatibility Modes
2482 */
2483 gaiaToSpatiaLiteBlobWkbEx (geom, result, size, 0);
2484 }
2485
2486 GAIAGEO_DECLARE void
gaiaToCompressedBlobWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)2487 gaiaToCompressedBlobWkb (gaiaGeomCollPtr geom, unsigned char **result,
2488 int *size)
2489 {
2490 /*
2491 / builds the SpatiaLite BLOB representation for this GEOMETRY
2492 / geometry-compression will be applied to LINESTRINGs and RINGs
2493 */
2494 int ib;
2495 int iv;
2496 double x;
2497 double y;
2498 double z;
2499 double m;
2500 double last_x = 0.0;
2501 double last_y = 0.0;
2502 double last_z = 0.0;
2503 float fx;
2504 float fy;
2505 float fz;
2506 int entities = 0;
2507 int n_points = 0;
2508 int n_linestrings = 0;
2509 int n_polygons = 0;
2510 int type;
2511 unsigned char *ptr;
2512 gaiaPointPtr pt;
2513 gaiaLinestringPtr ln;
2514 gaiaPolygonPtr pg;
2515 gaiaRingPtr rng;
2516 gaiaPointPtr point = NULL;
2517 gaiaLinestringPtr line = NULL;
2518 gaiaPolygonPtr polyg = NULL;
2519 int endian_arch = gaiaEndianArch ();
2520 gaiaMbrGeometry (geom);
2521 /* how many entities, and of what kind, do we have ? */
2522 pt = geom->FirstPoint;
2523 while (pt)
2524 {
2525 point = pt;
2526 entities++;
2527 n_points++;
2528 pt = pt->Next;
2529 }
2530 ln = geom->FirstLinestring;
2531 while (ln)
2532 {
2533 line = ln;
2534 entities++;
2535 n_linestrings++;
2536 ln = ln->Next;
2537 }
2538 pg = geom->FirstPolygon;
2539 while (pg)
2540 {
2541 polyg = pg;
2542 entities++;
2543 n_polygons++;
2544 pg = pg->Next;
2545 }
2546 *size = 0;
2547 *result = NULL;
2548 if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
2549 return;
2550 /* ok, we can determine the geometry class */
2551 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
2552 {
2553 if (geom->DeclaredType == GAIA_MULTIPOINT)
2554 {
2555 if (geom->DimensionModel == GAIA_XY_Z)
2556 type = GAIA_MULTIPOINTZ;
2557 else if (geom->DimensionModel == GAIA_XY_M)
2558 type = GAIA_MULTIPOINTM;
2559 else if (geom->DimensionModel == GAIA_XY_Z_M)
2560 type = GAIA_MULTIPOINTZM;
2561 else
2562 type = GAIA_MULTIPOINT;
2563 }
2564 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2565 {
2566 if (geom->DimensionModel == GAIA_XY_Z)
2567 type = GAIA_GEOMETRYCOLLECTIONZ;
2568 else if (geom->DimensionModel == GAIA_XY_M)
2569 type = GAIA_GEOMETRYCOLLECTIONM;
2570 else if (geom->DimensionModel == GAIA_XY_Z_M)
2571 type = GAIA_GEOMETRYCOLLECTIONZM;
2572 else
2573 type = GAIA_GEOMETRYCOLLECTION;
2574 }
2575 else
2576 {
2577 if (geom->DimensionModel == GAIA_XY_Z)
2578 type = GAIA_POINTZ;
2579 else if (geom->DimensionModel == GAIA_XY_M)
2580 type = GAIA_POINTM;
2581 else if (geom->DimensionModel == GAIA_XY_Z_M)
2582 type = GAIA_POINTZM;
2583 else
2584 type = GAIA_POINT;
2585 }
2586 }
2587 else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
2588 {
2589 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2590 {
2591 if (geom->DimensionModel == GAIA_XY_Z)
2592 type = GAIA_GEOMETRYCOLLECTIONZ;
2593 else if (geom->DimensionModel == GAIA_XY_M)
2594 type = GAIA_GEOMETRYCOLLECTIONM;
2595 else if (geom->DimensionModel == GAIA_XY_Z_M)
2596 type = GAIA_GEOMETRYCOLLECTIONZM;
2597 else
2598 type = GAIA_GEOMETRYCOLLECTION;
2599 }
2600 else
2601 {
2602 if (geom->DimensionModel == GAIA_XY_Z)
2603 type = GAIA_MULTIPOINTZ;
2604 else if (geom->DimensionModel == GAIA_XY_M)
2605 type = GAIA_MULTIPOINTM;
2606 else if (geom->DimensionModel == GAIA_XY_Z_M)
2607 type = GAIA_MULTIPOINTZM;
2608 else
2609 type = GAIA_MULTIPOINT;
2610 }
2611 }
2612 else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
2613 {
2614 if (geom->DeclaredType == GAIA_MULTILINESTRING)
2615 {
2616 if (geom->DimensionModel == GAIA_XY_Z)
2617 type = GAIA_MULTILINESTRINGZ;
2618 else if (geom->DimensionModel == GAIA_XY_M)
2619 type = GAIA_MULTILINESTRINGM;
2620 else if (geom->DimensionModel == GAIA_XY_Z_M)
2621 type = GAIA_MULTILINESTRINGZM;
2622 else
2623 type = GAIA_MULTILINESTRING;
2624 }
2625 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2626 {
2627 if (geom->DimensionModel == GAIA_XY_Z)
2628 type = GAIA_GEOMETRYCOLLECTIONZ;
2629 else if (geom->DimensionModel == GAIA_XY_M)
2630 type = GAIA_GEOMETRYCOLLECTIONM;
2631 else if (geom->DimensionModel == GAIA_XY_Z_M)
2632 type = GAIA_GEOMETRYCOLLECTIONZM;
2633 else
2634 type = GAIA_GEOMETRYCOLLECTION;
2635 }
2636 else
2637 {
2638 if (geom->DimensionModel == GAIA_XY_Z)
2639 type = GAIA_LINESTRINGZ;
2640 else if (geom->DimensionModel == GAIA_XY_M)
2641 type = GAIA_LINESTRINGM;
2642 else if (geom->DimensionModel == GAIA_XY_Z_M)
2643 type = GAIA_LINESTRINGZM;
2644 else
2645 type = GAIA_LINESTRING;
2646 }
2647 }
2648 else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
2649 {
2650 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2651 {
2652 if (geom->DimensionModel == GAIA_XY_Z)
2653 type = GAIA_GEOMETRYCOLLECTIONZ;
2654 else if (geom->DimensionModel == GAIA_XY_M)
2655 type = GAIA_GEOMETRYCOLLECTIONM;
2656 else if (geom->DimensionModel == GAIA_XY_Z_M)
2657 type = GAIA_GEOMETRYCOLLECTIONZM;
2658 else
2659 type = GAIA_GEOMETRYCOLLECTION;
2660 }
2661 else
2662 {
2663 if (geom->DimensionModel == GAIA_XY_Z)
2664 type = GAIA_MULTILINESTRINGZ;
2665 else if (geom->DimensionModel == GAIA_XY_M)
2666 type = GAIA_MULTILINESTRINGM;
2667 else if (geom->DimensionModel == GAIA_XY_Z_M)
2668 type = GAIA_MULTILINESTRINGZM;
2669 else
2670 type = GAIA_MULTILINESTRING;
2671 }
2672 }
2673 else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
2674 {
2675 if (geom->DeclaredType == GAIA_MULTIPOLYGON)
2676 {
2677 if (geom->DimensionModel == GAIA_XY_Z)
2678 type = GAIA_MULTIPOLYGONZ;
2679 else if (geom->DimensionModel == GAIA_XY_M)
2680 type = GAIA_MULTIPOLYGONM;
2681 else if (geom->DimensionModel == GAIA_XY_Z_M)
2682 type = GAIA_MULTIPOLYGONZM;
2683 else
2684 type = GAIA_MULTIPOLYGON;
2685 }
2686 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2687 {
2688 if (geom->DimensionModel == GAIA_XY_Z)
2689 type = GAIA_GEOMETRYCOLLECTIONZ;
2690 else if (geom->DimensionModel == GAIA_XY_M)
2691 type = GAIA_GEOMETRYCOLLECTIONM;
2692 else if (geom->DimensionModel == GAIA_XY_Z_M)
2693 type = GAIA_GEOMETRYCOLLECTIONZM;
2694 else
2695 type = GAIA_GEOMETRYCOLLECTION;
2696 }
2697 else
2698 {
2699 if (geom->DimensionModel == GAIA_XY_Z)
2700 type = GAIA_POLYGONZ;
2701 else if (geom->DimensionModel == GAIA_XY_M)
2702 type = GAIA_POLYGONM;
2703 else if (geom->DimensionModel == GAIA_XY_Z_M)
2704 type = GAIA_POLYGONZM;
2705 else
2706 type = GAIA_POLYGON;
2707 }
2708 }
2709 else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
2710 {
2711 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2712 {
2713 if (geom->DimensionModel == GAIA_XY_Z)
2714 type = GAIA_GEOMETRYCOLLECTIONZ;
2715 else if (geom->DimensionModel == GAIA_XY_M)
2716 type = GAIA_GEOMETRYCOLLECTIONM;
2717 else if (geom->DimensionModel == GAIA_XY_Z_M)
2718 type = GAIA_GEOMETRYCOLLECTIONZM;
2719 else
2720 type = GAIA_GEOMETRYCOLLECTION;
2721 }
2722 else
2723 {
2724 if (geom->DimensionModel == GAIA_XY_Z)
2725 type = GAIA_MULTIPOLYGONZ;
2726 else if (geom->DimensionModel == GAIA_XY_M)
2727 type = GAIA_MULTIPOLYGONM;
2728 else if (geom->DimensionModel == GAIA_XY_Z_M)
2729 type = GAIA_MULTIPOLYGONZM;
2730 else
2731 type = GAIA_MULTIPOLYGON;
2732 }
2733 }
2734 else
2735 {
2736 if (geom->DimensionModel == GAIA_XY_Z)
2737 type = GAIA_GEOMETRYCOLLECTIONZ;
2738 else if (geom->DimensionModel == GAIA_XY_M)
2739 type = GAIA_GEOMETRYCOLLECTIONM;
2740 else if (geom->DimensionModel == GAIA_XY_Z_M)
2741 type = GAIA_GEOMETRYCOLLECTIONZM;
2742 else
2743 type = GAIA_GEOMETRYCOLLECTION;
2744 }
2745 /* and now we compute the size of BLOB */
2746 *size = 44; /* header size */
2747 switch (type)
2748 {
2749 case GAIA_POINT:
2750 *size += (sizeof (double) * 2); /* [x,y] coords */
2751 break;
2752 case GAIA_POINTZ:
2753 *size += (sizeof (double) * 3); /* [x,y,z] coords */
2754 break;
2755 case GAIA_POINTM:
2756 *size += (sizeof (double) * 3); /* [x,y,m] coords */
2757 break;
2758 case GAIA_POINTZM:
2759 *size += (sizeof (double) * 4); /* [x,y,z,m] coords */
2760 break;
2761 case GAIA_LINESTRING:
2762 *size += (4 + (8 * line->Points) + 16); /* # points + [x,y] for each vertex */
2763 break;
2764 case GAIA_LINESTRINGZ:
2765 *size += (4 + (12 * line->Points) + 24); /* # points + [x,y,z] for each vertex */
2766 break;
2767 case GAIA_LINESTRINGM:
2768 *size += (4 + (16 * line->Points) + 16); /* # points + [x,y,m] for each vertex */
2769 break;
2770 case GAIA_LINESTRINGZM:
2771 *size += (4 + (20 * line->Points) + 24); /* # points + [x,y,z,m] for each vertex */
2772 break;
2773 case GAIA_POLYGON:
2774 rng = polyg->Exterior;
2775 *size += (8 + (8 * rng->Points) + 16); /* # rings + # points + [x.y] array - exterior ring */
2776 for (ib = 0; ib < polyg->NumInteriors; ib++)
2777 {
2778 rng = polyg->Interiors + ib;
2779 *size += (4 + (8 * rng->Points) + 16); /* # points + [x,y] array - interior ring */
2780 }
2781 break;
2782 case GAIA_POLYGONZ:
2783 rng = polyg->Exterior;
2784 *size += (8 + (12 * rng->Points) + 24); /* # rings + # points + [x,y,z] array - exterior ring */
2785 for (ib = 0; ib < polyg->NumInteriors; ib++)
2786 {
2787 rng = polyg->Interiors + ib;
2788 *size += (4 + (12 * rng->Points) + 24); /* # points + [x,y,z] array - interior ring */
2789 }
2790 break;
2791 case GAIA_POLYGONM:
2792 rng = polyg->Exterior;
2793 *size += (8 + (16 * rng->Points) + 16); /* # rings + # points + [x,y,m] array - exterior ring */
2794 for (ib = 0; ib < polyg->NumInteriors; ib++)
2795 {
2796 rng = polyg->Interiors + ib;
2797 *size += (4 + (16 * rng->Points) + 16); /* # points + [x,y,m] array - interior ring */
2798 }
2799 break;
2800 case GAIA_POLYGONZM:
2801 rng = polyg->Exterior;
2802 *size += (8 + (20 * rng->Points) + 24); /* # rings + # points + [x,y,z,m] array - exterior ring */
2803 for (ib = 0; ib < polyg->NumInteriors; ib++)
2804 {
2805 rng = polyg->Interiors + ib;
2806 *size += (4 + (20 * rng->Points) + 24); /* # points + [x,y,z,m] array - interior ring */
2807 }
2808 break;
2809 default:
2810 /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */
2811 *size += 4; /* # entities */
2812 point = geom->FirstPoint;
2813 while (point)
2814 {
2815 *size += 5; /* entity header */
2816 if (geom->DimensionModel == GAIA_XY_Z
2817 || geom->DimensionModel == GAIA_XY_M)
2818 *size += (sizeof (double) * 3); /* three doubles for each POINT */
2819 else if (geom->DimensionModel == GAIA_XY_Z_M)
2820 *size += (sizeof (double) * 4); /* four doubles for each POINT */
2821 else
2822 *size += (sizeof (double) * 2); /* two doubles for each POINT */
2823 point = point->Next;
2824 }
2825 line = geom->FirstLinestring;
2826 while (line)
2827 {
2828 *size += 5; /* entity header */
2829 if (geom->DimensionModel == GAIA_XY_Z)
2830 *size += (4 + (12 * line->Points) + 24); /* # points + [x,y,z] for each vertex */
2831 else if (geom->DimensionModel == GAIA_XY_M)
2832 *size += (4 + (16 * line->Points) + 16); /* # points + [x,y,m] for each vertex */
2833 else if (geom->DimensionModel == GAIA_XY_Z_M)
2834 *size += (4 + (20 * line->Points) + 24); /* # points + [x,y,z,m] for each vertex */
2835 else
2836 *size += (4 + (8 * line->Points) + 16); /* # points + [x,y] for each vertex */
2837 line = line->Next;
2838 }
2839 polyg = geom->FirstPolygon;
2840 while (polyg)
2841 {
2842 *size += 5; /* entity header */
2843 rng = polyg->Exterior;
2844 if (geom->DimensionModel == GAIA_XY_Z)
2845 *size += (8 + (12 * rng->Points) + 24); /* # rings + # points + [x,y,z] array - exterior ring */
2846 else if (geom->DimensionModel == GAIA_XY_M)
2847 *size += (8 + (16 * rng->Points) + 16); /* # rings + # points + [x,y,m] array - exterior ring */
2848 else if (geom->DimensionModel == GAIA_XY_Z_M)
2849 *size += (8 + (20 * rng->Points) + 24); /* # rings + # points + [x,y,z,m] array - exterior ring */
2850 else
2851 *size += (8 + (8 * rng->Points) + 16); /* # rings + # points + [x,y] array - exterior ring */
2852 for (ib = 0; ib < polyg->NumInteriors; ib++)
2853 {
2854 rng = polyg->Interiors + ib;
2855 if (geom->DimensionModel == GAIA_XY_Z)
2856 *size += (4 + (12 * rng->Points) + 24); /* # points + [x,y,z] array - interior ring */
2857 else if (geom->DimensionModel == GAIA_XY_M)
2858 *size += (4 + (16 * rng->Points) + 16); /* # points + [x,y,m] array - interior ring */
2859 else if (geom->DimensionModel == GAIA_XY_Z_M)
2860 *size += (4 + (20 * rng->Points) + 24); /* # points + [x,y,z,m] array - interior ring */
2861 else
2862 *size += (4 + (8 * rng->Points) + 16); /* # points + [x,y] array - interior ring */
2863 }
2864 polyg = polyg->Next;
2865 }
2866 };
2867 *result = malloc (*size);
2868 ptr = *result;
2869 /* and finally we build the BLOB */
2870 switch (type)
2871 {
2872 case GAIA_POINT:
2873 *ptr = GAIA_MARK_START; /* START signature */
2874 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2875 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2876 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2877 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2878 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2879 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2880 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2881 gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch); /* class POINT */
2882 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2883 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2884 *(ptr + 59) = GAIA_MARK_END; /* END signature */
2885 break;
2886 case GAIA_POINTZ:
2887 *ptr = GAIA_MARK_START; /* START signature */
2888 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2889 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2890 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2891 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2892 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2893 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2894 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2895 gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */
2896 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2897 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2898 gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* Z */
2899 *(ptr + 67) = GAIA_MARK_END; /* END signature */
2900 break;
2901 case GAIA_POINTM:
2902 *ptr = GAIA_MARK_START; /* START signature */
2903 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2904 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2905 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2906 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2907 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2908 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2909 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2910 gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */
2911 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2912 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2913 gaiaExport64 (ptr + 59, point->M, 1, endian_arch); /* M */
2914 *(ptr + 67) = GAIA_MARK_END; /* END signature */
2915 break;
2916 case GAIA_POINTZM:
2917 *ptr = GAIA_MARK_START; /* START signature */
2918 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2919 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2920 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2921 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2922 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2923 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2924 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2925 gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */
2926 gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */
2927 gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */
2928 gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* M */
2929 gaiaExport64 (ptr + 67, point->M, 1, endian_arch); /* Z */
2930 *(ptr + 75) = GAIA_MARK_END; /* END signature */
2931 break;
2932 case GAIA_LINESTRING:
2933 *ptr = GAIA_MARK_START; /* START signature */
2934 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2935 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2936 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2937 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2938 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2939 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2940 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2941 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRING, 1, endian_arch); /* class LINESTRING */
2942 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2943 ptr += 47;
2944 for (iv = 0; iv < line->Points; iv++)
2945 {
2946 gaiaGetPoint (line->Coords, iv, &x, &y);
2947 if (iv == 0 || iv == (line->Points - 1))
2948 {
2949 /* first and last vertices are uncompressed */
2950 gaiaExport64 (ptr, x, 1, endian_arch);
2951 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2952 ptr += 16;
2953 }
2954 else
2955 {
2956 /* compressing any other intermediate vertex */
2957 fx = (float) (x - last_x);
2958 fy = (float) (y - last_y);
2959 gaiaExportF32 (ptr, fx, 1, endian_arch);
2960 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
2961 ptr += 8;
2962 }
2963 last_x = x;
2964 last_y = y;
2965 }
2966 *ptr = GAIA_MARK_END; /* END signature */
2967 break;
2968 case GAIA_LINESTRINGZ:
2969 *ptr = GAIA_MARK_START; /* START signature */
2970 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
2971 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
2972 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
2973 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
2974 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
2975 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
2976 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
2977 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */
2978 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
2979 ptr += 47;
2980 for (iv = 0; iv < line->Points; iv++)
2981 {
2982 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2983 if (iv == 0 || iv == (line->Points - 1))
2984 {
2985 /* first and last vertices are uncompressed */
2986 gaiaExport64 (ptr, x, 1, endian_arch);
2987 gaiaExport64 (ptr + 8, y, 1, endian_arch);
2988 gaiaExport64 (ptr + 16, z, 1, endian_arch);
2989 ptr += 24;
2990 }
2991 else
2992 {
2993 /* compressing any other intermediate vertex */
2994 fx = (float) (x - last_x);
2995 fy = (float) (y - last_y);
2996 fz = (float) (z - last_z);
2997 gaiaExportF32 (ptr, fx, 1, endian_arch);
2998 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
2999 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3000 ptr += 12;
3001 }
3002 last_x = x;
3003 last_y = y;
3004 last_z = z;
3005 }
3006 *ptr = GAIA_MARK_END; /* END signature */
3007 break;
3008 case GAIA_LINESTRINGM:
3009 *ptr = GAIA_MARK_START; /* START signature */
3010 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3011 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3012 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3013 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3014 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3015 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3016 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3017 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */
3018 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
3019 ptr += 47;
3020 for (iv = 0; iv < line->Points; iv++)
3021 {
3022 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3023 if (iv == 0 || iv == (line->Points - 1))
3024 {
3025 /* first and last vertices are uncompressed */
3026 gaiaExport64 (ptr, x, 1, endian_arch);
3027 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3028 gaiaExport64 (ptr + 16, m, 1, endian_arch);
3029 ptr += 24;
3030 }
3031 else
3032 {
3033 /* compressing any other intermediate vertex */
3034 fx = (float) (x - last_x);
3035 fy = (float) (y - last_y);
3036 gaiaExportF32 (ptr, fx, 1, endian_arch);
3037 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3038 gaiaExport64 (ptr + 8, m, 1, endian_arch);
3039 ptr += 16;
3040 }
3041 last_x = x;
3042 last_y = y;
3043 }
3044 *ptr = GAIA_MARK_END; /* END signature */
3045 break;
3046 case GAIA_LINESTRINGZM:
3047 *ptr = GAIA_MARK_START; /* START signature */
3048 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3049 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3050 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3051 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3052 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3053 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3054 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3055 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */
3056 gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */
3057 ptr += 47;
3058 for (iv = 0; iv < line->Points; iv++)
3059 {
3060 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3061 if (iv == 0 || iv == (line->Points - 1))
3062 {
3063 /* first and last vertices are uncompressed */
3064 gaiaExport64 (ptr, x, 1, endian_arch);
3065 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3066 gaiaExport64 (ptr + 16, z, 1, endian_arch);
3067 gaiaExport64 (ptr + 24, m, 1, endian_arch);
3068 ptr += 32;
3069 }
3070 else
3071 {
3072 /* compressing any other intermediate vertex */
3073 fx = (float) (x - last_x);
3074 fy = (float) (y - last_y);
3075 fz = (float) (z - last_z);
3076 gaiaExportF32 (ptr, fx, 1, endian_arch);
3077 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3078 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3079 gaiaExport64 (ptr + 12, m, 1, endian_arch);
3080 ptr += 20;
3081 }
3082 last_x = x;
3083 last_y = y;
3084 last_z = z;
3085 }
3086 *ptr = GAIA_MARK_END; /* END signature */
3087 break;
3088 case GAIA_POLYGON:
3089 *ptr = GAIA_MARK_START; /* START signature */
3090 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3091 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3092 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3093 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3094 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3095 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3096 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3097 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGON, 1, endian_arch); /* class POLYGON */
3098 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
3099 rng = polyg->Exterior;
3100 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
3101 ptr += 51;
3102 for (iv = 0; iv < rng->Points; iv++)
3103 {
3104 gaiaGetPoint (rng->Coords, iv, &x, &y);
3105 if (iv == 0 || iv == (rng->Points - 1))
3106 {
3107 /* first and last vertices are uncompressed */
3108 gaiaExport64 (ptr, x, 1, endian_arch);
3109 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3110 ptr += 16;
3111 }
3112 else
3113 {
3114 /* compressing any other intermediate vertex */
3115 fx = (float) (x - last_x);
3116 fy = (float) (y - last_y);
3117 gaiaExportF32 (ptr, fx, 1, endian_arch);
3118 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3119 ptr += 8;
3120 }
3121 last_x = x;
3122 last_y = y;
3123 }
3124 for (ib = 0; ib < polyg->NumInteriors; ib++)
3125 {
3126 rng = polyg->Interiors + ib;
3127 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
3128 ptr += 4;
3129 for (iv = 0; iv < rng->Points; iv++)
3130 {
3131 gaiaGetPoint (rng->Coords, iv, &x, &y);
3132 if (iv == 0 || iv == (rng->Points - 1))
3133 {
3134 /* first and last vertices are uncompressed */
3135 gaiaExport64 (ptr, x, 1, endian_arch);
3136 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3137 ptr += 16;
3138 }
3139 else
3140 {
3141 /* compressing any other intermediate vertex */
3142 fx = (float) (x - last_x);
3143 fy = (float) (y - last_y);
3144 gaiaExportF32 (ptr, fx, 1, endian_arch);
3145 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3146 ptr += 8;
3147 }
3148 last_x = x;
3149 last_y = y;
3150 }
3151 }
3152 *ptr = GAIA_MARK_END; /* END signature */
3153 break;
3154 case GAIA_POLYGONZ:
3155 *ptr = GAIA_MARK_START; /* START signature */
3156 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3157 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3158 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3159 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3160 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3161 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3162 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3163 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */
3164 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
3165 rng = polyg->Exterior;
3166 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
3167 ptr += 51;
3168 for (iv = 0; iv < rng->Points; iv++)
3169 {
3170 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3171 if (iv == 0 || iv == (rng->Points - 1))
3172 {
3173 /* first and last vertices are uncompressed */
3174 gaiaExport64 (ptr, x, 1, endian_arch);
3175 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3176 gaiaExport64 (ptr + 16, z, 1, endian_arch);
3177 ptr += 24;
3178 }
3179 else
3180 {
3181 /* compressing any other intermediate vertex */
3182 fx = (float) (x - last_x);
3183 fy = (float) (y - last_y);
3184 fz = (float) (z - last_z);
3185 gaiaExportF32 (ptr, fx, 1, endian_arch);
3186 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3187 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3188 ptr += 12;
3189 }
3190 last_x = x;
3191 last_y = y;
3192 last_z = z;
3193 }
3194 for (ib = 0; ib < polyg->NumInteriors; ib++)
3195 {
3196 rng = polyg->Interiors + ib;
3197 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
3198 ptr += 4;
3199 for (iv = 0; iv < rng->Points; iv++)
3200 {
3201 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3202 if (iv == 0 || iv == (rng->Points - 1))
3203 {
3204 /* first and last vertices are uncompressed */
3205 gaiaExport64 (ptr, x, 1, endian_arch);
3206 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3207 gaiaExport64 (ptr + 16, z, 1, endian_arch);
3208 ptr += 24;
3209 }
3210 else
3211 {
3212 /* compressing any other intermediate vertex */
3213 fx = (float) (x - last_x);
3214 fy = (float) (y - last_y);
3215 fz = (float) (z - last_z);
3216 gaiaExportF32 (ptr, fx, 1, endian_arch);
3217 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3218 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3219 ptr += 12;
3220 }
3221 last_x = x;
3222 last_y = y;
3223 last_z = z;
3224 }
3225 }
3226 *ptr = GAIA_MARK_END; /* END signature */
3227 break;
3228 case GAIA_POLYGONM:
3229 *ptr = GAIA_MARK_START; /* START signature */
3230 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3231 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3232 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3233 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3234 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3235 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3236 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3237 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONM, 1, endian_arch); /* class POLYGON XYM */
3238 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
3239 rng = polyg->Exterior;
3240 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
3241 ptr += 51;
3242 for (iv = 0; iv < rng->Points; iv++)
3243 {
3244 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3245 if (iv == 0 || iv == (rng->Points - 1))
3246 {
3247 /* first and last vertices are uncompressed */
3248 gaiaExport64 (ptr, x, 1, endian_arch);
3249 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3250 gaiaExport64 (ptr + 16, m, 1, endian_arch);
3251 ptr += 24;
3252 }
3253 else
3254 {
3255 /* compressing any other intermediate vertex */
3256 fx = (float) (x - last_x);
3257 fy = (float) (y - last_y);
3258 gaiaExportF32 (ptr, fx, 1, endian_arch);
3259 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3260 gaiaExport64 (ptr + 8, m, 1, endian_arch);
3261 ptr += 16;
3262 }
3263 last_x = x;
3264 last_y = y;
3265 }
3266 for (ib = 0; ib < polyg->NumInteriors; ib++)
3267 {
3268 rng = polyg->Interiors + ib;
3269 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
3270 ptr += 4;
3271 for (iv = 0; iv < rng->Points; iv++)
3272 {
3273 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3274 if (iv == 0 || iv == (rng->Points - 1))
3275 {
3276 /* first and last vertices are uncompressed */
3277 gaiaExport64 (ptr, x, 1, endian_arch);
3278 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3279 gaiaExport64 (ptr + 16, m, 1, endian_arch);
3280 ptr += 24;
3281 }
3282 else
3283 {
3284 /* compressing any other intermediate vertex */
3285 fx = (float) (x - last_x);
3286 fy = (float) (y - last_y);
3287 gaiaExportF32 (ptr, fx, 1, endian_arch);
3288 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3289 gaiaExport64 (ptr + 8, m, 1, endian_arch);
3290 ptr += 16;
3291 }
3292 last_x = x;
3293 last_y = y;
3294 }
3295 }
3296 *ptr = GAIA_MARK_END; /* END signature */
3297 break;
3298 case GAIA_POLYGONZM:
3299 *ptr = GAIA_MARK_START; /* START signature */
3300 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3301 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3302 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3303 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3304 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3305 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3306 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3307 gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch); /* class POLYGON */
3308 gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
3309 rng = polyg->Exterior;
3310 gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */
3311 ptr += 51;
3312 for (iv = 0; iv < rng->Points; iv++)
3313 {
3314 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3315 if (iv == 0 || iv == (rng->Points - 1))
3316 {
3317 /* first and last vertices are uncompressed */
3318 gaiaExport64 (ptr, x, 1, endian_arch);
3319 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3320 gaiaExport64 (ptr + 16, z, 1, endian_arch);
3321 gaiaExport64 (ptr + 24, m, 1, endian_arch);
3322 ptr += 32;
3323 }
3324 else
3325 {
3326 /* compressing any other intermediate vertex */
3327 fx = (float) (x - last_x);
3328 fy = (float) (y - last_y);
3329 fz = (float) (z - last_z);
3330 gaiaExportF32 (ptr, fx, 1, endian_arch);
3331 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3332 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3333 gaiaExport64 (ptr + 12, m, 1, endian_arch);
3334 ptr += 20;
3335 }
3336 last_x = x;
3337 last_y = y;
3338 last_z = z;
3339 }
3340 for (ib = 0; ib < polyg->NumInteriors; ib++)
3341 {
3342 rng = polyg->Interiors + ib;
3343 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
3344 ptr += 4;
3345 for (iv = 0; iv < rng->Points; iv++)
3346 {
3347 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3348 if (iv == 0 || iv == (rng->Points - 1))
3349 {
3350 /* first and last vertices are uncompressed */
3351 gaiaExport64 (ptr, x, 1, endian_arch);
3352 gaiaExport64 (ptr + 8, y, 1, endian_arch);
3353 gaiaExport64 (ptr + 16, z, 1, endian_arch);
3354 gaiaExport64 (ptr + 24, m, 1, endian_arch);
3355 ptr += 32;
3356 }
3357 else
3358 {
3359 /* compressing any other intermediate vertex */
3360 fx = (float) (x - last_x);
3361 fy = (float) (y - last_y);
3362 fz = (float) (z - last_z);
3363 gaiaExportF32 (ptr, fx, 1, endian_arch);
3364 gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3365 gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3366 gaiaExport64 (ptr + 12, m, 1, endian_arch);
3367 ptr += 20;
3368 }
3369 last_x = x;
3370 last_y = y;
3371 last_z = z;
3372 }
3373 }
3374 *ptr = GAIA_MARK_END; /* END signature */
3375 break;
3376 default:
3377 /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */
3378 *ptr = GAIA_MARK_START; /* START signature */
3379 *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
3380 gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */
3381 gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */
3382 gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */
3383 gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */
3384 gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */
3385 *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */
3386 gaiaExport32 (ptr + 39, type, 1, endian_arch); /* geometric class */
3387 gaiaExport32 (ptr + 43, entities, 1, endian_arch); /* # entities */
3388 ptr += 47;
3389 point = geom->FirstPoint;
3390 while (point)
3391 {
3392 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
3393 if (geom->DimensionModel == GAIA_XY_Z)
3394 {
3395 gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */
3396 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
3397 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
3398 gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */
3399 ptr += 29;
3400 }
3401 else if (geom->DimensionModel == GAIA_XY_M)
3402 {
3403 gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */
3404 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
3405 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
3406 gaiaExport64 (ptr + 21, point->M, 1, endian_arch); /* M */
3407 ptr += 29;
3408 }
3409 else if (geom->DimensionModel == GAIA_XY_Z_M)
3410 {
3411 gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */
3412 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
3413 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
3414 gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */
3415 gaiaExport64 (ptr + 29, point->M, 1, endian_arch); /* M */
3416 ptr += 37;
3417 }
3418 else
3419 {
3420 gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch); /* class POINT */
3421 gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */
3422 gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */
3423 ptr += 21;
3424 }
3425 point = point->Next;
3426 }
3427 line = geom->FirstLinestring;
3428 while (line)
3429 {
3430 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
3431 if (geom->DimensionModel == GAIA_XY_Z)
3432 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */
3433 else if (geom->DimensionModel == GAIA_XY_M)
3434 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */
3435 else if (geom->DimensionModel == GAIA_XY_Z_M)
3436 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */
3437 else
3438 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRING, 1, endian_arch); /* class LINESTRING */
3439 gaiaExport32 (ptr + 5, line->Points, 1, endian_arch); /* # points */
3440 ptr += 9;
3441 for (iv = 0; iv < line->Points; iv++)
3442 {
3443 z = 0.0;
3444 m = 0.0;
3445 if (geom->DimensionModel == GAIA_XY_Z)
3446 {
3447 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
3448 }
3449 else if (geom->DimensionModel == GAIA_XY_M)
3450 {
3451 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3452 }
3453 else if (geom->DimensionModel == GAIA_XY_Z_M)
3454 {
3455 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3456 }
3457 else
3458 {
3459 gaiaGetPoint (line->Coords, iv, &x, &y);
3460 }
3461 if (iv == 0 || iv == (line->Points - 1))
3462 {
3463 /* first and last vertices are uncompressed */
3464 gaiaExport64 (ptr, x, 1, endian_arch); /* X */
3465 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */
3466 ptr += 16;
3467 }
3468 else
3469 {
3470 /* compressing any other intermediate vertex */
3471 fx = (float) (x - last_x);
3472 fy = (float) (y - last_y);
3473 gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */
3474 gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */
3475 ptr += 8;
3476 }
3477 if (geom->DimensionModel == GAIA_XY_Z)
3478 {
3479 if (iv == 0 || iv == (line->Points - 1))
3480 {
3481 /* first and last vertices are uncompressed */
3482 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3483 ptr += 8;
3484 }
3485 else
3486 {
3487 /* compressing any other intermediate vertex */
3488 fz = (float) (z - last_z);
3489 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3490 ptr += 4;
3491 }
3492 }
3493 if (geom->DimensionModel == GAIA_XY_M)
3494 {
3495 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3496 ptr += 8;
3497 }
3498 if (geom->DimensionModel == GAIA_XY_Z_M)
3499 {
3500 if (iv == 0 || iv == (line->Points - 1))
3501 {
3502 /* first and last vertices are uncompressed */
3503 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3504 ptr += 8;
3505 }
3506 else
3507 {
3508 /* compressing any other intermediate vertex */
3509 fz = (float) (z - last_z);
3510 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3511 ptr += 4;
3512 }
3513 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3514 ptr += 8;
3515 }
3516 last_x = x;
3517 last_y = y;
3518 last_z = z;
3519 }
3520 line = line->Next;
3521 }
3522 polyg = geom->FirstPolygon;
3523 while (polyg)
3524 {
3525 *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */
3526 if (geom->DimensionModel == GAIA_XY_Z)
3527 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */
3528 else if (geom->DimensionModel == GAIA_XY_M)
3529 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONM, 1, endian_arch); /* class POLYGON XYM */
3530 else if (geom->DimensionModel == GAIA_XY_Z_M)
3531 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch); /* class POLYGON XYZM */
3532 else
3533 gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGON, 1, endian_arch); /* class POLYGON */
3534 gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
3535 rng = polyg->Exterior;
3536 gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch); /* # points - exterior ring */
3537 ptr += 13;
3538 for (iv = 0; iv < rng->Points; iv++)
3539 {
3540 z = 0.0;
3541 m = 0.0;
3542 if (geom->DimensionModel == GAIA_XY_Z)
3543 {
3544 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3545 }
3546 else if (geom->DimensionModel == GAIA_XY_M)
3547 {
3548 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3549 }
3550 else if (geom->DimensionModel == GAIA_XY_Z_M)
3551 {
3552 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3553 }
3554 else
3555 {
3556 gaiaGetPoint (rng->Coords, iv, &x, &y);
3557 }
3558 if (iv == 0 || iv == (rng->Points - 1))
3559 {
3560 /* first and last vertices are uncompressed */
3561 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
3562 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
3563 ptr += 16;
3564 }
3565 else
3566 {
3567 /* compressing any other intermediate vertex */
3568 fx = (float) (x - last_x);
3569 fy = (float) (y - last_y);
3570 gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */
3571 gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */
3572 ptr += 8;
3573 }
3574 if (geom->DimensionModel == GAIA_XY_Z)
3575 {
3576 if (iv == 0 || iv == (rng->Points - 1))
3577 {
3578 /* first and last vertices are uncompressed */
3579 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3580 ptr += 8;
3581 }
3582 else
3583 {
3584 /* compressing any other intermediate vertex */
3585 fz = (float) (z - last_z);
3586 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3587 ptr += 4;
3588 }
3589 }
3590 if (geom->DimensionModel == GAIA_XY_M)
3591 {
3592 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3593 ptr += 8;
3594 }
3595 if (geom->DimensionModel == GAIA_XY_Z_M)
3596 {
3597 if (iv == 0 || iv == (rng->Points - 1))
3598 {
3599 /* first and last vertices are uncompressed */
3600 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3601 ptr += 8;
3602 }
3603 else
3604 {
3605 /* compressing any other intermediate vertex */
3606 fz = (float) (z - last_z);
3607 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3608 ptr += 4;
3609 }
3610 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3611 ptr += 8;
3612 }
3613 last_x = x;
3614 last_y = y;
3615 last_z = z;
3616 }
3617 for (ib = 0; ib < polyg->NumInteriors; ib++)
3618 {
3619 rng = polyg->Interiors + ib;
3620 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
3621 ptr += 4;
3622 for (iv = 0; iv < rng->Points; iv++)
3623 {
3624 z = 0.0;
3625 m = 0.0;
3626 if (geom->DimensionModel == GAIA_XY_Z)
3627 {
3628 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3629 }
3630 else if (geom->DimensionModel == GAIA_XY_M)
3631 {
3632 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3633 }
3634 else if (geom->DimensionModel == GAIA_XY_Z_M)
3635 {
3636 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z,
3637 &m);
3638 }
3639 else
3640 {
3641 gaiaGetPoint (rng->Coords, iv, &x, &y);
3642 }
3643 if (iv == 0 || iv == (rng->Points - 1))
3644 {
3645 /* first and last vertices are uncompressed */
3646 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
3647 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
3648 ptr += 16;
3649 }
3650 else
3651 {
3652 /* compressing any other intermediate vertex */
3653 fx = (float) (x - last_x);
3654 fy = (float) (y - last_y);
3655 gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */
3656 gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */
3657 ptr += 8;
3658 }
3659 if (geom->DimensionModel == GAIA_XY_Z)
3660 {
3661 if (iv == 0 || iv == (rng->Points - 1))
3662 {
3663 /* first and last vertices are uncompressed */
3664 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3665 ptr += 8;
3666 }
3667 else
3668 {
3669 /* compressing any other intermediate vertex */
3670 fz = (float) (z - last_z);
3671 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3672 ptr += 4;
3673 }
3674 }
3675 if (geom->DimensionModel == GAIA_XY_M)
3676 {
3677 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3678 ptr += 8;
3679 }
3680 if (geom->DimensionModel == GAIA_XY_Z_M)
3681 {
3682 if (iv == 0 || iv == (rng->Points - 1))
3683 {
3684 /* first and last vertices are uncompressed */
3685 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
3686 ptr += 8;
3687 }
3688 else
3689 {
3690 /* compressing any other intermediate vertex */
3691 fz = (float) (z - last_z);
3692 gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */
3693 ptr += 4;
3694 }
3695 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
3696 ptr += 8;
3697 }
3698 last_x = x;
3699 last_y = y;
3700 last_z = z;
3701 }
3702 }
3703 polyg = polyg->Next;
3704 }
3705 *ptr = GAIA_MARK_END; /* END signature */
3706 };
3707 }
3708
3709 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromWkb(const unsigned char * blob,unsigned int size)3710 gaiaFromWkb (const unsigned char *blob, unsigned int size)
3711 {
3712 /* decoding from WKB to GEOMETRY */
3713 int type;
3714 int little_endian;
3715 gaiaGeomCollPtr geo = NULL;
3716 int endian_arch = gaiaEndianArch ();
3717 if (size < 5)
3718 return NULL;
3719 if (*(blob + 0) == 0x01)
3720 little_endian = GAIA_LITTLE_ENDIAN;
3721 else
3722 little_endian = GAIA_BIG_ENDIAN;
3723 type = gaiaImport32 (blob + 1, little_endian, endian_arch);
3724 if (type == GAIA_POINTZ || type == GAIA_LINESTRINGZ || type == GAIA_POLYGONZ
3725 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
3726 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
3727 || type == GAIA_GEOSWKB_POINTZ || type == GAIA_GEOSWKB_LINESTRINGZ
3728 || type == GAIA_GEOSWKB_POLYGONZ || type == GAIA_GEOSWKB_MULTIPOINTZ
3729 || type == GAIA_GEOSWKB_MULTILINESTRINGZ
3730 || type == GAIA_GEOSWKB_MULTIPOLYGONZ
3731 || type == GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ)
3732 geo = gaiaAllocGeomCollXYZ ();
3733 else if (type == GAIA_POINTM || type == GAIA_LINESTRINGM
3734 || type == GAIA_POLYGONM || type == GAIA_MULTIPOINTM
3735 || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM
3736 || type == GAIA_GEOMETRYCOLLECTIONM)
3737 geo = gaiaAllocGeomCollXYM ();
3738 else if (type == GAIA_POINTZM || type == GAIA_LINESTRINGZM
3739 || type == GAIA_POLYGONZM || type == GAIA_MULTIPOINTZM
3740 || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM
3741 || type == GAIA_GEOMETRYCOLLECTIONZM)
3742 geo = gaiaAllocGeomCollXYZM ();
3743 else
3744 geo = gaiaAllocGeomColl ();
3745 geo->Srid = 0;
3746 geo->endian_arch = (char) endian_arch;
3747 geo->endian = (char) little_endian;
3748 geo->blob = blob;
3749 geo->size = size;
3750 geo->offset = 5;
3751 switch (type)
3752 {
3753 case GAIA_POINT:
3754 ParseWkbPoint (geo);
3755 break;
3756 case GAIA_POINTZ:
3757 case GAIA_GEOSWKB_POINTZ:
3758 ParseWkbPointZ (geo);
3759 break;
3760 case GAIA_POINTM:
3761 ParseWkbPointM (geo);
3762 break;
3763 case GAIA_POINTZM:
3764 ParseWkbPointZM (geo);
3765 break;
3766 case GAIA_LINESTRING:
3767 ParseWkbLine (geo);
3768 break;
3769 case GAIA_LINESTRINGZ:
3770 case GAIA_GEOSWKB_LINESTRINGZ:
3771 ParseWkbLineZ (geo);
3772 break;
3773 case GAIA_LINESTRINGM:
3774 ParseWkbLineM (geo);
3775 break;
3776 case GAIA_LINESTRINGZM:
3777 ParseWkbLineZM (geo);
3778 break;
3779 case GAIA_POLYGON:
3780 ParseWkbPolygon (geo);
3781 break;
3782 case GAIA_POLYGONZ:
3783 case GAIA_GEOSWKB_POLYGONZ:
3784 ParseWkbPolygonZ (geo);
3785 break;
3786 case GAIA_POLYGONM:
3787 ParseWkbPolygonM (geo);
3788 break;
3789 case GAIA_POLYGONZM:
3790 ParseWkbPolygonZM (geo);
3791 break;
3792 case GAIA_MULTIPOINT:
3793 case GAIA_MULTILINESTRING:
3794 case GAIA_MULTIPOLYGON:
3795 case GAIA_GEOMETRYCOLLECTION:
3796 case GAIA_MULTIPOINTZ:
3797 case GAIA_MULTILINESTRINGZ:
3798 case GAIA_MULTIPOLYGONZ:
3799 case GAIA_GEOMETRYCOLLECTIONZ:
3800 case GAIA_GEOSWKB_MULTIPOINTZ:
3801 case GAIA_GEOSWKB_MULTILINESTRINGZ:
3802 case GAIA_GEOSWKB_MULTIPOLYGONZ:
3803 case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ:
3804 case GAIA_MULTIPOINTM:
3805 case GAIA_MULTILINESTRINGM:
3806 case GAIA_MULTIPOLYGONM:
3807 case GAIA_GEOMETRYCOLLECTIONM:
3808 case GAIA_MULTIPOINTZM:
3809 case GAIA_MULTILINESTRINGZM:
3810 case GAIA_MULTIPOLYGONZM:
3811 case GAIA_GEOMETRYCOLLECTIONZM:
3812 ParseWkbGeometry (geo, 1);
3813 break;
3814 default:
3815 break;
3816 };
3817 gaiaMbrGeometry (geo);
3818 switch (type)
3819 {
3820 case GAIA_POINT:
3821 case GAIA_POINTZ:
3822 case GAIA_GEOSWKB_POINTZ:
3823 case GAIA_POINTM:
3824 case GAIA_POINTZM:
3825 geo->DeclaredType = GAIA_POINT;
3826 break;
3827 case GAIA_LINESTRING:
3828 case GAIA_LINESTRINGZ:
3829 case GAIA_GEOSWKB_LINESTRINGZ:
3830 case GAIA_LINESTRINGM:
3831 case GAIA_LINESTRINGZM:
3832 geo->DeclaredType = GAIA_LINESTRING;
3833 break;
3834 case GAIA_POLYGON:
3835 case GAIA_POLYGONZ:
3836 case GAIA_GEOSWKB_POLYGONZ:
3837 case GAIA_POLYGONM:
3838 case GAIA_POLYGONZM:
3839 geo->DeclaredType = GAIA_POLYGON;
3840 break;
3841 case GAIA_MULTIPOINT:
3842 case GAIA_MULTIPOINTZ:
3843 case GAIA_GEOSWKB_MULTIPOINTZ:
3844 case GAIA_MULTIPOINTM:
3845 case GAIA_MULTIPOINTZM:
3846 geo->DeclaredType = GAIA_MULTIPOINT;
3847 break;
3848 case GAIA_MULTILINESTRING:
3849 case GAIA_MULTILINESTRINGZ:
3850 case GAIA_GEOSWKB_MULTILINESTRINGZ:
3851 case GAIA_MULTILINESTRINGM:
3852 case GAIA_MULTILINESTRINGZM:
3853 geo->DeclaredType = GAIA_MULTILINESTRING;
3854 break;
3855 case GAIA_MULTIPOLYGON:
3856 case GAIA_MULTIPOLYGONZ:
3857 case GAIA_GEOSWKB_MULTIPOLYGONZ:
3858 case GAIA_MULTIPOLYGONM:
3859 case GAIA_MULTIPOLYGONZM:
3860 geo->DeclaredType = GAIA_MULTIPOLYGON;
3861 break;
3862 case GAIA_GEOMETRYCOLLECTION:
3863 case GAIA_GEOMETRYCOLLECTIONZ:
3864 case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ:
3865 case GAIA_GEOMETRYCOLLECTIONM:
3866 case GAIA_GEOMETRYCOLLECTIONZM:
3867 geo->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3868 break;
3869 }
3870 return geo;
3871 }
3872
3873 GAIAGEO_DECLARE char *
gaiaToHexWkb(gaiaGeomCollPtr geom)3874 gaiaToHexWkb (gaiaGeomCollPtr geom)
3875 {
3876 /* builds the hexadecimal WKB representation for this GEOMETRY */
3877 unsigned char *wkb = NULL;
3878 int size = 0;
3879 char *hexbuf = NULL;
3880 int i;
3881 char hex[16];
3882 char *p;
3883 gaiaToWkb (geom, &wkb, &size);
3884 if (!wkb)
3885 return NULL;
3886 hexbuf = malloc ((size * 2) + 1);
3887 p = hexbuf;
3888 for (i = 0; i < size; i++)
3889 {
3890 sprintf (hex, "%02X", *(wkb + i));
3891 *p++ = hex[0];
3892 *p++ = hex[1];
3893 }
3894 *p = '\0';
3895 return hexbuf;
3896 }
3897
3898 GAIAGEO_DECLARE void
gaiaToWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)3899 gaiaToWkb (gaiaGeomCollPtr geom, unsigned char **result, int *size)
3900 {
3901 /* builds the WKB representation for this GEOMETRY */
3902 int ib;
3903 int iv;
3904 double x;
3905 double y;
3906 double z = 0.0;
3907 double m = 0.0;
3908 int entities = 0;
3909 int n_points = 0;
3910 int n_linestrings = 0;
3911 int n_polygons = 0;
3912 int type;
3913 unsigned char *ptr;
3914 gaiaPointPtr pt;
3915 gaiaLinestringPtr ln;
3916 gaiaPolygonPtr pg;
3917 gaiaRingPtr rng;
3918 gaiaPointPtr point = NULL;
3919 gaiaLinestringPtr line = NULL;
3920 gaiaPolygonPtr polyg = NULL;
3921 int endian_arch = gaiaEndianArch ();
3922 gaiaMbrGeometry (geom);
3923 /* how many entities, and of what kind, do we have ? */
3924 pt = geom->FirstPoint;
3925 while (pt)
3926 {
3927 point = pt;
3928 entities++;
3929 n_points++;
3930 pt = pt->Next;
3931 }
3932 ln = geom->FirstLinestring;
3933 while (ln)
3934 {
3935 line = ln;
3936 entities++;
3937 n_linestrings++;
3938 ln = ln->Next;
3939 }
3940 pg = geom->FirstPolygon;
3941 while (pg)
3942 {
3943 polyg = pg;
3944 entities++;
3945 n_polygons++;
3946 pg = pg->Next;
3947 }
3948 *size = 0;
3949 *result = NULL;
3950 if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
3951 return;
3952 /* ok, we can determine the geometry class */
3953 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
3954 {
3955 if (geom->DeclaredType == GAIA_MULTIPOINT)
3956 {
3957 if (geom->DimensionModel == GAIA_XY_Z)
3958 type = GAIA_MULTIPOINTZ;
3959 else if (geom->DimensionModel == GAIA_XY_M)
3960 type = GAIA_MULTIPOINTM;
3961 else if (geom->DimensionModel == GAIA_XY_Z_M)
3962 type = GAIA_MULTIPOINTZM;
3963 else
3964 type = GAIA_MULTIPOINT;
3965 }
3966 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3967 {
3968 if (geom->DimensionModel == GAIA_XY_Z)
3969 type = GAIA_GEOMETRYCOLLECTIONZ;
3970 else if (geom->DimensionModel == GAIA_XY_M)
3971 type = GAIA_GEOMETRYCOLLECTIONM;
3972 else if (geom->DimensionModel == GAIA_XY_Z_M)
3973 type = GAIA_GEOMETRYCOLLECTIONZM;
3974 else
3975 type = GAIA_GEOMETRYCOLLECTION;
3976 }
3977 else
3978 {
3979 if (geom->DimensionModel == GAIA_XY_Z)
3980 type = GAIA_POINTZ;
3981 else if (geom->DimensionModel == GAIA_XY_M)
3982 type = GAIA_POINTM;
3983 else if (geom->DimensionModel == GAIA_XY_Z_M)
3984 type = GAIA_POINTZM;
3985 else
3986 type = GAIA_POINT;
3987 }
3988 }
3989 else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
3990 {
3991 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3992 {
3993 if (geom->DimensionModel == GAIA_XY_Z)
3994 type = GAIA_GEOMETRYCOLLECTIONZ;
3995 else if (geom->DimensionModel == GAIA_XY_M)
3996 type = GAIA_GEOMETRYCOLLECTIONM;
3997 else if (geom->DimensionModel == GAIA_XY_Z_M)
3998 type = GAIA_GEOMETRYCOLLECTIONZM;
3999 else
4000 type = GAIA_GEOMETRYCOLLECTION;
4001 }
4002 else
4003 {
4004 if (geom->DimensionModel == GAIA_XY_Z)
4005 type = GAIA_MULTIPOINTZ;
4006 else if (geom->DimensionModel == GAIA_XY_M)
4007 type = GAIA_MULTIPOINTM;
4008 else if (geom->DimensionModel == GAIA_XY_Z_M)
4009 type = GAIA_MULTIPOINTZM;
4010 else
4011 type = GAIA_MULTIPOINT;
4012 }
4013 }
4014 else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
4015 {
4016 if (geom->DeclaredType == GAIA_MULTILINESTRING)
4017 {
4018 if (geom->DimensionModel == GAIA_XY_Z)
4019 type = GAIA_MULTILINESTRINGZ;
4020 else if (geom->DimensionModel == GAIA_XY_M)
4021 type = GAIA_MULTILINESTRINGM;
4022 else if (geom->DimensionModel == GAIA_XY_Z_M)
4023 type = GAIA_MULTILINESTRINGZM;
4024 else
4025 type = GAIA_MULTILINESTRING;
4026 }
4027 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4028 {
4029 if (geom->DimensionModel == GAIA_XY_Z)
4030 type = GAIA_GEOMETRYCOLLECTIONZ;
4031 else if (geom->DimensionModel == GAIA_XY_M)
4032 type = GAIA_GEOMETRYCOLLECTIONM;
4033 else if (geom->DimensionModel == GAIA_XY_Z_M)
4034 type = GAIA_GEOMETRYCOLLECTIONZM;
4035 else
4036 type = GAIA_GEOMETRYCOLLECTION;
4037 }
4038 else
4039 {
4040 if (geom->DimensionModel == GAIA_XY_Z)
4041 type = GAIA_LINESTRINGZ;
4042 else if (geom->DimensionModel == GAIA_XY_M)
4043 type = GAIA_LINESTRINGM;
4044 else if (geom->DimensionModel == GAIA_XY_Z_M)
4045 type = GAIA_LINESTRINGZM;
4046 else
4047 type = GAIA_LINESTRING;
4048 }
4049 }
4050 else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
4051 {
4052 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4053 {
4054 if (geom->DimensionModel == GAIA_XY_Z)
4055 type = GAIA_GEOMETRYCOLLECTIONZ;
4056 else if (geom->DimensionModel == GAIA_XY_M)
4057 type = GAIA_GEOMETRYCOLLECTIONM;
4058 else if (geom->DimensionModel == GAIA_XY_Z_M)
4059 type = GAIA_GEOMETRYCOLLECTIONZM;
4060 else
4061 type = GAIA_GEOMETRYCOLLECTION;
4062 }
4063 else
4064 {
4065 if (geom->DimensionModel == GAIA_XY_Z)
4066 type = GAIA_MULTILINESTRINGZ;
4067 else if (geom->DimensionModel == GAIA_XY_M)
4068 type = GAIA_MULTILINESTRINGM;
4069 else if (geom->DimensionModel == GAIA_XY_Z_M)
4070 type = GAIA_MULTILINESTRINGZM;
4071 else
4072 type = GAIA_MULTILINESTRING;
4073 }
4074 }
4075 else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
4076 {
4077 if (geom->DeclaredType == GAIA_MULTIPOLYGON)
4078 {
4079 if (geom->DimensionModel == GAIA_XY_Z)
4080 type = GAIA_MULTIPOLYGONZ;
4081 else if (geom->DimensionModel == GAIA_XY_M)
4082 type = GAIA_MULTIPOLYGONM;
4083 else if (geom->DimensionModel == GAIA_XY_Z_M)
4084 type = GAIA_MULTIPOLYGONZM;
4085 else
4086 type = GAIA_MULTIPOLYGON;
4087 }
4088 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4089 {
4090 if (geom->DimensionModel == GAIA_XY_Z)
4091 type = GAIA_GEOMETRYCOLLECTIONZ;
4092 else if (geom->DimensionModel == GAIA_XY_M)
4093 type = GAIA_GEOMETRYCOLLECTIONM;
4094 else if (geom->DimensionModel == GAIA_XY_Z_M)
4095 type = GAIA_GEOMETRYCOLLECTIONZM;
4096 else
4097 type = GAIA_GEOMETRYCOLLECTION;
4098 }
4099 else
4100 {
4101 if (geom->DimensionModel == GAIA_XY_Z)
4102 type = GAIA_POLYGONZ;
4103 else if (geom->DimensionModel == GAIA_XY_M)
4104 type = GAIA_POLYGONM;
4105 else if (geom->DimensionModel == GAIA_XY_Z_M)
4106 type = GAIA_POLYGONZM;
4107 else
4108 type = GAIA_POLYGON;
4109 }
4110 }
4111 else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
4112 {
4113 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4114 {
4115 if (geom->DimensionModel == GAIA_XY_Z)
4116 type = GAIA_GEOMETRYCOLLECTIONZ;
4117 else if (geom->DimensionModel == GAIA_XY_M)
4118 type = GAIA_GEOMETRYCOLLECTIONM;
4119 else if (geom->DimensionModel == GAIA_XY_Z_M)
4120 type = GAIA_GEOMETRYCOLLECTIONZM;
4121 else
4122 type = GAIA_GEOMETRYCOLLECTION;
4123 }
4124 else
4125 {
4126 if (geom->DimensionModel == GAIA_XY_Z)
4127 type = GAIA_MULTIPOLYGONZ;
4128 else if (geom->DimensionModel == GAIA_XY_M)
4129 type = GAIA_MULTIPOLYGONM;
4130 else if (geom->DimensionModel == GAIA_XY_Z_M)
4131 type = GAIA_MULTIPOLYGONZM;
4132 else
4133 type = GAIA_MULTIPOLYGON;
4134 }
4135 }
4136 else
4137 {
4138 if (geom->DimensionModel == GAIA_XY_Z)
4139 type = GAIA_GEOMETRYCOLLECTIONZ;
4140 else if (geom->DimensionModel == GAIA_XY_M)
4141 type = GAIA_GEOMETRYCOLLECTIONM;
4142 else if (geom->DimensionModel == GAIA_XY_Z_M)
4143 type = GAIA_GEOMETRYCOLLECTIONZM;
4144 else
4145 type = GAIA_GEOMETRYCOLLECTION;
4146 }
4147 /* and now we compute the size of WKB */
4148 *size = 5; /* header size */
4149 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4150 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4151 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4152 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4153 || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4154 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4155 || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4156 || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4157 *size += 4;
4158 point = geom->FirstPoint;
4159 while (point)
4160 {
4161 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4162 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4163 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4164 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4165 || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4166 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4167 || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4168 || type == GAIA_MULTIPOLYGONZM
4169 || type == GAIA_GEOMETRYCOLLECTIONZM)
4170 *size += 5;
4171 if (geom->DimensionModel == GAIA_XY_Z
4172 || geom->DimensionModel == GAIA_XY_M)
4173 *size += (sizeof (double) * 3); /* three doubles for each POINT */
4174 else if (geom->DimensionModel == GAIA_XY_Z_M)
4175 *size += (sizeof (double) * 4); /* four doubles for each POINT */
4176 else
4177 *size += (sizeof (double) * 2); /* two doubles for each POINT */
4178 point = point->Next;
4179 }
4180 line = geom->FirstLinestring;
4181 while (line)
4182 {
4183 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4184 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4185 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4186 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4187 || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4188 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4189 || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4190 || type == GAIA_MULTIPOLYGONZM
4191 || type == GAIA_GEOMETRYCOLLECTIONZM)
4192 *size += 5;
4193 if (geom->DimensionModel == GAIA_XY_Z
4194 || geom->DimensionModel == GAIA_XY_M)
4195 *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */
4196 else if (geom->DimensionModel == GAIA_XY_Z_M)
4197 *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */
4198 else
4199 *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */
4200 line = line->Next;
4201 }
4202 polyg = geom->FirstPolygon;
4203 while (polyg)
4204 {
4205 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4206 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4207 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4208 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4209 || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4210 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4211 || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4212 || type == GAIA_MULTIPOLYGONZM
4213 || type == GAIA_GEOMETRYCOLLECTIONZM)
4214 *size += 5;
4215 rng = polyg->Exterior;
4216 if (geom->DimensionModel == GAIA_XY_Z
4217 || geom->DimensionModel == GAIA_XY_M)
4218 *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */
4219 else if (geom->DimensionModel == GAIA_XY_Z_M)
4220 *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */
4221 else
4222 *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x,y] array - exterior ring */
4223 for (ib = 0; ib < polyg->NumInteriors; ib++)
4224 {
4225 rng = polyg->Interiors + ib;
4226 if (geom->DimensionModel == GAIA_XY_Z
4227 || geom->DimensionModel == GAIA_XY_M)
4228 *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */
4229 else if (geom->DimensionModel == GAIA_XY_Z_M)
4230 *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */
4231 else
4232 *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */
4233 }
4234 polyg = polyg->Next;
4235 }
4236 *result = malloc (*size);
4237 ptr = *result;
4238 /* and finally we build the WKB */
4239 *ptr = 0x01; /* little endian byte order */
4240 gaiaExport32 (ptr + 1, type, 1, endian_arch); /* the main CLASS TYPE */
4241 ptr += 5;
4242 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4243 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4244 || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4245 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4246 || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4247 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4248 || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4249 || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4250 {
4251 gaiaExport32 (ptr, entities, 1, endian_arch); /* it's a collection; # entities */
4252 ptr += 4;
4253 }
4254 point = geom->FirstPoint;
4255 while (point)
4256 {
4257 if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION
4258 || type == GAIA_MULTIPOINTZ || type == GAIA_GEOMETRYCOLLECTIONZ
4259 || type == GAIA_MULTIPOINTM || type == GAIA_GEOMETRYCOLLECTIONM
4260 || type == GAIA_MULTIPOINTZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4261 {
4262 *ptr = 0x01;
4263 /* it's a collection: the CLASS TYPE for this element */
4264 if (type == GAIA_MULTIPOINTZ
4265 || type == GAIA_GEOMETRYCOLLECTIONZ)
4266 gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch);
4267 else if (type == GAIA_MULTIPOINTM
4268 || type == GAIA_GEOMETRYCOLLECTIONM)
4269 gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch);
4270 else if (type == GAIA_MULTIPOINTZM
4271 || type == GAIA_GEOMETRYCOLLECTIONZM)
4272 gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch);
4273 else
4274 gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch);
4275 ptr += 5;
4276 }
4277 gaiaExport64 (ptr, point->X, 1, endian_arch); /* X */
4278 gaiaExport64 (ptr + 8, point->Y, 1, endian_arch); /* Y */
4279 ptr += 16;
4280 if (type == GAIA_POINTZ || type == GAIA_MULTIPOINTZ
4281 || type == GAIA_GEOMETRYCOLLECTIONZ)
4282 {
4283 gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */
4284 ptr += 8;
4285 }
4286 if (type == GAIA_POINTM || type == GAIA_MULTIPOINTM
4287 || type == GAIA_GEOMETRYCOLLECTIONM)
4288 {
4289 gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */
4290 ptr += 8;
4291 }
4292 if (type == GAIA_POINTZM || type == GAIA_MULTIPOINTZM
4293 || type == GAIA_GEOMETRYCOLLECTIONZM)
4294 {
4295 gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */
4296 gaiaExport64 (ptr + 8, point->M, 1, endian_arch); /* M */
4297 ptr += 16;
4298 }
4299 point = point->Next;
4300 }
4301 line = geom->FirstLinestring;
4302 while (line)
4303 {
4304 if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION
4305 || type == GAIA_MULTILINESTRINGZ
4306 || type == GAIA_GEOMETRYCOLLECTIONZ
4307 || type == GAIA_MULTILINESTRINGM
4308 || type == GAIA_GEOMETRYCOLLECTIONM
4309 || type == GAIA_MULTILINESTRINGZM
4310 || type == GAIA_GEOMETRYCOLLECTIONZM)
4311 {
4312 *ptr = 0x01;
4313 /* it's a collection: the CLASS TYPE for this element */
4314 if (type == GAIA_MULTILINESTRINGZ
4315 || type == GAIA_GEOMETRYCOLLECTIONZ)
4316 gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch);
4317 else if (type == GAIA_MULTILINESTRINGM
4318 || type == GAIA_GEOMETRYCOLLECTIONM)
4319 gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch);
4320 else if (type == GAIA_MULTILINESTRINGZM
4321 || type == GAIA_GEOMETRYCOLLECTIONZM)
4322 gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch);
4323 else
4324 gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch);
4325 ptr += 5;
4326 }
4327 gaiaExport32 (ptr, line->Points, 1, endian_arch); /* # points */
4328 ptr += 4;
4329 for (iv = 0; iv < line->Points; iv++)
4330 {
4331 if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ
4332 || type == GAIA_GEOMETRYCOLLECTIONZ)
4333 {
4334 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
4335 }
4336 else if (type == GAIA_LINESTRINGM
4337 || type == GAIA_MULTILINESTRINGM
4338 || type == GAIA_GEOMETRYCOLLECTIONM)
4339 {
4340 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
4341 }
4342 else if (type == GAIA_LINESTRINGZM
4343 || type == GAIA_MULTILINESTRINGZM
4344 || type == GAIA_GEOMETRYCOLLECTIONZM)
4345 {
4346 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
4347 }
4348 else
4349 {
4350 gaiaGetPoint (line->Coords, iv, &x, &y);
4351 }
4352 gaiaExport64 (ptr, x, 1, endian_arch); /* X */
4353 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */
4354 ptr += 16;
4355 if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ
4356 || type == GAIA_GEOMETRYCOLLECTIONZ)
4357 {
4358 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
4359 ptr += 8;
4360 }
4361 if (type == GAIA_LINESTRINGM || type == GAIA_MULTILINESTRINGM
4362 || type == GAIA_GEOMETRYCOLLECTIONM)
4363 {
4364 gaiaExport64 (ptr, m, 1, endian_arch); /* M */
4365 ptr += 8;
4366 }
4367 if (type == GAIA_LINESTRINGZM || type == GAIA_MULTILINESTRINGZM
4368 || type == GAIA_GEOMETRYCOLLECTIONZM)
4369 {
4370 gaiaExport64 (ptr, z, 1, endian_arch); /* Z */
4371 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */
4372 ptr += 16;
4373 }
4374 }
4375 line = line->Next;
4376 }
4377 polyg = geom->FirstPolygon;
4378 while (polyg)
4379 {
4380 if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4381 || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4382 || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4383 || type == GAIA_MULTIPOLYGONZM
4384 || type == GAIA_GEOMETRYCOLLECTIONZM)
4385 {
4386 *ptr = 0x01;
4387 /* it's a collection: the CLASS TYPE for this element */
4388 if (type == GAIA_MULTIPOLYGONZ
4389 || type == GAIA_GEOMETRYCOLLECTIONZ)
4390 gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch);
4391 else if (type == GAIA_MULTIPOLYGONM
4392 || type == GAIA_GEOMETRYCOLLECTIONM)
4393 gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch);
4394 else if (type == GAIA_MULTIPOLYGONZM
4395 || type == GAIA_GEOMETRYCOLLECTIONZM)
4396 gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch);
4397 else
4398 gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch);
4399 ptr += 5;
4400 }
4401 gaiaExport32 (ptr, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
4402 rng = polyg->Exterior;
4403 gaiaExport32 (ptr + 4, rng->Points, 1, endian_arch); /* # points - exterior ring */
4404 ptr += 8;
4405 for (iv = 0; iv < rng->Points; iv++)
4406 {
4407 if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4408 || type == GAIA_GEOMETRYCOLLECTIONZ)
4409 {
4410 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4411 }
4412 else if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4413 || type == GAIA_GEOMETRYCOLLECTIONM)
4414 {
4415 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4416 }
4417 else if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4418 || type == GAIA_GEOMETRYCOLLECTIONZM)
4419 {
4420 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4421 }
4422 else
4423 {
4424 gaiaGetPoint (rng->Coords, iv, &x, &y);
4425 }
4426 gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */
4427 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */
4428 ptr += 16;
4429 if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4430 || type == GAIA_GEOMETRYCOLLECTIONZ)
4431 {
4432 gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */
4433 ptr += 8;
4434 }
4435 if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4436 || type == GAIA_GEOMETRYCOLLECTIONM)
4437 {
4438 gaiaExport64 (ptr, m, 1, endian_arch); /* M - exterior ring */
4439 ptr += 8;
4440 }
4441 if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4442 || type == GAIA_GEOMETRYCOLLECTIONZM)
4443 {
4444 gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */
4445 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M - exterior ring */
4446 ptr += 16;
4447 }
4448 }
4449 for (ib = 0; ib < polyg->NumInteriors; ib++)
4450 {
4451 rng = polyg->Interiors + ib;
4452 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
4453 ptr += 4;
4454 for (iv = 0; iv < rng->Points; iv++)
4455 {
4456 if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4457 || type == GAIA_GEOMETRYCOLLECTIONZ)
4458 {
4459 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4460 }
4461 else if (type == GAIA_POLYGONM
4462 || type == GAIA_MULTIPOLYGONM
4463 || type == GAIA_GEOMETRYCOLLECTIONM)
4464 {
4465 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4466 }
4467 else if (type == GAIA_POLYGONZM
4468 || type == GAIA_MULTIPOLYGONZM
4469 || type == GAIA_GEOMETRYCOLLECTIONZM)
4470 {
4471 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4472 }
4473 else
4474 {
4475 gaiaGetPoint (rng->Coords, iv, &x, &y);
4476 }
4477 gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */
4478 gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */
4479 ptr += 16;
4480 if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4481 || type == GAIA_GEOMETRYCOLLECTIONZ)
4482 {
4483 gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */
4484 ptr += 8;
4485 }
4486 if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4487 || type == GAIA_GEOMETRYCOLLECTIONM)
4488 {
4489 gaiaExport64 (ptr, m, 1, endian_arch); /* M - exterior ring */
4490 ptr += 8;
4491 }
4492 if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4493 || type == GAIA_GEOMETRYCOLLECTIONZM)
4494 {
4495 gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */
4496 gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M - exterior ring */
4497 ptr += 16;
4498 }
4499 }
4500 }
4501 polyg = polyg->Next;
4502 }
4503 }
4504
4505 GAIAGEO_DECLARE int
gaiaEwkbGetPoint(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4506 gaiaEwkbGetPoint (gaiaGeomCollPtr geom, unsigned char *blob,
4507 int offset, int blob_size, int endian, int endian_arch,
4508 int dims)
4509 {
4510 /* decodes a POINT from PostGIS EWKB binary GEOMETRY */
4511 double x;
4512 double y;
4513 double z;
4514 double m;
4515 switch (dims)
4516 {
4517 case GAIA_XY_Z_M:
4518 if (blob_size < offset + 32)
4519 return -1;
4520 break;
4521 case GAIA_XY_Z:
4522 case GAIA_XY_M:
4523 if (blob_size < offset + 24)
4524 return -1;
4525 break;
4526 default:
4527 if (blob_size < offset + 16)
4528 return -1;
4529 break;
4530 }
4531 x = gaiaImport64 (blob + offset, endian, endian_arch);
4532 offset += 8;
4533 y = gaiaImport64 (blob + offset, endian, endian_arch);
4534 offset += 8;
4535 if (dims == GAIA_XY_Z_M)
4536 {
4537 z = gaiaImport64 (blob + offset, endian, endian_arch);
4538 offset += 8;
4539 m = gaiaImport64 (blob + offset, endian, endian_arch);
4540 offset += 8;
4541 gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
4542 }
4543 else if (dims == GAIA_XY_Z)
4544 {
4545 z = gaiaImport64 (blob + offset, endian, endian_arch);
4546 offset += 8;
4547 gaiaAddPointToGeomCollXYZ (geom, x, y, z);
4548 }
4549 else if (dims == GAIA_XY_M)
4550 {
4551 m = gaiaImport64 (blob + offset, endian, endian_arch);
4552 offset += 8;
4553 gaiaAddPointToGeomCollXYM (geom, x, y, m);
4554 }
4555 else
4556 gaiaAddPointToGeomColl (geom, x, y);
4557 return offset;
4558 }
4559
4560 GAIAGEO_DECLARE int
gaiaEwkbGetLinestring(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4561 gaiaEwkbGetLinestring (gaiaGeomCollPtr geom, unsigned char *blob,
4562 int offset, int blob_size, int endian,
4563 int endian_arch, int dims)
4564 {
4565 /* decodes a LINESTRING from PostGIS binary GEOMETRY */
4566 int npoints;
4567 int iv;
4568 double x;
4569 double y;
4570 double z;
4571 double m;
4572 gaiaLinestringPtr ln;
4573 if (blob_size < offset + 4)
4574 return -1;
4575 npoints = gaiaImport32 (blob + offset, endian, endian_arch);
4576 offset += 4;
4577 switch (dims)
4578 {
4579 case GAIA_XY_Z_M:
4580 if (blob_size < offset + (32 * npoints))
4581 return -1;
4582 break;
4583 case GAIA_XY_Z:
4584 case GAIA_XY_M:
4585 if (blob_size < offset + (24 * npoints))
4586 return -1;
4587 break;
4588 default:
4589 if (blob_size < offset + (16 * npoints))
4590 return -1;
4591 break;
4592 }
4593 ln = gaiaAddLinestringToGeomColl (geom, npoints);
4594 for (iv = 0; iv < npoints; iv++)
4595 {
4596 x = gaiaImport64 (blob + offset, endian, endian_arch);
4597 offset += 8;
4598 y = gaiaImport64 (blob + offset, endian, endian_arch);
4599 offset += 8;
4600 if (dims == GAIA_XY_Z_M)
4601 {
4602 z = gaiaImport64 (blob + offset, endian, endian_arch);
4603 offset += 8;
4604 m = gaiaImport64 (blob + offset, endian, endian_arch);
4605 offset += 8;
4606 gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m);
4607 }
4608 else if (dims == GAIA_XY_Z)
4609 {
4610 z = gaiaImport64 (blob + offset, endian, endian_arch);
4611 offset += 8;
4612 gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
4613 }
4614 else if (dims == GAIA_XY_M)
4615 {
4616 m = gaiaImport64 (blob + offset, endian, endian_arch);
4617 offset += 8;
4618 gaiaSetPointXYM (ln->Coords, iv, x, y, m);
4619 }
4620 else
4621 gaiaSetPoint (ln->Coords, iv, x, y);
4622 }
4623 return offset;
4624 }
4625
4626 GAIAGEO_DECLARE int
gaiaEwkbGetPolygon(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4627 gaiaEwkbGetPolygon (gaiaGeomCollPtr geom, unsigned char *blob,
4628 int offset, int blob_size, int endian,
4629 int endian_arch, int dims)
4630 {
4631 /* decodes a POLYGON from PostGIS binary GEOMETRY */
4632 int rings;
4633 int npoints;
4634 int iv;
4635 int ib;
4636 double x;
4637 double y;
4638 double z;
4639 double m;
4640 gaiaPolygonPtr polyg = NULL;
4641 gaiaRingPtr rng;
4642 if (blob_size < offset + 4)
4643 return -1;
4644 rings = gaiaImport32 (blob + offset, endian, endian_arch);
4645 offset += 4;
4646 for (ib = 0; ib < rings; ib++)
4647 {
4648 if (blob_size < offset + 4)
4649 return -1;
4650 npoints = gaiaImport32 (blob + offset, endian, endian_arch);
4651 offset += 4;
4652 switch (dims)
4653 {
4654 case GAIA_XY_Z_M:
4655 if (blob_size < offset + (32 * npoints))
4656 return -1;
4657 break;
4658 case GAIA_XY_Z:
4659 case GAIA_XY_M:
4660 if (blob_size < offset + (24 * npoints))
4661 return -1;
4662 break;
4663 default:
4664 if (blob_size < offset + (16 * npoints))
4665 return -1;
4666 break;
4667 }
4668 if (ib == 0)
4669 {
4670 polyg = gaiaAddPolygonToGeomColl (geom, npoints, rings - 1);
4671 rng = polyg->Exterior;
4672 }
4673 else
4674 rng = gaiaAddInteriorRing (polyg, ib - 1, npoints);
4675 for (iv = 0; iv < npoints; iv++)
4676 {
4677 x = gaiaImport64 (blob + offset, endian, endian_arch);
4678 offset += 8;
4679 y = gaiaImport64 (blob + offset, endian, endian_arch);
4680 offset += 8;
4681 if (dims == GAIA_XY_Z_M)
4682 {
4683 z = gaiaImport64 (blob + offset, endian, endian_arch);
4684 offset += 8;
4685 m = gaiaImport64 (blob + offset, endian, endian_arch);
4686 offset += 8;
4687 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
4688 }
4689 else if (dims == GAIA_XY_Z)
4690 {
4691 z = gaiaImport64 (blob + offset, endian, endian_arch);
4692 offset += 8;
4693 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
4694 }
4695 else if (dims == GAIA_XY_M)
4696 {
4697 m = gaiaImport64 (blob + offset, endian, endian_arch);
4698 offset += 8;
4699 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
4700 }
4701 else
4702 gaiaSetPoint (rng->Coords, iv, x, y);
4703 }
4704 }
4705 return offset;
4706 }
4707
4708 GAIAGEO_DECLARE int
gaiaEwkbGetMultiGeometry(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4709 gaiaEwkbGetMultiGeometry (gaiaGeomCollPtr geom, unsigned char *blob,
4710 int offset, int blob_size, int endian,
4711 int endian_arch, int dims)
4712 {
4713 /* decodes a MultiGeometry from PostGIS EWKB binary GEOMETRY */
4714 int entities;
4715 int type;
4716 unsigned char xtype[4];
4717 int ie;
4718 int off;
4719 if (blob_size < offset + 4)
4720 return -1;
4721 entities = gaiaImport32 (blob + offset, endian, endian_arch);
4722 offset += 4;
4723 for (ie = 0; ie < entities; ie++)
4724 {
4725 if (blob_size < offset + 5)
4726 return -1;
4727 memcpy (xtype, blob + offset + 1, 4);
4728 if (endian)
4729 xtype[3] = 0x00;
4730 else
4731 xtype[0] = 0x00;
4732 type = gaiaImport32 (xtype, endian, endian_arch);
4733 offset += 5;
4734 switch (type)
4735 {
4736 case GAIA_POINT:
4737 off =
4738 gaiaEwkbGetPoint (geom, blob, offset, blob_size, endian,
4739 endian_arch, dims);
4740 if (off < 0)
4741 return -1;
4742 offset = off;
4743 break;
4744 case GAIA_LINESTRING:
4745 off =
4746 gaiaEwkbGetLinestring (geom, blob, offset, blob_size,
4747 endian, endian_arch, dims);
4748 if (off < 0)
4749 return -1;
4750 offset = off;
4751 break;
4752 case GAIA_POLYGON:
4753 off =
4754 gaiaEwkbGetPolygon (geom, blob, offset, blob_size, endian,
4755 endian_arch, dims);
4756 if (off < 0)
4757 return -1;
4758 offset = off;
4759 break;
4760 default: /* unexpected: invalid EWKB */
4761 return -1;
4762 };
4763 }
4764 return offset;
4765 }
4766
4767 static int
parseHexEwkbByte(const unsigned char high,const unsigned char low,unsigned char * byte)4768 parseHexEwkbByte (const unsigned char high, const unsigned char low,
4769 unsigned char *byte)
4770 {
4771 /* parsing an Hexadecimal byte */
4772 unsigned char hex;
4773 switch (high)
4774 {
4775 case '0':
4776 hex = 16 * 0;
4777 break;
4778 case '1':
4779 hex = 16 * 1;
4780 break;
4781 case '2':
4782 hex = 16 * 2;
4783 break;
4784 case '3':
4785 hex = 16 * 3;
4786 break;
4787 case '4':
4788 hex = 16 * 4;
4789 break;
4790 case '5':
4791 hex = 16 * 5;
4792 break;
4793 case '6':
4794 hex = 16 * 6;
4795 break;
4796 case '7':
4797 hex = 16 * 7;
4798 break;
4799 case '8':
4800 hex = 16 * 8;
4801 break;
4802 case '9':
4803 hex = 16 * 9;
4804 break;
4805 case 'A':
4806 case 'a':
4807 hex = 16 * 10;
4808 break;
4809 case 'B':
4810 case 'b':
4811 hex = 16 * 11;
4812 break;
4813 case 'C':
4814 case 'c':
4815 hex = 16 * 12;
4816 break;
4817 case 'D':
4818 case 'd':
4819 hex = 16 * 13;
4820 break;
4821 case 'E':
4822 case 'e':
4823 hex = 16 * 14;
4824 break;
4825 case 'F':
4826 case 'f':
4827 hex = 16 * 15;
4828 break;
4829 default:
4830 return 0;
4831 };
4832 switch (low)
4833 {
4834 case '0':
4835 hex += 0;
4836 break;
4837 case '1':
4838 hex += 1;
4839 break;
4840 case '2':
4841 hex += 2;
4842 break;
4843 case '3':
4844 hex += 3;
4845 break;
4846 case '4':
4847 hex += 4;
4848 break;
4849 case '5':
4850 hex += 5;
4851 break;
4852 case '6':
4853 hex += 6;
4854 break;
4855 case '7':
4856 hex += 7;
4857 break;
4858 case '8':
4859 hex += 8;
4860 break;
4861 case '9':
4862 hex += 9;
4863 break;
4864 case 'A':
4865 case 'a':
4866 hex += 10;
4867 break;
4868 case 'B':
4869 case 'b':
4870 hex += 11;
4871 break;
4872 case 'C':
4873 case 'c':
4874 hex += 12;
4875 break;
4876 case 'D':
4877 case 'd':
4878 hex += 13;
4879 break;
4880 case 'E':
4881 case 'e':
4882 hex += 14;
4883 break;
4884 case 'F':
4885 case 'f':
4886 hex += 15;
4887 break;
4888 default:
4889 return 0;
4890 };
4891 *byte = hex;
4892 return 1;
4893 }
4894
4895 GAIAGEO_DECLARE unsigned char *
gaiaParseHexEWKB(const unsigned char * blob_hex,int * blob_size)4896 gaiaParseHexEWKB (const unsigned char *blob_hex, int *blob_size)
4897 {
4898 /* parsing an Hexadecimal EWKB Geometry */
4899 unsigned char *blob;
4900 unsigned char *p_out;
4901 const unsigned char *p_in;
4902 char high;
4903 char low;
4904 unsigned char hex;
4905 int size;
4906 int len = strlen ((const char *) blob_hex);
4907 size = len / 2;
4908 if (size * 2 != len)
4909 return NULL;
4910 blob = malloc (size);
4911 if (!blob)
4912 return NULL;
4913 *blob_size = size;
4914 p_in = blob_hex;
4915 p_out = blob;
4916 while (*p_in != '\0')
4917 {
4918 high = *p_in++;
4919 low = *p_in++;
4920 if (!parseHexEwkbByte (high, low, &hex))
4921 {
4922 free (blob);
4923 return NULL;
4924 }
4925 *p_out++ = hex;
4926 }
4927 *blob_size = size;
4928 return blob;
4929 }
4930
4931 gaiaGeomCollPtr
gaiaFromEWKB(const unsigned char * in_buffer)4932 gaiaFromEWKB (const unsigned char *in_buffer)
4933 {
4934 /* creates a Gaia own Geometry from GEOS/PostGIS EWKB */
4935 unsigned char *blob;
4936 int blob_size;
4937 unsigned char xtype[4];
4938 unsigned char xdims;
4939 int type;
4940 int has_z = 0;
4941 int has_m = 0;
4942 int dims = GAIA_XY;
4943 int srid;
4944 int ret;
4945 int endian;
4946 int endian_arch = gaiaEndianArch ();
4947 gaiaGeomCollPtr geom = NULL;
4948 blob = gaiaParseHexEWKB (in_buffer, &blob_size);
4949 if (!blob)
4950 return NULL;
4951 if (blob_size < 9)
4952 {
4953 free (blob);
4954 return NULL;
4955 }
4956 if (*(blob + 0) == 0x01)
4957 endian = 1;
4958 else
4959 endian = 0;
4960 memcpy (xtype, blob + 1, 4);
4961 if (endian)
4962 {
4963 xdims = xtype[3];
4964 xtype[3] = 0x00;
4965 }
4966 else
4967 {
4968 xdims = xtype[0];
4969 xtype[0] = 0x00;
4970 }
4971 type = gaiaImport32 (xtype, endian, endian_arch);
4972 if (xdims & 0x40)
4973 has_m = 1;
4974 if (xdims & 0x80)
4975 has_z = 1;
4976 if (has_m && has_z)
4977 {
4978 dims = GAIA_XY_Z_M;
4979 geom = gaiaAllocGeomCollXYZM ();
4980 }
4981 else if (has_m)
4982 {
4983 dims = GAIA_XY_M;
4984 geom = gaiaAllocGeomCollXYM ();
4985 }
4986 else if (has_z)
4987 {
4988 dims = GAIA_XY_Z;
4989 geom = gaiaAllocGeomCollXYZ ();
4990 }
4991 else
4992 {
4993 dims = GAIA_XY;
4994 geom = gaiaAllocGeomColl ();
4995 }
4996 srid = gaiaImport32 (blob + 5, endian, endian_arch);
4997 geom->Srid = srid;
4998 if (geom->Srid <= 0)
4999 geom->Srid = 0;
5000 switch (type)
5001 {
5002 case GAIA_POINT:
5003 ret =
5004 gaiaEwkbGetPoint (geom, blob, 9, blob_size, endian, endian_arch,
5005 dims);
5006 break;
5007 case GAIA_LINESTRING:
5008 ret =
5009 gaiaEwkbGetLinestring (geom, blob, 9, blob_size, endian,
5010 endian_arch, dims);
5011 break;
5012 case GAIA_POLYGON:
5013 ret =
5014 gaiaEwkbGetPolygon (geom, blob, 9, blob_size, endian, endian_arch,
5015 dims);
5016 break;
5017 default:
5018 ret =
5019 gaiaEwkbGetMultiGeometry (geom, blob, 9, blob_size, endian,
5020 endian_arch, dims);
5021 break;
5022 };
5023 free (blob);
5024 if (ret < 0)
5025 {
5026 /* invalid EWKB !!! */
5027 gaiaFreeGeomColl (geom);
5028 return NULL;
5029 }
5030 return geom;
5031 }
5032
5033 GAIAGEO_DECLARE void
gaiaToEWKB(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom)5034 gaiaToEWKB (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom)
5035 {
5036 /* prints the GEOS/PostGIS EWKB text representation of current geometry */
5037 char buf[2048];
5038 unsigned char endian_buf[16];
5039 char byte[3];
5040 char *ptr;
5041 int size;
5042 int type;
5043 int entities = 0;
5044 int n_points = 0;
5045 int n_linestrings = 0;
5046 int n_polygons = 0;
5047 int i;
5048 int iv;
5049 int ib;
5050 double x;
5051 double y;
5052 double z;
5053 double m;
5054 int endian_arch = gaiaEndianArch ();
5055 gaiaPointPtr pt;
5056 gaiaLinestringPtr ln;
5057 gaiaPolygonPtr pg;
5058 gaiaRingPtr rng;
5059 gaiaPointPtr point = NULL;
5060 gaiaLinestringPtr line = NULL;
5061 gaiaPolygonPtr polyg = NULL;
5062
5063 /* precomputing the required size */
5064 size = 5; /* SRID and terminating '\0' */
5065 pt = geom->FirstPoint;
5066 while (pt)
5067 {
5068 point = pt;
5069 entities++;
5070 n_points++;
5071 pt = pt->Next;
5072 }
5073 ln = geom->FirstLinestring;
5074 while (ln)
5075 {
5076 line = ln;
5077 entities++;
5078 n_linestrings++;
5079 ln = ln->Next;
5080 }
5081 pg = geom->FirstPolygon;
5082 while (pg)
5083 {
5084 polyg = pg;
5085 entities++;
5086 n_polygons++;
5087 pg = pg->Next;
5088 }
5089 if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
5090 return;
5091 /* ok, we can determine the geometry class */
5092 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
5093 {
5094 if (geom->DeclaredType == GAIA_MULTIPOINT)
5095 type = GAIA_MULTIPOINT;
5096 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5097 type = GAIA_GEOMETRYCOLLECTION;
5098 else
5099 type = GAIA_POINT;
5100 }
5101 else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
5102 {
5103 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5104 type = GAIA_GEOMETRYCOLLECTION;
5105 else
5106 type = GAIA_MULTIPOINT;
5107 }
5108 else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
5109 {
5110 if (geom->DeclaredType == GAIA_MULTILINESTRING)
5111 type = GAIA_MULTILINESTRING;
5112 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5113 type = GAIA_GEOMETRYCOLLECTION;
5114 else
5115 type = GAIA_LINESTRING;
5116 }
5117 else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
5118 {
5119 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5120 type = GAIA_GEOMETRYCOLLECTION;
5121 else
5122 type = GAIA_MULTILINESTRING;
5123 }
5124 else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
5125 {
5126 if (geom->DeclaredType == GAIA_MULTIPOLYGON)
5127 type = GAIA_MULTIPOLYGON;
5128 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5129 type = GAIA_GEOMETRYCOLLECTION;
5130 else
5131 type = GAIA_POLYGON;
5132 }
5133 else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
5134 {
5135 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5136 type = GAIA_GEOMETRYCOLLECTION;
5137 else
5138 type = GAIA_MULTIPOLYGON;
5139 }
5140 else
5141 type = GAIA_GEOMETRYCOLLECTION;
5142 /* and now we compute the size of EWKB */
5143 size += 10; /* header size */
5144 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5145 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5146 size += 8;
5147 point = geom->FirstPoint;
5148 while (point)
5149 {
5150 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5151 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5152 size += 10;
5153 if (geom->DimensionModel == GAIA_XY_Z
5154 || geom->DimensionModel == GAIA_XY_M)
5155 size += 48; /* three doubles for each POINT */
5156 else if (geom->DimensionModel == GAIA_XY_Z_M)
5157 size += 64; /* four doubles for each POINT */
5158 else
5159 size += 32; /* two doubles for each POINT */
5160 point = point->Next;
5161 }
5162 line = geom->FirstLinestring;
5163 while (line)
5164 {
5165 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5166 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5167 size += 10;
5168 if (geom->DimensionModel == GAIA_XY_Z
5169 || geom->DimensionModel == GAIA_XY_M)
5170 size += 8 + (line->Points * 48); /* three doubles for each VERTEX */
5171 else if (geom->DimensionModel == GAIA_XY_Z_M)
5172 size += 8 + (line->Points * 64); /* four doubles for each VERTEX */
5173 else
5174 size += 8 + (line->Points * 32); /* two doubles for each VERTEX */
5175 line = line->Next;
5176 }
5177 polyg = geom->FirstPolygon;
5178 while (polyg)
5179 {
5180 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5181 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5182 size += 10;
5183 rng = polyg->Exterior;
5184 if (geom->DimensionModel == GAIA_XY_Z
5185 || geom->DimensionModel == GAIA_XY_M)
5186 size += 16 + (rng->Points * 48); /* three doubles for each VERTEX */
5187 else if (geom->DimensionModel == GAIA_XY_Z_M)
5188 size += 16 + (rng->Points * 64); /* four doubles for each VERTEX */
5189 else
5190 size += 16 + (rng->Points * 32); /* two doubles for each VERTEX */
5191 for (ib = 0; ib < polyg->NumInteriors; ib++)
5192 {
5193 rng = polyg->Interiors + ib;
5194 if (geom->DimensionModel == GAIA_XY_Z
5195 || geom->DimensionModel == GAIA_XY_M)
5196 size += 8 + (rng->Points * 48); /* three doubles for each VERTEX */
5197 else if (geom->DimensionModel == GAIA_XY_Z_M)
5198 size += 8 + (rng->Points * 64); /* four doubles for each VERTEX */
5199 else
5200 size += 8 + (rng->Points * 32); /* two doubles for each VERTEX */
5201 }
5202 polyg = polyg->Next;
5203 }
5204 /* and finally we build the EWKB expression */
5205 ptr = buf;
5206 *ptr++ = '0'; /* little endian byte order */
5207 *ptr++ = '1';
5208 gaiaExport32 (endian_buf, type, 1, endian_arch); /* the main CLASS TYPE */
5209 for (i = 0; i < 3; i++)
5210 {
5211 /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5212 sprintf (byte, "%02X", endian_buf[i]);
5213 *ptr++ = byte[0];
5214 *ptr++ = byte[1];
5215 }
5216 /* marking dimensions and M/Z presence */
5217 if (geom->DimensionModel == GAIA_XY_Z)
5218 {
5219 *ptr++ = 'A';
5220 *ptr++ = '0';
5221 }
5222 else if (geom->DimensionModel == GAIA_XY_M)
5223 {
5224 *ptr++ = '6';
5225 *ptr++ = '0';
5226 }
5227 else if (geom->DimensionModel == GAIA_XY_Z_M)
5228 {
5229 *ptr++ = 'E';
5230 *ptr++ = '0';
5231 }
5232 else
5233 {
5234 *ptr++ = '2';
5235 *ptr++ = '0';
5236 }
5237 gaiaExport32 (endian_buf, geom->Srid, 1, endian_arch);
5238 for (i = 0; i < 4; i++)
5239 {
5240 sprintf (byte, "%02X", endian_buf[i]);
5241 *ptr++ = byte[0];
5242 *ptr++ = byte[1];
5243 }
5244 *ptr++ = '\0';
5245 gaiaAppendToOutBuffer (out_buf, buf);
5246 ptr = buf;
5247 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5248 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5249 {
5250 gaiaExport32 (endian_buf, entities, 1, endian_arch); /* it's a collection; # entities */
5251 for (i = 0; i < 4; i++)
5252 {
5253 sprintf (byte, "%02X", endian_buf[i]);
5254 *ptr++ = byte[0];
5255 *ptr++ = byte[1];
5256 }
5257 }
5258 point = geom->FirstPoint;
5259 while (point)
5260 {
5261 if ((ptr - buf) > 1024)
5262 {
5263 /* flushing the internal buffer */
5264 *ptr++ = '\0';
5265 gaiaAppendToOutBuffer (out_buf, buf);
5266 ptr = buf;
5267 }
5268 if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION)
5269 {
5270 *ptr++ = '0';
5271 *ptr++ = '1';
5272 /* it's a collection: the CLASS TYPE for this element */
5273 gaiaExport32 (endian_buf, GAIA_POINT, 1, endian_arch);
5274 for (i = 0; i < 3; i++)
5275 {
5276 /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5277 sprintf (byte, "%02X", endian_buf[i]);
5278 *ptr++ = byte[0];
5279 *ptr++ = byte[1];
5280 }
5281 /* marking M/Z presence */
5282 if (geom->DimensionModel == GAIA_XY_Z)
5283 *ptr++ = '8';
5284 else if (geom->DimensionModel == GAIA_XY_M)
5285 *ptr++ = '4';
5286 else if (geom->DimensionModel == GAIA_XY_Z_M)
5287 *ptr++ = 'C';
5288 else
5289 *ptr++ = '0';
5290 *ptr++ = '0';
5291 }
5292 gaiaExport64 (endian_buf, point->X, 1, endian_arch); /* X */
5293 for (i = 0; i < 8; i++)
5294 {
5295 sprintf (byte, "%02X", endian_buf[i]);
5296 *ptr++ = byte[0];
5297 *ptr++ = byte[1];
5298 }
5299 gaiaExport64 (endian_buf, point->Y, 1, endian_arch); /* Y */
5300 for (i = 0; i < 8; i++)
5301 {
5302 sprintf (byte, "%02X", endian_buf[i]);
5303 *ptr++ = byte[0];
5304 *ptr++ = byte[1];
5305 }
5306 if (geom->DimensionModel == GAIA_XY_Z)
5307 {
5308 gaiaExport64 (endian_buf, point->Z, 1, endian_arch); /* Z */
5309 for (i = 0; i < 8; i++)
5310 {
5311 sprintf (byte, "%02X", endian_buf[i]);
5312 *ptr++ = byte[0];
5313 *ptr++ = byte[1];
5314 }
5315 }
5316 else if (geom->DimensionModel == GAIA_XY_M)
5317 {
5318 gaiaExport64 (endian_buf, point->M, 1, endian_arch); /* M */
5319 for (i = 0; i < 8; i++)
5320 {
5321 sprintf (byte, "%02X", endian_buf[i]);
5322 *ptr++ = byte[0];
5323 *ptr++ = byte[1];
5324 }
5325 }
5326 else if (geom->DimensionModel == GAIA_XY_Z_M)
5327 {
5328 gaiaExport64 (endian_buf, point->Z, 1, endian_arch); /* Z */
5329 for (i = 0; i < 8; i++)
5330 {
5331 sprintf (byte, "%02X", endian_buf[i]);
5332 *ptr++ = byte[0];
5333 *ptr++ = byte[1];
5334 }
5335 gaiaExport64 (endian_buf, point->M, 1, endian_arch); /* M */
5336 for (i = 0; i < 8; i++)
5337 {
5338 sprintf (byte, "%02X", endian_buf[i]);
5339 *ptr++ = byte[0];
5340 *ptr++ = byte[1];
5341 }
5342 }
5343 point = point->Next;
5344 }
5345 line = geom->FirstLinestring;
5346 while (line)
5347 {
5348 if ((ptr - buf) > 1024)
5349 {
5350 /* flushing the internal buffer */
5351 *ptr++ = '\0';
5352 gaiaAppendToOutBuffer (out_buf, buf);
5353 ptr = buf;
5354 }
5355 if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION)
5356 {
5357 *ptr++ = '0';
5358 *ptr++ = '1';
5359 /* it's a collection: the CLASS TYPE for this element */
5360 gaiaExport32 (endian_buf, GAIA_LINESTRING, 1, endian_arch);
5361 for (i = 0; i < 3; i++)
5362 {
5363 /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5364 sprintf (byte, "%02X", endian_buf[i]);
5365 *ptr++ = byte[0];
5366 *ptr++ = byte[1];
5367 }
5368 /* marking M/Z presence */
5369 if (geom->DimensionModel == GAIA_XY_Z)
5370 *ptr++ = '8';
5371 else if (geom->DimensionModel == GAIA_XY_M)
5372 *ptr++ = '4';
5373 else if (geom->DimensionModel == GAIA_XY_Z_M)
5374 *ptr++ = 'C';
5375 else
5376 *ptr++ = '0';
5377 *ptr++ = '0';
5378 }
5379 gaiaExport32 (endian_buf, line->Points, 1, endian_arch); /* # points */
5380 for (i = 0; i < 4; i++)
5381 {
5382 sprintf (byte, "%02X", endian_buf[i]);
5383 *ptr++ = byte[0];
5384 *ptr++ = byte[1];
5385 }
5386 for (iv = 0; iv < line->Points; iv++)
5387 {
5388 if ((ptr - buf) > 1024)
5389 {
5390 /* flushing the internal buffer */
5391 *ptr++ = '\0';
5392 gaiaAppendToOutBuffer (out_buf, buf);
5393 ptr = buf;
5394 }
5395 gaiaLineGetPoint (line, iv, &x, &y, &z, &m);
5396 gaiaExport64 (endian_buf, x, 1, endian_arch); /* X */
5397 for (i = 0; i < 8; i++)
5398 {
5399 sprintf (byte, "%02X", endian_buf[i]);
5400 *ptr++ = byte[0];
5401 *ptr++ = byte[1];
5402 }
5403 gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y */
5404 for (i = 0; i < 8; i++)
5405 {
5406 sprintf (byte, "%02X", endian_buf[i]);
5407 *ptr++ = byte[0];
5408 *ptr++ = byte[1];
5409 }
5410 if (geom->DimensionModel == GAIA_XY_Z)
5411 {
5412 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5413 for (i = 0; i < 8; i++)
5414 {
5415 sprintf (byte, "%02X", endian_buf[i]);
5416 *ptr++ = byte[0];
5417 *ptr++ = byte[1];
5418 }
5419 }
5420 else if (geom->DimensionModel == GAIA_XY_M)
5421 {
5422 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5423 for (i = 0; i < 8; i++)
5424 {
5425 sprintf (byte, "%02X", endian_buf[i]);
5426 *ptr++ = byte[0];
5427 *ptr++ = byte[1];
5428 }
5429 }
5430 else if (geom->DimensionModel == GAIA_XY_Z_M)
5431 {
5432 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5433 for (i = 0; i < 8; i++)
5434 {
5435 sprintf (byte, "%02X", endian_buf[i]);
5436 *ptr++ = byte[0];
5437 *ptr++ = byte[1];
5438 }
5439 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5440 for (i = 0; i < 8; i++)
5441 {
5442 sprintf (byte, "%02X", endian_buf[i]);
5443 *ptr++ = byte[0];
5444 *ptr++ = byte[1];
5445 }
5446 }
5447 }
5448 line = line->Next;
5449 }
5450 polyg = geom->FirstPolygon;
5451 while (polyg)
5452 {
5453 if ((ptr - buf) > 1024)
5454 {
5455 /* flushing the internal buffer */
5456 *ptr++ = '\0';
5457 gaiaAppendToOutBuffer (out_buf, buf);
5458 ptr = buf;
5459 }
5460 if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5461 {
5462 *ptr++ = '0';
5463 *ptr++ = '1';
5464 /* it's a collection: the CLASS TYPE for this element */
5465 gaiaExport32 (endian_buf, GAIA_POLYGON, 1, endian_arch);
5466 for (i = 0; i < 3; i++)
5467 {
5468 /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5469 sprintf (byte, "%02X", endian_buf[i]);
5470 *ptr++ = byte[0];
5471 *ptr++ = byte[1];
5472 }
5473 /* marking M/Z presence */
5474 if (geom->DimensionModel == GAIA_XY_Z)
5475 *ptr++ = '8';
5476 else if (geom->DimensionModel == GAIA_XY_M)
5477 *ptr++ = '4';
5478 else if (geom->DimensionModel == GAIA_XY_Z_M)
5479 *ptr++ = 'C';
5480 else
5481 *ptr++ = '0';
5482 *ptr++ = '0';
5483 }
5484 gaiaExport32 (endian_buf, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */
5485 for (i = 0; i < 4; i++)
5486 {
5487 sprintf (byte, "%02X", endian_buf[i]);
5488 *ptr++ = byte[0];
5489 *ptr++ = byte[1];
5490 }
5491 rng = polyg->Exterior;
5492 gaiaExport32 (endian_buf, rng->Points, 1, endian_arch); /* # points - exterior ring */
5493 for (i = 0; i < 4; i++)
5494 {
5495 sprintf (byte, "%02X", endian_buf[i]);
5496 *ptr++ = byte[0];
5497 *ptr++ = byte[1];
5498 }
5499 for (iv = 0; iv < rng->Points; iv++)
5500 {
5501 if ((ptr - buf) > 1024)
5502 {
5503 /* flushing the internal buffer */
5504 *ptr++ = '\0';
5505 gaiaAppendToOutBuffer (out_buf, buf);
5506 ptr = buf;
5507 }
5508 gaiaRingGetPoint (rng, iv, &x, &y, &z, &m);
5509 gaiaExport64 (endian_buf, x, 1, endian_arch); /* X - exterior ring */
5510 for (i = 0; i < 8; i++)
5511 {
5512 sprintf (byte, "%02X", endian_buf[i]);
5513 *ptr++ = byte[0];
5514 *ptr++ = byte[1];
5515 }
5516 gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y - exterior ring */
5517 for (i = 0; i < 8; i++)
5518 {
5519 sprintf (byte, "%02X", endian_buf[i]);
5520 *ptr++ = byte[0];
5521 *ptr++ = byte[1];
5522 }
5523 if (geom->DimensionModel == GAIA_XY_Z)
5524 {
5525 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5526 for (i = 0; i < 8; i++)
5527 {
5528 sprintf (byte, "%02X", endian_buf[i]);
5529 *ptr++ = byte[0];
5530 *ptr++ = byte[1];
5531 }
5532 }
5533 else if (geom->DimensionModel == GAIA_XY_M)
5534 {
5535 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5536 for (i = 0; i < 8; i++)
5537 {
5538 sprintf (byte, "%02X", endian_buf[i]);
5539 *ptr++ = byte[0];
5540 *ptr++ = byte[1];
5541 }
5542 }
5543 else if (geom->DimensionModel == GAIA_XY_Z_M)
5544 {
5545 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5546 for (i = 0; i < 8; i++)
5547 {
5548 sprintf (byte, "%02X", endian_buf[i]);
5549 *ptr++ = byte[0];
5550 *ptr++ = byte[1];
5551 }
5552 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5553 for (i = 0; i < 8; i++)
5554 {
5555 sprintf (byte, "%02X", endian_buf[i]);
5556 *ptr++ = byte[0];
5557 *ptr++ = byte[1];
5558 }
5559 }
5560 }
5561 for (ib = 0; ib < polyg->NumInteriors; ib++)
5562 {
5563 rng = polyg->Interiors + ib;
5564 gaiaExport32 (endian_buf, rng->Points, 1, endian_arch); /* # points - interior ring */
5565 for (i = 0; i < 4; i++)
5566 {
5567 sprintf (byte, "%02X", endian_buf[i]);
5568 *ptr++ = byte[0];
5569 *ptr++ = byte[1];
5570 }
5571 for (iv = 0; iv < rng->Points; iv++)
5572 {
5573 if ((ptr - buf) > 1024)
5574 {
5575 /* flushing the internal buffer */
5576 *ptr++ = '\0';
5577 gaiaAppendToOutBuffer (out_buf, buf);
5578 ptr = buf;
5579 }
5580 gaiaRingGetPoint (rng, iv, &x, &y, &z, &m);
5581 gaiaExport64 (endian_buf, x, 1, endian_arch); /* X - interior ring */
5582 for (i = 0; i < 8; i++)
5583 {
5584 sprintf (byte, "%02X", endian_buf[i]);
5585 *ptr++ = byte[0];
5586 *ptr++ = byte[1];
5587 }
5588 gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y - interior ring */
5589 for (i = 0; i < 8; i++)
5590 {
5591 sprintf (byte, "%02X", endian_buf[i]);
5592 *ptr++ = byte[0];
5593 *ptr++ = byte[1];
5594 }
5595 if (geom->DimensionModel == GAIA_XY_Z)
5596 {
5597 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5598 for (i = 0; i < 8; i++)
5599 {
5600 sprintf (byte, "%02X", endian_buf[i]);
5601 *ptr++ = byte[0];
5602 *ptr++ = byte[1];
5603 }
5604 }
5605 else if (geom->DimensionModel == GAIA_XY_M)
5606 {
5607 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5608 for (i = 0; i < 8; i++)
5609 {
5610 sprintf (byte, "%02X", endian_buf[i]);
5611 *ptr++ = byte[0];
5612 *ptr++ = byte[1];
5613 }
5614 }
5615 else if (geom->DimensionModel == GAIA_XY_Z_M)
5616 {
5617 gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */
5618 for (i = 0; i < 8; i++)
5619 {
5620 sprintf (byte, "%02X", endian_buf[i]);
5621 *ptr++ = byte[0];
5622 *ptr++ = byte[1];
5623 }
5624 gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */
5625 for (i = 0; i < 8; i++)
5626 {
5627 sprintf (byte, "%02X", endian_buf[i]);
5628 *ptr++ = byte[0];
5629 *ptr++ = byte[1];
5630 }
5631 }
5632 }
5633 }
5634 polyg = polyg->Next;
5635 }
5636
5637 /* terminating the EWKB string */
5638 *ptr = '\0';
5639 gaiaAppendToOutBuffer (out_buf, buf);
5640 }
5641
5642 static int
coordDimsFromFgf(int endian_arch,const unsigned char * blob,unsigned int size,int * type)5643 coordDimsFromFgf (int endian_arch, const unsigned char *blob, unsigned int size,
5644 int *type)
5645 {
5646 /* decoding the coordinate Dimensions for an FGF Geometry */
5647 int coord_dims;
5648 if (size < 4)
5649 return 0;
5650 coord_dims = gaiaImport32 (blob, GAIA_LITTLE_ENDIAN, endian_arch);
5651 *type = coord_dims;
5652 switch (coord_dims)
5653 {
5654 case GAIA_XY:
5655 return 2;
5656 case GAIA_XY_M:
5657 case GAIA_XY_Z:
5658 return 3;
5659 case GAIA_XY_Z_M:
5660 return 4;
5661 default:
5662 return 0;
5663 }
5664 }
5665
5666 static int
pointFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5667 pointFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob,
5668 unsigned int size, unsigned int *consumed)
5669 {
5670 /* decoding a POINT Geometry from FGF */
5671 double x;
5672 double y;
5673 double z;
5674 double m;
5675 unsigned int sz = size;
5676 const unsigned char *ptr = blob;
5677 int coord_dims;
5678 int type;
5679 /* checking Geometry Type */
5680 if (sz < 4)
5681 return 0;
5682 if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_POINT)
5683 return 0;
5684 ptr += 4;
5685 sz -= 4;
5686 /* checking size */
5687 if (sz < 4)
5688 return 0;
5689 coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5690 if (!coord_dims)
5691 return 0;
5692 ptr += 4;
5693 sz -= 4;
5694 if (sz < (coord_dims * sizeof (double)))
5695 return 0;
5696 if (consumed)
5697 *consumed = coord_dims * sizeof (double);
5698 if (type == GAIA_XY_Z)
5699 {
5700 /* building the POINTZ */
5701 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5702 y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5703 z = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5704 gaiaAddPointToGeomCollXYZ (geom, x, y, z);
5705 }
5706 else if (type == GAIA_XY_M)
5707 {
5708 /* building the POINTM */
5709 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5710 y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5711 m = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5712 gaiaAddPointToGeomCollXYM (geom, x, y, m);
5713 }
5714 else if (type == GAIA_XY_Z_M)
5715 {
5716 /* building the POINTZM */
5717 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5718 y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5719 z = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5720 m = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5721 gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
5722 }
5723 else
5724 {
5725 /* building the POINT */
5726 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5727 y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5728 gaiaAddPointToGeomColl (geom, x, y);
5729 }
5730 return 1;
5731 }
5732
5733 static int
linestringFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5734 linestringFromFgf (gaiaGeomCollPtr geom, int endian_arch,
5735 const unsigned char *blob, unsigned int size,
5736 unsigned int *consumed)
5737 {
5738 /* decoding a LINESTRING Geometry from FGF */
5739 gaiaLinestringPtr ln;
5740 int pts;
5741 int iv;
5742 double x;
5743 double y;
5744 unsigned int ln_sz;
5745 unsigned int sz = size;
5746 const unsigned char *ptr = blob;
5747 int coord_dims;
5748 int type;
5749 /* checking Geometry Type */
5750 if (sz < 4)
5751 return 0;
5752 if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_LINESTRING)
5753 return 0;
5754 ptr += 4;
5755 sz -= 4;
5756 /* checking size */
5757 coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5758 if (!coord_dims)
5759 return 0;
5760 ptr += 4;
5761 sz -= 4;
5762 /* how many points are there ? */
5763 if (sz < 4)
5764 return 0;
5765 pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5766 ptr += 4;
5767 sz -= 4;
5768 if (pts < 2)
5769 return 0;
5770 ln_sz = pts * coord_dims * sizeof (double);
5771 if (sz < ln_sz)
5772 return 0;
5773 if (consumed)
5774 *consumed = (12 + ln_sz);
5775 if (type == GAIA_XY_Z)
5776 {
5777 /* building the LINESTRINGZ */
5778 geom->DimensionModel = GAIA_XY_Z;
5779 ln = gaiaAddLinestringToGeomColl (geom, pts);
5780 for (iv = 0; iv < pts; iv++)
5781 {
5782 /* inserting vertices into the linestring */
5783 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5784 y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5785 endian_arch);
5786 ptr += (coord_dims * sizeof (double));
5787 gaiaSetPoint (ln->Coords, iv, x, y);
5788 }
5789 }
5790 else if (type == GAIA_XY_M)
5791 {
5792 /* building the LINESTRINGM */
5793 geom->DimensionModel = GAIA_XY_M;
5794 ln = gaiaAddLinestringToGeomColl (geom, pts);
5795 for (iv = 0; iv < pts; iv++)
5796 {
5797 /* inserting vertices into the linestring */
5798 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5799 y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5800 endian_arch);
5801 ptr += (coord_dims * sizeof (double));
5802 gaiaSetPoint (ln->Coords, iv, x, y);
5803 }
5804 }
5805 else if (type == GAIA_XY_Z_M)
5806 {
5807 /* building the LINESTRINGZM */
5808 geom->DimensionModel = GAIA_XY_Z_M;
5809 ln = gaiaAddLinestringToGeomColl (geom, pts);
5810 for (iv = 0; iv < pts; iv++)
5811 {
5812 /* inserting vertices into the linestring */
5813 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5814 y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5815 endian_arch);
5816 ptr += (coord_dims * sizeof (double));
5817 gaiaSetPoint (ln->Coords, iv, x, y);
5818 }
5819 }
5820 else
5821 {
5822 /* building the LINESTRING */
5823 geom->DimensionModel = GAIA_XY;
5824 ln = gaiaAddLinestringToGeomColl (geom, pts);
5825 for (iv = 0; iv < pts; iv++)
5826 {
5827 /* inserting vertices into the linestring */
5828 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5829 y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5830 endian_arch);
5831 ptr += (coord_dims * sizeof (double));
5832 gaiaSetPoint (ln->Coords, iv, x, y);
5833 }
5834 }
5835 return 1;
5836 }
5837
5838 static int
polygonFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5839 polygonFromFgf (gaiaGeomCollPtr geom, int endian_arch,
5840 const unsigned char *blob, unsigned int size,
5841 unsigned int *consumed)
5842 {
5843 /* decoding a POLYGON Geometry from FGF */
5844 gaiaPolygonPtr pg = NULL;
5845 gaiaRingPtr rng;
5846 int rings;
5847 int ir;
5848 int pts;
5849 int iv;
5850 double x;
5851 double y;
5852 double z;
5853 double m;
5854 unsigned int rng_sz;
5855 unsigned int sz = size;
5856 const unsigned char *ptr = blob;
5857 int coord_dims;
5858 int type;
5859 unsigned int bytes = 0;
5860 /* checking Geometry Type */
5861 if (sz < 4)
5862 return 0;
5863 if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_POLYGON)
5864 return 0;
5865 ptr += 4;
5866 sz -= 4;
5867 bytes += 4;
5868 /* checking size */
5869 coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5870 if (!coord_dims)
5871 return 0;
5872 ptr += 4;
5873 sz -= 4;
5874 bytes += 4;
5875 /* how many rings are there ? */
5876 if (sz < 4)
5877 return 0;
5878 rings = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5879 ptr += 4;
5880 sz -= 4;
5881 bytes += 4;
5882 if (rings < 1)
5883 return 0;
5884 for (ir = 0; ir < rings; ir++)
5885 {
5886 /* fetching Polygon's rings */
5887 if (sz < 4)
5888 return 0;
5889 pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5890 ptr += 4;
5891 sz -= 4;
5892 bytes += 4;
5893 if (pts < 4)
5894 return 0;
5895 rng_sz = pts * coord_dims * sizeof (double);
5896 if (sz < rng_sz)
5897 return 0;
5898 bytes += rng_sz;
5899 if (type == GAIA_XY_Z)
5900 {
5901 /* POLYGONZ */
5902 geom->DimensionModel = GAIA_XY_Z;
5903 if (ir == 0)
5904 {
5905 /* building the EXTERIOR RING */
5906 pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5907 rng = pg->Exterior;
5908 for (iv = 0; iv < pts; iv++)
5909 {
5910 /* inserting vertices into the EXTERIOR Ring */
5911 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5912 endian_arch);
5913 y = gaiaImport64 (ptr + sizeof (double),
5914 GAIA_LITTLE_ENDIAN, endian_arch);
5915 z = gaiaImport64 (ptr + (sizeof (double) * 2),
5916 GAIA_LITTLE_ENDIAN, endian_arch);
5917 ptr += (coord_dims * sizeof (double));
5918 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5919 }
5920 }
5921 else
5922 {
5923 /* building an INTERIOR RING */
5924 rng = gaiaAddInteriorRing (pg, ir - 1, pts);
5925 for (iv = 0; iv < pts; iv++)
5926 {
5927 /* inserting vertices into some INTERIOR Ring */
5928 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5929 endian_arch);
5930 y = gaiaImport64 (ptr + sizeof (double),
5931 GAIA_LITTLE_ENDIAN, endian_arch);
5932 z = gaiaImport64 (ptr + (sizeof (double) * 2),
5933 GAIA_LITTLE_ENDIAN, endian_arch);
5934 ptr += (coord_dims * sizeof (double));
5935 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5936 }
5937 }
5938 }
5939 if (type == GAIA_XY_M)
5940 {
5941 /* POLYGONM */
5942 geom->DimensionModel = GAIA_XY_M;
5943 if (ir == 0)
5944 {
5945 /* building the EXTERIOR RING */
5946 pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5947 rng = pg->Exterior;
5948 for (iv = 0; iv < pts; iv++)
5949 {
5950 /* inserting vertices into the EXTERIOR Ring */
5951 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5952 endian_arch);
5953 y = gaiaImport64 (ptr + sizeof (double),
5954 GAIA_LITTLE_ENDIAN, endian_arch);
5955 m = gaiaImport64 (ptr + (sizeof (double) * 2),
5956 GAIA_LITTLE_ENDIAN, endian_arch);
5957 ptr += (coord_dims * sizeof (double));
5958 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5959 }
5960 }
5961 else
5962 {
5963 /* building an INTERIOR RING */
5964 rng = gaiaAddInteriorRing (pg, ir - 1, pts);
5965 for (iv = 0; iv < pts; iv++)
5966 {
5967 /* inserting vertices into some INTERIOR Ring */
5968 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5969 endian_arch);
5970 y = gaiaImport64 (ptr + sizeof (double),
5971 GAIA_LITTLE_ENDIAN, endian_arch);
5972 m = gaiaImport64 (ptr + (sizeof (double) * 2),
5973 GAIA_LITTLE_ENDIAN, endian_arch);
5974 ptr += (coord_dims * sizeof (double));
5975 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5976 }
5977 }
5978 }
5979 else if (type == GAIA_XY_Z_M)
5980 {
5981 /* POLYGONZM */
5982 geom->DimensionModel = GAIA_XY_Z_M;
5983 if (ir == 0)
5984 {
5985 /* building the EXTERIOR RING */
5986 pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5987 rng = pg->Exterior;
5988 for (iv = 0; iv < pts; iv++)
5989 {
5990 /* inserting vertices into the EXTERIOR Ring */
5991 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5992 endian_arch);
5993 y = gaiaImport64 (ptr + sizeof (double),
5994 GAIA_LITTLE_ENDIAN, endian_arch);
5995 z = gaiaImport64 (ptr + (sizeof (double) * 2),
5996 GAIA_LITTLE_ENDIAN, endian_arch);
5997 m = gaiaImport64 (ptr + (sizeof (double) * 3),
5998 GAIA_LITTLE_ENDIAN, endian_arch);
5999 ptr += (coord_dims * sizeof (double));
6000 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
6001 }
6002 }
6003 else
6004 {
6005 /* building an INTERIOR RING */
6006 rng = gaiaAddInteriorRing (pg, ir - 1, pts);
6007 for (iv = 0; iv < pts; iv++)
6008 {
6009 /* inserting vertices into some INTERIOR Ring */
6010 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6011 endian_arch);
6012 y = gaiaImport64 (ptr + sizeof (double),
6013 GAIA_LITTLE_ENDIAN, endian_arch);
6014 z = gaiaImport64 (ptr + (sizeof (double) * 2),
6015 GAIA_LITTLE_ENDIAN, endian_arch);
6016 m = gaiaImport64 (ptr + (sizeof (double) * 3),
6017 GAIA_LITTLE_ENDIAN, endian_arch);
6018 ptr += (coord_dims * sizeof (double));
6019 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
6020 }
6021 }
6022 }
6023 else
6024 {
6025 /* POLYGON */
6026 geom->DimensionModel = GAIA_XY;
6027 if (ir == 0)
6028 {
6029 /* building the EXTERIOR RING */
6030 pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
6031 rng = pg->Exterior;
6032 for (iv = 0; iv < pts; iv++)
6033 {
6034 /* inserting vertices into the EXTERIOR Ring */
6035 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6036 endian_arch);
6037 y = gaiaImport64 (ptr + sizeof (double),
6038 GAIA_LITTLE_ENDIAN, endian_arch);
6039 ptr += (coord_dims * sizeof (double));
6040 gaiaSetPoint (rng->Coords, iv, x, y);
6041 }
6042 }
6043 else
6044 {
6045 /* building an INTERIOR RING */
6046 rng = gaiaAddInteriorRing (pg, ir - 1, pts);
6047 for (iv = 0; iv < pts; iv++)
6048 {
6049 /* inserting vertices into some INTERIOR Ring */
6050 x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6051 endian_arch);
6052 y = gaiaImport64 (ptr + sizeof (double),
6053 GAIA_LITTLE_ENDIAN, endian_arch);
6054 ptr += (coord_dims * sizeof (double));
6055 gaiaSetPoint (rng->Coords, iv, x, y);
6056 }
6057 }
6058 }
6059 sz -= rng_sz;
6060 }
6061 if (consumed)
6062 *consumed = bytes;
6063 return 1;
6064 }
6065
6066 static int
multiPointFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6067 multiPointFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6068 const unsigned char *blob, unsigned int size)
6069 {
6070 /* decoding a MULTIPOINT Geometry from FGF */
6071 int pts;
6072 int ipt;
6073 unsigned int sz = size;
6074 const unsigned char *ptr = blob;
6075 unsigned int consumed;
6076 /* checking Geometry Type */
6077 if (sz < 4)
6078 return 0;
6079 if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOINT)
6080 return 0;
6081 ptr += 4;
6082 sz -= 4;
6083 /* how many points are there ? */
6084 if (sz < 4)
6085 return 0;
6086 pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6087 ptr += 4;
6088 sz -= 4;
6089 if (pts < 1)
6090 return 0;
6091 for (ipt = 0; ipt < pts; ipt++)
6092 {
6093 /* fetching individual Points from FGF */
6094 if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed))
6095 return 0;
6096 ptr += consumed;
6097 sz -= consumed;
6098 }
6099 return 1;
6100 }
6101
6102 static int
multiLinestringFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6103 multiLinestringFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6104 const unsigned char *blob, unsigned int size)
6105 {
6106 /* decoding a MULTILINESTRING Geometry from FGF */
6107 int lns;
6108 int iln;
6109 unsigned int sz = size;
6110 const unsigned char *ptr = blob;
6111 unsigned int consumed;
6112 /* checking Geometry Type */
6113 if (sz < 4)
6114 return 0;
6115 if (gaiaImport32
6116 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTILINESTRING)
6117 return 0;
6118 ptr += 4;
6119 sz -= 4;
6120 /* how many linestrings are there ? */
6121 if (sz < 4)
6122 return 0;
6123 lns = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6124 ptr += 4;
6125 sz -= 4;
6126 if (lns < 1)
6127 return 0;
6128 for (iln = 0; iln < lns; iln++)
6129 {
6130 /* fetching individual Linestrings from FGF */
6131 if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed))
6132 return 0;
6133 ptr += consumed;
6134 sz -= consumed;
6135 }
6136 return 1;
6137 }
6138
6139 static int
multiPolygonFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6140 multiPolygonFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6141 const unsigned char *blob, unsigned int size)
6142 {
6143 /* decoding a MULTIPOLYGON Geometry from FGF */
6144 int pgs;
6145 int ipg;
6146 unsigned int sz = size;
6147 const unsigned char *ptr = blob;
6148 unsigned int consumed;
6149 /* checking Geometry Type */
6150 if (sz < 4)
6151 return 0;
6152 if (gaiaImport32
6153 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOLYGON)
6154 return 0;
6155 ptr += 4;
6156 sz -= 4;
6157 /* how many polygons are there ? */
6158 if (sz < 4)
6159 return 0;
6160 pgs = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6161 ptr += 4;
6162 sz -= 4;
6163 if (pgs < 1)
6164 return 0;
6165 for (ipg = 0; ipg < pgs; ipg++)
6166 {
6167 /* fetching individual Polygons from FGF */
6168 if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed))
6169 return 0;
6170 ptr += consumed;
6171 sz -= consumed;
6172 }
6173 return 1;
6174 }
6175
6176 static int
geomCollectionFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6177 geomCollectionFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6178 const unsigned char *blob, unsigned int size)
6179 {
6180 /* decoding a GEOMETRYCOLLECTION Geometry from FGF */
6181 int geoms;
6182 int ig;
6183 int geom_type;
6184 unsigned int sz = size;
6185 const unsigned char *ptr = blob;
6186 unsigned int consumed;
6187 /* checking Geometry Type */
6188 if (sz < 4)
6189 return 0;
6190 if (gaiaImport32
6191 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_GEOMETRYCOLLECTION)
6192 return 0;
6193 ptr += 4;
6194 sz -= 4;
6195 /* how many individual Geometries are there ? */
6196 if (sz < 4)
6197 return 0;
6198 geoms = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6199 ptr += 4;
6200 sz -= 4;
6201 if (geoms < 1)
6202 return 0;
6203 for (ig = 0; ig < geoms; ig++)
6204 {
6205 /* fetching individual Geometries from FGF */
6206 if (sz < 4)
6207 return 0;
6208 geom_type = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6209 switch (geom_type)
6210 {
6211 case GAIA_POINT:
6212 if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed))
6213 return 0;
6214 break;
6215 case GAIA_LINESTRING:
6216 if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed))
6217 return 0;
6218 break;
6219 case GAIA_POLYGON:
6220 if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed))
6221 return 0;
6222 break;
6223 default: /* unsupported geometry type */
6224 return 0;
6225 break;
6226 };
6227 ptr += consumed;
6228 sz -= consumed;
6229 }
6230 return 1;
6231 }
6232
6233 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromFgf(const unsigned char * blob,unsigned int size)6234 gaiaFromFgf (const unsigned char *blob, unsigned int size)
6235 {
6236 /* decoding from FGF to GEOMETRY */
6237 gaiaGeomCollPtr geom = NULL;
6238 int geom_type;
6239 int endian_arch = gaiaEndianArch ();
6240 if (size < 4)
6241 return NULL;
6242 /* checking FGF type */
6243 geom_type = gaiaImport32 (blob, GAIA_LITTLE_ENDIAN, endian_arch);
6244 geom = gaiaAllocGeomColl ();
6245 geom->DeclaredType = geom_type;
6246 switch (geom_type)
6247 {
6248 case GAIA_POINT:
6249 if (pointFromFgf (geom, endian_arch, blob, size, NULL))
6250 return geom;
6251 break;
6252 case GAIA_LINESTRING:
6253 if (linestringFromFgf (geom, endian_arch, blob, size, NULL))
6254 return geom;
6255 break;
6256 case GAIA_POLYGON:
6257 if (polygonFromFgf (geom, endian_arch, blob, size, NULL))
6258 return geom;
6259 break;
6260 case GAIA_MULTIPOINT:
6261 if (multiPointFromFgf (geom, endian_arch, blob, size))
6262 return geom;
6263 break;
6264 case GAIA_MULTILINESTRING:
6265 if (multiLinestringFromFgf (geom, endian_arch, blob, size))
6266 return geom;
6267 break;
6268 case GAIA_MULTIPOLYGON:
6269 if (multiPolygonFromFgf (geom, endian_arch, blob, size))
6270 return geom;
6271 break;
6272 case GAIA_GEOMETRYCOLLECTION:
6273 if (geomCollectionFromFgf (geom, endian_arch, blob, size))
6274 return geom;
6275 break;
6276 default: /* unsupported geometry type */
6277 break;
6278 };
6279 gaiaFreeGeomColl (geom);
6280 return NULL;
6281 }
6282
6283 GAIAGEO_DECLARE void
gaiaToFgf(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int coord_dims)6284 gaiaToFgf (gaiaGeomCollPtr geom, unsigned char **result, int *size,
6285 int coord_dims)
6286 {
6287 /* builds the FGF representation for this GEOMETRY */
6288 int ib;
6289 int iv;
6290 double x;
6291 double y;
6292 double z;
6293 double m;
6294 int entities = 0;
6295 int n_points = 0;
6296 int n_linestrings = 0;
6297 int n_polygons = 0;
6298 int type;
6299 int n_coords;
6300 unsigned char *ptr;
6301 int sz = 0;
6302 gaiaPointPtr pt;
6303 gaiaLinestringPtr ln;
6304 gaiaPolygonPtr pg;
6305 gaiaRingPtr rng;
6306 gaiaPointPtr point = NULL;
6307 gaiaLinestringPtr line = NULL;
6308 gaiaPolygonPtr polyg = NULL;
6309 int endian_arch = gaiaEndianArch ();
6310 gaiaMbrGeometry (geom);
6311 switch (coord_dims)
6312 {
6313 case GAIA_XY:
6314 n_coords = 2;
6315 break;
6316 case GAIA_XY_M:
6317 case GAIA_XY_Z:
6318 n_coords = 3;
6319 break;
6320 case GAIA_XY_Z_M:
6321 n_coords = 4;
6322 break;
6323 default:
6324 n_coords = 0;
6325 break;
6326 }
6327 /* how many entities, and of what kind, do we have ? */
6328 pt = geom->FirstPoint;
6329 while (pt)
6330 {
6331 point = pt;
6332 entities++;
6333 n_points++;
6334 pt = pt->Next;
6335 }
6336 ln = geom->FirstLinestring;
6337 while (ln)
6338 {
6339 line = ln;
6340 entities++;
6341 n_linestrings++;
6342 ln = ln->Next;
6343 }
6344 pg = geom->FirstPolygon;
6345 while (pg)
6346 {
6347 polyg = pg;
6348 entities++;
6349 n_polygons++;
6350 pg = pg->Next;
6351 }
6352 *size = 0;
6353 sz = 0;
6354 *result = NULL;
6355 if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
6356 return;
6357 /* ok, we can determine the geometry class */
6358 if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
6359 {
6360 if (geom->DeclaredType == GAIA_MULTIPOINT)
6361 type = GAIA_MULTIPOINT;
6362 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6363 type = GAIA_GEOMETRYCOLLECTION;
6364 else
6365 type = GAIA_POINT;
6366 }
6367 else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
6368 {
6369 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6370 type = GAIA_GEOMETRYCOLLECTION;
6371 else
6372 type = GAIA_MULTIPOINT;
6373 }
6374 else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
6375 {
6376 if (geom->DeclaredType == GAIA_MULTILINESTRING)
6377 type = GAIA_MULTILINESTRING;
6378 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6379 type = GAIA_GEOMETRYCOLLECTION;
6380 else
6381 type = GAIA_LINESTRING;
6382 }
6383 else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
6384 {
6385 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6386 type = GAIA_GEOMETRYCOLLECTION;
6387 else
6388 type = GAIA_MULTILINESTRING;
6389 }
6390 else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
6391 {
6392 if (geom->DeclaredType == GAIA_MULTIPOLYGON)
6393 type = GAIA_MULTIPOLYGON;
6394 else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6395 type = GAIA_GEOMETRYCOLLECTION;
6396 else
6397 type = GAIA_POLYGON;
6398 }
6399 else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
6400 {
6401 if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6402 type = GAIA_GEOMETRYCOLLECTION;
6403 else
6404 type = GAIA_MULTIPOLYGON;
6405 }
6406 else
6407 type = GAIA_GEOMETRYCOLLECTION;
6408 /* and now we compute the size of FGF */
6409 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
6410 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
6411 sz += 8;
6412 point = geom->FirstPoint;
6413 while (point)
6414 {
6415 sz += (8 + (n_coords * sizeof (double))); /* the size of each POINT */
6416 point = point->Next;
6417 }
6418 line = geom->FirstLinestring;
6419 while (line)
6420 {
6421 sz += (12 + ((n_coords * sizeof (double)) * line->Points)); /* # points + [x,y] for each vertex */
6422 line = line->Next;
6423 }
6424 polyg = geom->FirstPolygon;
6425 while (polyg)
6426 {
6427 rng = polyg->Exterior;
6428 sz += (16 + ((n_coords * sizeof (double)) * rng->Points)); /* # rings + # points + [x.y] array - exterior ring */
6429 for (ib = 0; ib < polyg->NumInteriors; ib++)
6430 {
6431 rng = polyg->Interiors + ib;
6432 sz += (4 + ((n_coords * sizeof (double)) * rng->Points)); /* # points + [x,y] array - interior ring */
6433 }
6434 polyg = polyg->Next;
6435 }
6436 *size = sz;
6437 ptr = malloc (sz);
6438 *result = ptr;
6439 /* and finally we build the FGF */
6440 if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
6441 || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
6442 {
6443 gaiaExport32 (ptr, type, GAIA_LITTLE_ENDIAN, endian_arch); /* Geometry Type */
6444 ptr += 4;
6445 gaiaExport32 (ptr, entities, GAIA_LITTLE_ENDIAN, endian_arch); /* it's a collection; # entities */
6446 ptr += 4;
6447 }
6448 point = geom->FirstPoint;
6449 while (point)
6450 {
6451 gaiaExport32 (ptr, GAIA_POINT, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */
6452 ptr += 4;
6453 gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension */
6454 ptr += 4;
6455 gaiaExport64 (ptr, point->X, GAIA_LITTLE_ENDIAN, endian_arch); /* X */
6456 ptr += 8;
6457 gaiaExport64 (ptr, point->Y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y */
6458 ptr += 8;
6459 if (n_coords > 2)
6460 {
6461 /* the third coordinate [Z or M] */
6462 if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6463 gaiaExport64 (ptr, point->Z, GAIA_LITTLE_ENDIAN,
6464 endian_arch);
6465 else
6466 gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN,
6467 endian_arch);
6468 ptr += 8;
6469 }
6470 if (n_coords > 3)
6471 {
6472 /* the fourth coordinate [M] */
6473 gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN, endian_arch);
6474 ptr += 8;
6475 }
6476 point = point->Next;
6477 }
6478 line = geom->FirstLinestring;
6479 while (line)
6480 {
6481 gaiaExport32 (ptr, GAIA_LINESTRING, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */
6482 ptr += 4;
6483 gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension */
6484 ptr += 4;
6485 gaiaExport32 (ptr, line->Points, GAIA_LITTLE_ENDIAN, endian_arch); /* # points */
6486 ptr += 4;
6487 for (iv = 0; iv < line->Points; iv++)
6488 {
6489 z = 0.0;
6490 m = 0.0;
6491 if (geom->DimensionModel == GAIA_XY_Z)
6492 {
6493 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
6494 }
6495 else if (geom->DimensionModel == GAIA_XY_M)
6496 {
6497 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
6498 }
6499 else if (geom->DimensionModel == GAIA_XY_Z_M)
6500 {
6501 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
6502 }
6503 else
6504 {
6505 gaiaGetPoint (line->Coords, iv, &x, &y);
6506 }
6507 gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X */
6508 ptr += 8;
6509 gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y */
6510 ptr += 8;
6511 if (n_coords > 2)
6512 {
6513 /* the third coordinate [Z or M] */
6514 if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6515 gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6516 endian_arch);
6517 else
6518 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6519 endian_arch);
6520 ptr += 8;
6521 }
6522 if (n_coords > 3)
6523 {
6524 /* the fourth coordinate [M]; */
6525 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch);
6526 ptr += 8;
6527 }
6528 }
6529 line = line->Next;
6530 }
6531 polyg = geom->FirstPolygon;
6532 while (polyg)
6533 {
6534 gaiaExport32 (ptr, GAIA_POLYGON, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */
6535 ptr += 4;
6536 gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension */
6537 ptr += 4;
6538 gaiaExport32 (ptr, polyg->NumInteriors + 1, GAIA_LITTLE_ENDIAN, endian_arch); /* # rings */
6539 ptr += 4;
6540 rng = polyg->Exterior;
6541 gaiaExport32 (ptr, rng->Points, GAIA_LITTLE_ENDIAN, endian_arch); /* # points - exterior ring */
6542 ptr += 4;
6543 for (iv = 0; iv < rng->Points; iv++)
6544 {
6545 z = 0.0;
6546 m = 0.0;
6547 if (geom->DimensionModel == GAIA_XY_Z)
6548 {
6549 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
6550 }
6551 else if (geom->DimensionModel == GAIA_XY_M)
6552 {
6553 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
6554 }
6555 else if (geom->DimensionModel == GAIA_XY_Z_M)
6556 {
6557 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
6558 }
6559 else
6560 {
6561 gaiaGetPoint (rng->Coords, iv, &x, &y);
6562 }
6563 gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X - exterior ring */
6564 ptr += 8;
6565 gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y - exterior ring */
6566 ptr += 8;
6567 if (n_coords > 2)
6568 {
6569 /* the third coordinate [Z or M] */
6570 if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6571 gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6572 endian_arch);
6573 else
6574 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6575 endian_arch);
6576 ptr += 8;
6577 }
6578 if (n_coords > 3)
6579 {
6580 /* the fourth coordinate [M] */
6581 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch);
6582 ptr += 8;
6583 }
6584 }
6585 for (ib = 0; ib < polyg->NumInteriors; ib++)
6586 {
6587 rng = polyg->Interiors + ib;
6588 gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */
6589 ptr += 4;
6590 for (iv = 0; iv < rng->Points; iv++)
6591 {
6592 z = 0.0;
6593 m = 0.0;
6594 if (geom->DimensionModel == GAIA_XY_Z)
6595 {
6596 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
6597 }
6598 else if (geom->DimensionModel == GAIA_XY_M)
6599 {
6600 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
6601 }
6602 else if (geom->DimensionModel == GAIA_XY_Z_M)
6603 {
6604 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
6605 }
6606 else
6607 {
6608 gaiaGetPoint (rng->Coords, iv, &x, &y);
6609 }
6610 gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X - interior ring */
6611 ptr += 8;
6612 gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y - interior ring */
6613 ptr += 8;
6614 if (n_coords > 2)
6615 {
6616 /* the third coordinate [Z or M]; defaulting to ZERO */
6617 if (coord_dims == GAIA_XY_Z
6618 || coord_dims == GAIA_XY_Z_M)
6619 gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6620 endian_arch);
6621 else
6622 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6623 endian_arch);
6624 ptr += 8;
6625 }
6626 if (n_coords > 3)
6627 {
6628 /* the fourth coordinate [M] */
6629 gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6630 endian_arch);
6631 ptr += 8;
6632 }
6633 }
6634 }
6635 polyg = polyg->Next;
6636 }
6637 }
6638