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