1 /*
2
3 gg_rttopo.c -- Gaia RTTOPO support
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) 2012-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 /*
47
48 CREDITS:
49
50 this module (wrapping liblwgeom APIs) has been entierely funded by:
51 Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
52
53 HISTORY:
54 this module was previously name gg_lwgeom.c and was based on liblwgeom;
55 the current version depends on the newer RTTOPO support
56
57 */
58
59 #include <sys/types.h>
60 #include <stdlib.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <float.h>
64 #include <math.h>
65
66 #if defined(_WIN32) && !defined(__MINGW32__)
67 #include "config-msvc.h"
68 #else
69 #include "config.h"
70 #endif
71
72 #include <spatialite_private.h>
73 #include <spatialite/sqlite.h>
74 #include <spatialite.h>
75 #include <spatialite/debug.h>
76
77 #include <spatialite/gaiageo.h>
78
79 #ifdef ENABLE_RTTOPO /* enabling RTTOPO support */
80
81 #include <librttopo_geom.h>
82
83 extern char *rtgeom_to_encoded_polyline (const RTCTX * ctx, const RTGEOM * geom,
84 int precision);
85 static RTGEOM *rtgeom_from_encoded_polyline (const RTCTX * ctx,
86 const char *encodedpolyline,
87 int precision);
88
89 SPATIALITE_PRIVATE const char *
splite_rttopo_version(void)90 splite_rttopo_version (void)
91 {
92 return rtgeom_version ();
93 }
94
95 GAIAGEO_DECLARE void
gaiaResetRtTopoMsg(const void * p_cache)96 gaiaResetRtTopoMsg (const void *p_cache)
97 {
98 /* Resets the RTTOPO error and warning messages to an empty state */
99 struct splite_internal_cache *cache =
100 (struct splite_internal_cache *) p_cache;
101 if (cache == NULL)
102 return;
103 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
104 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
105 return;
106
107 if (cache->gaia_rttopo_error_msg)
108 free (cache->gaia_rttopo_error_msg);
109 if (cache->gaia_rttopo_warning_msg)
110 free (cache->gaia_rttopo_warning_msg);
111 cache->gaia_rttopo_error_msg = NULL;
112 cache->gaia_rttopo_warning_msg = NULL;
113 }
114
115 GAIAGEO_DECLARE const char *
gaiaGetRtTopoErrorMsg(const void * p_cache)116 gaiaGetRtTopoErrorMsg (const void *p_cache)
117 {
118 /* Return the latest RTTOPO error message (if any) */
119 struct splite_internal_cache *cache =
120 (struct splite_internal_cache *) p_cache;
121 if (cache == NULL)
122 return NULL;
123 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
124 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
125 return NULL;
126
127 return cache->gaia_rttopo_error_msg;
128 }
129
130 GAIAGEO_DECLARE void
gaiaSetRtTopoErrorMsg(const void * p_cache,const char * msg)131 gaiaSetRtTopoErrorMsg (const void *p_cache, const char *msg)
132 {
133 /* Sets the RTTOPO error message */
134 int len;
135 struct splite_internal_cache *cache =
136 (struct splite_internal_cache *) p_cache;
137 if (cache == NULL)
138 return;
139 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
140 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
141 return;
142
143 if (cache->gaia_rttopo_error_msg)
144 free (cache->gaia_rttopo_error_msg);
145 cache->gaia_rttopo_error_msg = NULL;
146 if (msg == NULL)
147 return;
148
149 len = strlen (msg);
150 cache->gaia_rttopo_error_msg = malloc (len + 1);
151 strcpy (cache->gaia_rttopo_error_msg, msg);
152 }
153
154 GAIAGEO_DECLARE const char *
gaiaGetRtTopoWarningMsg(const void * p_cache)155 gaiaGetRtTopoWarningMsg (const void *p_cache)
156 {
157 /* Return the latest RTTOPO warning message (if any) */
158 struct splite_internal_cache *cache =
159 (struct splite_internal_cache *) p_cache;
160 if (cache == NULL)
161 return NULL;
162 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
163 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
164 return NULL;
165
166 return cache->gaia_rttopo_warning_msg;
167 }
168
169 GAIAGEO_DECLARE void
gaiaSetRtTopoWarningMsg(const void * p_cache,const char * msg)170 gaiaSetRtTopoWarningMsg (const void *p_cache, const char *msg)
171 {
172 /* Sets the RTTOPO warning message */
173 int len;
174 struct splite_internal_cache *cache =
175 (struct splite_internal_cache *) p_cache;
176 if (cache == NULL)
177 return;
178 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
179 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
180 return;
181
182 if (cache->gaia_rttopo_warning_msg)
183 free (cache->gaia_rttopo_warning_msg);
184 cache->gaia_rttopo_warning_msg = NULL;
185 if (msg == NULL)
186 return;
187
188 len = strlen (msg);
189 cache->gaia_rttopo_warning_msg = malloc (len + 1);
190 strcpy (cache->gaia_rttopo_warning_msg, msg);
191 }
192
193 static int
check_unclosed_ring(gaiaRingPtr rng)194 check_unclosed_ring (gaiaRingPtr rng)
195 {
196 /* checks if a Ring is closed or not */
197 double x0;
198 double y0;
199 double z0 = 0.0;
200 double m0 = 0.0;
201 double x1;
202 double y1;
203 double z1 = 0.0;
204 double m1 = 0.0;
205 int last = rng->Points - 1;
206 if (rng->DimensionModel == GAIA_XY_Z)
207 {
208 gaiaGetPointXYZ (rng->Coords, 0, &x0, &y0, &z0);
209 }
210 else if (rng->DimensionModel == GAIA_XY_M)
211 {
212 gaiaGetPointXYM (rng->Coords, 0, &x0, &y0, &m0);
213 }
214 else if (rng->DimensionModel == GAIA_XY_Z_M)
215 {
216 gaiaGetPointXYZM (rng->Coords, 0, &x0, &y0, &z0, &m0);
217 }
218 else
219 {
220 gaiaGetPoint (rng->Coords, 0, &x0, &y0);
221 }
222 if (rng->DimensionModel == GAIA_XY_Z)
223 {
224 gaiaGetPointXYZ (rng->Coords, last, &x1, &y1, &z1);
225 }
226 else if (rng->DimensionModel == GAIA_XY_M)
227 {
228 gaiaGetPointXYM (rng->Coords, last, &x1, &y1, &m1);
229 }
230 else if (rng->DimensionModel == GAIA_XY_Z_M)
231 {
232 gaiaGetPointXYZM (rng->Coords, last, &x1, &y1, &z1, &m1);
233 }
234 else
235 {
236 gaiaGetPoint (rng->Coords, last, &x1, &y1);
237 }
238 if (x0 == x1 && y0 == y1 && z0 == z1 && m0 == m1)
239 return 0;
240 return 1;
241 }
242
243 SPATIALITE_PRIVATE void *
toRTGeom(const void * pctx,const void * pgaia)244 toRTGeom (const void *pctx, const void *pgaia)
245 {
246 /* converting a GAIA Geometry into a RTGEOM Geometry */
247 const RTCTX *ctx = (const RTCTX *) pctx;
248 const gaiaGeomCollPtr gaia = (const gaiaGeomCollPtr) pgaia;
249 int pts = 0;
250 int lns = 0;
251 int pgs = 0;
252 int has_z;
253 int has_m;
254 int ngeoms;
255 int numg;
256 int ib;
257 int iv;
258 int type;
259 double x = 0.0;
260 double y = 0.0;
261 double z = 0.0;
262 double m = 0.0;
263 int close_ring;
264 gaiaPointPtr pt;
265 gaiaLinestringPtr ln;
266 gaiaPolygonPtr pg;
267 gaiaRingPtr rng;
268 RTPOINTARRAY *pa;
269 RTPOINTARRAY **ppaa;
270 RTPOINT4D point;
271 RTGEOM **geoms;
272
273 if (!gaia)
274 return NULL;
275 pt = gaia->FirstPoint;
276 while (pt)
277 {
278 /* counting how many POINTs are there */
279 pts++;
280 pt = pt->Next;
281 }
282 ln = gaia->FirstLinestring;
283 while (ln)
284 {
285 /* counting how many LINESTRINGs are there */
286 lns++;
287 ln = ln->Next;
288 }
289 pg = gaia->FirstPolygon;
290 while (pg)
291 {
292 /* counting how many POLYGONs are there */
293 pgs++;
294 pg = pg->Next;
295 }
296 if (pts == 0 && lns == 0 && pgs == 0)
297 return NULL;
298
299 if (pts == 1 && lns == 0 && pgs == 0)
300 {
301 /* single Point */
302 pt = gaia->FirstPoint;
303 has_z = 0;
304 has_m = 0;
305 if (gaia->DimensionModel == GAIA_XY_Z
306 || gaia->DimensionModel == GAIA_XY_Z_M)
307 has_z = 1;
308 if (gaia->DimensionModel == GAIA_XY_M
309 || gaia->DimensionModel == GAIA_XY_Z_M)
310 has_m = 1;
311 pa = ptarray_construct (ctx, has_z, has_m, 1);
312 point.x = pt->X;
313 point.y = pt->Y;
314 if (has_z)
315 point.z = pt->Z;
316 if (has_m)
317 point.m = pt->M;
318 ptarray_set_point4d (ctx, pa, 0, &point);
319 return (RTGEOM *) rtpoint_construct (ctx, gaia->Srid, NULL, pa);
320 }
321 else if (pts == 0 && lns == 1 && pgs == 0)
322 {
323 /* single Linestring */
324 ln = gaia->FirstLinestring;
325 has_z = 0;
326 has_m = 0;
327 if (gaia->DimensionModel == GAIA_XY_Z
328 || gaia->DimensionModel == GAIA_XY_Z_M)
329 has_z = 1;
330 if (gaia->DimensionModel == GAIA_XY_M
331 || gaia->DimensionModel == GAIA_XY_Z_M)
332 has_m = 1;
333 pa = ptarray_construct (ctx, has_z, has_m, ln->Points);
334 for (iv = 0; iv < ln->Points; iv++)
335 {
336 /* copying vertices */
337 if (gaia->DimensionModel == GAIA_XY_Z)
338 {
339 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
340 }
341 else if (gaia->DimensionModel == GAIA_XY_M)
342 {
343 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
344 }
345 else if (gaia->DimensionModel == GAIA_XY_Z_M)
346 {
347 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
348 }
349 else
350 {
351 gaiaGetPoint (ln->Coords, iv, &x, &y);
352 }
353 point.x = x;
354 point.y = y;
355 if (has_z)
356 point.z = z;
357 if (has_m)
358 point.m = m;
359 ptarray_set_point4d (ctx, pa, iv, &point);
360 }
361 return (RTGEOM *) rtline_construct (ctx, gaia->Srid, NULL, pa);
362 }
363 else if (pts == 0 && lns == 0 && pgs == 1)
364 {
365 /* single Polygon */
366 pg = gaia->FirstPolygon;
367 has_z = 0;
368 has_m = 0;
369 if (gaia->DimensionModel == GAIA_XY_Z
370 || gaia->DimensionModel == GAIA_XY_Z_M)
371 has_z = 1;
372 if (gaia->DimensionModel == GAIA_XY_M
373 || gaia->DimensionModel == GAIA_XY_Z_M)
374 has_m = 1;
375 ngeoms = pg->NumInteriors;
376 ppaa = rtalloc (ctx, sizeof (RTPOINTARRAY *) * (ngeoms + 1));
377 rng = pg->Exterior;
378 close_ring = check_unclosed_ring (rng);
379 if (close_ring)
380 ppaa[0] = ptarray_construct (ctx, has_z, has_m, rng->Points + 1);
381 else
382 ppaa[0] = ptarray_construct (ctx, has_z, has_m, rng->Points);
383 for (iv = 0; iv < rng->Points; iv++)
384 {
385 /* copying vertices - Exterior Ring */
386 if (gaia->DimensionModel == GAIA_XY_Z)
387 {
388 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
389 }
390 else if (gaia->DimensionModel == GAIA_XY_M)
391 {
392 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
393 }
394 else if (gaia->DimensionModel == GAIA_XY_Z_M)
395 {
396 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
397 }
398 else
399 {
400 gaiaGetPoint (rng->Coords, iv, &x, &y);
401 }
402 point.x = x;
403 point.y = y;
404 if (has_z)
405 point.z = z;
406 if (has_m)
407 point.m = m;
408 ptarray_set_point4d (ctx, ppaa[0], iv, &point);
409 }
410 if (close_ring)
411 {
412 /* making an unclosed ring to be closed */
413 if (gaia->DimensionModel == GAIA_XY_Z)
414 {
415 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
416 }
417 else if (gaia->DimensionModel == GAIA_XY_M)
418 {
419 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
420 }
421 else if (gaia->DimensionModel == GAIA_XY_Z_M)
422 {
423 gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
424 }
425 else
426 {
427 gaiaGetPoint (rng->Coords, 0, &x, &y);
428 }
429 point.x = x;
430 point.y = y;
431 if (has_z)
432 point.z = z;
433 if (has_m)
434 point.m = m;
435 ptarray_set_point4d (ctx, ppaa[0], rng->Points, &point);
436 }
437 for (ib = 0; ib < pg->NumInteriors; ib++)
438 {
439 /* copying vertices - Interior Rings */
440 rng = pg->Interiors + ib;
441 close_ring = check_unclosed_ring (rng);
442 if (close_ring)
443 ppaa[1 + ib] =
444 ptarray_construct (ctx, has_z, has_m, rng->Points + 1);
445 else
446 ppaa[1 + ib] =
447 ptarray_construct (ctx, has_z, has_m, rng->Points);
448 for (iv = 0; iv < rng->Points; iv++)
449 {
450 if (gaia->DimensionModel == GAIA_XY_Z)
451 {
452 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
453 }
454 else if (gaia->DimensionModel == GAIA_XY_M)
455 {
456 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
457 }
458 else if (gaia->DimensionModel == GAIA_XY_Z_M)
459 {
460 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
461 }
462 else
463 {
464 gaiaGetPoint (rng->Coords, iv, &x, &y);
465 }
466 point.x = x;
467 point.y = y;
468 if (has_z)
469 point.z = z;
470 if (has_m)
471 point.m = m;
472 ptarray_set_point4d (ctx, ppaa[1 + ib], iv, &point);
473 }
474 if (close_ring)
475 {
476 /* making an unclosed ring to be closed */
477 if (gaia->DimensionModel == GAIA_XY_Z)
478 {
479 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
480 }
481 else if (gaia->DimensionModel == GAIA_XY_M)
482 {
483 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
484 }
485 else if (gaia->DimensionModel == GAIA_XY_Z_M)
486 {
487 gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
488 }
489 else
490 {
491 gaiaGetPoint (rng->Coords, 0, &x, &y);
492 }
493 point.x = x;
494 point.y = y;
495 if (has_z)
496 point.z = z;
497 if (has_m)
498 point.m = m;
499 ptarray_set_point4d (ctx, ppaa[1 + ib], rng->Points,
500 &point);
501 }
502 }
503 return (RTGEOM *) rtpoly_construct (ctx, gaia->Srid, NULL, ngeoms + 1,
504 ppaa);
505 }
506 else
507 {
508 /* some Collection */
509 switch (gaia->DeclaredType)
510 {
511 case GAIA_POINT:
512 type = RTPOINTTYPE;
513 break;
514 case GAIA_LINESTRING:
515 type = RTLINETYPE;
516 break;
517 case GAIA_POLYGON:
518 type = RTPOLYGONTYPE;
519 break;
520 case GAIA_MULTIPOINT:
521 type = RTMULTIPOINTTYPE;
522 break;
523 case GAIA_MULTILINESTRING:
524 type = RTMULTILINETYPE;
525 break;
526 case GAIA_MULTIPOLYGON:
527 type = RTMULTIPOLYGONTYPE;
528 break;
529 case GAIA_GEOMETRYCOLLECTION:
530 type = RTCOLLECTIONTYPE;
531 break;
532 default:
533 if (lns == 0 && pgs == 0)
534 type = RTMULTIPOINTTYPE;
535 else if (pts == 0 && pgs == 0)
536 type = RTMULTILINETYPE;
537 else if (pts == 0 && lns == 0)
538 type = RTMULTIPOLYGONTYPE;
539 else
540 type = RTCOLLECTIONTYPE;
541 break;
542 };
543 numg = pts + lns + pgs;
544 geoms = rtalloc (ctx, sizeof (RTGEOM *) * numg);
545
546 numg = 0;
547 pt = gaia->FirstPoint;
548 while (pt)
549 {
550 /* copying POINTs */
551 has_z = 0;
552 has_m = 0;
553 if (gaia->DimensionModel == GAIA_XY_Z
554 || gaia->DimensionModel == GAIA_XY_Z_M)
555 has_z = 1;
556 if (gaia->DimensionModel == GAIA_XY_M
557 || gaia->DimensionModel == GAIA_XY_Z_M)
558 has_m = 1;
559 pa = ptarray_construct (ctx, has_z, has_m, 1);
560 point.x = pt->X;
561 point.y = pt->Y;
562 if (has_z)
563 point.z = pt->Z;
564 if (has_m)
565 point.m = pt->M;
566 ptarray_set_point4d (ctx, pa, 0, &point);
567 geoms[numg++] =
568 (RTGEOM *) rtpoint_construct (ctx, gaia->Srid, NULL, pa);
569 pt = pt->Next;
570 }
571 ln = gaia->FirstLinestring;
572 while (ln)
573 {
574 /* copying LINESTRINGs */
575 has_z = 0;
576 has_m = 0;
577 if (gaia->DimensionModel == GAIA_XY_Z
578 || gaia->DimensionModel == GAIA_XY_Z_M)
579 has_z = 1;
580 if (gaia->DimensionModel == GAIA_XY_M
581 || gaia->DimensionModel == GAIA_XY_Z_M)
582 has_m = 1;
583 pa = ptarray_construct (ctx, has_z, has_m, ln->Points);
584 for (iv = 0; iv < ln->Points; iv++)
585 {
586 /* copying vertices */
587 if (gaia->DimensionModel == GAIA_XY_Z)
588 {
589 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
590 }
591 else if (gaia->DimensionModel == GAIA_XY_M)
592 {
593 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
594 }
595 else if (gaia->DimensionModel == GAIA_XY_Z_M)
596 {
597 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
598 }
599 else
600 {
601 gaiaGetPoint (ln->Coords, iv, &x, &y);
602 }
603 point.x = x;
604 point.y = y;
605 if (has_z)
606 point.z = z;
607 if (has_m)
608 point.m = m;
609 ptarray_set_point4d (ctx, pa, iv, &point);
610 }
611 geoms[numg++] =
612 (RTGEOM *) rtline_construct (ctx, gaia->Srid, NULL, pa);
613 ln = ln->Next;
614 }
615 pg = gaia->FirstPolygon;
616 while (pg)
617 {
618 /* copying POLYGONs */
619 has_z = 0;
620 has_m = 0;
621 if (gaia->DimensionModel == GAIA_XY_Z
622 || gaia->DimensionModel == GAIA_XY_Z_M)
623 has_z = 1;
624 if (gaia->DimensionModel == GAIA_XY_M
625 || gaia->DimensionModel == GAIA_XY_Z_M)
626 has_m = 1;
627 ngeoms = pg->NumInteriors;
628 ppaa = rtalloc (ctx, sizeof (RTPOINTARRAY *) * (ngeoms + 1));
629 rng = pg->Exterior;
630 close_ring = check_unclosed_ring (rng);
631 if (close_ring)
632 ppaa[0] =
633 ptarray_construct (ctx, has_z, has_m, rng->Points + 1);
634 else
635 ppaa[0] =
636 ptarray_construct (ctx, has_z, has_m, rng->Points);
637 for (iv = 0; iv < rng->Points; iv++)
638 {
639 /* copying vertices - Exterior Ring */
640 if (gaia->DimensionModel == GAIA_XY_Z)
641 {
642 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
643 }
644 else if (gaia->DimensionModel == GAIA_XY_M)
645 {
646 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
647 }
648 else if (gaia->DimensionModel == GAIA_XY_Z_M)
649 {
650 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
651 }
652 else
653 {
654 gaiaGetPoint (rng->Coords, iv, &x, &y);
655 }
656 point.x = x;
657 point.y = y;
658 if (has_z)
659 point.z = z;
660 if (has_m)
661 point.m = m;
662 ptarray_set_point4d (ctx, ppaa[0], iv, &point);
663 }
664 if (close_ring)
665 {
666 /* making an unclosed ring to be closed */
667 if (gaia->DimensionModel == GAIA_XY_Z)
668 {
669 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
670 }
671 else if (gaia->DimensionModel == GAIA_XY_M)
672 {
673 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
674 }
675 else if (gaia->DimensionModel == GAIA_XY_Z_M)
676 {
677 gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
678 }
679 else
680 {
681 gaiaGetPoint (rng->Coords, 0, &x, &y);
682 }
683 point.x = x;
684 point.y = y;
685 if (has_z)
686 point.z = z;
687 if (has_m)
688 point.m = m;
689 ptarray_set_point4d (ctx, ppaa[0], rng->Points, &point);
690 }
691 for (ib = 0; ib < pg->NumInteriors; ib++)
692 {
693 /* copying vertices - Interior Rings */
694 rng = pg->Interiors + ib;
695 close_ring = check_unclosed_ring (rng);
696 if (close_ring)
697 ppaa[1 + ib] =
698 ptarray_construct (ctx, has_z, has_m,
699 rng->Points + 1);
700 else
701 ppaa[1 + ib] =
702 ptarray_construct (ctx, has_z, has_m,
703 rng->Points);
704 for (iv = 0; iv < rng->Points; iv++)
705 {
706 if (gaia->DimensionModel == GAIA_XY_Z)
707 {
708 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
709 }
710 else if (gaia->DimensionModel == GAIA_XY_M)
711 {
712 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
713 }
714 else if (gaia->DimensionModel == GAIA_XY_Z_M)
715 {
716 gaiaGetPointXYZM (rng->Coords, iv, &x, &y,
717 &z, &m);
718 }
719 else
720 {
721 gaiaGetPoint (rng->Coords, iv, &x, &y);
722 }
723 point.x = x;
724 point.y = y;
725 if (has_z)
726 point.z = z;
727 if (has_m)
728 point.m = m;
729 ptarray_set_point4d (ctx, ppaa[1 + ib], iv, &point);
730 }
731 if (close_ring)
732 {
733 /* making an unclosed ring to be closed */
734 if (gaia->DimensionModel == GAIA_XY_Z)
735 {
736 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
737 }
738 else if (gaia->DimensionModel == GAIA_XY_M)
739 {
740 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
741 }
742 else if (gaia->DimensionModel == GAIA_XY_Z_M)
743 {
744 gaiaGetPointXYZM (rng->Coords, 0, &x, &y,
745 &z, &m);
746 }
747 else
748 {
749 gaiaGetPoint (rng->Coords, 0, &x, &y);
750 }
751 point.x = x;
752 point.y = y;
753 if (has_z)
754 point.z = z;
755 if (has_m)
756 point.m = m;
757 ptarray_set_point4d (ctx, ppaa[1 + ib], rng->Points,
758 &point);
759 }
760 }
761 geoms[numg++] =
762 (RTGEOM *) rtpoly_construct (ctx, gaia->Srid, NULL,
763 ngeoms + 1, ppaa);
764 pg = pg->Next;
765 }
766 return (RTGEOM *) rtcollection_construct (ctx, type, gaia->Srid, NULL,
767 numg, geoms);
768 }
769 return NULL;
770 }
771
772 static gaiaGeomCollPtr
fromRTGeomIncremental(const RTCTX * ctx,gaiaGeomCollPtr gaia,const RTGEOM * rtgeom)773 fromRTGeomIncremental (const RTCTX * ctx, gaiaGeomCollPtr gaia,
774 const RTGEOM * rtgeom)
775 {
776 /* converting a RTGEOM Geometry into a GAIA Geometry */
777 gaiaLinestringPtr ln;
778 gaiaPolygonPtr pg;
779 gaiaRingPtr rng;
780 int dimension_model = gaia->DimensionModel;
781 int declared_type = gaia->DeclaredType;
782 RTGEOM *rtg2 = NULL;
783 RTPOINT *rtp = NULL;
784 RTLINE *rtl = NULL;
785 RTPOLY *rtpoly = NULL;
786 RTCOLLECTION *rtc = NULL;
787 RTPOINTARRAY *pa;
788 RTPOINT4D pt4d;
789 int has_z;
790 int has_m;
791 int iv;
792 int ib;
793 int ngeoms;
794 int ng;
795 double x;
796 double y;
797 double z;
798 double m;
799
800 if (rtgeom == NULL)
801 return NULL;
802 if (rtgeom_is_empty (ctx, rtgeom))
803 return NULL;
804
805 switch (rtgeom->type)
806 {
807 case RTPOINTTYPE:
808 rtp = (RTPOINT *) rtgeom;
809 has_z = 0;
810 has_m = 0;
811 pa = rtp->point;
812 if (RTFLAGS_GET_Z (pa->flags))
813 has_z = 1;
814 if (RTFLAGS_GET_M (pa->flags))
815 has_m = 1;
816 rt_getPoint4d_p (ctx, pa, 0, &pt4d);
817 x = pt4d.x;
818 y = pt4d.y;
819 if (has_z)
820 z = pt4d.z;
821 else
822 z = 0.0;
823 if (has_m)
824 m = pt4d.m;
825 else
826 m = 0.0;
827 if (dimension_model == GAIA_XY_Z)
828 gaiaAddPointToGeomCollXYZ (gaia, x, y, z);
829 else if (dimension_model == GAIA_XY_M)
830 gaiaAddPointToGeomCollXYM (gaia, x, y, m);
831 else if (dimension_model == GAIA_XY_Z_M)
832 gaiaAddPointToGeomCollXYZM (gaia, x, y, z, m);
833 else
834 gaiaAddPointToGeomColl (gaia, x, y);
835 if (declared_type == GAIA_MULTIPOINT)
836 gaia->DeclaredType = GAIA_MULTIPOINT;
837 else if (declared_type == GAIA_GEOMETRYCOLLECTION)
838 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
839 else
840 gaia->DeclaredType = GAIA_POINT;
841 break;
842 case RTLINETYPE:
843 rtl = (RTLINE *) rtgeom;
844 has_z = 0;
845 has_m = 0;
846 pa = rtl->points;
847 if (RTFLAGS_GET_Z (pa->flags))
848 has_z = 1;
849 if (RTFLAGS_GET_M (pa->flags))
850 has_m = 1;
851 ln = gaiaAddLinestringToGeomColl (gaia, pa->npoints);
852 for (iv = 0; iv < pa->npoints; iv++)
853 {
854 /* copying LINESTRING vertices */
855 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
856 x = pt4d.x;
857 y = pt4d.y;
858 if (has_z)
859 z = pt4d.z;
860 else
861 z = 0.0;
862 if (has_m)
863 m = pt4d.m;
864 else
865 m = 0.0;
866 if (dimension_model == GAIA_XY_Z)
867 {
868 gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
869 }
870 else if (dimension_model == GAIA_XY_M)
871 {
872 gaiaSetPointXYM (ln->Coords, iv, x, y, m);
873 }
874 else if (dimension_model == GAIA_XY_Z_M)
875 {
876 gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m);
877 }
878 else
879 {
880 gaiaSetPoint (ln->Coords, iv, x, y);
881 }
882 }
883 if (declared_type == GAIA_MULTILINESTRING)
884 gaia->DeclaredType = GAIA_MULTILINESTRING;
885 else if (declared_type == GAIA_GEOMETRYCOLLECTION)
886 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
887 else
888 gaia->DeclaredType = GAIA_LINESTRING;
889 break;
890 case RTPOLYGONTYPE:
891 rtpoly = (RTPOLY *) rtgeom;
892 has_z = 0;
893 has_m = 0;
894 pa = rtpoly->rings[0];
895 if (RTFLAGS_GET_Z (pa->flags))
896 has_z = 1;
897 if (RTFLAGS_GET_M (pa->flags))
898 has_m = 1;
899 pg = gaiaAddPolygonToGeomColl (gaia, pa->npoints, rtpoly->nrings - 1);
900 rng = pg->Exterior;
901 for (iv = 0; iv < pa->npoints; iv++)
902 {
903 /* copying Exterion Ring vertices */
904 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
905 x = pt4d.x;
906 y = pt4d.y;
907 if (has_z)
908 z = pt4d.z;
909 else
910 z = 0.0;
911 if (has_m)
912 m = pt4d.m;
913 else
914 m = 0.0;
915 if (dimension_model == GAIA_XY_Z)
916 {
917 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
918 }
919 else if (dimension_model == GAIA_XY_M)
920 {
921 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
922 }
923 else if (dimension_model == GAIA_XY_Z_M)
924 {
925 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
926 }
927 else
928 {
929 gaiaSetPoint (rng->Coords, iv, x, y);
930 }
931 }
932 for (ib = 1; ib < rtpoly->nrings; ib++)
933 {
934 has_z = 0;
935 has_m = 0;
936 pa = rtpoly->rings[ib];
937 if (RTFLAGS_GET_Z (pa->flags))
938 has_z = 1;
939 if (RTFLAGS_GET_M (pa->flags))
940 has_m = 1;
941 rng = gaiaAddInteriorRing (pg, ib - 1, pa->npoints);
942 for (iv = 0; iv < pa->npoints; iv++)
943 {
944 /* copying Exterion Ring vertices */
945 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
946 x = pt4d.x;
947 y = pt4d.y;
948 if (has_z)
949 z = pt4d.z;
950 else
951 z = 0.0;
952 if (has_m)
953 m = pt4d.m;
954 else
955 m = 0.0;
956 if (dimension_model == GAIA_XY_Z)
957 {
958 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
959 }
960 else if (dimension_model == GAIA_XY_M)
961 {
962 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
963 }
964 else if (dimension_model == GAIA_XY_Z_M)
965 {
966 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
967 }
968 else
969 {
970 gaiaSetPoint (rng->Coords, iv, x, y);
971 }
972 }
973 }
974 if (declared_type == GAIA_MULTIPOLYGON)
975 gaia->DeclaredType = GAIA_MULTIPOLYGON;
976 else if (declared_type == GAIA_GEOMETRYCOLLECTION)
977 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
978 else
979 gaia->DeclaredType = GAIA_POLYGON;
980 break;
981 case RTMULTIPOINTTYPE:
982 case RTMULTILINETYPE:
983 case RTMULTIPOLYGONTYPE:
984 case RTCOLLECTIONTYPE:
985 if (rtgeom->type == RTMULTIPOINTTYPE)
986 {
987 if (declared_type == GAIA_GEOMETRYCOLLECTION)
988 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
989 else
990 gaia->DeclaredType = GAIA_MULTIPOINT;
991 }
992 else if (rtgeom->type == RTMULTILINETYPE)
993 {
994 if (declared_type == GAIA_GEOMETRYCOLLECTION)
995 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
996 else
997 gaia->DeclaredType = GAIA_MULTILINESTRING;
998 }
999 else if (rtgeom->type == RTMULTIPOLYGONTYPE)
1000 {
1001 if (declared_type == GAIA_GEOMETRYCOLLECTION)
1002 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1003 else
1004 gaia->DeclaredType = GAIA_MULTIPOLYGON;
1005 }
1006 else
1007 gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1008
1009 rtc = (RTCOLLECTION *) rtgeom;
1010 ngeoms = rtc->ngeoms;
1011 if (ngeoms == 0)
1012 {
1013 gaiaFreeGeomColl (gaia);
1014 gaia = NULL;
1015 break;
1016 }
1017 for (ng = 0; ng < ngeoms; ++ng)
1018 {
1019 /* looping on elementary geometries */
1020 rtg2 = rtc->geoms[ng];
1021 switch (rtg2->type)
1022 {
1023 case RTPOINTTYPE:
1024 rtp = (RTPOINT *) rtg2;
1025 has_z = 0;
1026 has_m = 0;
1027 pa = rtp->point;
1028 if (RTFLAGS_GET_Z (pa->flags))
1029 has_z = 1;
1030 if (RTFLAGS_GET_M (pa->flags))
1031 has_m = 1;
1032 rt_getPoint4d_p (ctx, pa, 0, &pt4d);
1033 x = pt4d.x;
1034 y = pt4d.y;
1035 if (has_z)
1036 z = pt4d.z;
1037 else
1038 z = 0.0;
1039 if (has_m)
1040 m = pt4d.m;
1041 else
1042 m = 0.0;
1043 if (dimension_model == GAIA_XY_Z)
1044 gaiaAddPointToGeomCollXYZ (gaia, x, y, z);
1045 else if (dimension_model == GAIA_XY_M)
1046 gaiaAddPointToGeomCollXYM (gaia, x, y, m);
1047 else if (dimension_model == GAIA_XY_Z_M)
1048 gaiaAddPointToGeomCollXYZM (gaia, x, y, z, m);
1049 else
1050 gaiaAddPointToGeomColl (gaia, x, y);
1051 break;
1052 case RTLINETYPE:
1053 rtl = (RTLINE *) rtg2;
1054 has_z = 0;
1055 has_m = 0;
1056 pa = rtl->points;
1057 if (RTFLAGS_GET_Z (pa->flags))
1058 has_z = 1;
1059 if (RTFLAGS_GET_M (pa->flags))
1060 has_m = 1;
1061 ln = gaiaAddLinestringToGeomColl (gaia, pa->npoints);
1062 for (iv = 0; iv < pa->npoints; iv++)
1063 {
1064 /* copying LINESTRING vertices */
1065 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
1066 x = pt4d.x;
1067 y = pt4d.y;
1068 if (has_z)
1069 z = pt4d.z;
1070 else
1071 z = 0.0;
1072 if (has_m)
1073 m = pt4d.m;
1074 else
1075 m = 0.0;
1076 if (dimension_model == GAIA_XY_Z)
1077 {
1078 gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
1079 }
1080 else if (dimension_model == GAIA_XY_M)
1081 {
1082 gaiaSetPointXYM (ln->Coords, iv, x, y, m);
1083 }
1084 else if (dimension_model == GAIA_XY_Z_M)
1085 {
1086 gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m);
1087 }
1088 else
1089 {
1090 gaiaSetPoint (ln->Coords, iv, x, y);
1091 }
1092 }
1093 break;
1094 case RTPOLYGONTYPE:
1095 rtpoly = (RTPOLY *) rtg2;
1096 has_z = 0;
1097 has_m = 0;
1098 pa = rtpoly->rings[0];
1099 if (RTFLAGS_GET_Z (pa->flags))
1100 has_z = 1;
1101 if (RTFLAGS_GET_M (pa->flags))
1102 has_m = 1;
1103 pg = gaiaAddPolygonToGeomColl (gaia, pa->npoints,
1104 rtpoly->nrings - 1);
1105 rng = pg->Exterior;
1106 for (iv = 0; iv < pa->npoints; iv++)
1107 {
1108 /* copying Exterion Ring vertices */
1109 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
1110 x = pt4d.x;
1111 y = pt4d.y;
1112 if (has_z)
1113 z = pt4d.z;
1114 else
1115 z = 0.0;
1116 if (has_m)
1117 m = pt4d.m;
1118 else
1119 m = 0.0;
1120 if (dimension_model == GAIA_XY_Z)
1121 {
1122 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
1123 }
1124 else if (dimension_model == GAIA_XY_M)
1125 {
1126 gaiaSetPointXYM (rng->Coords, iv, x, y, m);
1127 }
1128 else if (dimension_model == GAIA_XY_Z_M)
1129 {
1130 gaiaSetPointXYZM (rng->Coords, iv, x, y, z,
1131 m);
1132 }
1133 else
1134 {
1135 gaiaSetPoint (rng->Coords, iv, x, y);
1136 }
1137 }
1138 for (ib = 1; ib < rtpoly->nrings; ib++)
1139 {
1140 has_z = 0;
1141 has_m = 0;
1142 pa = rtpoly->rings[ib];
1143 if (RTFLAGS_GET_Z (pa->flags))
1144 has_z = 1;
1145 if (RTFLAGS_GET_M (pa->flags))
1146 has_m = 1;
1147 rng = gaiaAddInteriorRing (pg, ib - 1, pa->npoints);
1148 for (iv = 0; iv < pa->npoints; iv++)
1149 {
1150 /* copying Exterion Ring vertices */
1151 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
1152 x = pt4d.x;
1153 y = pt4d.y;
1154 if (has_z)
1155 z = pt4d.z;
1156 else
1157 z = 0.0;
1158 if (has_m)
1159 m = pt4d.m;
1160 else
1161 m = 0.0;
1162 if (dimension_model == GAIA_XY_Z)
1163 {
1164 gaiaSetPointXYZ (rng->Coords, iv, x,
1165 y, z);
1166 }
1167 else if (dimension_model == GAIA_XY_M)
1168 {
1169 gaiaSetPointXYM (rng->Coords, iv, x,
1170 y, m);
1171 }
1172 else if (dimension_model == GAIA_XY_Z_M)
1173 {
1174 gaiaSetPointXYZM (rng->Coords, iv, x,
1175 y, z, m);
1176 }
1177 else
1178 {
1179 gaiaSetPoint (rng->Coords, iv, x, y);
1180 }
1181 }
1182 }
1183 break;
1184 };
1185 }
1186 break;
1187 default:
1188 gaiaFreeGeomColl (gaia);
1189 gaia = NULL;
1190 break;
1191 };
1192
1193 return gaia;
1194 }
1195
1196 SPATIALITE_PRIVATE void *
fromRTGeom(const void * pctx,const void * prtgeom,const int dimension_model,const int declared_type)1197 fromRTGeom (const void *pctx, const void *prtgeom, const int dimension_model,
1198 const int declared_type)
1199 {
1200 /* converting a RTGEOM Geometry into a GAIA Geometry */
1201 gaiaGeomCollPtr gaia = NULL;
1202 const RTCTX *ctx = (const RTCTX *) pctx;
1203 const RTGEOM *rtgeom = (const RTGEOM *) prtgeom;
1204
1205 if (rtgeom == NULL)
1206 return NULL;
1207 if (rtgeom_is_empty (ctx, rtgeom))
1208 return NULL;
1209
1210 if (dimension_model == GAIA_XY_Z)
1211 gaia = gaiaAllocGeomCollXYZ ();
1212 else if (dimension_model == GAIA_XY_M)
1213 gaia = gaiaAllocGeomCollXYM ();
1214 else if (dimension_model == GAIA_XY_Z_M)
1215 gaia = gaiaAllocGeomCollXYZM ();
1216 else
1217 gaia = gaiaAllocGeomColl ();
1218 gaia->DeclaredType = declared_type;
1219 fromRTGeomIncremental (ctx, gaia, rtgeom);
1220
1221 return gaia;
1222 }
1223
1224 static int
check_valid_type(const RTGEOM * rtgeom,int declared_type)1225 check_valid_type (const RTGEOM * rtgeom, int declared_type)
1226 {
1227 /* checking if the geometry type is a valid one */
1228 int ret = 0;
1229 switch (rtgeom->type)
1230 {
1231 case RTPOINTTYPE:
1232 case RTMULTIPOINTTYPE:
1233 if (declared_type == GAIA_POINT || declared_type == GAIA_POINTZ
1234 || declared_type == GAIA_POINTM || declared_type == GAIA_POINTZM)
1235 ret = 1;
1236 if (declared_type == GAIA_MULTIPOINT
1237 || declared_type == GAIA_MULTIPOINTZ
1238 || declared_type == GAIA_MULTIPOINTM
1239 || declared_type == GAIA_MULTIPOINTZM)
1240 ret = 1;
1241 break;
1242 case RTLINETYPE:
1243 case RTMULTILINETYPE:
1244 if (declared_type == GAIA_LINESTRING
1245 || declared_type == GAIA_LINESTRINGZ
1246 || declared_type == GAIA_LINESTRINGM
1247 || declared_type == GAIA_LINESTRINGZM)
1248 ret = 1;
1249 if (declared_type == GAIA_MULTILINESTRING
1250 || declared_type == GAIA_MULTILINESTRINGZ
1251 || declared_type == GAIA_MULTILINESTRINGM
1252 || declared_type == GAIA_MULTILINESTRINGZM)
1253 ret = 1;
1254 break;
1255 case RTPOLYGONTYPE:
1256 case RTMULTIPOLYGONTYPE:
1257 if (declared_type == GAIA_POLYGON || declared_type == GAIA_POLYGONZ
1258 || declared_type == GAIA_POLYGONM
1259 || declared_type == GAIA_POLYGONZM)
1260 ret = 1;
1261 if (declared_type == GAIA_MULTIPOLYGON
1262 || declared_type == GAIA_MULTIPOLYGONZ
1263 || declared_type == GAIA_MULTIPOLYGONM
1264 || declared_type == GAIA_MULTIPOLYGONZM)
1265 ret = 1;
1266 break;
1267 case RTCOLLECTIONTYPE:
1268 if (declared_type == GAIA_GEOMETRYCOLLECTION
1269 || declared_type == GAIA_GEOMETRYCOLLECTIONZ
1270 || declared_type == GAIA_GEOMETRYCOLLECTIONM
1271 || declared_type == GAIA_GEOMETRYCOLLECTIONZM)
1272 ret = 1;
1273 break;
1274 };
1275 return ret;
1276 }
1277
1278 static gaiaGeomCollPtr
fromRTGeomValidated(const RTCTX * ctx,const RTGEOM * rtgeom,const int dimension_model,const int declared_type)1279 fromRTGeomValidated (const RTCTX * ctx, const RTGEOM * rtgeom,
1280 const int dimension_model, const int declared_type)
1281 {
1282 /*
1283 / converting a RTGEOM Geometry into a GAIA Geometry
1284 / first collection - validated items
1285 */
1286 gaiaGeomCollPtr gaia = NULL;
1287 RTGEOM *rtg2 = NULL;
1288 RTCOLLECTION *rtc = NULL;
1289 int ngeoms;
1290
1291 if (rtgeom == NULL)
1292 return NULL;
1293 if (rtgeom_is_empty (ctx, rtgeom))
1294 return NULL;
1295
1296 switch (rtgeom->type)
1297 {
1298 case RTCOLLECTIONTYPE:
1299 rtc = (RTCOLLECTION *) rtgeom;
1300 ngeoms = rtc->ngeoms;
1301 if (ngeoms <= 2)
1302 {
1303 rtg2 = rtc->geoms[0];
1304 if (check_valid_type (rtg2, declared_type))
1305 gaia =
1306 fromRTGeom (ctx, rtg2, dimension_model, declared_type);
1307 }
1308 break;
1309 default:
1310 if (check_valid_type (rtgeom, declared_type))
1311 gaia = fromRTGeom (ctx, rtgeom, dimension_model, declared_type);
1312 if (gaia == NULL)
1313 {
1314 /* Andrea Peri: 2013-05-02 returning anyway the RTGEOM geometry,
1315 / even if it has a mismatching type */
1316 int type = -1;
1317 switch (rtgeom->type)
1318 {
1319 case RTPOINTTYPE:
1320 type = GAIA_POINT;
1321 break;
1322 case RTLINETYPE:
1323 type = GAIA_LINESTRING;
1324 break;
1325 case RTPOLYGONTYPE:
1326 type = GAIA_POLYGON;
1327 break;
1328 case RTMULTIPOINTTYPE:
1329 type = GAIA_MULTIPOINT;
1330 break;
1331 case RTMULTILINETYPE:
1332 type = GAIA_MULTILINESTRING;
1333 break;
1334 case RTMULTIPOLYGONTYPE:
1335 type = GAIA_MULTIPOLYGON;
1336 break;
1337 };
1338 if (type >= 0)
1339 gaia = fromRTGeom (ctx, rtgeom, dimension_model, type);
1340 }
1341 break;
1342 }
1343 return gaia;
1344 }
1345
1346 static gaiaGeomCollPtr
fromRTGeomDiscarded(const RTCTX * ctx,const RTGEOM * rtgeom,const int dimension_model,const int declared_type)1347 fromRTGeomDiscarded (const RTCTX * ctx, const RTGEOM * rtgeom,
1348 const int dimension_model, const int declared_type)
1349 {
1350 /*
1351 / converting a RTGEOM Geometry into a GAIA Geometry
1352 / second collection - discarded items
1353 */
1354 gaiaGeomCollPtr gaia = NULL;
1355 RTGEOM *rtg2 = NULL;
1356 RTCOLLECTION *rtc = NULL;
1357 int ngeoms;
1358 int ig;
1359
1360 if (rtgeom == NULL)
1361 return NULL;
1362 if (rtgeom_is_empty (ctx, rtgeom))
1363 return NULL;
1364
1365 if (rtgeom->type == RTCOLLECTIONTYPE)
1366 {
1367 if (dimension_model == GAIA_XY_Z)
1368 gaia = gaiaAllocGeomCollXYZ ();
1369 else if (dimension_model == GAIA_XY_M)
1370 gaia = gaiaAllocGeomCollXYM ();
1371 else if (dimension_model == GAIA_XY_Z_M)
1372 gaia = gaiaAllocGeomCollXYZM ();
1373 else
1374 gaia = gaiaAllocGeomColl ();
1375 rtc = (RTCOLLECTION *) rtgeom;
1376 ngeoms = rtc->ngeoms;
1377 for (ig = 0; ig < ngeoms; ig++)
1378 {
1379 rtg2 = rtc->geoms[ig];
1380 if (!check_valid_type (rtg2, declared_type))
1381 fromRTGeomIncremental (ctx, gaia, rtg2);
1382 }
1383 }
1384 /*
1385 Andrea Peri: 2013-05-02
1386 when a single geometry is returned by RTGEOM it's always "valid"
1387 and there are no discarded items at all
1388
1389 else if (!check_valid_type (lwgeom, declared_type))
1390 gaia = fromRTGeom (lwgeom, dimension_model, declared_type);
1391 */
1392 return gaia;
1393 }
1394
1395 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaMakeValid(const void * p_cache,gaiaGeomCollPtr geom)1396 gaiaMakeValid (const void *p_cache, gaiaGeomCollPtr geom)
1397 {
1398 /* wrapping RTGEOM MakeValid [collecting valid items] */
1399 const RTCTX *ctx = NULL;
1400 struct splite_internal_cache *cache =
1401 (struct splite_internal_cache *) p_cache;
1402 RTGEOM *g1;
1403 RTGEOM *g2;
1404 gaiaGeomCollPtr result = NULL;
1405
1406 if (!geom)
1407 return NULL;
1408 if (cache == NULL)
1409 return NULL;
1410 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1411 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1412 return NULL;
1413 ctx = cache->RTTOPO_handle;
1414 if (ctx == NULL)
1415 return NULL;
1416
1417 g1 = toRTGeom (ctx, geom);
1418 g2 = rtgeom_make_valid (ctx, g1);
1419 if (!g2)
1420 {
1421 rtgeom_free (ctx, g1);
1422 goto done;
1423 }
1424 result =
1425 fromRTGeomValidated (ctx, g2, geom->DimensionModel, geom->DeclaredType);
1426 spatialite_init_geos ();
1427 rtgeom_free (ctx, g1);
1428 rtgeom_free (ctx, g2);
1429 if (result == NULL)
1430 goto done;
1431 result->Srid = geom->Srid;
1432
1433 done:
1434 return result;
1435 }
1436
1437 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaMakeValidDiscarded(const void * p_cache,gaiaGeomCollPtr geom)1438 gaiaMakeValidDiscarded (const void *p_cache, gaiaGeomCollPtr geom)
1439 {
1440 /* wrapping RTGEOM MakeValid [collecting discarder items] */
1441 const RTCTX *ctx = NULL;
1442 struct splite_internal_cache *cache =
1443 (struct splite_internal_cache *) p_cache;
1444 RTGEOM *g1;
1445 RTGEOM *g2;
1446 gaiaGeomCollPtr result = NULL;
1447
1448 if (!geom)
1449 return NULL;
1450 if (cache == NULL)
1451 return NULL;
1452 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1453 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1454 return NULL;
1455 ctx = cache->RTTOPO_handle;
1456 if (ctx == NULL)
1457 return NULL;
1458
1459 g1 = toRTGeom (ctx, geom);
1460 g2 = rtgeom_make_valid (ctx, g1);
1461 if (!g2)
1462 {
1463 rtgeom_free (ctx, g1);
1464 goto done;
1465 }
1466 result =
1467 fromRTGeomDiscarded (ctx, g2, geom->DimensionModel, geom->DeclaredType);
1468 spatialite_init_geos ();
1469 rtgeom_free (ctx, g1);
1470 rtgeom_free (ctx, g2);
1471 if (result == NULL)
1472 goto done;
1473 result->Srid = geom->Srid;
1474
1475 done:
1476 return result;
1477 }
1478
1479 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaSegmentize(const void * p_cache,gaiaGeomCollPtr geom,double dist)1480 gaiaSegmentize (const void *p_cache, gaiaGeomCollPtr geom, double dist)
1481 {
1482 /* wrapping RTGEOM Segmentize */
1483 const RTCTX *ctx = NULL;
1484 struct splite_internal_cache *cache =
1485 (struct splite_internal_cache *) p_cache;
1486 RTGEOM *g1;
1487 RTGEOM *g2;
1488 gaiaGeomCollPtr result = NULL;
1489
1490 if (!geom)
1491 return NULL;
1492 if (dist <= 0.0)
1493 return NULL;
1494 if (cache == NULL)
1495 return NULL;
1496 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1497 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1498 return NULL;
1499 ctx = cache->RTTOPO_handle;
1500 if (ctx == NULL)
1501 return NULL;
1502
1503 g1 = toRTGeom (ctx, geom);
1504 g2 = rtgeom_segmentize2d (ctx, g1, dist);
1505 if (!g2)
1506 {
1507 rtgeom_free (ctx, g1);
1508 goto done;
1509 }
1510 result = fromRTGeom (ctx, g2, geom->DimensionModel, geom->DeclaredType);
1511 spatialite_init_geos ();
1512 rtgeom_free (ctx, g1);
1513 rtgeom_free (ctx, g2);
1514 if (result == NULL)
1515 goto done;
1516 result->Srid = geom->Srid;
1517
1518 done:
1519 return result;
1520 }
1521
1522 static int
check_split_args(gaiaGeomCollPtr input,gaiaGeomCollPtr blade)1523 check_split_args (gaiaGeomCollPtr input, gaiaGeomCollPtr blade)
1524 {
1525 /* testing Split arguments */
1526 gaiaPointPtr pt;
1527 gaiaLinestringPtr ln;
1528 gaiaPolygonPtr pg;
1529 int i_lns = 0;
1530 int i_pgs = 0;
1531 int b_pts = 0;
1532 int b_lns = 0;
1533
1534 if (!input)
1535 return 0;
1536 if (!blade)
1537 return 0;
1538
1539 /* testing the Input type */
1540 if (input->FirstPoint != NULL)
1541 {
1542 /* Point(s) on Input is forbidden !!!! */
1543 return 0;
1544 }
1545 ln = input->FirstLinestring;
1546 while (ln)
1547 {
1548 /* counting how many Linestrings are there */
1549 i_lns++;
1550 ln = ln->Next;
1551 }
1552 pg = input->FirstPolygon;
1553 while (pg)
1554 {
1555 /* counting how many Polygons are there */
1556 i_pgs++;
1557 pg = pg->Next;
1558 }
1559 if (i_lns + i_pgs == 0)
1560 {
1561 /* empty Input */
1562 return 0;
1563 }
1564
1565 /* testing the Blade type */
1566 pt = blade->FirstPoint;
1567 while (pt)
1568 {
1569 /* counting how many Points are there */
1570 b_pts++;
1571 pt = pt->Next;
1572 }
1573 ln = blade->FirstLinestring;
1574 while (ln)
1575 {
1576 /* counting how many Linestrings are there */
1577 b_lns++;
1578 ln = ln->Next;
1579 }
1580 if (blade->FirstPolygon != NULL)
1581 {
1582 /* Polygon(s) on Blade is forbidden !!!! */
1583 return 0;
1584 }
1585 if (b_pts + b_lns == 0)
1586 {
1587 /* empty Blade */
1588 return 0;
1589 }
1590 if (b_pts >= 1 && b_lns >= 1)
1591 {
1592 /* invalid Blade [point + linestring] */
1593 return 0;
1594 }
1595
1596 /* compatibility check */
1597 if (b_lns >= 1)
1598 {
1599 /* Linestring blade is always valid */
1600 return 1;
1601 }
1602 if (i_lns >= 1 && b_pts >= 1)
1603 {
1604 /* Linestring or MultiLinestring input and Point blade is allowed */
1605 return 1;
1606 }
1607
1608 return 0;
1609 }
1610
1611 static void
set_split_gtype(gaiaGeomCollPtr geom)1612 set_split_gtype (gaiaGeomCollPtr geom)
1613 {
1614 /* assignign the actual geometry type */
1615 gaiaPointPtr pt;
1616 gaiaLinestringPtr ln;
1617 gaiaPolygonPtr pg;
1618 int pts = 0;
1619 int lns = 0;
1620 int pgs = 0;
1621
1622 pt = geom->FirstPoint;
1623 while (pt)
1624 {
1625 /* counting how many Points are there */
1626 pts++;
1627 pt = pt->Next;
1628 }
1629 ln = geom->FirstLinestring;
1630 while (ln)
1631 {
1632 /* counting how many Linestrings are there */
1633 lns++;
1634 ln = ln->Next;
1635 }
1636 pg = geom->FirstPolygon;
1637 while (pg)
1638 {
1639 /* counting how many Polygons are there */
1640 pgs++;
1641 pg = pg->Next;
1642 }
1643
1644 if (pts == 1 && lns == 0 && pgs == 0)
1645 {
1646 geom->DeclaredType = GAIA_POINT;
1647 return;
1648 }
1649 if (pts > 1 && lns == 0 && pgs == 0)
1650 {
1651 geom->DeclaredType = GAIA_MULTIPOINT;
1652 return;
1653 }
1654 if (pts == 0 && lns == 1 && pgs == 0)
1655 {
1656 geom->DeclaredType = GAIA_LINESTRING;
1657 return;
1658 }
1659 if (pts == 0 && lns > 1 && pgs == 0)
1660 {
1661 geom->DeclaredType = GAIA_MULTILINESTRING;
1662 return;
1663 }
1664 if (pts == 0 && lns == 0 && pgs == 1)
1665 {
1666 geom->DeclaredType = GAIA_POLYGON;
1667 return;
1668 }
1669 if (pts == 0 && lns == 0 && pgs > 1)
1670 {
1671 geom->DeclaredType = GAIA_MULTIPOLYGON;
1672 return;
1673 }
1674 geom->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1675 }
1676
1677 static RTGEOM *
toRTGeomLinestring(const RTCTX * ctx,gaiaLinestringPtr ln,int srid)1678 toRTGeomLinestring (const RTCTX * ctx, gaiaLinestringPtr ln, int srid)
1679 {
1680 /* converting a GAIA Linestring into a RTGEOM Geometry */
1681 int iv;
1682 double x = 0.0;
1683 double y = 0.0;
1684 double z = 0.0;
1685 double m = 0.0;
1686 int has_z = 0;
1687 int has_m = 0;
1688 RTPOINTARRAY *pa;
1689 RTPOINT4D point;
1690
1691 if (ln->DimensionModel == GAIA_XY_Z || ln->DimensionModel == GAIA_XY_Z_M)
1692 has_z = 1;
1693 if (ln->DimensionModel == GAIA_XY_M || ln->DimensionModel == GAIA_XY_Z_M)
1694 has_m = 1;
1695 pa = ptarray_construct (ctx, has_z, has_m, ln->Points);
1696 for (iv = 0; iv < ln->Points; iv++)
1697 {
1698 /* copying vertices */
1699 if (ln->DimensionModel == GAIA_XY_Z)
1700 {
1701 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
1702 }
1703 else if (ln->DimensionModel == GAIA_XY_M)
1704 {
1705 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
1706 }
1707 else if (ln->DimensionModel == GAIA_XY_Z_M)
1708 {
1709 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
1710 }
1711 else
1712 {
1713 gaiaGetPoint (ln->Coords, iv, &x, &y);
1714 }
1715 point.x = x;
1716 point.y = y;
1717 if (has_z)
1718 point.z = z;
1719 if (has_m)
1720 point.m = m;
1721 ptarray_set_point4d (ctx, pa, iv, &point);
1722 }
1723 return (RTGEOM *) rtline_construct (ctx, srid, NULL, pa);
1724 }
1725
1726 static RTGEOM *
toRTGeomPolygon(const RTCTX * ctx,gaiaPolygonPtr pg,int srid)1727 toRTGeomPolygon (const RTCTX * ctx, gaiaPolygonPtr pg, int srid)
1728 {
1729 /* converting a GAIA Linestring into a RTGEOM Geometry */
1730 int iv;
1731 int ib;
1732 double x = 0.0;
1733 double y = 0.0;
1734 double z = 0.0;
1735 double m = 0.0;
1736 int ngeoms;
1737 int has_z = 0;
1738 int has_m = 0;
1739 int close_ring;
1740 gaiaRingPtr rng;
1741 RTPOINTARRAY **ppaa;
1742 RTPOINT4D point;
1743
1744 if (pg->DimensionModel == GAIA_XY_Z || pg->DimensionModel == GAIA_XY_Z_M)
1745 has_z = 1;
1746 if (pg->DimensionModel == GAIA_XY_M || pg->DimensionModel == GAIA_XY_Z_M)
1747 has_m = 1;
1748 ngeoms = pg->NumInteriors;
1749 ppaa = rtalloc (ctx, sizeof (RTPOINTARRAY *) * (ngeoms + 1));
1750 rng = pg->Exterior;
1751 close_ring = check_unclosed_ring (rng);
1752 if (close_ring)
1753 ppaa[0] = ptarray_construct (ctx, has_z, has_m, rng->Points + 1);
1754 else
1755 ppaa[0] = ptarray_construct (ctx, has_z, has_m, rng->Points);
1756 for (iv = 0; iv < rng->Points; iv++)
1757 {
1758 /* copying vertices - Exterior Ring */
1759 if (pg->DimensionModel == GAIA_XY_Z)
1760 {
1761 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
1762 }
1763 else if (pg->DimensionModel == GAIA_XY_M)
1764 {
1765 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
1766 }
1767 else if (pg->DimensionModel == GAIA_XY_Z_M)
1768 {
1769 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
1770 }
1771 else
1772 {
1773 gaiaGetPoint (rng->Coords, iv, &x, &y);
1774 }
1775 point.x = x;
1776 point.y = y;
1777 if (has_z)
1778 point.z = z;
1779 if (has_m)
1780 point.m = m;
1781 ptarray_set_point4d (ctx, ppaa[0], iv, &point);
1782 }
1783 if (close_ring)
1784 {
1785 /* making an unclosed ring to be closed */
1786 if (pg->DimensionModel == GAIA_XY_Z)
1787 {
1788 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
1789 }
1790 else if (pg->DimensionModel == GAIA_XY_M)
1791 {
1792 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
1793 }
1794 else if (pg->DimensionModel == GAIA_XY_Z_M)
1795 {
1796 gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
1797 }
1798 else
1799 {
1800 gaiaGetPoint (rng->Coords, 0, &x, &y);
1801 }
1802 point.x = x;
1803 point.y = y;
1804 if (has_z)
1805 point.z = z;
1806 if (has_m)
1807 point.m = m;
1808 ptarray_set_point4d (ctx, ppaa[0], rng->Points, &point);
1809 }
1810 for (ib = 0; ib < pg->NumInteriors; ib++)
1811 {
1812 /* copying vertices - Interior Rings */
1813 rng = pg->Interiors + ib;
1814 close_ring = check_unclosed_ring (rng);
1815 if (close_ring)
1816 ppaa[1 + ib] =
1817 ptarray_construct (ctx, has_z, has_m, rng->Points + 1);
1818 else
1819 ppaa[1 + ib] = ptarray_construct (ctx, has_z, has_m, rng->Points);
1820 for (iv = 0; iv < rng->Points; iv++)
1821 {
1822 if (pg->DimensionModel == GAIA_XY_Z)
1823 {
1824 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
1825 }
1826 else if (pg->DimensionModel == GAIA_XY_M)
1827 {
1828 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
1829 }
1830 else if (pg->DimensionModel == GAIA_XY_Z_M)
1831 {
1832 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
1833 }
1834 else
1835 {
1836 gaiaGetPoint (rng->Coords, iv, &x, &y);
1837 }
1838 point.x = x;
1839 point.y = y;
1840 if (has_z)
1841 point.z = z;
1842 if (has_m)
1843 point.m = m;
1844 ptarray_set_point4d (ctx, ppaa[1 + ib], iv, &point);
1845 }
1846 if (close_ring)
1847 {
1848 /* making an unclosed ring to be closed */
1849 if (pg->DimensionModel == GAIA_XY_Z)
1850 {
1851 gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
1852 }
1853 else if (pg->DimensionModel == GAIA_XY_M)
1854 {
1855 gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
1856 }
1857 else if (pg->DimensionModel == GAIA_XY_Z_M)
1858 {
1859 gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
1860 }
1861 else
1862 {
1863 gaiaGetPoint (rng->Coords, 0, &x, &y);
1864 }
1865 point.x = x;
1866 point.y = y;
1867 if (has_z)
1868 point.z = z;
1869 if (has_m)
1870 point.m = m;
1871 ptarray_set_point4d (ctx, ppaa[0], rng->Points, &point);
1872 }
1873 }
1874 return (RTGEOM *) rtpoly_construct (ctx, srid, NULL, ngeoms + 1, ppaa);
1875 }
1876
1877 static gaiaGeomCollPtr
fromRTGeomLeft(const RTCTX * ctx,gaiaGeomCollPtr gaia,const RTGEOM * rtgeom)1878 fromRTGeomLeft (const RTCTX * ctx, gaiaGeomCollPtr gaia, const RTGEOM * rtgeom)
1879 {
1880 /*
1881 / converting a RTGEOM Geometry into a GAIA Geometry
1882 / collecting "left side" items
1883 */
1884 RTGEOM *rtg2 = NULL;
1885 RTCOLLECTION *rtc = NULL;
1886 int ngeoms;
1887 int ig;
1888
1889 if (rtgeom == NULL)
1890 return NULL;
1891 if (rtgeom_is_empty (ctx, rtgeom))
1892 return NULL;
1893
1894 if (rtgeom->type == RTCOLLECTIONTYPE)
1895 {
1896 rtc = (RTCOLLECTION *) rtgeom;
1897 ngeoms = rtc->ngeoms;
1898 for (ig = 0; ig < ngeoms; ig += 2)
1899 {
1900 rtg2 = rtc->geoms[ig];
1901 fromRTGeomIncremental (ctx, gaia, rtg2);
1902 }
1903 }
1904 else
1905 gaia =
1906 fromRTGeom (ctx, rtgeom, gaia->DimensionModel, gaia->DeclaredType);
1907
1908 return gaia;
1909 }
1910
1911 static gaiaGeomCollPtr
fromRTGeomRight(const RTCTX * ctx,gaiaGeomCollPtr gaia,const RTGEOM * rtgeom)1912 fromRTGeomRight (const RTCTX * ctx, gaiaGeomCollPtr gaia, const RTGEOM * rtgeom)
1913 {
1914 /*
1915 / converting a RTGEOM Geometry into a GAIA Geometry
1916 / collecting "right side" items
1917 */
1918 RTGEOM *rtg2 = NULL;
1919 RTCOLLECTION *rtc = NULL;
1920 int ngeoms;
1921 int ig;
1922
1923 if (rtgeom == NULL)
1924 return NULL;
1925 if (rtgeom_is_empty (ctx, rtgeom))
1926 return NULL;
1927
1928 if (rtgeom->type == RTCOLLECTIONTYPE)
1929 {
1930 rtc = (RTCOLLECTION *) rtgeom;
1931 ngeoms = rtc->ngeoms;
1932 for (ig = 1; ig < ngeoms; ig += 2)
1933 {
1934 rtg2 = rtc->geoms[ig];
1935 fromRTGeomIncremental (ctx, gaia, rtg2);
1936 }
1937 }
1938
1939 return gaia;
1940 }
1941
1942 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaSplit(const void * p_cache,gaiaGeomCollPtr input,gaiaGeomCollPtr blade)1943 gaiaSplit (const void *p_cache, gaiaGeomCollPtr input, gaiaGeomCollPtr blade)
1944 {
1945 /* wrapping RTGEOM Split */
1946 const RTCTX *ctx = NULL;
1947 struct splite_internal_cache *cache =
1948 (struct splite_internal_cache *) p_cache;
1949 RTGEOM *g1;
1950 RTGEOM *g2;
1951 RTGEOM *g3;
1952 gaiaGeomCollPtr result = NULL;
1953
1954 if (!check_split_args (input, blade))
1955 return NULL;
1956 if (cache == NULL)
1957 return NULL;
1958 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1959 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1960 return NULL;
1961 ctx = cache->RTTOPO_handle;
1962 if (ctx == NULL)
1963 return NULL;
1964
1965 g1 = toRTGeom (ctx, input);
1966 g2 = toRTGeom (ctx, blade);
1967 g3 = rtgeom_split (ctx, g1, g2);
1968 if (!g3)
1969 {
1970 rtgeom_free (ctx, g1);
1971 rtgeom_free (ctx, g2);
1972 goto done;
1973 }
1974 result = fromRTGeom (ctx, g3, input->DimensionModel, input->DeclaredType);
1975 spatialite_init_geos ();
1976 rtgeom_free (ctx, g1);
1977 rtgeom_free (ctx, g2);
1978 rtgeom_free (ctx, g3);
1979 if (result == NULL)
1980 goto done;
1981 result->Srid = input->Srid;
1982 set_split_gtype (result);
1983
1984 done:
1985 return result;
1986 }
1987
1988 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaSplitLeft(const void * p_cache,gaiaGeomCollPtr input,gaiaGeomCollPtr blade)1989 gaiaSplitLeft (const void *p_cache, gaiaGeomCollPtr input,
1990 gaiaGeomCollPtr blade)
1991 {
1992 /* wrapping RTGEOM Split [left half] */
1993 const RTCTX *ctx = NULL;
1994 struct splite_internal_cache *cache =
1995 (struct splite_internal_cache *) p_cache;
1996 RTGEOM *g1;
1997 RTGEOM *g2;
1998 RTGEOM *g3;
1999 gaiaGeomCollPtr result = NULL;
2000 gaiaLinestringPtr ln;
2001 gaiaPolygonPtr pg;
2002
2003 if (!check_split_args (input, blade))
2004 return NULL;
2005 if (cache == NULL)
2006 return NULL;
2007 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2008 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2009 return NULL;
2010 ctx = cache->RTTOPO_handle;
2011 if (ctx == NULL)
2012 return NULL;
2013
2014 if (input->DimensionModel == GAIA_XY_Z)
2015 result = gaiaAllocGeomCollXYZ ();
2016 else if (input->DimensionModel == GAIA_XY_M)
2017 result = gaiaAllocGeomCollXYM ();
2018 else if (input->DimensionModel == GAIA_XY_Z_M)
2019 result = gaiaAllocGeomCollXYZM ();
2020 else
2021 result = gaiaAllocGeomColl ();
2022
2023 g2 = toRTGeom (ctx, blade);
2024
2025 ln = input->FirstLinestring;
2026 while (ln)
2027 {
2028 /* splitting some Linestring */
2029 g1 = toRTGeomLinestring (ctx, ln, input->Srid);
2030 g3 = rtgeom_split (ctx, g1, g2);
2031 if (g3)
2032 {
2033 result = fromRTGeomLeft (ctx, result, g3);
2034 rtgeom_free (ctx, g3);
2035 }
2036 spatialite_init_geos ();
2037 rtgeom_free (ctx, g1);
2038 ln = ln->Next;
2039 }
2040 pg = input->FirstPolygon;
2041 while (pg)
2042 {
2043 /* splitting some Polygon */
2044 g1 = toRTGeomPolygon (ctx, pg, input->Srid);
2045 g3 = rtgeom_split (ctx, g1, g2);
2046 if (g3)
2047 {
2048 result = fromRTGeomLeft (ctx, result, g3);
2049 rtgeom_free (ctx, g3);
2050 }
2051 spatialite_init_geos ();
2052 rtgeom_free (ctx, g1);
2053 pg = pg->Next;
2054 }
2055
2056 rtgeom_free (ctx, g2);
2057 if (result == NULL)
2058 goto done;
2059 if (result->FirstPoint == NULL && result->FirstLinestring == NULL
2060 && result->FirstPolygon == NULL)
2061 {
2062 gaiaFreeGeomColl (result);
2063 result = NULL;
2064 goto done;
2065 }
2066 result->Srid = input->Srid;
2067 set_split_gtype (result);
2068
2069 done:
2070 return result;
2071 }
2072
2073 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaSplitRight(const void * p_cache,gaiaGeomCollPtr input,gaiaGeomCollPtr blade)2074 gaiaSplitRight (const void *p_cache, gaiaGeomCollPtr input,
2075 gaiaGeomCollPtr blade)
2076 {
2077 /* wrapping RTGEOM Split [right half] */
2078 const RTCTX *ctx = NULL;
2079 struct splite_internal_cache *cache =
2080 (struct splite_internal_cache *) p_cache;
2081 RTGEOM *g1;
2082 RTGEOM *g2;
2083 RTGEOM *g3;
2084 gaiaGeomCollPtr result = NULL;
2085 gaiaLinestringPtr ln;
2086 gaiaPolygonPtr pg;
2087
2088 if (!check_split_args (input, blade))
2089 return NULL;
2090 if (cache == NULL)
2091 return NULL;
2092 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2093 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2094 return NULL;
2095 ctx = cache->RTTOPO_handle;
2096 if (ctx == NULL)
2097 return NULL;
2098
2099 if (input->DimensionModel == GAIA_XY_Z)
2100 result = gaiaAllocGeomCollXYZ ();
2101 else if (input->DimensionModel == GAIA_XY_M)
2102 result = gaiaAllocGeomCollXYM ();
2103 else if (input->DimensionModel == GAIA_XY_Z_M)
2104 result = gaiaAllocGeomCollXYZM ();
2105 else
2106 result = gaiaAllocGeomColl ();
2107
2108 g2 = toRTGeom (ctx, blade);
2109
2110 ln = input->FirstLinestring;
2111 while (ln)
2112 {
2113 /* splitting some Linestring */
2114 g1 = toRTGeomLinestring (ctx, ln, input->Srid);
2115 g3 = rtgeom_split (ctx, g1, g2);
2116 if (g3)
2117 {
2118 result = fromRTGeomRight (ctx, result, g3);
2119 rtgeom_free (ctx, g3);
2120 }
2121 spatialite_init_geos ();
2122 rtgeom_free (ctx, g1);
2123 ln = ln->Next;
2124 }
2125 pg = input->FirstPolygon;
2126 while (pg)
2127 {
2128 /* splitting some Polygon */
2129 g1 = toRTGeomPolygon (ctx, pg, input->Srid);
2130 g3 = rtgeom_split (ctx, g1, g2);
2131 if (g3)
2132 {
2133 result = fromRTGeomRight (ctx, result, g3);
2134 rtgeom_free (ctx, g3);
2135 }
2136 spatialite_init_geos ();
2137 rtgeom_free (ctx, g1);
2138 pg = pg->Next;
2139 }
2140
2141 rtgeom_free (ctx, g2);
2142 if (result == NULL)
2143 goto done;
2144 if (result->FirstPoint == NULL && result->FirstLinestring == NULL
2145 && result->FirstPolygon == NULL)
2146 {
2147 gaiaFreeGeomColl (result);
2148 result = NULL;
2149 goto done;
2150 }
2151 result->Srid = input->Srid;
2152 set_split_gtype (result);
2153
2154 done:
2155 return result;
2156 }
2157
2158 GAIAGEO_DECLARE int
gaiaAzimuth(const void * p_cache,double xa,double ya,double xb,double yb,double * azimuth)2159 gaiaAzimuth (const void *p_cache, double xa, double ya, double xb, double yb,
2160 double *azimuth)
2161 {
2162 /* wrapping RTGEOM Azimuth */
2163 const RTCTX *ctx = NULL;
2164 struct splite_internal_cache *cache =
2165 (struct splite_internal_cache *) p_cache;
2166 RTPOINT2D pt1;
2167 RTPOINT2D pt2;
2168 double az;
2169 int ret = 1;
2170
2171 if (cache == NULL)
2172 return 0;
2173 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2174 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2175 return 0;
2176 ctx = cache->RTTOPO_handle;
2177 if (ctx == NULL)
2178 return 0;
2179
2180 pt1.x = xa;
2181 pt1.y = ya;
2182 pt2.x = xb;
2183 pt2.y = yb;
2184
2185 if (!azimuth_pt_pt (ctx, &pt1, &pt2, &az))
2186 ret = 0;
2187 *azimuth = az;
2188
2189 return ret;
2190 }
2191
2192 GAIAGEO_DECLARE int
gaiaEllipsoidAzimuth(const void * p_cache,double xa,double ya,double xb,double yb,double a,double b,double * azimuth)2193 gaiaEllipsoidAzimuth (const void *p_cache, double xa, double ya, double xb,
2194 double yb, double a, double b, double *azimuth)
2195 {
2196 /* wrapping RTGEOM AzimuthSpheroid */
2197 const RTCTX *ctx = NULL;
2198 struct splite_internal_cache *cache =
2199 (struct splite_internal_cache *) p_cache;
2200 RTPOINT *pt1;
2201 RTPOINT *pt2;
2202 SPHEROID ellips;
2203 int ret = 1;
2204
2205 if (cache == NULL)
2206 return 0;
2207 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2208 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2209 return 0;
2210 ctx = cache->RTTOPO_handle;
2211 if (ctx == NULL)
2212 return 0;
2213
2214 pt1 = rtpoint_make2d (ctx, 0, xa, ya);
2215 pt2 = rtpoint_make2d (ctx, 0, xb, yb);
2216 spheroid_init (ctx, &ellips, a, b);
2217 *azimuth = rtgeom_azumith_spheroid (ctx, pt1, pt2, &ellips);
2218 rtpoint_free (ctx, pt1);
2219 rtpoint_free (ctx, pt2);
2220
2221 return ret;
2222 }
2223
2224 GAIAGEO_DECLARE int
gaiaProjectedPoint(const void * p_cache,double x1,double y1,double a,double b,double distance,double azimuth,double * x2,double * y2)2225 gaiaProjectedPoint (const void *p_cache, double x1, double y1, double a,
2226 double b, double distance, double azimuth, double *x2,
2227 double *y2)
2228 {
2229 /* wrapping RTGEOM Project */
2230 const RTCTX *ctx = NULL;
2231 struct splite_internal_cache *cache =
2232 (struct splite_internal_cache *) p_cache;
2233 RTPOINT *pt1;
2234 RTPOINT *pt2;
2235 SPHEROID ellips;
2236 int ret = 0;
2237
2238 if (cache == NULL)
2239 return 0;
2240 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2241 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2242 return 0;
2243 ctx = cache->RTTOPO_handle;
2244 if (ctx == NULL)
2245 return 0;
2246
2247 pt1 = rtpoint_make2d (ctx, 0, x1, y1);
2248 spheroid_init (ctx, &ellips, a, b);
2249 pt2 = rtgeom_project_spheroid (ctx, pt1, &ellips, distance, azimuth);
2250 rtpoint_free (ctx, pt1);
2251 if (pt2 != NULL)
2252 {
2253 *x2 = rtpoint_get_x (ctx, pt2);
2254 *y2 = rtpoint_get_y (ctx, pt2);
2255 rtpoint_free (ctx, pt2);
2256 ret = 1;
2257 }
2258
2259 return ret;
2260 }
2261
2262 GAIAGEO_DECLARE int
gaiaGeodesicArea(const void * p_cache,gaiaGeomCollPtr geom,double a,double b,int use_ellipsoid,double * area)2263 gaiaGeodesicArea (const void *p_cache, gaiaGeomCollPtr geom, double a, double b,
2264 int use_ellipsoid, double *area)
2265 {
2266 /* wrapping RTGEOM AreaSphere and AreaSpheroid */
2267 const RTCTX *ctx = NULL;
2268 struct splite_internal_cache *cache =
2269 (struct splite_internal_cache *) p_cache;
2270 RTGEOM *g;
2271 SPHEROID ellips;
2272 RTGBOX gbox;
2273 double tolerance = 1e-12;
2274 int ret = 1;
2275
2276 if (cache == NULL)
2277 return 0;
2278 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2279 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2280 return 0;
2281 ctx = cache->RTTOPO_handle;
2282 if (ctx == NULL)
2283 return 0;
2284
2285 g = toRTGeom (ctx, geom);
2286 spheroid_init (ctx, &ellips, a, b);
2287 if (g == NULL)
2288 {
2289 ret = 0;
2290 goto done;
2291 }
2292 rtgeom_calculate_gbox_geodetic (ctx, g, &gbox);
2293 if (use_ellipsoid)
2294 {
2295 /* testing for "forbidden" calculations on the ellipsoid */
2296 if ((gbox.zmax + tolerance) >= 1.0 || (gbox.zmin - tolerance) <= -1.0)
2297 use_ellipsoid = 0; /* can't circle the poles */
2298 if (gbox.zmax > 0.0 && gbox.zmin < 0.0)
2299 use_ellipsoid = 0; /* can't cross the equator */
2300 }
2301 if (use_ellipsoid)
2302 *area = rtgeom_area_spheroid (ctx, g, &ellips);
2303 else
2304 *area = rtgeom_area_sphere (ctx, g, &ellips);
2305 rtgeom_free (ctx, g);
2306
2307 done:
2308 return ret;
2309 }
2310
2311 GAIAGEO_DECLARE char *
gaiaGeoHash(const void * p_cache,gaiaGeomCollPtr geom,int precision)2312 gaiaGeoHash (const void *p_cache, gaiaGeomCollPtr geom, int precision)
2313 {
2314 /* wrapping RTGEOM GeoHash */
2315 const RTCTX *ctx = NULL;
2316 struct splite_internal_cache *cache =
2317 (struct splite_internal_cache *) p_cache;
2318 RTGEOM *g;
2319 char *result;
2320 char *geo_hash = NULL;
2321 int len;
2322
2323 if (!geom)
2324 return NULL;
2325 gaiaMbrGeometry (geom);
2326 if (geom->MinX < -180.0 || geom->MaxX > 180.0 || geom->MinY < -90.0
2327 || geom->MaxY > 90.0)
2328 return NULL;
2329 if (cache == NULL)
2330 return NULL;
2331 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2332 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2333 return NULL;
2334 ctx = cache->RTTOPO_handle;
2335 if (ctx == NULL)
2336 return NULL;
2337
2338 g = toRTGeom (ctx, geom);
2339 result = rtgeom_geohash (ctx, g, precision);
2340 rtgeom_free (ctx, g);
2341 if (result == NULL)
2342 goto done;
2343 len = strlen (result);
2344 if (len == 0)
2345 {
2346 rtfree (ctx, result);
2347 goto done;
2348 }
2349 geo_hash = malloc (len + 1);
2350 strcpy (geo_hash, result);
2351 rtfree (ctx, result);
2352
2353 done:
2354 return geo_hash;
2355 }
2356
2357 GAIAGEO_DECLARE char *
gaiaAsX3D(const void * p_cache,gaiaGeomCollPtr geom,const char * srs,int precision,int options,const char * defid)2358 gaiaAsX3D (const void *p_cache, gaiaGeomCollPtr geom, const char *srs,
2359 int precision, int options, const char *defid)
2360 {
2361 /* wrapping RTGEOM AsX3D */
2362 const RTCTX *ctx = NULL;
2363 struct splite_internal_cache *cache =
2364 (struct splite_internal_cache *) p_cache;
2365 RTGEOM *g;
2366 char *result;
2367 char *x3d = NULL;
2368 int len;
2369
2370 if (!geom)
2371 return NULL;
2372 if (cache == NULL)
2373 return NULL;
2374 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2375 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2376 return NULL;
2377 ctx = cache->RTTOPO_handle;
2378 if (ctx == NULL)
2379 return NULL;
2380
2381 gaiaMbrGeometry (geom);
2382 g = toRTGeom (ctx, geom);
2383 result = rtgeom_to_x3d3 (ctx, g, (char *) srs, precision, options, defid);
2384 rtgeom_free (ctx, g);
2385 if (result == NULL)
2386 goto done;
2387 len = strlen (result);
2388 if (len == 0)
2389 {
2390 rtfree (ctx, result);
2391 goto done;
2392 }
2393 x3d = malloc (len + 1);
2394 strcpy (x3d, result);
2395 rtfree (ctx, result);
2396
2397 done:
2398 return x3d;
2399 }
2400
2401 GAIAGEO_DECLARE int
gaia3DDistance(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,double * dist)2402 gaia3DDistance (const void *p_cache, gaiaGeomCollPtr geom1,
2403 gaiaGeomCollPtr geom2, double *dist)
2404 {
2405 /* wrapping RTGEOM mindistance3d */
2406 const RTCTX *ctx = NULL;
2407 struct splite_internal_cache *cache =
2408 (struct splite_internal_cache *) p_cache;
2409 RTGEOM *g1;
2410 RTGEOM *g2;
2411 double d;
2412 int ret = 1;
2413
2414 if (cache == NULL)
2415 return 0;
2416 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2417 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2418 return 0;
2419 ctx = cache->RTTOPO_handle;
2420 if (ctx == NULL)
2421 return 0;
2422
2423 g1 = toRTGeom (ctx, geom1);
2424 g2 = toRTGeom (ctx, geom2);
2425
2426 d = rtgeom_mindistance3d (ctx, g1, g2);
2427 rtgeom_free (ctx, g1);
2428 rtgeom_free (ctx, g2);
2429 *dist = d;
2430
2431 return ret;
2432 }
2433
2434 GAIAGEO_DECLARE int
gaiaMaxDistance(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,double * dist)2435 gaiaMaxDistance (const void *p_cache, gaiaGeomCollPtr geom1,
2436 gaiaGeomCollPtr geom2, double *dist)
2437 {
2438 /* wrapping RTGEOM maxdistance2d */
2439 const RTCTX *ctx = NULL;
2440 struct splite_internal_cache *cache =
2441 (struct splite_internal_cache *) p_cache;
2442 RTGEOM *g1;
2443 RTGEOM *g2;
2444 double d;
2445 int ret = 1;
2446
2447 if (cache == NULL)
2448 return 0;
2449 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2450 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2451 return 0;
2452 ctx = cache->RTTOPO_handle;
2453 if (ctx == NULL)
2454 return 0;
2455
2456 g1 = toRTGeom (ctx, geom1);
2457 g2 = toRTGeom (ctx, geom2);
2458
2459 d = rtgeom_maxdistance2d (ctx, g1, g2);
2460 rtgeom_free (ctx, g1);
2461 rtgeom_free (ctx, g2);
2462 *dist = d;
2463
2464 return ret;
2465 }
2466
2467 GAIAGEO_DECLARE int
gaia3DMaxDistance(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,double * dist)2468 gaia3DMaxDistance (const void *p_cache, gaiaGeomCollPtr geom1,
2469 gaiaGeomCollPtr geom2, double *dist)
2470 {
2471 /* wrapping RTGEOM maxdistance2d */
2472 const RTCTX *ctx = NULL;
2473 struct splite_internal_cache *cache =
2474 (struct splite_internal_cache *) p_cache;
2475 RTGEOM *g1;
2476 RTGEOM *g2;
2477 double d;
2478 int ret = 1;
2479
2480 if (cache == NULL)
2481 return 0;
2482 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2483 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2484 return 0;
2485 ctx = cache->RTTOPO_handle;
2486 if (ctx == NULL)
2487 return 0;
2488
2489 g1 = toRTGeom (ctx, geom1);
2490 g2 = toRTGeom (ctx, geom2);
2491
2492 d = rtgeom_maxdistance3d (ctx, g1, g2);
2493 rtgeom_free (ctx, g1);
2494 rtgeom_free (ctx, g2);
2495 *dist = d;
2496
2497 return ret;
2498 }
2499
2500 static RTLINE *
linestring2rtline(const RTCTX * ctx,gaiaLinestringPtr ln,int srid)2501 linestring2rtline (const RTCTX * ctx, gaiaLinestringPtr ln, int srid)
2502 {
2503 /* converting a Linestring into an RTLINE */
2504 RTPOINTARRAY *pa;
2505 RTPOINT4D point;
2506 int iv;
2507 double x;
2508 double y;
2509 double z;
2510 double m;
2511 int has_z = 0;
2512
2513 if (ln->DimensionModel == GAIA_XY_Z || ln->DimensionModel == GAIA_XY_Z_M)
2514 has_z = 1;
2515
2516 pa = ptarray_construct (ctx, has_z, 0, ln->Points);
2517 for (iv = 0; iv < ln->Points; iv++)
2518 {
2519 /* copying vertices */
2520 if (ln->DimensionModel == GAIA_XY_Z)
2521 {
2522 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2523 }
2524 else if (ln->DimensionModel == GAIA_XY_M)
2525 {
2526 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2527 }
2528 else if (ln->DimensionModel == GAIA_XY_Z_M)
2529 {
2530 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2531 }
2532 else
2533 {
2534 gaiaGetPoint (ln->Coords, iv, &x, &y);
2535 }
2536 point.x = x;
2537 point.y = y;
2538 if (has_z)
2539 point.z = z;
2540 else
2541 point.z = 0.0;
2542 point.m = 0.0;
2543 ptarray_set_point4d (ctx, pa, iv, &point);
2544 }
2545 return rtline_construct (ctx, srid, NULL, pa);
2546 }
2547
2548 GAIAGEO_DECLARE int
gaia3dLength(const void * p_cache,gaiaGeomCollPtr geom,double * length)2549 gaia3dLength (const void *p_cache, gaiaGeomCollPtr geom, double *length)
2550 {
2551 /* wrapping RTGEOM rtline_length */
2552 const RTCTX *ctx = NULL;
2553 struct splite_internal_cache *cache =
2554 (struct splite_internal_cache *) p_cache;
2555 RTLINE *line;
2556 gaiaLinestringPtr ln;
2557 double l = 0.0;
2558 int ret = 0;
2559
2560 if (cache == NULL)
2561 return 0;
2562 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2563 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2564 return 0;
2565 ctx = cache->RTTOPO_handle;
2566 if (ctx == NULL)
2567 return 0;
2568
2569 ln = geom->FirstLinestring;
2570 while (ln != NULL)
2571 {
2572 ret = 1;
2573 line = linestring2rtline (ctx, ln, geom->Srid);
2574 l += rtgeom_length (ctx, (RTGEOM *) line);
2575 rtline_free (ctx, line);
2576 ln = ln->Next;
2577 }
2578 *length = l;
2579
2580 return ret;
2581 }
2582
2583 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaNodeLines(const void * p_cache,gaiaGeomCollPtr geom)2584 gaiaNodeLines (const void *p_cache, gaiaGeomCollPtr geom)
2585 {
2586 /* wrapping RTGEOM rtgeom_node */
2587 const RTCTX *ctx = NULL;
2588 struct splite_internal_cache *cache =
2589 (struct splite_internal_cache *) p_cache;
2590 RTGEOM *g1;
2591 RTGEOM *g2;
2592 gaiaGeomCollPtr result = NULL;
2593
2594 if (!geom)
2595 return NULL;
2596 if (cache == NULL)
2597 return NULL;
2598 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2599 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2600 return NULL;
2601 ctx = cache->RTTOPO_handle;
2602 if (ctx == NULL)
2603 return NULL;
2604
2605 g1 = toRTGeom (ctx, geom);
2606 g2 = rtgeom_node (ctx, g1);
2607 if (!g2)
2608 {
2609 rtgeom_free (ctx, g1);
2610 goto done;
2611 }
2612 result = fromRTGeom (ctx, g2, geom->DimensionModel, geom->DeclaredType);
2613 spatialite_init_geos ();
2614 rtgeom_free (ctx, g1);
2615 rtgeom_free (ctx, g2);
2616 if (result == NULL)
2617 goto done;
2618 result->Srid = geom->Srid;
2619
2620 done:
2621 return result;
2622 }
2623
2624 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaSubdivide(const void * p_cache,gaiaGeomCollPtr geom,int max_vertices)2625 gaiaSubdivide (const void *p_cache, gaiaGeomCollPtr geom, int max_vertices)
2626 {
2627 /* wrapping RTGEOM rtgeom_node */
2628 const RTCTX *ctx = NULL;
2629 struct splite_internal_cache *cache =
2630 (struct splite_internal_cache *) p_cache;
2631 RTGEOM *g1;
2632 RTCOLLECTION *g2;
2633 gaiaGeomCollPtr result = NULL;
2634 int i;
2635
2636 if (!geom)
2637 return NULL;
2638 if (cache == NULL)
2639 return NULL;
2640 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2641 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2642 return NULL;
2643 ctx = cache->RTTOPO_handle;
2644 if (ctx == NULL)
2645 return NULL;
2646
2647 g1 = toRTGeom (ctx, geom);
2648 g2 = rtgeom_subdivide (ctx, g1, max_vertices);
2649 if (!g2)
2650 {
2651 rtgeom_free (ctx, g1);
2652 goto done;
2653 }
2654
2655 /* building the subdivided geometry to be returned */
2656 if (geom->DimensionModel == GAIA_XY_Z)
2657 result = gaiaAllocGeomCollXYZ ();
2658 else if (geom->DimensionModel == GAIA_XY_M)
2659 result = gaiaAllocGeomCollXYM ();
2660 else if (geom->DimensionModel == GAIA_XY_Z_M)
2661 result = gaiaAllocGeomCollXYZM ();
2662 else
2663 result = gaiaAllocGeomColl ();
2664 for (i = 0; i < g2->ngeoms; i++)
2665 {
2666 RTGEOM *g3 = *(g2->geoms + i);
2667 fromRTGeomIncremental (ctx, result, g3);
2668 }
2669 spatialite_init_geos ();
2670 rtgeom_free (ctx, g1);
2671 rtcollection_free (ctx, g2);
2672 if (result == NULL)
2673 goto done;
2674 result->Srid = geom->Srid;
2675
2676 done:
2677 return result;
2678 }
2679
2680 GAIAGEO_DECLARE int
gaiaToTWKB(const void * p_cache,gaiaGeomCollPtr geom,unsigned char precision_xy,unsigned char precision_z,unsigned char precision_m,int with_size,int with_bbox,unsigned char ** twkb,int * size_twkb)2681 gaiaToTWKB (const void *p_cache, gaiaGeomCollPtr geom,
2682 unsigned char precision_xy, unsigned char precision_z,
2683 unsigned char precision_m, int with_size, int with_bbox,
2684 unsigned char **twkb, int *size_twkb)
2685 {
2686 /* wrapping RTGEOM rtgeom_to_twkb */
2687 const RTCTX *ctx = NULL;
2688 struct splite_internal_cache *cache =
2689 (struct splite_internal_cache *) p_cache;
2690 unsigned char variant = 0;
2691 RTGEOM *g;
2692 unsigned char *p_twkb;
2693 size_t twkb_size;
2694
2695 *twkb = NULL;
2696 *size_twkb = 0;
2697
2698 if (!geom)
2699 return 0;
2700 if (cache == NULL)
2701 return 0;
2702 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2703 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2704 return 0;
2705 ctx = cache->RTTOPO_handle;
2706 if (ctx == NULL)
2707 return 0;
2708
2709 if (with_size)
2710 variant |= TWKB_SIZE;
2711 if (with_bbox)
2712 variant |= TWKB_BBOX;
2713
2714 g = toRTGeom (ctx, geom);
2715 p_twkb =
2716 rtgeom_to_twkb (ctx, g, variant, precision_xy, precision_z, precision_m,
2717 &twkb_size);
2718 rtgeom_free (ctx, g);
2719
2720 if (p_twkb == NULL)
2721 return 0;
2722 *twkb = p_twkb;
2723 *size_twkb = twkb_size;
2724 return 1;
2725 }
2726
2727 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromTWKB(const void * p_cache,const unsigned char * twkb,int twkb_size,int srid)2728 gaiaFromTWKB (const void *p_cache, const unsigned char *twkb, int twkb_size,
2729 int srid)
2730 {
2731 /* wrapping RTGEOM rtgeom_from_twkb */
2732 const RTCTX *ctx = NULL;
2733 int dims = GAIA_XY_Z_M;
2734 int type = GAIA_GEOMETRYCOLLECTION;
2735 struct splite_internal_cache *cache =
2736 (struct splite_internal_cache *) p_cache;
2737 RTGEOM *g;
2738 gaiaGeomCollPtr result;
2739
2740 if (twkb == NULL)
2741 return NULL;
2742 if (cache == NULL)
2743 return NULL;
2744 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2745 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2746 return NULL;
2747 ctx = cache->RTTOPO_handle;
2748 if (ctx == NULL)
2749 return NULL;
2750
2751 g = rtgeom_from_twkb (ctx, (unsigned char *) twkb, twkb_size, 0);
2752 if (g == NULL)
2753 return NULL;
2754 if ((*(twkb + 0) & 0x01) == 0x01)
2755 type = GAIA_POINT;
2756 if ((*(twkb + 0) & 0x02) == 0x02)
2757 type = GAIA_LINESTRING;
2758 if ((*(twkb + 0) & 0x03) == 0x03)
2759 type = GAIA_POLYGON;
2760 if ((*(twkb + 0) & 0x04) == 0x04)
2761 type = GAIA_MULTIPOINT;
2762 if ((*(twkb + 0) & 0x05) == 0x05)
2763 type = GAIA_MULTILINESTRING;
2764 if ((*(twkb + 0) & 0x06) == 0x06)
2765 type = GAIA_MULTIPOLYGON;
2766 if ((*(twkb + 0) & 0x07) == 0x07)
2767 type = GAIA_GEOMETRYCOLLECTION;
2768 if ((*(twkb + 1) & 0x08) == 0x08)
2769 {
2770 if ((*(twkb + 2) & 0x01) == 0x01)
2771 dims = GAIA_XY_Z;
2772 if ((*(twkb + 2) & 0x02) == 0x02)
2773 dims = GAIA_XY_M;
2774 if ((*(twkb + 2) & 0x03) == 0x03)
2775 dims = GAIA_XY_Z_M;
2776 }
2777 else
2778 dims = GAIA_XY;
2779 result = fromRTGeom (ctx, g, dims, type);
2780 spatialite_init_geos ();
2781 rtgeom_free (ctx, g);
2782 if (result != NULL)
2783 result->Srid = srid;
2784 return result;
2785 }
2786
2787 GAIAGEO_DECLARE int
gaiaAsEncodedPolyLine(const void * p_cache,gaiaGeomCollPtr geom,unsigned char precision,char ** encoded,int * len)2788 gaiaAsEncodedPolyLine (const void *p_cache, gaiaGeomCollPtr geom,
2789 unsigned char precision, char **encoded, int *len)
2790 {
2791 /* wrapping RTGEOM rtline_to_encoded_polyline */
2792 const RTCTX *ctx = NULL;
2793 struct splite_internal_cache *cache =
2794 (struct splite_internal_cache *) p_cache;
2795 RTGEOM *g;
2796 char *p_encoded;
2797
2798 *encoded = NULL;
2799 *len = 0;
2800
2801 if (!geom)
2802 return 0;
2803 if (cache == NULL)
2804 return 0;
2805 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2806 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2807 return 0;
2808 ctx = cache->RTTOPO_handle;
2809 if (ctx == NULL)
2810 return 0;
2811
2812 g = toRTGeom (ctx, geom);
2813 p_encoded = rtgeom_to_encoded_polyline (ctx, g, precision);
2814 rtgeom_free (ctx, g);
2815
2816 if (p_encoded == NULL)
2817 return 0;
2818 *encoded = p_encoded;
2819 *len = strlen (p_encoded);
2820 return 1;
2821 }
2822
2823 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaLineFromEncodedPolyline(const void * p_cache,const char * encoded,unsigned char precision)2824 gaiaLineFromEncodedPolyline (const void *p_cache, const char *encoded,
2825 unsigned char precision)
2826 {
2827 /* wrapping RTGEOM rtline_from_encoded_polyline */
2828 const RTCTX *ctx = NULL;
2829 struct splite_internal_cache *cache =
2830 (struct splite_internal_cache *) p_cache;
2831 RTGEOM *g;
2832 gaiaGeomCollPtr result;
2833 int dims = GAIA_XY;
2834 int type = GAIA_LINESTRING;
2835
2836 if (encoded == NULL)
2837 return NULL;
2838 if (cache == NULL)
2839 return NULL;
2840 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2841 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2842 return NULL;
2843 ctx = cache->RTTOPO_handle;
2844 if (ctx == NULL)
2845 return NULL;
2846
2847 g = rtgeom_from_encoded_polyline (ctx, encoded, precision);
2848 if (g == NULL)
2849 return NULL;
2850 result = fromRTGeom (ctx, g, dims, type);
2851 spatialite_init_geos ();
2852 rtgeom_free (ctx, g);
2853 if (result != NULL)
2854 result->Srid = 4326;
2855 return result;
2856 }
2857
2858 static RTGEOM *
rtgeom_from_encoded_polyline(const RTCTX * ctx,const char * encodedpolyline,int precision)2859 rtgeom_from_encoded_polyline (const RTCTX * ctx, const char *encodedpolyline,
2860 int precision)
2861 {
2862 /*
2863 * RTTOPO lacks an implementation of rtgeom_from_encoded_polyline
2864 *
2865 * this simply is a rearranged version of the original code available
2866 * on LWGOEM lwin_encoded_polyline.c
2867 *
2868 * Copyright 2014 Kashif Rasul <kashif.rasul@gmail.com>
2869 *
2870 * the original code was released under the terms of the GNU General
2871 * Public License as published by the Free Software Foundation, either
2872 * version 2 of the License, or (at your option) any later version.
2873 */
2874 RTGEOM *geom = NULL;
2875 RTPOINTARRAY *pa = NULL;
2876 int length = strlen (encodedpolyline);
2877 int idx = 0;
2878 double scale = pow (10, precision);
2879
2880 float latitude = 0.0f;
2881 float longitude = 0.0f;
2882
2883 pa = ptarray_construct_empty (ctx, RT_FALSE, RT_FALSE, 1);
2884
2885 while (idx < length)
2886 {
2887 RTPOINT4D pt;
2888 char byte = 0;
2889
2890 int res = 0;
2891 char shift = 0;
2892 do
2893 {
2894 byte = encodedpolyline[idx++] - 63;
2895 res |= (byte & 0x1F) << shift;
2896 shift += 5;
2897 }
2898 while (byte >= 0x20);
2899 float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
2900 latitude += deltaLat;
2901
2902 shift = 0;
2903 res = 0;
2904 do
2905 {
2906 byte = encodedpolyline[idx++] - 63;
2907 res |= (byte & 0x1F) << shift;
2908 shift += 5;
2909 }
2910 while (byte >= 0x20);
2911 float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
2912 longitude += deltaLon;
2913
2914 pt.x = longitude / scale;
2915 pt.y = latitude / scale;
2916 pt.m = pt.z = 0.0;
2917 ptarray_append_point (ctx, pa, &pt, RT_FALSE);
2918 }
2919
2920 geom = (RTGEOM *) rtline_construct (ctx, 4326, NULL, pa);
2921 rtgeom_add_bbox (ctx, geom);
2922
2923 return geom;
2924 }
2925
2926
2927 #endif /* end enabling RTTOPO support */
2928