1 /*
2
3 gg_relations.c -- Gaia spatial relations
4
5 version 5.0, 2020 August 1
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 ------------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29
30 Contributor(s):
31
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43
44 */
45
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <float.h>
51
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57
58 #ifndef OMIT_GEOS /* including GEOS */
59 #ifdef GEOS_REENTRANT
60 #ifdef GEOS_ONLY_REENTRANT
61 #define GEOS_USE_ONLY_R_API /* only fully thread-safe GEOS API */
62 #endif
63 #endif
64 #include <geos_c.h>
65 #endif
66
67 #include <spatialite_private.h>
68 #include <spatialite/sqlite.h>
69
70 #include <spatialite/gaiageo.h>
71
72 /* GLOBAL variables */
73 char *gaia_geos_error_msg = NULL;
74 char *gaia_geos_warning_msg = NULL;
75 char *gaia_geosaux_error_msg = NULL;
76
77 SPATIALITE_PRIVATE void
splite_free_geos_cache_item(struct splite_geos_cache_item * p)78 splite_free_geos_cache_item (struct splite_geos_cache_item *p)
79 {
80 #ifndef OMIT_GEOS /* including GEOS */
81 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
82 if (p->preparedGeosGeom)
83 GEOSPreparedGeom_destroy (p->preparedGeosGeom);
84 if (p->geosGeom)
85 GEOSGeom_destroy (p->geosGeom);
86 #endif
87 #endif
88 p->geosGeom = NULL;
89 p->preparedGeosGeom = NULL;
90 }
91
92 SPATIALITE_PRIVATE void
splite_free_geos_cache_item_r(const void * p_cache,struct splite_geos_cache_item * p)93 splite_free_geos_cache_item_r (const void *p_cache,
94 struct splite_geos_cache_item *p)
95 {
96 #ifndef OMIT_GEOS /* including GEOS */
97 struct splite_internal_cache *cache =
98 (struct splite_internal_cache *) p_cache;
99 GEOSContextHandle_t handle = NULL;
100 if (cache == NULL)
101 {
102 splite_free_geos_cache_item (p);
103 return;
104 }
105 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
106 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
107 {
108 splite_free_geos_cache_item (p);
109 return;
110 }
111 handle = cache->GEOS_handle;
112 if (handle == NULL)
113 {
114 splite_free_geos_cache_item (p);
115 return;
116 }
117 if (p->preparedGeosGeom)
118 GEOSPreparedGeom_destroy_r (handle, p->preparedGeosGeom);
119 if (p->geosGeom)
120 GEOSGeom_destroy_r (handle, p->geosGeom);
121 #endif
122 p->geosGeom = NULL;
123 p->preparedGeosGeom = NULL;
124 }
125
126 GAIAGEO_DECLARE void
gaiaResetGeosMsg()127 gaiaResetGeosMsg ()
128 {
129 /* resets the GEOS error and warning messages */
130 if (gaia_geos_error_msg != NULL)
131 free (gaia_geos_error_msg);
132 if (gaia_geos_warning_msg != NULL)
133 free (gaia_geos_warning_msg);
134 if (gaia_geosaux_error_msg != NULL)
135 free (gaia_geosaux_error_msg);
136 gaia_geos_error_msg = NULL;
137 gaia_geos_warning_msg = NULL;
138 gaia_geosaux_error_msg = NULL;
139 }
140
141 GAIAGEO_DECLARE const char *
gaiaGetGeosErrorMsg()142 gaiaGetGeosErrorMsg ()
143 {
144 /* return the latest GEOS error message */
145 return gaia_geos_error_msg;
146 }
147
148 GAIAGEO_DECLARE const char *
gaiaGetGeosWarningMsg()149 gaiaGetGeosWarningMsg ()
150 {
151 /* return the latest GEOS error message */
152 return gaia_geos_warning_msg;
153 }
154
155 GAIAGEO_DECLARE const char *
gaiaGetGeosAuxErrorMsg()156 gaiaGetGeosAuxErrorMsg ()
157 {
158 /* return the latest GEOS (auxialiary) error message */
159 return gaia_geosaux_error_msg;
160 }
161
162 GAIAGEO_DECLARE void
gaiaSetGeosErrorMsg(const char * msg)163 gaiaSetGeosErrorMsg (const char *msg)
164 {
165 /* setting the latest GEOS error message */
166 int len;
167 if (gaia_geos_error_msg != NULL)
168 free (gaia_geos_error_msg);
169 gaia_geos_error_msg = NULL;
170 if (msg == NULL)
171 return;
172 len = strlen (msg);
173 gaia_geos_error_msg = malloc (len + 1);
174 strcpy (gaia_geos_error_msg, msg);
175 }
176
177 GAIAGEO_DECLARE void
gaiaSetGeosWarningMsg(const char * msg)178 gaiaSetGeosWarningMsg (const char *msg)
179 {
180 /* setting the latest GEOS error message */
181 int len;
182 if (gaia_geos_warning_msg != NULL)
183 free (gaia_geos_warning_msg);
184 gaia_geos_warning_msg = NULL;
185 if (msg == NULL)
186 return;
187 len = strlen (msg);
188 gaia_geos_warning_msg = malloc (len + 1);
189 strcpy (gaia_geos_warning_msg, msg);
190 }
191
192 GAIAGEO_DECLARE void
gaiaSetGeosAuxErrorMsg(const char * msg)193 gaiaSetGeosAuxErrorMsg (const char *msg)
194 {
195 /* setting the latest GEOS (auxiliary) error message */
196 int len;
197 if (gaia_geosaux_error_msg != NULL)
198 free (gaia_geosaux_error_msg);
199 gaia_geosaux_error_msg = NULL;
200 if (msg == NULL)
201 return;
202 len = strlen (msg);
203 gaia_geosaux_error_msg = malloc (len + 1);
204 strcpy (gaia_geosaux_error_msg, msg);
205 }
206
207 static int
check_point(double * coords,int points,double x,double y)208 check_point (double *coords, int points, double x, double y)
209 {
210 /* checks if [X,Y] point is defined into this coordinate array [Linestring or Ring] */
211 int iv;
212 double xx;
213 double yy;
214 for (iv = 0; iv < points; iv++)
215 {
216 gaiaGetPoint (coords, iv, &xx, &yy);
217 if (xx == x && yy == y)
218 return 1;
219 }
220 return 0;
221 }
222
223 GAIAGEO_DECLARE int
gaiaLinestringEquals(gaiaLinestringPtr line1,gaiaLinestringPtr line2)224 gaiaLinestringEquals (gaiaLinestringPtr line1, gaiaLinestringPtr line2)
225 {
226 /* checks if two Linestrings are "spatially equal" */
227 int iv;
228 double x;
229 double y;
230 if (line1->Points != line2->Points)
231 return 0;
232 for (iv = 0; iv < line1->Points; iv++)
233 {
234 gaiaGetPoint (line1->Coords, iv, &x, &y);
235 if (!check_point (line2->Coords, line2->Points, x, y))
236 return 0;
237 }
238 return 1;
239 }
240
241 GAIAGEO_DECLARE int
gaiaPolygonEquals(gaiaPolygonPtr polyg1,gaiaPolygonPtr polyg2)242 gaiaPolygonEquals (gaiaPolygonPtr polyg1, gaiaPolygonPtr polyg2)
243 {
244 /* checks if two Polygons are "spatially equal" */
245 int ib;
246 int ib2;
247 int iv;
248 int ok2;
249 double x;
250 double y;
251 gaiaRingPtr ring1;
252 gaiaRingPtr ring2;
253 if (polyg1->NumInteriors != polyg2->NumInteriors)
254 return 0;
255 /* checking the EXTERIOR RINGs */
256 ring1 = polyg1->Exterior;
257 ring2 = polyg2->Exterior;
258 if (ring1->Points != ring2->Points)
259 return 0;
260 for (iv = 0; iv < ring1->Points; iv++)
261 {
262 gaiaGetPoint (ring1->Coords, iv, &x, &y);
263 if (!check_point (ring2->Coords, ring2->Points, x, y))
264 return 0;
265 }
266 for (ib = 0; ib < polyg1->NumInteriors; ib++)
267 {
268 /* checking the INTERIOR RINGS */
269 int ok = 0;
270 ring1 = polyg1->Interiors + ib;
271 for (ib2 = 0; ib2 < polyg2->NumInteriors; ib2++)
272 {
273 ok2 = 1;
274 ring2 = polyg2->Interiors + ib2;
275 for (iv = 0; iv < ring1->Points; iv++)
276 {
277 gaiaGetPoint (ring1->Coords, iv, &x, &y);
278 if (!check_point (ring2->Coords, ring2->Points, x, y))
279 {
280 ok2 = 0;
281 break;
282 }
283 }
284 if (ok2)
285 {
286 ok = 1;
287 break;
288 }
289 }
290 if (!ok)
291 return 0;
292 }
293 return 1;
294 }
295
296 #ifndef OMIT_GEOS /* including GEOS */
297
298 static int
splite_mbr_overlaps(gaiaGeomCollPtr g1,gaiaGeomCollPtr g2)299 splite_mbr_overlaps (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
300 {
301 /* checks if two MBRs do overlap */
302 if (g1->MaxX < g2->MinX)
303 return 0;
304 if (g1->MinX > g2->MaxX)
305 return 0;
306 if (g1->MaxY < g2->MinY)
307 return 0;
308 if (g1->MinY > g2->MaxY)
309 return 0;
310 return 1;
311 }
312
313 static int
splite_mbr_contains(gaiaGeomCollPtr g1,gaiaGeomCollPtr g2)314 splite_mbr_contains (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
315 {
316 /* checks if MBR#1 fully contains MBR#2 */
317 if (g2->MinX < g1->MinX)
318 return 0;
319 if (g2->MaxX > g1->MaxX)
320 return 0;
321 if (g2->MinY < g1->MinY)
322 return 0;
323 if (g2->MaxY > g1->MaxY)
324 return 0;
325 return 1;
326 }
327
328 static int
splite_mbr_within(gaiaGeomCollPtr g1,gaiaGeomCollPtr g2)329 splite_mbr_within (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
330 {
331 /* checks if MBR#1 is fully contained within MBR#2 */
332 if (g1->MinX < g2->MinX)
333 return 0;
334 if (g1->MaxX > g2->MaxX)
335 return 0;
336 if (g1->MinY < g2->MinY)
337 return 0;
338 if (g1->MaxY > g2->MaxY)
339 return 0;
340 return 1;
341 }
342
343 static int
splite_mbr_equals(gaiaGeomCollPtr g1,gaiaGeomCollPtr g2)344 splite_mbr_equals (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2)
345 {
346 /* checks if MBR#1 equals MBR#2 */
347 if (g1->MinX != g2->MinX)
348 return 0;
349 if (g1->MaxX != g2->MaxX)
350 return 0;
351 if (g1->MinY != g2->MinY)
352 return 0;
353 if (g1->MaxY != g2->MaxY)
354 return 0;
355 return 1;
356 }
357
358 static int
evalGeosCacheItem(unsigned char * blob,int blob_size,uLong crc,struct splite_geos_cache_item * p)359 evalGeosCacheItem (unsigned char *blob, int blob_size, uLong crc,
360 struct splite_geos_cache_item *p)
361 {
362 /* evaluting if this one could be a valid cache hit */
363 if (blob_size != p->gaiaBlobSize)
364 {
365 /* surely not a match; different size */
366 return 0;
367 }
368 if (crc != p->crc32)
369 {
370 /* surely not a match: different CRC32 */
371 return 0;
372 }
373
374 /* the first 46 bytes of the BLOB contain the MBR,
375 the SRID and the Type; so are assumed to represent
376 a valid signature */
377 if (memcmp (blob, p->gaiaBlob, 46) == 0)
378 return 1;
379 return 0;
380 }
381
382 static int
sniffTinyPointBlob(const unsigned char * blob,const int size)383 sniffTinyPointBlob (const unsigned char *blob, const int size)
384 {
385 /* sniffing for a possible TinyPoint BLOB */
386 if (size == 24 || size == 32 || size == 40)
387 ;
388 else
389 return 0;
390 if (*(blob + 0) != GAIA_MARK_START)
391 return 0;
392 if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
393 || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
394 ;
395 else
396 return 0;
397 if (*(blob + (size - 1)) != GAIA_MARK_END)
398 return 0;
399 return 1;
400 }
401
402 static void
tinyPoint2Geom(const unsigned char * tiny,unsigned char ** geom,int * geom_sz)403 tinyPoint2Geom (const unsigned char *tiny, unsigned char **geom, int *geom_sz)
404 {
405 /* quickly converting from BLOB-TinyPoint to BLOB-Geometry */
406 int little_endian;
407 int endian_arch = gaiaEndianArch ();
408 int srid;
409 int type;
410 double x;
411 double y;
412 double z;
413 double m;
414 unsigned char *blob;
415 int blob_sz;
416
417 /* parsing the BLOB-TinyPoint */
418 if (*(tiny + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
419 little_endian = 1;
420 else
421 little_endian = 0;
422 srid = gaiaImport32 (tiny + 2, little_endian, endian_arch);
423 if (*(tiny + 6) == GAIA_TINYPOINT_XYZ)
424 type = GAIA_POINTZ;
425 else if (*(tiny + 6) == GAIA_TINYPOINT_XYM)
426 type = GAIA_POINTM;
427 else if (*(tiny + 6) == GAIA_TINYPOINT_XYZM)
428 type = GAIA_POINTZM;
429 else
430 type = GAIA_POINT;
431 x = gaiaImport64 (tiny + 7, little_endian, endian_arch);
432 y = gaiaImport64 (tiny + 15, little_endian, endian_arch);
433 if (type == GAIA_POINTZ)
434 z = gaiaImport64 (tiny + 23, little_endian, endian_arch);
435 if (type == GAIA_POINTM)
436 m = gaiaImport64 (tiny + 23, little_endian, endian_arch);
437 if (type == GAIA_POINTZM)
438 {
439 z = gaiaImport64 (tiny + 23, little_endian, endian_arch);
440 m = gaiaImport64 (tiny + 31, little_endian, endian_arch);
441 }
442
443 /* allocating and initializing the BLOB-Geometry */
444 switch (type)
445 {
446 case GAIA_POINT:
447 blob_sz = 60;
448 break;
449 case GAIA_POINTZ:
450 case GAIA_POINTM:
451 blob_sz = 68;
452 break;
453 case GAIA_POINTZM:
454 blob_sz = 76;
455 break;
456 };
457 blob = malloc (blob_sz);
458
459 *geom = blob;
460 *geom_sz = blob_sz;
461 switch (type)
462 {
463 case GAIA_POINT:
464 *blob = GAIA_MARK_START; /* START signature */
465 *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
466 gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */
467 gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */
468 gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */
469 gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */
470 gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */
471 *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */
472 gaiaExport32 (blob + 39, GAIA_POINT, 1, endian_arch); /* class POINT */
473 gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */
474 gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */
475 *(blob + 59) = GAIA_MARK_END; /* END signature */
476 break;
477 case GAIA_POINTZ:
478 *blob = GAIA_MARK_START; /* START signature */
479 *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
480 gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */
481 gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */
482 gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */
483 gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */
484 gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */
485 *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */
486 gaiaExport32 (blob + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */
487 gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */
488 gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */
489 gaiaExport64 (blob + 59, z, 1, endian_arch); /* Z */
490 *(blob + 67) = GAIA_MARK_END; /* END signature */
491 break;
492 case GAIA_POINTM:
493 *blob = GAIA_MARK_START; /* START signature */
494 *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
495 gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */
496 gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */
497 gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */
498 gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */
499 gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */
500 *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */
501 gaiaExport32 (blob + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */
502 gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */
503 gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */
504 gaiaExport64 (blob + 59, m, 1, endian_arch); /* M */
505 *(blob + 67) = GAIA_MARK_END; /* END signature */
506 break;
507 case GAIA_POINTZM:
508 *blob = GAIA_MARK_START; /* START signature */
509 *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */
510 gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */
511 gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */
512 gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */
513 gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */
514 gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */
515 *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */
516 gaiaExport32 (blob + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */
517 gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */
518 gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */
519 gaiaExport64 (blob + 59, z, 1, endian_arch); /* M */
520 gaiaExport64 (blob + 67, m, 1, endian_arch); /* Z */
521 *(blob + 75) = GAIA_MARK_END; /* END signature */
522 break;
523 };
524 }
525
526 static int
evalGeosCache(struct splite_internal_cache * cache,gaiaGeomCollPtr geom1,const unsigned char * blob1,const int size1,gaiaGeomCollPtr geom2,const unsigned char * blob2,const int size2,GEOSPreparedGeometry ** gPrep,gaiaGeomCollPtr * geom)527 evalGeosCache (struct splite_internal_cache *cache, gaiaGeomCollPtr geom1,
528 const unsigned char *blob1, const int size1,
529 gaiaGeomCollPtr geom2, const unsigned char *blob2,
530 const int size2, GEOSPreparedGeometry ** gPrep,
531 gaiaGeomCollPtr * geom)
532 {
533 /* handling the internal GEOS cache */
534 struct splite_geos_cache_item *p1 = &(cache->cacheItem1);
535 struct splite_geos_cache_item *p2 = &(cache->cacheItem2);
536 uLong crc1;
537 uLong crc2;
538 unsigned char *tiny1 = NULL;
539 unsigned char *tiny2 = NULL;
540 unsigned char *p_blob1;
541 unsigned char *p_blob2;
542 int sz1;
543 int sz2;
544 int tiny_sz;
545 int retcode;
546 GEOSContextHandle_t handle = NULL;
547 if (cache == NULL)
548 return 0;
549 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
550 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
551 return 0;
552 handle = cache->GEOS_handle;
553 if (handle == NULL)
554 return 0;
555
556 if (sniffTinyPointBlob (blob1, size1))
557 {
558 tinyPoint2Geom (blob1, &tiny1, &tiny_sz);
559 p_blob1 = tiny1;
560 sz1 = tiny_sz;
561 }
562 else
563 {
564 p_blob1 = (unsigned char *) blob1;
565 sz1 = size1;
566 }
567 if (sniffTinyPointBlob (blob2, size2))
568 {
569 tinyPoint2Geom (blob2, &tiny2, &tiny_sz);
570 p_blob2 = tiny2;
571 sz2 = tiny_sz;
572 }
573 else
574 {
575 p_blob2 = (unsigned char *) blob2;
576 sz2 = size2;
577 }
578 crc1 = crc32 (0L, p_blob1, sz1);
579 crc2 = crc32 (0L, p_blob2, sz2);
580
581 /* checking the first cache item */
582 if (evalGeosCacheItem (p_blob1, sz1, crc1, p1))
583 {
584 /* found a matching item */
585 if (p1->preparedGeosGeom == NULL)
586 {
587 /* preparing the GeosGeometries */
588 p1->geosGeom = gaiaToGeos_r (cache, geom1);
589 if (p1->geosGeom)
590 {
591 p1->preparedGeosGeom =
592 (void *) GEOSPrepare_r (handle, p1->geosGeom);
593 if (p1->preparedGeosGeom == NULL)
594 {
595 /* unexpected failure */
596 GEOSGeom_destroy_r (handle, p1->geosGeom);
597 p1->geosGeom = NULL;
598 }
599 }
600 }
601 if (p1->preparedGeosGeom)
602 {
603 /* returning the corresponding GeosPreparedGeometry */
604 *gPrep = p1->preparedGeosGeom;
605 *geom = geom2;
606 retcode = 1;
607 goto end;
608 }
609 retcode = 0;
610 goto end;
611 }
612
613 /* checking the second cache item */
614 if (evalGeosCacheItem (p_blob2, sz2, crc2, p2))
615 {
616 /* found a matching item */
617 if (p2->preparedGeosGeom == NULL)
618 {
619 /* preparing the GeosGeometries */
620 p2->geosGeom = gaiaToGeos_r (cache, geom2);
621 if (p2->geosGeom)
622 {
623 p2->preparedGeosGeom =
624 (void *) GEOSPrepare_r (handle, p2->geosGeom);
625 if (p2->preparedGeosGeom == NULL)
626 {
627 /* unexpected failure */
628 GEOSGeom_destroy_r (handle, p2->geosGeom);
629 p2->geosGeom = NULL;
630 }
631 }
632 }
633 if (p2->preparedGeosGeom)
634 {
635 /* returning the corresponding GeosPreparedGeometry */
636 *gPrep = p2->preparedGeosGeom;
637 *geom = geom1;
638 retcode = 1;
639 goto end;
640 }
641 retcode = 0;
642 goto end;
643 }
644
645 /* updating the GEOS cache item#1 */
646 memcpy (p1->gaiaBlob, p_blob1, 46);
647 p1->gaiaBlobSize = sz1;
648 p1->crc32 = crc1;
649 if (p1->preparedGeosGeom)
650 GEOSPreparedGeom_destroy_r (handle, p1->preparedGeosGeom);
651 if (p1->geosGeom)
652 GEOSGeom_destroy_r (handle, p1->geosGeom);
653 p1->geosGeom = NULL;
654 p1->preparedGeosGeom = NULL;
655
656 /* updating the GEOS cache item#2 */
657 memcpy (p2->gaiaBlob, p_blob2, 46);
658 p2->gaiaBlobSize = sz2;
659 p2->crc32 = crc2;
660 if (p2->preparedGeosGeom)
661 GEOSPreparedGeom_destroy_r (handle, p2->preparedGeosGeom);
662 if (p2->geosGeom)
663 GEOSGeom_destroy_r (handle, p2->geosGeom);
664 p2->geosGeom = NULL;
665 p2->preparedGeosGeom = NULL;
666 retcode = 0;
667
668 end:
669 if (tiny1 != NULL)
670 free (tiny1);
671 if (tiny2 != NULL)
672 free (tiny2);
673 return retcode;
674 }
675
676 GAIAGEO_DECLARE int
gaiaGeomCollEquals(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)677 gaiaGeomCollEquals (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
678 {
679 /* checks if two Geometries are "spatially equal" */
680 int ret = -1;
681 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
682 GEOSGeometry *g1;
683 GEOSGeometry *g2;
684 gaiaResetGeosMsg ();
685 if (!geom1 || !geom2)
686 return -1;
687 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
688 return -1;
689
690 /* quick check based on MBRs comparison */
691 if (!splite_mbr_equals (geom1, geom2))
692 return 0;
693
694 g1 = gaiaToGeos (geom1);
695 g2 = gaiaToGeos (geom2);
696 ret = GEOSEquals (g1, g2);
697 GEOSGeom_destroy (g1);
698 GEOSGeom_destroy (g2);
699 #else
700 if (geom1 == NULL || geom2 == NULL)
701 geom1 = NULL; /* silencing stupid compiler warnings */
702 #endif
703 return ret;
704 }
705
706 GAIAGEO_DECLARE int
gaiaGeomCollEquals_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)707 gaiaGeomCollEquals_r (const void *p_cache, gaiaGeomCollPtr geom1,
708 gaiaGeomCollPtr geom2)
709 {
710 /* checks if two Geometries are "spatially equal" */
711 int ret;
712 GEOSGeometry *g1;
713 GEOSGeometry *g2;
714 struct splite_internal_cache *cache =
715 (struct splite_internal_cache *) p_cache;
716 GEOSContextHandle_t handle = NULL;
717 if (cache == NULL)
718 return -1;
719 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
720 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
721 return -1;
722 handle = cache->GEOS_handle;
723 if (handle == NULL)
724 return -1;
725 gaiaResetGeosMsg_r (cache);
726 if (!geom1 || !geom2)
727 return -1;
728 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
729 return -1;
730
731 /* quick check based on MBRs comparison */
732 if (!splite_mbr_equals (geom1, geom2))
733 return 0;
734
735 g1 = gaiaToGeos_r (cache, geom1);
736 g2 = gaiaToGeos_r (cache, geom2);
737 ret = GEOSEquals_r (handle, g1, g2);
738 GEOSGeom_destroy_r (handle, g1);
739 GEOSGeom_destroy_r (handle, g2);
740 return ret;
741 }
742
743 GAIAGEO_DECLARE int
gaiaGeomCollIntersects(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)744 gaiaGeomCollIntersects (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
745 {
746 /* checks if two Geometries do "spatially intersects" */
747 int ret = -1;
748 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
749 GEOSGeometry *g1;
750 GEOSGeometry *g2;
751 gaiaResetGeosMsg ();
752 if (!geom1 || !geom2)
753 return -1;
754 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
755 return -1;
756
757 /* quick check based on MBRs comparison */
758 if (!splite_mbr_overlaps (geom1, geom2))
759 return 0;
760
761 g1 = gaiaToGeos (geom1);
762 g2 = gaiaToGeos (geom2);
763 ret = GEOSIntersects (g1, g2);
764 GEOSGeom_destroy (g1);
765 GEOSGeom_destroy (g2);
766 #else
767 if (geom1 == NULL || geom2 == NULL)
768 geom1 = NULL; /* silencing stupid compiler warnings */
769 #endif
770 return ret;
771 }
772
773 GAIAGEO_DECLARE int
gaiaGeomCollIntersects_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)774 gaiaGeomCollIntersects_r (const void *p_cache, gaiaGeomCollPtr geom1,
775 gaiaGeomCollPtr geom2)
776 {
777 /* checks if two Geometries do "spatially intersects" */
778 int ret;
779 GEOSGeometry *g1;
780 GEOSGeometry *g2;
781 struct splite_internal_cache *cache =
782 (struct splite_internal_cache *) p_cache;
783 GEOSContextHandle_t handle = NULL;
784 if (cache == NULL)
785 return -1;
786 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
787 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
788 return -1;
789 handle = cache->GEOS_handle;
790 if (handle == NULL)
791 return -1;
792 gaiaResetGeosMsg_r (cache);
793 if (!geom1 || !geom2)
794 return -1;
795 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
796 return -1;
797
798 /* quick check based on MBRs comparison */
799 if (!splite_mbr_overlaps (geom1, geom2))
800 return 0;
801
802 g1 = gaiaToGeos_r (cache, geom1);
803 g2 = gaiaToGeos_r (cache, geom2);
804 ret = GEOSIntersects_r (handle, g1, g2);
805 GEOSGeom_destroy_r (handle, g1);
806 GEOSGeom_destroy_r (handle, g2);
807 return ret;
808 }
809
810 GAIAGEO_DECLARE int
gaiaGeomCollPreparedIntersects(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)811 gaiaGeomCollPreparedIntersects (const void *p_cache, gaiaGeomCollPtr geom1,
812 unsigned char *blob1, int size1,
813 gaiaGeomCollPtr geom2, unsigned char *blob2,
814 int size2)
815 {
816 /* checks if two Geometries do "spatially intersects" */
817 int ret;
818 struct splite_internal_cache *cache =
819 (struct splite_internal_cache *) p_cache;
820 GEOSPreparedGeometry *gPrep;
821 GEOSGeometry *g1;
822 GEOSGeometry *g2;
823 gaiaGeomCollPtr geom;
824 GEOSContextHandle_t handle = NULL;
825 if (cache == NULL)
826 return -1;
827 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
828 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
829 return -1;
830 handle = cache->GEOS_handle;
831 if (handle == NULL)
832 return -1;
833 gaiaResetGeosMsg_r (cache);
834 if (!geom1 || !geom2)
835 return -1;
836 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
837 return -1;
838
839 /* quick check based on MBRs comparison */
840 if (!splite_mbr_overlaps (geom1, geom2))
841 return 0;
842
843 /* handling the internal GEOS cache */
844 if (evalGeosCache
845 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
846 {
847 g2 = gaiaToGeos_r (cache, geom);
848 ret = GEOSPreparedIntersects_r (handle, gPrep, g2);
849 GEOSGeom_destroy_r (handle, g2);
850 return ret;
851 }
852 g1 = gaiaToGeos_r (cache, geom1);
853 g2 = gaiaToGeos_r (cache, geom2);
854 ret = GEOSIntersects_r (handle, g1, g2);
855 GEOSGeom_destroy_r (handle, g1);
856 GEOSGeom_destroy_r (handle, g2);
857 return ret;
858 }
859
860 GAIAGEO_DECLARE int
gaiaGeomCollDisjoint(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)861 gaiaGeomCollDisjoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
862 {
863 /* checks if two Geometries are "spatially disjoint" */
864 int ret = -1;
865 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
866 GEOSGeometry *g1;
867 GEOSGeometry *g2;
868 gaiaResetGeosMsg ();
869 if (!geom1 || !geom2)
870 return -1;
871 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
872 return -1;
873
874 /* quick check based on MBRs comparison */
875 if (!splite_mbr_overlaps (geom1, geom2))
876 return 1;
877
878 g1 = gaiaToGeos (geom1);
879 g2 = gaiaToGeos (geom2);
880 ret = GEOSDisjoint (g1, g2);
881 GEOSGeom_destroy (g1);
882 GEOSGeom_destroy (g2);
883 #else
884 if (geom1 == NULL || geom2 == NULL)
885 geom1 = NULL; /* silencing stupid compiler warnings */
886 #endif
887 return ret;
888 }
889
890 GAIAGEO_DECLARE int
gaiaGeomCollDisjoint_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)891 gaiaGeomCollDisjoint_r (const void *p_cache, gaiaGeomCollPtr geom1,
892 gaiaGeomCollPtr geom2)
893 {
894 /* checks if two Geometries are "spatially disjoint" */
895 int ret;
896 GEOSGeometry *g1;
897 GEOSGeometry *g2;
898 struct splite_internal_cache *cache =
899 (struct splite_internal_cache *) p_cache;
900 GEOSContextHandle_t handle = NULL;
901 if (cache == NULL)
902 return -1;
903 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
904 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
905 return -1;
906 handle = cache->GEOS_handle;
907 if (handle == NULL)
908 return -1;
909 gaiaResetGeosMsg_r (cache);
910 if (!geom1 || !geom2)
911 return -1;
912 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
913 return -1;
914
915 /* quick check based on MBRs comparison */
916 if (!splite_mbr_overlaps (geom1, geom2))
917 return 1;
918
919 g1 = gaiaToGeos_r (cache, geom1);
920 g2 = gaiaToGeos_r (cache, geom2);
921 ret = GEOSDisjoint_r (handle, g1, g2);
922 GEOSGeom_destroy_r (handle, g1);
923 GEOSGeom_destroy_r (handle, g2);
924 return ret;
925 }
926
927 GAIAGEO_DECLARE int
gaiaGeomCollPreparedDisjoint(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)928 gaiaGeomCollPreparedDisjoint (const void *p_cache, gaiaGeomCollPtr geom1,
929 unsigned char *blob1, int size1,
930 gaiaGeomCollPtr geom2, unsigned char *blob2,
931 int size2)
932 {
933 /* checks if two Geometries are "spatially disjoint" */
934 int ret;
935 GEOSPreparedGeometry *gPrep;
936 GEOSGeometry *g1;
937 GEOSGeometry *g2;
938 gaiaGeomCollPtr geom;
939 GEOSContextHandle_t handle = NULL;
940 struct splite_internal_cache *cache =
941 (struct splite_internal_cache *) p_cache;
942 if (cache == NULL)
943 return -1;
944 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
945 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
946 return -1;
947 handle = cache->GEOS_handle;
948 if (handle == NULL)
949 return -1;
950 gaiaResetGeosMsg_r (cache);
951 if (!geom1 || !geom2)
952 return -1;
953 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
954 return -1;
955
956 /* quick check based on MBRs comparison */
957 if (!splite_mbr_overlaps (geom1, geom2))
958 return 1;
959
960 /* handling the internal GEOS cache */
961 if (evalGeosCache
962 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
963 {
964 g2 = gaiaToGeos_r (cache, geom);
965 ret = GEOSPreparedDisjoint_r (handle, gPrep, g2);
966 GEOSGeom_destroy_r (handle, g2);
967 return ret;
968 }
969
970 g1 = gaiaToGeos_r (cache, geom1);
971 g2 = gaiaToGeos_r (cache, geom2);
972 ret = GEOSDisjoint_r (handle, g1, g2);
973 GEOSGeom_destroy_r (handle, g1);
974 GEOSGeom_destroy_r (handle, g2);
975 return ret;
976 }
977
978 GAIAGEO_DECLARE int
gaiaGeomCollOverlaps(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)979 gaiaGeomCollOverlaps (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
980 {
981 /* checks if two Geometries do "spatially overlaps" */
982 int ret = -1;
983 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
984 GEOSGeometry *g1;
985 GEOSGeometry *g2;
986 gaiaResetGeosMsg ();
987 if (!geom1 || !geom2)
988 return -1;
989 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
990 return -1;
991
992 /* quick check based on MBRs comparison */
993 if (!splite_mbr_overlaps (geom1, geom2))
994 return 0;
995
996 g1 = gaiaToGeos (geom1);
997 g2 = gaiaToGeos (geom2);
998 ret = GEOSOverlaps (g1, g2);
999 GEOSGeom_destroy (g1);
1000 GEOSGeom_destroy (g2);
1001 #else
1002 if (geom1 == NULL || geom2 == NULL)
1003 geom1 = NULL; /* silencing stupid compiler warnings */
1004 #endif
1005 return ret;
1006 }
1007
1008 GAIAGEO_DECLARE int
gaiaGeomCollOverlaps_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1009 gaiaGeomCollOverlaps_r (const void *p_cache, gaiaGeomCollPtr geom1,
1010 gaiaGeomCollPtr geom2)
1011 {
1012 /* checks if two Geometries do "spatially overlaps" */
1013 int ret;
1014 GEOSGeometry *g1;
1015 GEOSGeometry *g2;
1016 struct splite_internal_cache *cache =
1017 (struct splite_internal_cache *) p_cache;
1018 GEOSContextHandle_t handle = NULL;
1019 if (cache == NULL)
1020 return -1;
1021 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1022 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1023 return -1;
1024 handle = cache->GEOS_handle;
1025 if (handle == NULL)
1026 return -1;
1027 gaiaResetGeosMsg_r (cache);
1028 if (!geom1 || !geom2)
1029 return -1;
1030 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1031 return -1;
1032
1033 /* quick check based on MBRs comparison */
1034 if (!splite_mbr_overlaps (geom1, geom2))
1035 return 0;
1036
1037 g1 = gaiaToGeos_r (cache, geom1);
1038 g2 = gaiaToGeos_r (cache, geom2);
1039 ret = GEOSOverlaps_r (handle, g1, g2);
1040 GEOSGeom_destroy_r (handle, g1);
1041 GEOSGeom_destroy_r (handle, g2);
1042 return ret;
1043 }
1044
1045 GAIAGEO_DECLARE int
gaiaGeomCollPreparedOverlaps(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)1046 gaiaGeomCollPreparedOverlaps (const void *p_cache, gaiaGeomCollPtr geom1,
1047 unsigned char *blob1, int size1,
1048 gaiaGeomCollPtr geom2, unsigned char *blob2,
1049 int size2)
1050 {
1051 /* checks if two Geometries do "spatially overlaps" */
1052 int ret;
1053 struct splite_internal_cache *cache =
1054 (struct splite_internal_cache *) p_cache;
1055 GEOSPreparedGeometry *gPrep;
1056 GEOSGeometry *g1;
1057 GEOSGeometry *g2;
1058 gaiaGeomCollPtr geom;
1059 GEOSContextHandle_t handle = NULL;
1060 if (cache == NULL)
1061 return -1;
1062 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1063 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1064 return -1;
1065 handle = cache->GEOS_handle;
1066 if (handle == NULL)
1067 return -1;
1068 gaiaResetGeosMsg_r (cache);
1069 if (!geom1 || !geom2)
1070 return -1;
1071 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1072 return -1;
1073
1074 /* quick check based on MBRs comparison */
1075 if (!splite_mbr_overlaps (geom1, geom2))
1076 return 0;
1077
1078 /* handling the internal GEOS cache */
1079 if (evalGeosCache
1080 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
1081 {
1082 g2 = gaiaToGeos_r (cache, geom);
1083 ret = GEOSPreparedOverlaps_r (handle, gPrep, g2);
1084 GEOSGeom_destroy_r (handle, g2);
1085 return ret;
1086 }
1087
1088 g1 = gaiaToGeos_r (cache, geom1);
1089 g2 = gaiaToGeos_r (cache, geom2);
1090 ret = GEOSOverlaps_r (handle, g1, g2);
1091 GEOSGeom_destroy_r (handle, g1);
1092 GEOSGeom_destroy_r (handle, g2);
1093 return ret;
1094 }
1095
1096 GAIAGEO_DECLARE int
gaiaGeomCollCrosses(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1097 gaiaGeomCollCrosses (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
1098 {
1099 /* checks if two Geometries do "spatially crosses" */
1100 int ret = -1;
1101 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1102 GEOSGeometry *g1;
1103 GEOSGeometry *g2;
1104 gaiaResetGeosMsg ();
1105 if (!geom1 || !geom2)
1106 return -1;
1107 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1108 return -1;
1109
1110 /* quick check based on MBRs comparison */
1111 if (!splite_mbr_overlaps (geom1, geom2))
1112 return 0;
1113
1114 g1 = gaiaToGeos (geom1);
1115 g2 = gaiaToGeos (geom2);
1116 ret = GEOSCrosses (g1, g2);
1117 GEOSGeom_destroy (g1);
1118 GEOSGeom_destroy (g2);
1119 #else
1120 if (geom1 == NULL || geom2 == NULL)
1121 geom1 = NULL; /* silencing stupid compiler warnings */
1122 #endif
1123 return ret;
1124 }
1125
1126 GAIAGEO_DECLARE int
gaiaGeomCollCrosses_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1127 gaiaGeomCollCrosses_r (const void *p_cache, gaiaGeomCollPtr geom1,
1128 gaiaGeomCollPtr geom2)
1129 {
1130 /* checks if two Geometries do "spatially crosses" */
1131 int ret;
1132 GEOSGeometry *g1;
1133 GEOSGeometry *g2;
1134 struct splite_internal_cache *cache =
1135 (struct splite_internal_cache *) p_cache;
1136 GEOSContextHandle_t handle = NULL;
1137 if (cache == NULL)
1138 return -1;
1139 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1140 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1141 return -1;
1142 handle = cache->GEOS_handle;
1143 if (handle == NULL)
1144 return -1;
1145 gaiaResetGeosMsg_r (cache);
1146 if (!geom1 || !geom2)
1147 return -1;
1148 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1149 return -1;
1150
1151 /* quick check based on MBRs comparison */
1152 if (!splite_mbr_overlaps (geom1, geom2))
1153 return 0;
1154
1155 g1 = gaiaToGeos_r (cache, geom1);
1156 g2 = gaiaToGeos_r (cache, geom2);
1157 ret = GEOSCrosses_r (handle, g1, g2);
1158 GEOSGeom_destroy_r (handle, g1);
1159 GEOSGeom_destroy_r (handle, g2);
1160 return ret;
1161 }
1162
1163 GAIAGEO_DECLARE int
gaiaGeomCollPreparedCrosses(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)1164 gaiaGeomCollPreparedCrosses (const void *p_cache, gaiaGeomCollPtr geom1,
1165 unsigned char *blob1, int size1,
1166 gaiaGeomCollPtr geom2, unsigned char *blob2,
1167 int size2)
1168 {
1169 /* checks if two Geometries do "spatially crosses" */
1170 int ret;
1171 struct splite_internal_cache *cache =
1172 (struct splite_internal_cache *) p_cache;
1173 GEOSPreparedGeometry *gPrep;
1174 GEOSGeometry *g1;
1175 GEOSGeometry *g2;
1176 gaiaGeomCollPtr geom;
1177 GEOSContextHandle_t handle = NULL;
1178 if (cache == NULL)
1179 return -1;
1180 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1181 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1182 return -1;
1183 handle = cache->GEOS_handle;
1184 if (handle == NULL)
1185 return -1;
1186 gaiaResetGeosMsg_r (cache);
1187 if (!geom1 || !geom2)
1188 return -1;
1189 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1190 return -1;
1191
1192 /* quick check based on MBRs comparison */
1193 if (!splite_mbr_overlaps (geom1, geom2))
1194 return 0;
1195
1196 /* handling the internal GEOS cache */
1197 if (evalGeosCache
1198 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
1199 {
1200 g2 = gaiaToGeos_r (cache, geom);
1201 ret = GEOSPreparedCrosses_r (handle, gPrep, g2);
1202 GEOSGeom_destroy_r (handle, g2);
1203 return ret;
1204 }
1205
1206 g1 = gaiaToGeos_r (cache, geom1);
1207 g2 = gaiaToGeos_r (cache, geom2);
1208 ret = GEOSCrosses_r (handle, g1, g2);
1209 GEOSGeom_destroy_r (handle, g1);
1210 GEOSGeom_destroy_r (handle, g2);
1211 return ret;
1212 }
1213
1214 GAIAGEO_DECLARE int
gaiaGeomCollTouches(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1215 gaiaGeomCollTouches (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
1216 {
1217 /* checks if two Geometries do "spatially touches" */
1218 int ret = -1;
1219 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1220 GEOSGeometry *g1;
1221 GEOSGeometry *g2;
1222 gaiaResetGeosMsg ();
1223 if (!geom1 || !geom2)
1224 return -1;
1225 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1226 return -1;
1227
1228 /* quick check based on MBRs comparison */
1229 if (!splite_mbr_overlaps (geom1, geom2))
1230 return 0;
1231
1232 g1 = gaiaToGeos (geom1);
1233 g2 = gaiaToGeos (geom2);
1234 ret = GEOSTouches (g1, g2);
1235 GEOSGeom_destroy (g1);
1236 GEOSGeom_destroy (g2);
1237 #else
1238 if (geom1 == NULL || geom2 == NULL)
1239 geom1 = NULL; /* silencing stupid compiler warnings */
1240 #endif
1241 return ret;
1242 }
1243
1244 GAIAGEO_DECLARE int
gaiaGeomCollTouches_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1245 gaiaGeomCollTouches_r (const void *p_cache, gaiaGeomCollPtr geom1,
1246 gaiaGeomCollPtr geom2)
1247 {
1248 /* checks if two Geometries do "spatially touches" */
1249 int ret;
1250 GEOSGeometry *g1;
1251 GEOSGeometry *g2;
1252 struct splite_internal_cache *cache =
1253 (struct splite_internal_cache *) p_cache;
1254 GEOSContextHandle_t handle = NULL;
1255 if (cache == NULL)
1256 return -1;
1257 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1258 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1259 return -1;
1260 handle = cache->GEOS_handle;
1261 if (handle == NULL)
1262 return -1;
1263 gaiaResetGeosMsg_r (cache);
1264 if (!geom1 || !geom2)
1265 return -1;
1266 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1267 return -1;
1268
1269 /* quick check based on MBRs comparison */
1270 if (!splite_mbr_overlaps (geom1, geom2))
1271 return 0;
1272
1273 g1 = gaiaToGeos_r (cache, geom1);
1274 g2 = gaiaToGeos_r (cache, geom2);
1275 ret = GEOSTouches_r (handle, g1, g2);
1276 GEOSGeom_destroy_r (handle, g1);
1277 GEOSGeom_destroy_r (handle, g2);
1278 return ret;
1279 }
1280
1281 GAIAGEO_DECLARE int
gaiaGeomCollPreparedTouches(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)1282 gaiaGeomCollPreparedTouches (const void *p_cache, gaiaGeomCollPtr geom1,
1283 unsigned char *blob1, int size1,
1284 gaiaGeomCollPtr geom2, unsigned char *blob2,
1285 int size2)
1286 {
1287 /* checks if two Geometries do "spatially touches" */
1288 int ret;
1289 struct splite_internal_cache *cache =
1290 (struct splite_internal_cache *) p_cache;
1291 GEOSGeometry *g1;
1292 GEOSGeometry *g2;
1293 GEOSPreparedGeometry *gPrep;
1294 gaiaGeomCollPtr geom;
1295 GEOSContextHandle_t handle = NULL;
1296 if (cache == NULL)
1297 return -1;
1298 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1299 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1300 return -1;
1301 handle = cache->GEOS_handle;
1302 if (handle == NULL)
1303 return -1;
1304 gaiaResetGeosMsg_r (cache);
1305 if (!geom1 || !geom2)
1306 return -1;
1307 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1308 return -1;
1309
1310 /* quick check based on MBRs comparison */
1311 if (!splite_mbr_overlaps (geom1, geom2))
1312 return 0;
1313
1314 /* handling the internal GEOS cache */
1315 if (evalGeosCache
1316 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
1317 {
1318 g2 = gaiaToGeos_r (cache, geom);
1319 ret = GEOSPreparedTouches_r (handle, gPrep, g2);
1320 GEOSGeom_destroy_r (handle, g2);
1321 return ret;
1322 }
1323
1324 g1 = gaiaToGeos_r (cache, geom1);
1325 g2 = gaiaToGeos_r (cache, geom2);
1326 ret = GEOSTouches_r (handle, g1, g2);
1327 GEOSGeom_destroy_r (handle, g1);
1328 GEOSGeom_destroy_r (handle, g2);
1329 return ret;
1330 }
1331
1332 GAIAGEO_DECLARE int
gaiaGeomCollWithin(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1333 gaiaGeomCollWithin (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
1334 {
1335 /* checks if GEOM-1 is completely contained within GEOM-2 */
1336 int ret = -1;
1337 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1338 GEOSGeometry *g1;
1339 GEOSGeometry *g2;
1340 gaiaResetGeosMsg ();
1341 if (!geom1 || !geom2)
1342 return -1;
1343 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1344 return -1;
1345
1346 /* quick check based on MBRs comparison */
1347 if (!splite_mbr_within (geom1, geom2))
1348 return 0;
1349
1350 g1 = gaiaToGeos (geom1);
1351 g2 = gaiaToGeos (geom2);
1352 ret = GEOSWithin (g1, g2);
1353 GEOSGeom_destroy (g1);
1354 GEOSGeom_destroy (g2);
1355 #else
1356 if (geom1 == NULL || geom2 == NULL)
1357 geom1 = NULL; /* silencing stupid compiler warnings */
1358 #endif
1359 return ret;
1360 }
1361
1362 GAIAGEO_DECLARE int
gaiaGeomCollWithin_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1363 gaiaGeomCollWithin_r (const void *p_cache, gaiaGeomCollPtr geom1,
1364 gaiaGeomCollPtr geom2)
1365 {
1366 /* checks if GEOM-1 is completely contained within GEOM-2 */
1367 int ret;
1368 GEOSGeometry *g1;
1369 GEOSGeometry *g2;
1370 struct splite_internal_cache *cache =
1371 (struct splite_internal_cache *) p_cache;
1372 GEOSContextHandle_t handle = NULL;
1373 if (cache == NULL)
1374 return -1;
1375 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1376 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1377 return -1;
1378 handle = cache->GEOS_handle;
1379 if (handle == NULL)
1380 return -1;
1381 gaiaResetGeosMsg_r (cache);
1382 if (!geom1 || !geom2)
1383 return -1;
1384 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1385 return -1;
1386
1387 /* quick check based on MBRs comparison */
1388 if (!splite_mbr_within (geom1, geom2))
1389 return 0;
1390
1391 g1 = gaiaToGeos_r (cache, geom1);
1392 g2 = gaiaToGeos_r (cache, geom2);
1393 ret = GEOSWithin_r (handle, g1, g2);
1394 GEOSGeom_destroy_r (handle, g1);
1395 GEOSGeom_destroy_r (handle, g2);
1396 return ret;
1397 }
1398
1399 GAIAGEO_DECLARE int
gaiaGeomCollPreparedWithin(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)1400 gaiaGeomCollPreparedWithin (const void *p_cache, gaiaGeomCollPtr geom1,
1401 unsigned char *blob1, int size1,
1402 gaiaGeomCollPtr geom2, unsigned char *blob2,
1403 int size2)
1404 {
1405 /* checks if GEOM-1 is completely contained within GEOM-2 */
1406 int ret;
1407 struct splite_internal_cache *cache =
1408 (struct splite_internal_cache *) p_cache;
1409 GEOSPreparedGeometry *gPrep;
1410 GEOSGeometry *g1;
1411 GEOSGeometry *g2;
1412 gaiaGeomCollPtr geom;
1413 GEOSContextHandle_t handle = NULL;
1414 if (cache == NULL)
1415 return -1;
1416 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1417 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1418 return -1;
1419 handle = cache->GEOS_handle;
1420 if (handle == NULL)
1421 return -1;
1422 gaiaResetGeosMsg_r (cache);
1423 if (!geom1 || !geom2)
1424 return -1;
1425 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1426 return -1;
1427
1428 /* quick check based on MBRs comparison */
1429 if (!splite_mbr_within (geom1, geom2))
1430 return 0;
1431
1432 /* handling the internal GEOS cache */
1433 if (evalGeosCache
1434 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
1435 {
1436 g2 = gaiaToGeos_r (cache, geom);
1437 if (geom == geom2)
1438 ret = GEOSPreparedWithin_r (handle, gPrep, g2);
1439 else
1440 ret = GEOSPreparedContains_r (handle, gPrep, g2);
1441 GEOSGeom_destroy_r (handle, g2);
1442 return ret;
1443 }
1444
1445 g1 = gaiaToGeos_r (cache, geom1);
1446 g2 = gaiaToGeos_r (cache, geom2);
1447 ret = GEOSWithin_r (handle, g1, g2);
1448 GEOSGeom_destroy_r (handle, g1);
1449 GEOSGeom_destroy_r (handle, g2);
1450 return ret;
1451 }
1452
1453 GAIAGEO_DECLARE int
gaiaGeomCollContains(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1454 gaiaGeomCollContains (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
1455 {
1456 /* checks if GEOM-1 completely contains GEOM-2 */
1457 int ret = -1;
1458 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1459 GEOSGeometry *g1;
1460 GEOSGeometry *g2;
1461 gaiaResetGeosMsg ();
1462 if (!geom1 || !geom2)
1463 return -1;
1464 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1465 return -1;
1466
1467 /* quick check based on MBRs comparison */
1468 if (!splite_mbr_contains (geom1, geom2))
1469 return 0;
1470
1471 g1 = gaiaToGeos (geom1);
1472 g2 = gaiaToGeos (geom2);
1473 ret = GEOSContains (g1, g2);
1474 GEOSGeom_destroy (g1);
1475 GEOSGeom_destroy (g2);
1476 #else
1477 if (geom1 == NULL || geom2 == NULL)
1478 geom1 = NULL; /* silencing stupid compiler warnings */
1479 #endif
1480 return ret;
1481 }
1482
1483 GAIAGEO_DECLARE int
gaiaGeomCollContains_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)1484 gaiaGeomCollContains_r (const void *p_cache, gaiaGeomCollPtr geom1,
1485 gaiaGeomCollPtr geom2)
1486 {
1487 /* checks if GEOM-1 completely contains GEOM-2 */
1488 int ret;
1489 GEOSGeometry *g1;
1490 GEOSGeometry *g2;
1491 struct splite_internal_cache *cache =
1492 (struct splite_internal_cache *) p_cache;
1493 GEOSContextHandle_t handle = NULL;
1494 if (cache == NULL)
1495 return -1;
1496 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1497 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1498 return -1;
1499 handle = cache->GEOS_handle;
1500 if (handle == NULL)
1501 return -1;
1502 gaiaResetGeosMsg_r (cache);
1503 if (!geom1 || !geom2)
1504 return -1;
1505 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1506 return -1;
1507
1508 /* quick check based on MBRs comparison */
1509 if (!splite_mbr_contains (geom1, geom2))
1510 return 0;
1511
1512 g1 = gaiaToGeos_r (cache, geom1);
1513 g2 = gaiaToGeos_r (cache, geom2);
1514 ret = GEOSContains_r (handle, g1, g2);
1515 GEOSGeom_destroy_r (handle, g1);
1516 GEOSGeom_destroy_r (handle, g2);
1517 return ret;
1518 }
1519
1520 GAIAGEO_DECLARE int
gaiaGeomCollPreparedContains(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)1521 gaiaGeomCollPreparedContains (const void *p_cache, gaiaGeomCollPtr geom1,
1522 unsigned char *blob1, int size1,
1523 gaiaGeomCollPtr geom2, unsigned char *blob2,
1524 int size2)
1525 {
1526 /* checks if GEOM-1 completely contains GEOM-2 */
1527 int ret;
1528 struct splite_internal_cache *cache =
1529 (struct splite_internal_cache *) p_cache;
1530 GEOSPreparedGeometry *gPrep;
1531 GEOSGeometry *g1;
1532 GEOSGeometry *g2;
1533 gaiaGeomCollPtr geom;
1534 GEOSContextHandle_t handle = NULL;
1535 if (cache == NULL)
1536 return -1;
1537 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1538 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1539 return -1;
1540 handle = cache->GEOS_handle;
1541 if (handle == NULL)
1542 return -1;
1543 gaiaResetGeosMsg_r (cache);
1544 if (!geom1 || !geom2)
1545 return -1;
1546 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1547 return -1;
1548
1549 /* quick check based on MBRs comparison */
1550 if (!splite_mbr_contains (geom1, geom2))
1551 return 0;
1552
1553 /* handling the internal GEOS cache */
1554 if (evalGeosCache
1555 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
1556 {
1557 g2 = gaiaToGeos_r (cache, geom);
1558 if (geom == geom2)
1559 ret = GEOSPreparedContains_r (handle, gPrep, g2);
1560 else
1561 ret = GEOSPreparedWithin_r (handle, gPrep, g2);
1562 GEOSGeom_destroy_r (handle, g2);
1563 return ret;
1564 }
1565
1566 g1 = gaiaToGeos_r (cache, geom1);
1567 g2 = gaiaToGeos_r (cache, geom2);
1568 ret = GEOSContains_r (handle, g1, g2);
1569 GEOSGeom_destroy_r (handle, g1);
1570 GEOSGeom_destroy_r (handle, g2);
1571 return ret;
1572 }
1573
1574 GAIAGEO_DECLARE int
gaiaGeomCollRelate(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,const char * pattern)1575 gaiaGeomCollRelate (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
1576 const char *pattern)
1577 {
1578 /* checks if if GEOM-1 and GEOM-2 have a spatial relationship as specified by the pattern Matrix */
1579 int ret = -1;
1580 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1581 GEOSGeometry *g1;
1582 GEOSGeometry *g2;
1583 gaiaResetGeosMsg ();
1584 if (!geom1 || !geom2)
1585 return -1;
1586 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1587 return -1;
1588 g1 = gaiaToGeos (geom1);
1589 g2 = gaiaToGeos (geom2);
1590 ret = GEOSRelatePattern (g1, g2, pattern);
1591 GEOSGeom_destroy (g1);
1592 GEOSGeom_destroy (g2);
1593 if (ret == 2)
1594 return -1;
1595 #else
1596 if (geom1 == NULL || geom2 == NULL || pattern == NULL)
1597 geom1 = NULL; /* silencing stupid compiler warnings */
1598 #endif
1599 return ret;
1600 }
1601
1602 GAIAGEO_DECLARE int
gaiaGeomCollRelate_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,const char * pattern)1603 gaiaGeomCollRelate_r (const void *p_cache, gaiaGeomCollPtr geom1,
1604 gaiaGeomCollPtr geom2, const char *pattern)
1605 {
1606 /* checks if if GEOM-1 and GEOM-2 have a spatial relationship as specified by the pattern Matrix */
1607 int ret;
1608 GEOSGeometry *g1;
1609 GEOSGeometry *g2;
1610 struct splite_internal_cache *cache =
1611 (struct splite_internal_cache *) p_cache;
1612 GEOSContextHandle_t handle = NULL;
1613 if (cache == NULL)
1614 return -1;
1615 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1616 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1617 return -1;
1618 handle = cache->GEOS_handle;
1619 if (handle == NULL)
1620 return -1;
1621 gaiaResetGeosMsg_r (cache);
1622 if (!geom1 || !geom2)
1623 return -1;
1624 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1625 return -1;
1626 g1 = gaiaToGeos_r (cache, geom1);
1627 g2 = gaiaToGeos_r (cache, geom2);
1628 ret = GEOSRelatePattern_r (handle, g1, g2, pattern);
1629 GEOSGeom_destroy_r (handle, g1);
1630 GEOSGeom_destroy_r (handle, g2);
1631 if (ret == 2)
1632 return -1;
1633 return ret;
1634 }
1635
1636 GAIAGEO_DECLARE char *
gaiaGeomCollRelateBoundaryNodeRule(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,int mode)1637 gaiaGeomCollRelateBoundaryNodeRule (gaiaGeomCollPtr geom1,
1638 gaiaGeomCollPtr geom2, int mode)
1639 {
1640 /* return the intesection matrix [DE-9IM] of GEOM-1 and GEOM-2 */
1641 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1642 GEOSGeometry *g1;
1643 GEOSGeometry *g2;
1644 int bnr;
1645 char *retMatrix;
1646 char *matrix;
1647 int len;
1648 gaiaResetGeosMsg ();
1649 if (!geom1 || !geom2)
1650 return NULL;
1651 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1652 return NULL;
1653 g1 = gaiaToGeos (geom1);
1654 g2 = gaiaToGeos (geom2);
1655 switch (mode)
1656 {
1657 case 2:
1658 bnr = GEOSRELATE_BNR_ENDPOINT;
1659 break;
1660 case 3:
1661 bnr = GEOSRELATE_BNR_MULTIVALENT_ENDPOINT;
1662 break;
1663 case 4:
1664 bnr = GEOSRELATE_BNR_MONOVALENT_ENDPOINT;
1665 break;
1666 default:
1667 bnr = GEOSRELATE_BNR_MOD2;
1668 break;
1669 };
1670 retMatrix = GEOSRelateBoundaryNodeRule (g1, g2, bnr);
1671 GEOSGeom_destroy (g1);
1672 GEOSGeom_destroy (g2);
1673 if (retMatrix == NULL)
1674 return NULL;
1675 len = strlen (retMatrix);
1676 matrix = malloc (len + 1);
1677 strcpy (matrix, retMatrix);
1678 GEOSFree (retMatrix);
1679 return matrix;
1680 #else
1681 if (geom1 == NULL || geom2 == NULL || mode == 0)
1682 geom1 = NULL; /* silencing stupid compiler warnings */
1683 #endif
1684 return NULL;
1685 }
1686
1687 GAIAGEO_DECLARE char *
gaiaGeomCollRelateBoundaryNodeRule_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,int mode)1688 gaiaGeomCollRelateBoundaryNodeRule_r (const void *p_cache,
1689 gaiaGeomCollPtr geom1,
1690 gaiaGeomCollPtr geom2, int mode)
1691 {
1692 /* return the intesection matrix [DE-9IM] of GEOM-1 and GEOM-2 */
1693 GEOSGeometry *g1;
1694 GEOSGeometry *g2;
1695 int bnr;
1696 char *retMatrix;
1697 char *matrix;
1698 int len;
1699 struct splite_internal_cache *cache =
1700 (struct splite_internal_cache *) p_cache;
1701 GEOSContextHandle_t handle = NULL;
1702 if (cache == NULL)
1703 return NULL;
1704 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1705 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1706 return NULL;
1707 handle = cache->GEOS_handle;
1708 if (handle == NULL)
1709 return NULL;
1710 gaiaResetGeosMsg_r (cache);
1711 if (!geom1 || !geom2)
1712 return NULL;
1713 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
1714 return NULL;
1715 g1 = gaiaToGeos_r (cache, geom1);
1716 g2 = gaiaToGeos_r (cache, geom2);
1717 switch (mode)
1718 {
1719 case 2:
1720 bnr = GEOSRELATE_BNR_ENDPOINT;
1721 break;
1722 case 3:
1723 bnr = GEOSRELATE_BNR_MULTIVALENT_ENDPOINT;
1724 break;
1725 case 4:
1726 bnr = GEOSRELATE_BNR_MONOVALENT_ENDPOINT;
1727 break;
1728 default:
1729 bnr = GEOSRELATE_BNR_MOD2;
1730 break;
1731 };
1732 retMatrix = GEOSRelateBoundaryNodeRule_r (handle, g1, g2, bnr);
1733 GEOSGeom_destroy_r (handle, g1);
1734 GEOSGeom_destroy_r (handle, g2);
1735 if (retMatrix == NULL)
1736 return NULL;
1737 len = strlen (retMatrix);
1738 matrix = malloc (len + 1);
1739 strcpy (matrix, retMatrix);
1740 GEOSFree_r (handle, retMatrix);
1741 return matrix;
1742 }
1743
1744 GAIAGEO_DECLARE int
gaiaIntersectionMatrixPatternMatch(const char * matrix,const char * pattern)1745 gaiaIntersectionMatrixPatternMatch (const char *matrix, const char *pattern)
1746 {
1747 /* evalutes if an intersection matrix [DE-9IM] matches a matrix pattern */
1748 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1749 int ret;
1750 gaiaResetGeosMsg ();
1751 if (matrix == NULL || pattern == NULL)
1752 return -1;
1753 ret = GEOSRelatePatternMatch (matrix, pattern);
1754 if (ret == 0 || ret == 1)
1755 return ret;
1756 #else
1757 if (matrix == NULL || pattern == NULL)
1758 matrix = NULL; /* silencing stupid compiler warnings */
1759 #endif
1760 return -1;
1761 }
1762
1763 GAIAGEO_DECLARE int
gaiaIntersectionMatrixPatternMatch_r(const void * p_cache,const char * matrix,const char * pattern)1764 gaiaIntersectionMatrixPatternMatch_r (const void *p_cache, const char *matrix,
1765 const char *pattern)
1766 {
1767 /* evalutes is an intersection matrix [DE-9IM] matches a matrix pattern */
1768 int ret;
1769 struct splite_internal_cache *cache =
1770 (struct splite_internal_cache *) p_cache;
1771 GEOSContextHandle_t handle = NULL;
1772 if (cache == NULL)
1773 return -1;
1774 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1775 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1776 return -1;
1777 handle = cache->GEOS_handle;
1778 if (handle == NULL)
1779 return -1;
1780 gaiaResetGeosMsg_r (cache);
1781 if (matrix == NULL || pattern == NULL)
1782 return -1;
1783 ret = GEOSRelatePatternMatch_r (handle, matrix, pattern);
1784 if (ret == 0 || ret == 1)
1785 return ret;
1786 return -1;
1787 }
1788
1789 GAIAGEO_DECLARE int
gaiaGeomCollLength(gaiaGeomCollPtr geom,double * xlength)1790 gaiaGeomCollLength (gaiaGeomCollPtr geom, double *xlength)
1791 {
1792 /* computes the total length for this Geometry */
1793 int ret = 0;
1794 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1795 double length;
1796 GEOSGeometry *g;
1797 gaiaResetGeosMsg ();
1798 if (!geom)
1799 return 0;
1800 if (gaiaIsToxic (geom))
1801 return 0;
1802 g = gaiaToGeos (geom);
1803 ret = GEOSLength (g, &length);
1804 GEOSGeom_destroy (g);
1805 if (ret)
1806 *xlength = length;
1807 #else
1808 if (geom == NULL || xlength == NULL)
1809 geom = NULL; /* silencing stupid compiler warnings */
1810 #endif
1811 return ret;
1812 }
1813
1814 GAIAGEO_DECLARE int
gaiaGeomCollLength_r(const void * p_cache,gaiaGeomCollPtr geom,double * xlength)1815 gaiaGeomCollLength_r (const void *p_cache, gaiaGeomCollPtr geom,
1816 double *xlength)
1817 {
1818 /* computes the total length for this Geometry */
1819 double length;
1820 int ret;
1821 GEOSGeometry *g;
1822 struct splite_internal_cache *cache =
1823 (struct splite_internal_cache *) p_cache;
1824 GEOSContextHandle_t handle = NULL;
1825 if (cache == NULL)
1826 return -1;
1827 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1828 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1829 return -1;
1830 handle = cache->GEOS_handle;
1831 if (handle == NULL)
1832 return -1;
1833 gaiaResetGeosMsg_r (cache);
1834 if (!geom)
1835 return 0;
1836 if (gaiaIsToxic_r (cache, geom))
1837 return 0;
1838 g = gaiaToGeos_r (cache, geom);
1839 ret = GEOSLength_r (handle, g, &length);
1840 GEOSGeom_destroy_r (handle, g);
1841 if (ret)
1842 *xlength = length;
1843 return ret;
1844 }
1845
1846 GAIAGEO_DECLARE int
gaiaGeomCollLengthOrPerimeter(gaiaGeomCollPtr geom,int perimeter,double * xlength)1847 gaiaGeomCollLengthOrPerimeter (gaiaGeomCollPtr geom, int perimeter,
1848 double *xlength)
1849 {
1850 /* computes the total length or perimeter for this Geometry */
1851 int ret = 0;
1852 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1853 double length;
1854 GEOSGeometry *g;
1855 int mode = GAIA2GEOS_ONLY_LINESTRINGS;
1856 if (perimeter)
1857 mode = GAIA2GEOS_ONLY_POLYGONS;
1858 gaiaResetGeosMsg ();
1859 if (!geom)
1860 return 0;
1861 if (gaiaIsToxic (geom))
1862 return 0;
1863 g = gaiaToGeosSelective (geom, mode);
1864 if (g == NULL)
1865 {
1866 *xlength = 0.0;
1867 return 1;
1868 }
1869 ret = GEOSLength (g, &length);
1870 GEOSGeom_destroy (g);
1871 if (ret)
1872 *xlength = length;
1873 #else
1874 if (geom == NULL || perimeter == 0 || xlength == NULL)
1875 geom = NULL; /* silencing stupid compiler warnings */
1876 #endif
1877 return ret;
1878 }
1879
1880 GAIAGEO_DECLARE int
gaiaGeomCollLengthOrPerimeter_r(const void * p_cache,gaiaGeomCollPtr geom,int perimeter,double * xlength)1881 gaiaGeomCollLengthOrPerimeter_r (const void *p_cache, gaiaGeomCollPtr geom,
1882 int perimeter, double *xlength)
1883 {
1884 /* computes the total length or perimeter for this Geometry */
1885 double length;
1886 int ret;
1887 int mode = GAIA2GEOS_ONLY_LINESTRINGS;
1888 GEOSGeometry *g;
1889 struct splite_internal_cache *cache =
1890 (struct splite_internal_cache *) p_cache;
1891 GEOSContextHandle_t handle = NULL;
1892 if (cache == NULL)
1893 return -1;
1894 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1895 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1896 return -1;
1897 handle = cache->GEOS_handle;
1898 if (handle == NULL)
1899 return -1;
1900 if (perimeter)
1901 mode = GAIA2GEOS_ONLY_POLYGONS;
1902 gaiaResetGeosMsg_r (cache);
1903 if (!geom)
1904 return 0;
1905 if (gaiaIsToxic_r (cache, geom))
1906 return 0;
1907 g = gaiaToGeosSelective_r (cache, geom, mode);
1908 if (g == NULL)
1909 {
1910 *xlength = 0.0;
1911 return 1;
1912 }
1913 ret = GEOSLength_r (handle, g, &length);
1914 GEOSGeom_destroy_r (handle, g);
1915 if (ret)
1916 *xlength = length;
1917 return ret;
1918 }
1919
1920 GAIAGEO_DECLARE int
gaiaGeomCollArea(gaiaGeomCollPtr geom,double * xarea)1921 gaiaGeomCollArea (gaiaGeomCollPtr geom, double *xarea)
1922 {
1923 /* computes the total area for this Geometry */
1924 int ret = 0;
1925 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1926 double area;
1927 GEOSGeometry *g;
1928 gaiaResetGeosMsg ();
1929 if (!geom)
1930 return 0;
1931 if (gaiaIsToxic (geom))
1932 return 0;
1933 g = gaiaToGeos (geom);
1934 ret = GEOSArea (g, &area);
1935 GEOSGeom_destroy (g);
1936 if (ret)
1937 *xarea = area;
1938 #else
1939 if (geom == NULL || xarea == NULL)
1940 geom = NULL; /* silencing stupid compiler warnings */
1941 #endif
1942 return ret;
1943 }
1944
1945 GAIAGEO_DECLARE int
gaiaGeomCollArea_r(const void * p_cache,gaiaGeomCollPtr geom,double * xarea)1946 gaiaGeomCollArea_r (const void *p_cache, gaiaGeomCollPtr geom, double *xarea)
1947 {
1948 /* computes the total area for this Geometry */
1949 double area;
1950 int ret;
1951 GEOSGeometry *g;
1952 struct splite_internal_cache *cache =
1953 (struct splite_internal_cache *) p_cache;
1954 GEOSContextHandle_t handle = NULL;
1955 if (cache == NULL)
1956 return -1;
1957 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1958 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1959 return -1;
1960 handle = cache->GEOS_handle;
1961 if (handle == NULL)
1962 return -1;
1963 gaiaResetGeosMsg_r (cache);
1964 if (!geom)
1965 return 0;
1966 if (gaiaIsToxic_r (cache, geom))
1967 return 0;
1968 g = gaiaToGeos_r (cache, geom);
1969 ret = GEOSArea_r (handle, g, &area);
1970 GEOSGeom_destroy_r (handle, g);
1971 if (ret)
1972 *xarea = area;
1973 return ret;
1974 }
1975
1976 GAIAGEO_DECLARE int
gaiaGeomCollDistance(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,double * xdist)1977 gaiaGeomCollDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
1978 double *xdist)
1979 {
1980 /* computes the minimum distance intercurring between GEOM-1 and GEOM-2 */
1981 int ret = 0;
1982 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
1983 double dist;
1984 GEOSGeometry *g1;
1985 GEOSGeometry *g2;
1986 gaiaResetGeosMsg ();
1987 if (!geom1 || !geom2)
1988 return 0;
1989 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
1990 return 0;
1991 g1 = gaiaToGeos (geom1);
1992 g2 = gaiaToGeos (geom2);
1993 ret = GEOSDistance (g1, g2, &dist);
1994 GEOSGeom_destroy (g1);
1995 GEOSGeom_destroy (g2);
1996 if (ret)
1997 *xdist = dist;
1998 #else
1999 if (geom1 == NULL || geom2 == NULL || xdist == NULL)
2000 geom1 = NULL; /* silencing stupid compiler warnings */
2001 #endif
2002 return ret;
2003 }
2004
2005 GAIAGEO_DECLARE int
gaiaGeomCollDistance_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,double * xdist)2006 gaiaGeomCollDistance_r (const void *p_cache, gaiaGeomCollPtr geom1,
2007 gaiaGeomCollPtr geom2, double *xdist)
2008 {
2009 /* computes the minimum distance intercurring between GEOM-1 and GEOM-2 */
2010 double dist;
2011 int ret;
2012 GEOSGeometry *g1;
2013 GEOSGeometry *g2;
2014 struct splite_internal_cache *cache =
2015 (struct splite_internal_cache *) p_cache;
2016 GEOSContextHandle_t handle = NULL;
2017 if (cache == NULL)
2018 return -1;
2019 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2020 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2021 return -1;
2022 handle = cache->GEOS_handle;
2023 if (handle == NULL)
2024 return -1;
2025 gaiaResetGeosMsg_r (cache);
2026 if (!geom1 || !geom2)
2027 return 0;
2028 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
2029 return 0;
2030 g1 = gaiaToGeos_r (cache, geom1);
2031 g2 = gaiaToGeos_r (cache, geom2);
2032 ret = GEOSDistance_r (handle, g1, g2, &dist);
2033 GEOSGeom_destroy_r (handle, g1);
2034 GEOSGeom_destroy_r (handle, g2);
2035 if (ret)
2036 *xdist = dist;
2037 return ret;
2038 }
2039
2040 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryIntersection(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2041 gaiaGeometryIntersection (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
2042 {
2043 /* builds a new geometry representing the "spatial intersection" of GEOM-1 and GEOM-2 */
2044 gaiaGeomCollPtr geo = NULL;
2045 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2046 GEOSGeometry *g1;
2047 GEOSGeometry *g2;
2048 GEOSGeometry *g3;
2049 gaiaResetGeosMsg ();
2050 if (!geom1 || !geom2)
2051 return NULL;
2052 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
2053 return NULL;
2054
2055 /* quick check based on MBRs comparison */
2056 if (!splite_mbr_overlaps (geom1, geom2))
2057 return NULL;
2058
2059 g1 = gaiaToGeos (geom1);
2060 g2 = gaiaToGeos (geom2);
2061 g3 = GEOSIntersection (g1, g2);
2062 GEOSGeom_destroy (g1);
2063 GEOSGeom_destroy (g2);
2064 if (!g3)
2065 return NULL;
2066 if (GEOSisEmpty (g3) == 1)
2067 {
2068 GEOSGeom_destroy (g3);
2069 return NULL;
2070 }
2071 if (geom1->DimensionModel == GAIA_XY_Z)
2072 geo = gaiaFromGeos_XYZ (g3);
2073 else if (geom1->DimensionModel == GAIA_XY_M)
2074 geo = gaiaFromGeos_XYM (g3);
2075 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2076 geo = gaiaFromGeos_XYZM (g3);
2077 else
2078 geo = gaiaFromGeos_XY (g3);
2079 GEOSGeom_destroy (g3);
2080 if (geo == NULL)
2081 return NULL;
2082 geo->Srid = geom1->Srid;
2083 #else
2084 if (geom1 == NULL || geom2 == NULL)
2085 geom1 = NULL; /* silencing stupid compiler warnings */
2086 #endif
2087 return geo;
2088 }
2089
2090 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryIntersection_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2091 gaiaGeometryIntersection_r (const void *p_cache, gaiaGeomCollPtr geom1,
2092 gaiaGeomCollPtr geom2)
2093 {
2094 /* builds a new geometry representing the "spatial intersection" of GEOM-1 and GEOM-2 */
2095 gaiaGeomCollPtr geo;
2096 GEOSGeometry *g1;
2097 GEOSGeometry *g2;
2098 GEOSGeometry *g3;
2099 struct splite_internal_cache *cache =
2100 (struct splite_internal_cache *) p_cache;
2101 GEOSContextHandle_t handle = NULL;
2102 if (cache == NULL)
2103 return NULL;
2104 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2105 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2106 return NULL;
2107 handle = cache->GEOS_handle;
2108 if (handle == NULL)
2109 return NULL;
2110 gaiaResetGeosMsg_r (cache);
2111 if (!geom1 || !geom2)
2112 return NULL;
2113 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
2114 return NULL;
2115
2116 /* quick check based on MBRs comparison */
2117 if (!splite_mbr_overlaps (geom1, geom2))
2118 return NULL;
2119
2120 g1 = gaiaToGeos_r (cache, geom1);
2121 g2 = gaiaToGeos_r (cache, geom2);
2122 g3 = GEOSIntersection_r (handle, g1, g2);
2123 GEOSGeom_destroy_r (handle, g1);
2124 GEOSGeom_destroy_r (handle, g2);
2125 if (!g3)
2126 return NULL;
2127 if (GEOSisEmpty_r (handle, g3) == 1)
2128 {
2129 GEOSGeom_destroy_r (handle, g3);
2130 return NULL;
2131 }
2132 if (geom1->DimensionModel == GAIA_XY_Z)
2133 geo = gaiaFromGeos_XYZ_r (cache, g3);
2134 else if (geom1->DimensionModel == GAIA_XY_M)
2135 geo = gaiaFromGeos_XYM_r (cache, g3);
2136 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2137 geo = gaiaFromGeos_XYZM_r (cache, g3);
2138 else
2139 geo = gaiaFromGeos_XY_r (cache, g3);
2140 GEOSGeom_destroy_r (handle, g3);
2141 if (geo == NULL)
2142 return NULL;
2143 geo->Srid = geom1->Srid;
2144 return geo;
2145 }
2146
2147 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryUnion(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2148 gaiaGeometryUnion (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
2149 {
2150 /* builds a new geometry representing the "spatial union" of GEOM-1 and GEOM-2 */
2151 gaiaGeomCollPtr geo = NULL;
2152 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2153 GEOSGeometry *g1;
2154 GEOSGeometry *g2;
2155 GEOSGeometry *g3;
2156 gaiaResetGeosMsg ();
2157 if (!geom1 || !geom2)
2158 return NULL;
2159 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
2160 return NULL;
2161 g1 = gaiaToGeos (geom1);
2162 g2 = gaiaToGeos (geom2);
2163 g3 = GEOSUnion (g1, g2);
2164 GEOSGeom_destroy (g1);
2165 GEOSGeom_destroy (g2);
2166 if (g3 == NULL)
2167 return NULL;
2168 if (GEOSisEmpty (g3) == 1)
2169 {
2170 GEOSGeom_destroy (g3);
2171 return NULL;
2172 }
2173 if (geom1->DimensionModel == GAIA_XY_Z)
2174 geo = gaiaFromGeos_XYZ (g3);
2175 else if (geom1->DimensionModel == GAIA_XY_M)
2176 geo = gaiaFromGeos_XYM (g3);
2177 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2178 geo = gaiaFromGeos_XYZM (g3);
2179 else
2180 geo = gaiaFromGeos_XY (g3);
2181 GEOSGeom_destroy (g3);
2182 if (geo == NULL)
2183 return NULL;
2184 geo->Srid = geom1->Srid;
2185 if (geo->DeclaredType == GAIA_POINT &&
2186 geom1->DeclaredType == GAIA_MULTIPOINT)
2187 geo->DeclaredType = GAIA_MULTIPOINT;
2188 if (geo->DeclaredType == GAIA_LINESTRING &&
2189 geom1->DeclaredType == GAIA_MULTILINESTRING)
2190 geo->DeclaredType = GAIA_MULTILINESTRING;
2191 if (geo->DeclaredType == GAIA_POLYGON &&
2192 geom1->DeclaredType == GAIA_MULTIPOLYGON)
2193 geo->DeclaredType = GAIA_MULTIPOLYGON;
2194 #else
2195 if (geom1 == NULL || geom2 == NULL)
2196 geom1 = NULL; /* silencing stupid compiler warnings */
2197 #endif
2198 return geo;
2199 }
2200
2201 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryUnion_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2202 gaiaGeometryUnion_r (const void *p_cache, gaiaGeomCollPtr geom1,
2203 gaiaGeomCollPtr geom2)
2204 {
2205 /* builds a new geometry representing the "spatial union" of GEOM-1 and GEOM-2 */
2206 gaiaGeomCollPtr geo;
2207 GEOSGeometry *g1;
2208 GEOSGeometry *g2;
2209 GEOSGeometry *g3;
2210 struct splite_internal_cache *cache =
2211 (struct splite_internal_cache *) p_cache;
2212 GEOSContextHandle_t handle = NULL;
2213 if (cache == NULL)
2214 return NULL;
2215 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2216 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2217 return NULL;
2218 handle = cache->GEOS_handle;
2219 if (handle == NULL)
2220 return NULL;
2221 gaiaResetGeosMsg_r (cache);
2222 if (!geom1 || !geom2)
2223 return NULL;
2224 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
2225 return NULL;
2226 g1 = gaiaToGeos_r (cache, geom1);
2227 g2 = gaiaToGeos_r (cache, geom2);
2228 g3 = GEOSUnion_r (handle, g1, g2);
2229 GEOSGeom_destroy_r (handle, g1);
2230 GEOSGeom_destroy_r (handle, g2);
2231 if (g3 == NULL)
2232 return NULL;
2233 if (GEOSisEmpty_r (handle, g3) == 1)
2234 {
2235 GEOSGeom_destroy_r (handle, g3);
2236 return NULL;
2237 }
2238 if (geom1->DimensionModel == GAIA_XY_Z)
2239 geo = gaiaFromGeos_XYZ_r (cache, g3);
2240 else if (geom1->DimensionModel == GAIA_XY_M)
2241 geo = gaiaFromGeos_XYM_r (cache, g3);
2242 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2243 geo = gaiaFromGeos_XYZM_r (cache, g3);
2244 else
2245 geo = gaiaFromGeos_XY_r (cache, g3);
2246 GEOSGeom_destroy_r (handle, g3);
2247 if (geo == NULL)
2248 return NULL;
2249 geo->Srid = geom1->Srid;
2250 if (geo->DeclaredType == GAIA_POINT &&
2251 geom1->DeclaredType == GAIA_MULTIPOINT)
2252 geo->DeclaredType = GAIA_MULTIPOINT;
2253 if (geo->DeclaredType == GAIA_LINESTRING &&
2254 geom1->DeclaredType == GAIA_MULTILINESTRING)
2255 geo->DeclaredType = GAIA_MULTILINESTRING;
2256 if (geo->DeclaredType == GAIA_POLYGON &&
2257 geom1->DeclaredType == GAIA_MULTIPOLYGON)
2258 geo->DeclaredType = GAIA_MULTIPOLYGON;
2259 return geo;
2260 }
2261
2262 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaUnionCascaded(gaiaGeomCollPtr geom)2263 gaiaUnionCascaded (gaiaGeomCollPtr geom)
2264 {
2265 /* UnionCascaded (single Collection of polygons) */
2266 gaiaGeomCollPtr result = NULL;
2267 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2268 GEOSGeometry *g1;
2269 GEOSGeometry *g2;
2270 int pts = 0;
2271 int lns = 0;
2272 int pgs = 0;
2273 gaiaPointPtr pt;
2274 gaiaLinestringPtr ln;
2275 gaiaPolygonPtr pg;
2276 gaiaResetGeosMsg ();
2277 if (!geom)
2278 return NULL;
2279 if (gaiaIsToxic (geom))
2280 return NULL;
2281
2282 /* testing if geom only contains Polygons */
2283 pt = geom->FirstPoint;
2284 while (pt)
2285 {
2286 pts++;
2287 pt = pt->Next;
2288 }
2289 ln = geom->FirstLinestring;
2290 while (ln)
2291 {
2292 lns++;
2293 ln = ln->Next;
2294 }
2295 pg = geom->FirstPolygon;
2296 while (pg)
2297 {
2298 pgs++;
2299 pg = pg->Next;
2300 }
2301 if (pts || lns)
2302 return NULL;
2303 if (!pgs)
2304 return NULL;
2305
2306 g1 = gaiaToGeos (geom);
2307 g2 = GEOSUnionCascaded (g1);
2308 GEOSGeom_destroy (g1);
2309 if (!g2)
2310 return NULL;
2311 if (GEOSisEmpty (g2) == 1)
2312 {
2313 GEOSGeom_destroy (g2);
2314 return NULL;
2315 }
2316 if (geom->DimensionModel == GAIA_XY_Z)
2317 result = gaiaFromGeos_XYZ (g2);
2318 else if (geom->DimensionModel == GAIA_XY_M)
2319 result = gaiaFromGeos_XYM (g2);
2320 else if (geom->DimensionModel == GAIA_XY_Z_M)
2321 result = gaiaFromGeos_XYZM (g2);
2322 else
2323 result = gaiaFromGeos_XY (g2);
2324 GEOSGeom_destroy (g2);
2325 if (result == NULL)
2326 return NULL;
2327 result->Srid = geom->Srid;
2328 #else
2329 if (geom == NULL)
2330 geom = NULL; /* silencing stupid compiler warnings */
2331 #endif
2332 return result;
2333 }
2334
2335 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaUnionCascaded_r(const void * p_cache,gaiaGeomCollPtr geom)2336 gaiaUnionCascaded_r (const void *p_cache, gaiaGeomCollPtr geom)
2337 {
2338 /* UnionCascaded (single Collection of polygons) */
2339 GEOSGeometry *g1;
2340 GEOSGeometry *g2;
2341 gaiaGeomCollPtr result;
2342 int pts = 0;
2343 int lns = 0;
2344 int pgs = 0;
2345 gaiaPointPtr pt;
2346 gaiaLinestringPtr ln;
2347 gaiaPolygonPtr pg;
2348 struct splite_internal_cache *cache =
2349 (struct splite_internal_cache *) p_cache;
2350 GEOSContextHandle_t handle = NULL;
2351 if (cache == NULL)
2352 return NULL;
2353 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2354 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2355 return NULL;
2356 handle = cache->GEOS_handle;
2357 if (handle == NULL)
2358 return NULL;
2359 gaiaResetGeosMsg_r (cache);
2360 if (!geom)
2361 return NULL;
2362 if (gaiaIsToxic_r (cache, geom))
2363 return NULL;
2364
2365 /* testing if geom only contains Polygons */
2366 pt = geom->FirstPoint;
2367 while (pt)
2368 {
2369 pts++;
2370 pt = pt->Next;
2371 }
2372 ln = geom->FirstLinestring;
2373 while (ln)
2374 {
2375 lns++;
2376 ln = ln->Next;
2377 }
2378 pg = geom->FirstPolygon;
2379 while (pg)
2380 {
2381 pgs++;
2382 pg = pg->Next;
2383 }
2384 if (pts || lns)
2385 return NULL;
2386 if (!pgs)
2387 return NULL;
2388
2389 g1 = gaiaToGeos_r (cache, geom);
2390 g2 = GEOSUnionCascaded_r (handle, g1);
2391 GEOSGeom_destroy_r (handle, g1);
2392 if (!g2)
2393 return NULL;
2394 if (GEOSisEmpty_r (handle, g2) == 1)
2395 {
2396 GEOSGeom_destroy_r (handle, g2);
2397 return NULL;
2398 }
2399 if (geom->DimensionModel == GAIA_XY_Z)
2400 result = gaiaFromGeos_XYZ_r (cache, g2);
2401 else if (geom->DimensionModel == GAIA_XY_M)
2402 result = gaiaFromGeos_XYM_r (cache, g2);
2403 else if (geom->DimensionModel == GAIA_XY_Z_M)
2404 result = gaiaFromGeos_XYZM_r (cache, g2);
2405 else
2406 result = gaiaFromGeos_XY_r (cache, g2);
2407 GEOSGeom_destroy_r (handle, g2);
2408 if (result == NULL)
2409 return NULL;
2410 result->Srid = geom->Srid;
2411 return result;
2412 }
2413
2414 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryDifference(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2415 gaiaGeometryDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
2416 {
2417 /* builds a new geometry representing the "spatial difference" of GEOM-1 and GEOM-2 */
2418 gaiaGeomCollPtr geo = NULL;
2419 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2420 GEOSGeometry *g1;
2421 GEOSGeometry *g2;
2422 GEOSGeometry *g3;
2423 gaiaResetGeosMsg ();
2424 if (!geom1 || !geom2)
2425 return NULL;
2426 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
2427 return NULL;
2428 g1 = gaiaToGeos (geom1);
2429 g2 = gaiaToGeos (geom2);
2430 g3 = GEOSDifference (g1, g2);
2431 GEOSGeom_destroy (g1);
2432 GEOSGeom_destroy (g2);
2433 if (!g3)
2434 return NULL;
2435 if (GEOSisEmpty (g3) == 1)
2436 {
2437 GEOSGeom_destroy (g3);
2438 return NULL;
2439 }
2440 if (geom1->DimensionModel == GAIA_XY_Z)
2441 geo = gaiaFromGeos_XYZ (g3);
2442 else if (geom1->DimensionModel == GAIA_XY_M)
2443 geo = gaiaFromGeos_XYM (g3);
2444 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2445 geo = gaiaFromGeos_XYZM (g3);
2446 else
2447 geo = gaiaFromGeos_XY (g3);
2448 GEOSGeom_destroy (g3);
2449 if (geo == NULL)
2450 return NULL;
2451 geo->Srid = geom1->Srid;
2452 #else
2453 if (geom1 == NULL || geom2 == NULL)
2454 geom1 = NULL; /* silencing stupid compiler warnings */
2455 #endif
2456 return geo;
2457 }
2458
2459 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometryDifference_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2460 gaiaGeometryDifference_r (const void *p_cache, gaiaGeomCollPtr geom1,
2461 gaiaGeomCollPtr geom2)
2462 {
2463 /* builds a new geometry representing the "spatial difference" of GEOM-1 and GEOM-2 */
2464 gaiaGeomCollPtr geo;
2465 GEOSGeometry *g1;
2466 GEOSGeometry *g2;
2467 GEOSGeometry *g3;
2468 struct splite_internal_cache *cache =
2469 (struct splite_internal_cache *) p_cache;
2470 GEOSContextHandle_t handle = NULL;
2471 if (cache == NULL)
2472 return NULL;
2473 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2474 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2475 return NULL;
2476 handle = cache->GEOS_handle;
2477 if (handle == NULL)
2478 return NULL;
2479 gaiaResetGeosMsg_r (cache);
2480 if (!geom1 || !geom2)
2481 return NULL;
2482 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
2483 return NULL;
2484 g1 = gaiaToGeos_r (cache, geom1);
2485 g2 = gaiaToGeos_r (cache, geom2);
2486 g3 = GEOSDifference_r (handle, g1, g2);
2487 GEOSGeom_destroy_r (handle, g1);
2488 GEOSGeom_destroy_r (handle, g2);
2489 if (!g3)
2490 return NULL;
2491 if (GEOSisEmpty_r (handle, g3) == 1)
2492 {
2493 GEOSGeom_destroy_r (handle, g3);
2494 return NULL;
2495 }
2496 if (geom1->DimensionModel == GAIA_XY_Z)
2497 geo = gaiaFromGeos_XYZ_r (cache, g3);
2498 else if (geom1->DimensionModel == GAIA_XY_M)
2499 geo = gaiaFromGeos_XYM_r (cache, g3);
2500 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2501 geo = gaiaFromGeos_XYZM_r (cache, g3);
2502 else
2503 geo = gaiaFromGeos_XY_r (cache, g3);
2504 GEOSGeom_destroy_r (handle, g3);
2505 if (geo == NULL)
2506 return NULL;
2507 geo->Srid = geom1->Srid;
2508 return geo;
2509 }
2510
2511 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometrySymDifference(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2512 gaiaGeometrySymDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
2513 {
2514 /* builds a new geometry representing the "spatial symmetric difference" of GEOM-1 and GEOM-2 */
2515 gaiaGeomCollPtr geo = NULL;
2516 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2517 GEOSGeometry *g1;
2518 GEOSGeometry *g2;
2519 GEOSGeometry *g3;
2520 gaiaResetGeosMsg ();
2521 if (!geom1 || !geom2)
2522 return NULL;
2523 if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2))
2524 return NULL;
2525 g1 = gaiaToGeos (geom1);
2526 g2 = gaiaToGeos (geom2);
2527 g3 = GEOSSymDifference (g1, g2);
2528 GEOSGeom_destroy (g1);
2529 GEOSGeom_destroy (g2);
2530 if (!g3)
2531 return NULL;
2532 if (GEOSisEmpty (g3) == 1)
2533 {
2534 GEOSGeom_destroy (g3);
2535 return NULL;
2536 }
2537 if (geom1->DimensionModel == GAIA_XY_Z)
2538 geo = gaiaFromGeos_XYZ (g3);
2539 else if (geom1->DimensionModel == GAIA_XY_M)
2540 geo = gaiaFromGeos_XYM (g3);
2541 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2542 geo = gaiaFromGeos_XYZM (g3);
2543 else
2544 geo = gaiaFromGeos_XY (g3);
2545 GEOSGeom_destroy (g3);
2546 if (geo == NULL)
2547 return NULL;
2548 geo->Srid = geom1->Srid;
2549 #else
2550 if (geom1 == NULL || geom2 == NULL)
2551 geom1 = NULL; /* silencing stupid compiler warnings */
2552 #endif
2553 return geo;
2554 }
2555
2556 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeometrySymDifference_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)2557 gaiaGeometrySymDifference_r (const void *p_cache, gaiaGeomCollPtr geom1,
2558 gaiaGeomCollPtr geom2)
2559 {
2560 /* builds a new geometry representing the "spatial symmetric difference" of GEOM-1 and GEOM-2 */
2561 gaiaGeomCollPtr geo;
2562 GEOSGeometry *g1;
2563 GEOSGeometry *g2;
2564 GEOSGeometry *g3;
2565 struct splite_internal_cache *cache =
2566 (struct splite_internal_cache *) p_cache;
2567 GEOSContextHandle_t handle = NULL;
2568 if (cache == NULL)
2569 return NULL;
2570 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2571 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2572 return NULL;
2573 handle = cache->GEOS_handle;
2574 if (handle == NULL)
2575 return NULL;
2576 gaiaResetGeosMsg_r (cache);
2577 if (!geom1 || !geom2)
2578 return NULL;
2579 if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2))
2580 return NULL;
2581 g1 = gaiaToGeos_r (cache, geom1);
2582 g2 = gaiaToGeos_r (cache, geom2);
2583 g3 = GEOSSymDifference_r (handle, g1, g2);
2584 GEOSGeom_destroy_r (handle, g1);
2585 GEOSGeom_destroy_r (handle, g2);
2586 if (!g3)
2587 return NULL;
2588 if (GEOSisEmpty_r (handle, g3) == 1)
2589 {
2590 GEOSGeom_destroy_r (handle, g3);
2591 return NULL;
2592 }
2593 if (geom1->DimensionModel == GAIA_XY_Z)
2594 geo = gaiaFromGeos_XYZ_r (cache, g3);
2595 else if (geom1->DimensionModel == GAIA_XY_M)
2596 geo = gaiaFromGeos_XYM_r (cache, g3);
2597 else if (geom1->DimensionModel == GAIA_XY_Z_M)
2598 geo = gaiaFromGeos_XYZM_r (cache, g3);
2599 else
2600 geo = gaiaFromGeos_XY_r (cache, g3);
2601 GEOSGeom_destroy_r (handle, g3);
2602 if (geo == NULL)
2603 return NULL;
2604 geo->Srid = geom1->Srid;
2605 return geo;
2606 }
2607
2608 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaBoundary(gaiaGeomCollPtr geom)2609 gaiaBoundary (gaiaGeomCollPtr geom)
2610 {
2611 /* builds a new geometry representing the combinatorial boundary of GEOM */
2612 gaiaGeomCollPtr geo = NULL;
2613 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2614 GEOSGeometry *g1;
2615 GEOSGeometry *g2;
2616 gaiaResetGeosMsg ();
2617 if (!geom)
2618 return NULL;
2619 if (gaiaIsToxic (geom))
2620 return NULL;
2621 g1 = gaiaToGeos (geom);
2622 g2 = GEOSBoundary (g1);
2623 GEOSGeom_destroy (g1);
2624 if (!g2)
2625 return NULL;
2626 if (GEOSisEmpty (g2) == 1)
2627 {
2628 GEOSGeom_destroy (g2);
2629 return NULL;
2630 }
2631 if (geom->DimensionModel == GAIA_XY_Z)
2632 geo = gaiaFromGeos_XYZ (g2);
2633 else if (geom->DimensionModel == GAIA_XY_M)
2634 geo = gaiaFromGeos_XYM (g2);
2635 else if (geom->DimensionModel == GAIA_XY_Z_M)
2636 geo = gaiaFromGeos_XYZM (g2);
2637 else
2638 geo = gaiaFromGeos_XY (g2);
2639 GEOSGeom_destroy (g2);
2640 if (geo == NULL)
2641 return NULL;
2642 geo->Srid = geom->Srid;
2643 #else
2644 if (geom == NULL)
2645 geom = NULL; /* silencing stupid compiler warnings */
2646 #endif
2647 return geo;
2648 }
2649
2650 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaBoundary_r(const void * p_cache,gaiaGeomCollPtr geom)2651 gaiaBoundary_r (const void *p_cache, gaiaGeomCollPtr geom)
2652 {
2653 /* builds a new geometry representing the combinatorial boundary of GEOM */
2654 gaiaGeomCollPtr geo;
2655 GEOSGeometry *g1;
2656 GEOSGeometry *g2;
2657 struct splite_internal_cache *cache =
2658 (struct splite_internal_cache *) p_cache;
2659 GEOSContextHandle_t handle = NULL;
2660 if (cache == NULL)
2661 return NULL;
2662 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2663 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2664 return NULL;
2665 handle = cache->GEOS_handle;
2666 if (handle == NULL)
2667 return NULL;
2668 gaiaResetGeosMsg_r (cache);
2669 if (!geom)
2670 return NULL;
2671 if (gaiaIsToxic_r (cache, geom))
2672 return NULL;
2673 g1 = gaiaToGeos_r (cache, geom);
2674 g2 = GEOSBoundary_r (handle, g1);
2675 GEOSGeom_destroy_r (handle, g1);
2676 if (!g2)
2677 return NULL;
2678 if (GEOSisEmpty_r (handle, g2) == 1)
2679 {
2680 GEOSGeom_destroy_r (handle, g2);
2681 return NULL;
2682 }
2683 if (geom->DimensionModel == GAIA_XY_Z)
2684 geo = gaiaFromGeos_XYZ_r (cache, g2);
2685 else if (geom->DimensionModel == GAIA_XY_M)
2686 geo = gaiaFromGeos_XYM_r (cache, g2);
2687 else if (geom->DimensionModel == GAIA_XY_Z_M)
2688 geo = gaiaFromGeos_XYZM_r (cache, g2);
2689 else
2690 geo = gaiaFromGeos_XY_r (cache, g2);
2691 GEOSGeom_destroy_r (handle, g2);
2692 if (geo == NULL)
2693 return NULL;
2694 geo->Srid = geom->Srid;
2695 return geo;
2696 }
2697
2698 GAIAGEO_DECLARE int
gaiaGeomCollCentroid(gaiaGeomCollPtr geom,double * x,double * y)2699 gaiaGeomCollCentroid (gaiaGeomCollPtr geom, double *x, double *y)
2700 {
2701 /* returns a Point representing the centroid for this Geometry */
2702 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2703 gaiaGeomCollPtr geo;
2704 GEOSGeometry *g1;
2705 GEOSGeometry *g2;
2706 gaiaResetGeosMsg ();
2707 if (!geom)
2708 return 0;
2709 if (gaiaIsToxic (geom))
2710 {
2711 return 0;
2712 }
2713 g1 = gaiaToGeos (geom);
2714 g2 = GEOSGetCentroid (g1);
2715 GEOSGeom_destroy (g1);
2716 if (!g2)
2717 return 0;
2718 if (GEOSisEmpty (g2) == 1)
2719 {
2720 GEOSGeom_destroy (g2);
2721 return 0;
2722 }
2723 if (geom->DimensionModel == GAIA_XY_Z)
2724 geo = gaiaFromGeos_XYZ (g2);
2725 else if (geom->DimensionModel == GAIA_XY_M)
2726 geo = gaiaFromGeos_XYM (g2);
2727 else if (geom->DimensionModel == GAIA_XY_Z_M)
2728 geo = gaiaFromGeos_XYZM (g2);
2729 else
2730 geo = gaiaFromGeos_XY (g2);
2731 GEOSGeom_destroy (g2);
2732 if (geo == NULL)
2733 return 0;
2734 if (geo->FirstPoint)
2735 {
2736 *x = geo->FirstPoint->X;
2737 *y = geo->FirstPoint->Y;
2738 gaiaFreeGeomColl (geo);
2739 return 1;
2740 }
2741 gaiaFreeGeomColl (geo);
2742 #else
2743 if (geom == NULL || x == NULL || y == NULL)
2744 geom = NULL; /* silencing stupid compiler warnings */
2745 #endif
2746 return 0;
2747 }
2748
2749 GAIAGEO_DECLARE int
gaiaGeomCollCentroid_r(const void * p_cache,gaiaGeomCollPtr geom,double * x,double * y)2750 gaiaGeomCollCentroid_r (const void *p_cache, gaiaGeomCollPtr geom, double *x,
2751 double *y)
2752 {
2753 /* returns a Point representing the centroid for this Geometry */
2754 gaiaGeomCollPtr geo;
2755 GEOSGeometry *g1;
2756 GEOSGeometry *g2;
2757 struct splite_internal_cache *cache =
2758 (struct splite_internal_cache *) p_cache;
2759 GEOSContextHandle_t handle = NULL;
2760 if (cache == NULL)
2761 return 0;
2762 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2763 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2764 return 0;
2765 handle = cache->GEOS_handle;
2766 if (handle == NULL)
2767 return 0;
2768 gaiaResetGeosMsg_r (cache);
2769 if (!geom)
2770 return 0;
2771 if (gaiaIsToxic_r (cache, geom))
2772 {
2773 return 0;
2774 }
2775 g1 = gaiaToGeos_r (cache, geom);
2776 g2 = GEOSGetCentroid_r (handle, g1);
2777 GEOSGeom_destroy_r (handle, g1);
2778 if (!g2)
2779 return 0;
2780 if (GEOSisEmpty_r (handle, g2) == 1)
2781 {
2782 GEOSGeom_destroy_r (handle, g2);
2783 return 0;
2784 }
2785 if (geom->DimensionModel == GAIA_XY_Z)
2786 geo = gaiaFromGeos_XYZ_r (cache, g2);
2787 else if (geom->DimensionModel == GAIA_XY_M)
2788 geo = gaiaFromGeos_XYM_r (cache, g2);
2789 else if (geom->DimensionModel == GAIA_XY_Z_M)
2790 geo = gaiaFromGeos_XYZM_r (cache, g2);
2791 else
2792 geo = gaiaFromGeos_XY_r (cache, g2);
2793 GEOSGeom_destroy_r (handle, g2);
2794 if (geo == NULL)
2795 return 0;
2796 if (geo->FirstPoint)
2797 {
2798 *x = geo->FirstPoint->X;
2799 *y = geo->FirstPoint->Y;
2800 gaiaFreeGeomColl (geo);
2801 return 1;
2802 }
2803 gaiaFreeGeomColl (geo);
2804 return 0;
2805 }
2806
2807 GAIAGEO_DECLARE int
gaiaGetPointOnSurface(gaiaGeomCollPtr geom,double * x,double * y)2808 gaiaGetPointOnSurface (gaiaGeomCollPtr geom, double *x, double *y)
2809 {
2810 /* returns a Point guaranteed to lie on the Surface */
2811 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2812 gaiaGeomCollPtr geo;
2813 GEOSGeometry *g1;
2814 GEOSGeometry *g2;
2815 gaiaResetGeosMsg ();
2816 if (!geom)
2817 return 0;
2818 if (gaiaIsToxic (geom))
2819 {
2820 return 0;
2821 }
2822 g1 = gaiaToGeos (geom);
2823 g2 = GEOSPointOnSurface (g1);
2824 GEOSGeom_destroy (g1);
2825 if (!g2)
2826 return 0;
2827 if (GEOSisEmpty (g2) == 1)
2828 {
2829 GEOSGeom_destroy (g2);
2830 return 0;
2831 }
2832 if (geom->DimensionModel == GAIA_XY_Z)
2833 geo = gaiaFromGeos_XYZ (g2);
2834 else if (geom->DimensionModel == GAIA_XY_M)
2835 geo = gaiaFromGeos_XYM (g2);
2836 else if (geom->DimensionModel == GAIA_XY_Z_M)
2837 geo = gaiaFromGeos_XYZM (g2);
2838 else
2839 geo = gaiaFromGeos_XY (g2);
2840 GEOSGeom_destroy (g2);
2841 if (geo == NULL)
2842 return 0;
2843 if (geo->FirstPoint)
2844 {
2845 *x = geo->FirstPoint->X;
2846 *y = geo->FirstPoint->Y;
2847 gaiaFreeGeomColl (geo);
2848 return 1;
2849 }
2850 gaiaFreeGeomColl (geo);
2851 #else
2852 if (geom == NULL || x == NULL || y == NULL)
2853 geom = NULL; /* silencing stupid compiler warnings */
2854 #endif
2855 return 0;
2856 }
2857
2858 GAIAGEO_DECLARE int
gaiaGetPointOnSurface_r(const void * p_cache,gaiaGeomCollPtr geom,double * x,double * y)2859 gaiaGetPointOnSurface_r (const void *p_cache, gaiaGeomCollPtr geom, double *x,
2860 double *y)
2861 {
2862 /* returns a Point guaranteed to lie on the Surface */
2863 gaiaGeomCollPtr geo;
2864 GEOSGeometry *g1;
2865 GEOSGeometry *g2;
2866 struct splite_internal_cache *cache =
2867 (struct splite_internal_cache *) p_cache;
2868 GEOSContextHandle_t handle = NULL;
2869 if (cache == NULL)
2870 return 0;
2871 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2872 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2873 return 0;
2874 handle = cache->GEOS_handle;
2875 if (handle == NULL)
2876 return 0;
2877 gaiaResetGeosMsg_r (cache);
2878 if (!geom)
2879 return 0;
2880 if (gaiaIsToxic_r (cache, geom))
2881 {
2882 return 0;
2883 }
2884 g1 = gaiaToGeos_r (cache, geom);
2885 g2 = GEOSPointOnSurface_r (handle, g1);
2886 GEOSGeom_destroy_r (handle, g1);
2887 if (!g2)
2888 return 0;
2889 if (GEOSisEmpty_r (handle, g2) == 1)
2890 {
2891 GEOSGeom_destroy_r (handle, g2);
2892 return 0;
2893 }
2894 if (geom->DimensionModel == GAIA_XY_Z)
2895 geo = gaiaFromGeos_XYZ_r (cache, g2);
2896 else if (geom->DimensionModel == GAIA_XY_M)
2897 geo = gaiaFromGeos_XYM_r (cache, g2);
2898 else if (geom->DimensionModel == GAIA_XY_Z_M)
2899 geo = gaiaFromGeos_XYZM_r (cache, g2);
2900 else
2901 geo = gaiaFromGeos_XYZ_r (cache, g2);
2902 GEOSGeom_destroy_r (handle, g2);
2903 if (geo == NULL)
2904 return 0;
2905 if (geo->FirstPoint)
2906 {
2907 *x = geo->FirstPoint->X;
2908 *y = geo->FirstPoint->Y;
2909 gaiaFreeGeomColl (geo);
2910 return 1;
2911 }
2912 gaiaFreeGeomColl (geo);
2913 return 0;
2914 }
2915
2916 GAIAGEO_DECLARE int
gaiaIsSimple(gaiaGeomCollPtr geom)2917 gaiaIsSimple (gaiaGeomCollPtr geom)
2918 {
2919 /* checks if this GEOMETRYCOLLECTION is a simple one */
2920 int ret = -1;
2921 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2922 GEOSGeometry *g;
2923 gaiaResetGeosMsg ();
2924 if (!geom)
2925 return -1;
2926 if (gaiaIsToxic (geom))
2927 return 0;
2928 g = gaiaToGeos (geom);
2929 ret = GEOSisSimple (g);
2930 GEOSGeom_destroy (g);
2931 if (ret == 2)
2932 return -1;
2933 #else
2934 if (geom == NULL)
2935 geom = NULL; /* silencing stupid compiler warnings */
2936 #endif
2937 return ret;
2938 }
2939
2940 GAIAGEO_DECLARE int
gaiaIsSimple_r(const void * p_cache,gaiaGeomCollPtr geom)2941 gaiaIsSimple_r (const void *p_cache, gaiaGeomCollPtr geom)
2942 {
2943 /* checks if this GEOMETRYCOLLECTION is a simple one */
2944 int ret;
2945 GEOSGeometry *g;
2946 struct splite_internal_cache *cache =
2947 (struct splite_internal_cache *) p_cache;
2948 GEOSContextHandle_t handle = NULL;
2949 if (cache == NULL)
2950 return -1;
2951 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2952 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2953 return -1;
2954 handle = cache->GEOS_handle;
2955 if (handle == NULL)
2956 return -1;
2957 gaiaResetGeosMsg_r (cache);
2958 if (!geom)
2959 return -1;
2960 if (gaiaIsToxic_r (cache, geom))
2961 return -1;
2962 g = gaiaToGeos_r (cache, geom);
2963 ret = GEOSisSimple_r (handle, g);
2964 GEOSGeom_destroy_r (handle, g);
2965 if (ret == 2)
2966 return -1;
2967 return ret;
2968 }
2969
2970 GAIAGEO_DECLARE int
gaiaIsRing(gaiaLinestringPtr line)2971 gaiaIsRing (gaiaLinestringPtr line)
2972 {
2973 /* checks if this LINESTRING can be a valid RING */
2974 int ret = -1;
2975 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
2976 gaiaGeomCollPtr geo;
2977 gaiaLinestringPtr line2;
2978 int iv;
2979 double x;
2980 double y;
2981 double z;
2982 double m;
2983 GEOSGeometry *g;
2984 gaiaResetGeosMsg ();
2985 if (!line)
2986 return -1;
2987 if (line->DimensionModel == GAIA_XY_Z)
2988 geo = gaiaAllocGeomCollXYZ ();
2989 else if (line->DimensionModel == GAIA_XY_M)
2990 geo = gaiaAllocGeomCollXYM ();
2991 else if (line->DimensionModel == GAIA_XY_Z_M)
2992 geo = gaiaAllocGeomCollXYZM ();
2993 else
2994 geo = gaiaAllocGeomColl ();
2995 line2 = gaiaAddLinestringToGeomColl (geo, line->Points);
2996 for (iv = 0; iv < line2->Points; iv++)
2997 {
2998 z = 0.0;
2999 m = 0.0;
3000 if (line->DimensionModel == GAIA_XY_Z)
3001 {
3002 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
3003 }
3004 else if (line->DimensionModel == GAIA_XY_M)
3005 {
3006 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3007 }
3008 else if (line->DimensionModel == GAIA_XY_Z_M)
3009 {
3010 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3011 }
3012 else
3013 {
3014 gaiaGetPoint (line->Coords, iv, &x, &y);
3015 }
3016 if (line2->DimensionModel == GAIA_XY_Z)
3017 {
3018 gaiaSetPointXYZ (line2->Coords, iv, x, y, z);
3019 }
3020 else if (line2->DimensionModel == GAIA_XY_M)
3021 {
3022 gaiaSetPointXYM (line2->Coords, iv, x, y, m);
3023 }
3024 else if (line2->DimensionModel == GAIA_XY_Z_M)
3025 {
3026 gaiaSetPointXYZM (line2->Coords, iv, x, y, z, m);
3027 }
3028 else
3029 {
3030 gaiaSetPoint (line2->Coords, iv, x, y);
3031 }
3032 }
3033 if (gaiaIsToxic (geo))
3034 {
3035 gaiaFreeGeomColl (geo);
3036 return -1;
3037 }
3038 g = gaiaToGeos (geo);
3039 gaiaFreeGeomColl (geo);
3040 ret = GEOSisRing (g);
3041 GEOSGeom_destroy (g);
3042 if (ret == 2)
3043 return -1;
3044 #else
3045 if (line == NULL)
3046 line = NULL; /* silencing stupid compiler warnings */
3047 #endif
3048 return ret;
3049 }
3050
3051 GAIAGEO_DECLARE int
gaiaIsRing_r(const void * p_cache,gaiaLinestringPtr line)3052 gaiaIsRing_r (const void *p_cache, gaiaLinestringPtr line)
3053 {
3054 /* checks if this LINESTRING can be a valid RING */
3055 gaiaGeomCollPtr geo;
3056 gaiaLinestringPtr line2;
3057 int ret;
3058 int iv;
3059 double x;
3060 double y;
3061 double z;
3062 double m;
3063 GEOSGeometry *g;
3064 struct splite_internal_cache *cache =
3065 (struct splite_internal_cache *) p_cache;
3066 GEOSContextHandle_t handle = NULL;
3067 if (cache == NULL)
3068 return -1;
3069 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3070 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3071 return -1;
3072 handle = cache->GEOS_handle;
3073 if (handle == NULL)
3074 return -1;
3075 gaiaResetGeosMsg_r (cache);
3076 if (!line)
3077 return -1;
3078 if (line->DimensionModel == GAIA_XY_Z)
3079 geo = gaiaAllocGeomCollXYZ ();
3080 else if (line->DimensionModel == GAIA_XY_M)
3081 geo = gaiaAllocGeomCollXYM ();
3082 else if (line->DimensionModel == GAIA_XY_Z_M)
3083 geo = gaiaAllocGeomCollXYZM ();
3084 else
3085 geo = gaiaAllocGeomColl ();
3086 line2 = gaiaAddLinestringToGeomColl (geo, line->Points);
3087 for (iv = 0; iv < line2->Points; iv++)
3088 {
3089 z = 0.0;
3090 m = 0.0;
3091 if (line->DimensionModel == GAIA_XY_Z)
3092 {
3093 gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
3094 }
3095 else if (line->DimensionModel == GAIA_XY_M)
3096 {
3097 gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3098 }
3099 else if (line->DimensionModel == GAIA_XY_Z_M)
3100 {
3101 gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3102 }
3103 else
3104 {
3105 gaiaGetPoint (line->Coords, iv, &x, &y);
3106 }
3107 if (line2->DimensionModel == GAIA_XY_Z)
3108 {
3109 gaiaSetPointXYZ (line2->Coords, iv, x, y, z);
3110 }
3111 else if (line2->DimensionModel == GAIA_XY_M)
3112 {
3113 gaiaSetPointXYM (line2->Coords, iv, x, y, m);
3114 }
3115 else if (line2->DimensionModel == GAIA_XY_Z_M)
3116 {
3117 gaiaSetPointXYZM (line2->Coords, iv, x, y, z, m);
3118 }
3119 else
3120 {
3121 gaiaSetPoint (line2->Coords, iv, x, y);
3122 }
3123 }
3124 if (gaiaIsToxic_r (cache, geo))
3125 {
3126 gaiaFreeGeomColl (geo);
3127 return -1;
3128 }
3129 g = gaiaToGeos_r (cache, geo);
3130 gaiaFreeGeomColl (geo);
3131 ret = GEOSisRing_r (handle, g);
3132 GEOSGeom_destroy_r (handle, g);
3133 if (ret == 2)
3134 return -1;
3135 return ret;
3136 }
3137
3138 GAIAGEO_DECLARE int
gaiaIsValid(gaiaGeomCollPtr geom)3139 gaiaIsValid (gaiaGeomCollPtr geom)
3140 {
3141 /* checks if this GEOMETRYCOLLECTION is a valid one */
3142 int ret = -1;
3143 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3144 GEOSGeometry *g;
3145 gaiaResetGeosMsg ();
3146 if (!geom)
3147 return -1;
3148 if (gaiaIsToxic (geom))
3149 return 0;
3150 if (gaiaIsNotClosedGeomColl (geom))
3151 return 0;
3152 g = gaiaToGeos (geom);
3153 ret = GEOSisValid (g);
3154 GEOSGeom_destroy (g);
3155 if (ret == 2)
3156 return -1;
3157 #else
3158 if (geom == NULL)
3159 geom = NULL; /* silencing stupid compiler warnings */
3160 #endif
3161 return ret;
3162 }
3163
3164 GAIAGEO_DECLARE int
gaiaIsValid_r(const void * p_cache,gaiaGeomCollPtr geom)3165 gaiaIsValid_r (const void *p_cache, gaiaGeomCollPtr geom)
3166 {
3167 /* checks if this GEOMETRYCOLLECTION is a valid one */
3168 int ret;
3169 GEOSGeometry *g;
3170 struct splite_internal_cache *cache =
3171 (struct splite_internal_cache *) p_cache;
3172 GEOSContextHandle_t handle = NULL;
3173 if (cache == NULL)
3174 return -1;
3175 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3176 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3177 return -1;
3178 handle = cache->GEOS_handle;
3179 if (handle == NULL)
3180 return -1;
3181 gaiaResetGeosMsg_r (cache);
3182 if (!geom)
3183 return -1;
3184 if (gaiaIsToxic_r (cache, geom))
3185 return 0;
3186 if (gaiaIsNotClosedGeomColl_r (cache, geom))
3187 return 0;
3188 g = gaiaToGeos_r (cache, geom);
3189 ret = GEOSisValid_r (handle, g);
3190 GEOSGeom_destroy_r (handle, g);
3191 if (ret == 2)
3192 return -1;
3193 return ret;
3194 }
3195
3196 GAIAGEO_DECLARE char *
gaiaIsValidReason(gaiaGeomCollPtr geom)3197 gaiaIsValidReason (gaiaGeomCollPtr geom)
3198 {
3199 /* return a TEXT string stating if a Geometry is valid
3200 / and if not valid, a reason why */
3201 char *text = NULL;
3202 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3203 int len;
3204 const char *str;
3205 char *gstr;
3206 GEOSGeometry *g;
3207 gaiaResetGeosMsg ();
3208 if (!geom)
3209 {
3210 str = "Invalid: NULL Geometry";
3211 len = strlen (str);
3212 text = malloc (len + 1);
3213 strcpy (text, str);
3214 return text;
3215 }
3216 if (gaiaIsToxic (geom))
3217 {
3218 str = "Invalid: Toxic Geometry ... too few points";
3219 len = strlen (str);
3220 text = malloc (len + 1);
3221 strcpy (text, str);
3222 return text;
3223 }
3224 if (gaiaIsNotClosedGeomColl (geom))
3225 {
3226 str = "Invalid: Unclosed Rings were detected";
3227 len = strlen (str);
3228 text = malloc (len + 1);
3229 strcpy (text, str);
3230 return text;
3231 }
3232 g = gaiaToGeos (geom);
3233 gstr = GEOSisValidReason (g);
3234 GEOSGeom_destroy (g);
3235 if (gstr == NULL)
3236 return NULL;
3237 len = strlen (gstr);
3238 text = malloc (len + 1);
3239 strcpy (text, gstr);
3240 GEOSFree (gstr);
3241 #else
3242 if (geom == NULL)
3243 geom = NULL; /* silencing stupid compiler warnings */
3244 #endif
3245 return text;
3246 }
3247
3248 GAIAGEO_DECLARE char *
gaiaIsValidReason_r(const void * p_cache,gaiaGeomCollPtr geom)3249 gaiaIsValidReason_r (const void *p_cache, gaiaGeomCollPtr geom)
3250 {
3251 /* return a TEXT string stating if a Geometry is valid
3252 / and if not valid, a reason why */
3253 char *text;
3254 int len;
3255 const char *str;
3256 char *gstr;
3257 GEOSGeometry *g;
3258 struct splite_internal_cache *cache =
3259 (struct splite_internal_cache *) p_cache;
3260 GEOSContextHandle_t handle = NULL;
3261 if (cache == NULL)
3262 return NULL;
3263 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3264 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3265 return NULL;
3266 handle = cache->GEOS_handle;
3267 if (handle == NULL)
3268 return NULL;
3269 gaiaResetGeosMsg_r (cache);
3270 if (!geom)
3271 {
3272 str = "Invalid: NULL Geometry";
3273 len = strlen (str);
3274 text = malloc (len + 1);
3275 strcpy (text, str);
3276 return text;
3277 }
3278 if (gaiaIsToxic_r (cache, geom))
3279 {
3280 str = "Invalid: Toxic Geometry ... too few points";
3281 len = strlen (str);
3282 text = malloc (len + 1);
3283 strcpy (text, str);
3284 return text;
3285 }
3286 if (gaiaIsNotClosedGeomColl_r (cache, geom))
3287 {
3288 str = "Invalid: Unclosed Rings were detected";
3289 len = strlen (str);
3290 text = malloc (len + 1);
3291 strcpy (text, str);
3292 return text;
3293 }
3294 g = gaiaToGeos_r (cache, geom);
3295 gstr = GEOSisValidReason_r (handle, g);
3296 GEOSGeom_destroy_r (handle, g);
3297 if (gstr == NULL)
3298 return NULL;
3299 len = strlen (gstr);
3300 text = malloc (len + 1);
3301 strcpy (text, gstr);
3302 GEOSFree_r (handle, gstr);
3303 return text;
3304 }
3305
3306 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaIsValidDetailEx(gaiaGeomCollPtr geom,int esri_flag)3307 gaiaIsValidDetailEx (gaiaGeomCollPtr geom, int esri_flag)
3308 {
3309 /* return a Geometry detail causing a Geometry to be invalid */
3310 gaiaGeomCollPtr detail = NULL;
3311 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3312 char *reason = NULL;
3313 GEOSGeometry *g;
3314 GEOSGeometry *d = NULL;
3315 gaiaResetGeosMsg ();
3316 if (!geom)
3317 return NULL;
3318 if (gaiaIsToxic (geom))
3319 return NULL;
3320 if (gaiaIsNotClosedGeomColl (geom))
3321 return NULL;
3322 g = gaiaToGeos (geom);
3323 if (esri_flag)
3324 esri_flag = GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE;
3325 GEOSisValidDetail (g, esri_flag, &reason, &d);
3326 GEOSGeom_destroy (g);
3327 if (reason != NULL)
3328 GEOSFree (reason);
3329 if (d == NULL)
3330 return NULL;
3331 detail = gaiaFromGeos_XY (d);
3332 GEOSGeom_destroy (d);
3333 #else
3334 if (geom == NULL && esri_flag == 0)
3335 geom = NULL; /* silencing stupid compiler warnings */
3336 #endif
3337 return detail;
3338 }
3339
3340 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaIsValidDetail(gaiaGeomCollPtr geom)3341 gaiaIsValidDetail (gaiaGeomCollPtr geom)
3342 {
3343 /* return a Geometry detail causing a Geometry to be invalid */
3344 return gaiaIsValidDetailEx (geom, 0);
3345 }
3346
3347 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaIsValidDetailEx_r(const void * p_cache,gaiaGeomCollPtr geom,int esri_flag)3348 gaiaIsValidDetailEx_r (const void *p_cache, gaiaGeomCollPtr geom, int esri_flag)
3349 {
3350 /* return a Geometry detail causing a Geometry to be invalid */
3351 char *reason = NULL;
3352 GEOSGeometry *g;
3353 GEOSGeometry *d = NULL;
3354 gaiaGeomCollPtr detail;
3355 struct splite_internal_cache *cache =
3356 (struct splite_internal_cache *) p_cache;
3357 GEOSContextHandle_t handle = NULL;
3358 if (cache == NULL)
3359 return NULL;
3360 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3361 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3362 return NULL;
3363 handle = cache->GEOS_handle;
3364 if (handle == NULL)
3365 return NULL;
3366 gaiaResetGeosMsg_r (cache);
3367 if (!geom)
3368 return NULL;
3369 if (gaiaIsToxic (geom))
3370 return NULL;
3371 if (gaiaIsNotClosedGeomColl_r (cache, geom))
3372 return NULL;
3373 g = gaiaToGeos_r (cache, geom);
3374 if (esri_flag)
3375 esri_flag = GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE;
3376 GEOSisValidDetail_r (handle, g, esri_flag, &reason, &d);
3377 GEOSGeom_destroy_r (handle, g);
3378 if (reason != NULL)
3379 GEOSFree_r (handle, reason);
3380 if (d == NULL)
3381 return NULL;
3382 detail = gaiaFromGeos_XY_r (cache, d);
3383 GEOSGeom_destroy_r (handle, d);
3384 return detail;
3385 }
3386
3387 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaIsValidDetail_r(const void * p_cache,gaiaGeomCollPtr geom)3388 gaiaIsValidDetail_r (const void *p_cache, gaiaGeomCollPtr geom)
3389 {
3390 /* return a Geometry detail causing a Geometry to be invalid */
3391 return gaiaIsValidDetailEx_r (p_cache, geom, 0);
3392 }
3393
3394 GAIAGEO_DECLARE int
gaiaIsClosedGeom_r(const void * cache,gaiaGeomCollPtr geom)3395 gaiaIsClosedGeom_r (const void *cache, gaiaGeomCollPtr geom)
3396 {
3397 /* checks if this geometry is a closed linestring (or multilinestring) */
3398 int ret = 0;
3399 gaiaLinestringPtr ln;
3400 if (cache != NULL)
3401 gaiaResetGeosMsg_r (cache);
3402 if (!geom)
3403 return -1;
3404 if (cache != NULL)
3405 ret = gaiaIsToxic_r (cache, geom);
3406 else
3407 ret = gaiaIsToxic (geom);
3408 if (ret)
3409 return 0;
3410 ln = geom->FirstLinestring;
3411 while (ln)
3412 {
3413 /* unhappily GEOS v3.2.2 [system package on Debian Lenny and Ubuntu 12.04]
3414 * doesn't exposes the GEOSisClosed() API at all !!!!
3415 *
3416 GEOSGeometry *g;
3417 gaiaGeomCollPtr geoColl = gaiaAllocGeomColl();
3418 gaiaInsertLinestringInGeomColl(geoColl, gaiaCloneLinestring(ln));
3419 g = gaiaToGeos (geoColl);
3420 ret = GEOSisClosed (g);
3421 GEOSGeom_destroy (g);
3422 gaiaFreeGeomColl(geoColl);
3423 */
3424
3425 /* so we'll use this internal default in order to circumvent the above issue */
3426 double x1;
3427 double y1;
3428 double z1;
3429 double m1;
3430 double x2;
3431 double y2;
3432 double z2;
3433 double m2;
3434 gaiaLineGetPoint (ln, 0, &x1, &y1, &z1, &m1);
3435 gaiaLineGetPoint (ln, ln->Points - 1, &x2, &y2, &z2, &m2);
3436 if (x1 == x2 && y1 == y2 && z1 == z2)
3437 ret = 1;
3438 else
3439 ret = 0;
3440 if (ret == 0)
3441 {
3442 /* this line isn't closed, so we don't need to continue */
3443 break;
3444 }
3445 ln = ln->Next;
3446 }
3447 if (ret == 2)
3448 return -1;
3449 return ret;
3450 }
3451
3452 GAIAGEO_DECLARE int
gaiaIsClosedGeom(gaiaGeomCollPtr geom)3453 gaiaIsClosedGeom (gaiaGeomCollPtr geom)
3454 {
3455 gaiaResetGeosMsg ();
3456 return gaiaIsClosedGeom_r (NULL, geom);
3457 }
3458
3459 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollSimplify(gaiaGeomCollPtr geom,double tolerance)3460 gaiaGeomCollSimplify (gaiaGeomCollPtr geom, double tolerance)
3461 {
3462 /* builds a simplified geometry using the Douglas-Peuker algorihtm */
3463 gaiaGeomCollPtr geo = NULL;
3464 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3465 GEOSGeometry *g1;
3466 GEOSGeometry *g2;
3467 gaiaResetGeosMsg ();
3468 if (!geom)
3469 return NULL;
3470 if (gaiaIsToxic (geom))
3471 return NULL;
3472 g1 = gaiaToGeos (geom);
3473 g2 = GEOSSimplify (g1, tolerance);
3474 GEOSGeom_destroy (g1);
3475 if (!g2)
3476 return NULL;
3477 if (GEOSisEmpty (g2) == 1)
3478 {
3479 GEOSGeom_destroy (g2);
3480 return NULL;
3481 }
3482 if (geom->DimensionModel == GAIA_XY_Z)
3483 geo = gaiaFromGeos_XYZ (g2);
3484 else if (geom->DimensionModel == GAIA_XY_M)
3485 geo = gaiaFromGeos_XYM (g2);
3486 else if (geom->DimensionModel == GAIA_XY_Z_M)
3487 geo = gaiaFromGeos_XYZM (g2);
3488 else
3489 geo = gaiaFromGeos_XY (g2);
3490 GEOSGeom_destroy (g2);
3491 if (geo == NULL)
3492 return NULL;
3493 geo->Srid = geom->Srid;
3494 #else
3495 if (geom == NULL || tolerance == 0.0)
3496 geom = NULL; /* silencing stupid compiler warnings */
3497 #endif
3498 return geo;
3499 }
3500
3501 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollSimplify_r(const void * p_cache,gaiaGeomCollPtr geom,double tolerance)3502 gaiaGeomCollSimplify_r (const void *p_cache, gaiaGeomCollPtr geom,
3503 double tolerance)
3504 {
3505 /* builds a simplified geometry using the Douglas-Peuker algorihtm */
3506 gaiaGeomCollPtr geo;
3507 GEOSGeometry *g1;
3508 GEOSGeometry *g2;
3509 struct splite_internal_cache *cache =
3510 (struct splite_internal_cache *) p_cache;
3511 GEOSContextHandle_t handle = NULL;
3512 if (cache == NULL)
3513 return NULL;
3514 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3515 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3516 return NULL;
3517 handle = cache->GEOS_handle;
3518 if (handle == NULL)
3519 return NULL;
3520 gaiaResetGeosMsg_r (cache);
3521 if (!geom)
3522 return NULL;
3523 if (gaiaIsToxic_r (cache, geom))
3524 return NULL;
3525 g1 = gaiaToGeos_r (cache, geom);
3526 g2 = GEOSSimplify_r (handle, g1, tolerance);
3527 GEOSGeom_destroy_r (handle, g1);
3528 if (!g2)
3529 return NULL;
3530 if (GEOSisEmpty_r (handle, g2) == 1)
3531 {
3532 GEOSGeom_destroy_r (handle, g2);
3533 return NULL;
3534 }
3535 if (geom->DimensionModel == GAIA_XY_Z)
3536 geo = gaiaFromGeos_XYZ_r (cache, g2);
3537 else if (geom->DimensionModel == GAIA_XY_M)
3538 geo = gaiaFromGeos_XYM_r (cache, g2);
3539 else if (geom->DimensionModel == GAIA_XY_Z_M)
3540 geo = gaiaFromGeos_XYZM_r (cache, g2);
3541 else
3542 geo = gaiaFromGeos_XY_r (cache, g2);
3543 GEOSGeom_destroy_r (handle, g2);
3544 if (geo == NULL)
3545 return NULL;
3546 geo->Srid = geom->Srid;
3547 return geo;
3548 }
3549
3550 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollSimplifyPreserveTopology(gaiaGeomCollPtr geom,double tolerance)3551 gaiaGeomCollSimplifyPreserveTopology (gaiaGeomCollPtr geom, double tolerance)
3552 {
3553 /* builds a simplified geometry using the Douglas-Peuker algorihtm [preserving topology] */
3554 gaiaGeomCollPtr geo = NULL;
3555 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3556 GEOSGeometry *g1;
3557 GEOSGeometry *g2;
3558 gaiaResetGeosMsg ();
3559 if (!geom)
3560 return NULL;
3561 if (gaiaIsToxic (geom))
3562 return NULL;
3563 g1 = gaiaToGeos (geom);
3564 g2 = GEOSTopologyPreserveSimplify (g1, tolerance);
3565 GEOSGeom_destroy (g1);
3566 if (!g2)
3567 return NULL;
3568 if (GEOSisEmpty (g2) == 1)
3569 {
3570 GEOSGeom_destroy (g2);
3571 return NULL;
3572 }
3573 if (geom->DimensionModel == GAIA_XY_Z)
3574 geo = gaiaFromGeos_XYZ (g2);
3575 else if (geom->DimensionModel == GAIA_XY_M)
3576 geo = gaiaFromGeos_XYM (g2);
3577 else if (geom->DimensionModel == GAIA_XY_Z_M)
3578 geo = gaiaFromGeos_XYZM (g2);
3579 else
3580 geo = gaiaFromGeos_XY (g2);
3581 GEOSGeom_destroy (g2);
3582 if (geo == NULL)
3583 return NULL;
3584 geo->Srid = geom->Srid;
3585 #else
3586 if (geom == NULL || tolerance == 0.0)
3587 geom = NULL; /* silencing stupid compiler warnings */
3588 #endif
3589 return geo;
3590 }
3591
3592 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollSimplifyPreserveTopology_r(const void * p_cache,gaiaGeomCollPtr geom,double tolerance)3593 gaiaGeomCollSimplifyPreserveTopology_r (const void *p_cache,
3594 gaiaGeomCollPtr geom, double tolerance)
3595 {
3596 /* builds a simplified geometry using the Douglas-Peuker algorihtm [preserving topology] */
3597 gaiaGeomCollPtr geo;
3598 GEOSGeometry *g1;
3599 GEOSGeometry *g2;
3600 struct splite_internal_cache *cache =
3601 (struct splite_internal_cache *) p_cache;
3602 GEOSContextHandle_t handle = NULL;
3603 if (cache == NULL)
3604 return NULL;
3605 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3606 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3607 return NULL;
3608 handle = cache->GEOS_handle;
3609 if (handle == NULL)
3610 return NULL;
3611 gaiaResetGeosMsg_r (cache);
3612 if (!geom)
3613 return NULL;
3614 if (gaiaIsToxic_r (cache, geom))
3615 return NULL;
3616 g1 = gaiaToGeos_r (cache, geom);
3617 g2 = GEOSTopologyPreserveSimplify_r (handle, g1, tolerance);
3618 GEOSGeom_destroy_r (handle, g1);
3619 if (!g2)
3620 return NULL;
3621 if (GEOSisEmpty_r (handle, g2) == 1)
3622 {
3623 GEOSGeom_destroy_r (handle, g2);
3624 return NULL;
3625 }
3626 if (geom->DimensionModel == GAIA_XY_Z)
3627 geo = gaiaFromGeos_XYZ_r (cache, g2);
3628 else if (geom->DimensionModel == GAIA_XY_M)
3629 geo = gaiaFromGeos_XYM_r (cache, g2);
3630 else if (geom->DimensionModel == GAIA_XY_Z_M)
3631 geo = gaiaFromGeos_XYZM_r (cache, g2);
3632 else
3633 geo = gaiaFromGeos_XY_r (cache, g2);
3634 GEOSGeom_destroy_r (handle, g2);
3635 if (geo == NULL)
3636 return NULL;
3637 geo->Srid = geom->Srid;
3638 return geo;
3639 }
3640
3641 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaConvexHull(gaiaGeomCollPtr geom)3642 gaiaConvexHull (gaiaGeomCollPtr geom)
3643 {
3644 /* builds a geometry that is the convex hull of GEOM */
3645 gaiaGeomCollPtr geo = NULL;
3646 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3647 GEOSGeometry *g1;
3648 GEOSGeometry *g2;
3649 gaiaResetGeosMsg ();
3650 if (!geom)
3651 return NULL;
3652 if (gaiaIsToxic (geom))
3653 return NULL;
3654 g1 = gaiaToGeos (geom);
3655 g2 = GEOSConvexHull (g1);
3656 GEOSGeom_destroy (g1);
3657 if (!g2)
3658 return NULL;
3659 if (GEOSisEmpty (g2) == 1)
3660 {
3661 GEOSGeom_destroy (g2);
3662 return NULL;
3663 }
3664 if (geom->DimensionModel == GAIA_XY_Z)
3665 geo = gaiaFromGeos_XYZ (g2);
3666 else if (geom->DimensionModel == GAIA_XY_M)
3667 geo = gaiaFromGeos_XYM (g2);
3668 else if (geom->DimensionModel == GAIA_XY_Z_M)
3669 geo = gaiaFromGeos_XYZM (g2);
3670 else
3671 geo = gaiaFromGeos_XY (g2);
3672 GEOSGeom_destroy (g2);
3673 if (geo == NULL)
3674 return NULL;
3675 geo->Srid = geom->Srid;
3676 #else
3677 if (geom == NULL)
3678 geom = NULL; /* silencing stupid compiler warnings */
3679 #endif
3680 return geo;
3681 }
3682
3683 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaConvexHull_r(const void * p_cache,gaiaGeomCollPtr geom)3684 gaiaConvexHull_r (const void *p_cache, gaiaGeomCollPtr geom)
3685 {
3686 /* builds a geometry that is the convex hull of GEOM */
3687 gaiaGeomCollPtr geo;
3688 GEOSGeometry *g1;
3689 GEOSGeometry *g2;
3690 struct splite_internal_cache *cache =
3691 (struct splite_internal_cache *) p_cache;
3692 GEOSContextHandle_t handle = NULL;
3693 if (cache == NULL)
3694 return NULL;
3695 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3696 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3697 return NULL;
3698 handle = cache->GEOS_handle;
3699 if (handle == NULL)
3700 return NULL;
3701 gaiaResetGeosMsg_r (cache);
3702 if (!geom)
3703 return NULL;
3704 if (gaiaIsToxic_r (cache, geom))
3705 return NULL;
3706 g1 = gaiaToGeos_r (cache, geom);
3707 g2 = GEOSConvexHull_r (handle, g1);
3708 GEOSGeom_destroy_r (handle, g1);
3709 if (!g2)
3710 return NULL;
3711 if (GEOSisEmpty_r (handle, g2) == 1)
3712 {
3713 GEOSGeom_destroy_r (handle, g2);
3714 return NULL;
3715 }
3716 if (geom->DimensionModel == GAIA_XY_Z)
3717 geo = gaiaFromGeos_XYZ_r (cache, g2);
3718 else if (geom->DimensionModel == GAIA_XY_M)
3719 geo = gaiaFromGeos_XYM_r (cache, g2);
3720 else if (geom->DimensionModel == GAIA_XY_Z_M)
3721 geo = gaiaFromGeos_XYZM_r (cache, g2);
3722 else
3723 geo = gaiaFromGeos_XY_r (cache, g2);
3724 GEOSGeom_destroy_r (handle, g2);
3725 if (geo == NULL)
3726 return NULL;
3727 geo->Srid = geom->Srid;
3728 return geo;
3729 }
3730
3731 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollBuffer(gaiaGeomCollPtr geom,double radius,int points)3732 gaiaGeomCollBuffer (gaiaGeomCollPtr geom, double radius, int points)
3733 {
3734 /* builds a geometry that is the GIS buffer of GEOM */
3735 gaiaGeomCollPtr geo = NULL;
3736 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3737 GEOSGeometry *g1;
3738 GEOSGeometry *g2;
3739 GEOSBufferParams *params = NULL;
3740 gaiaResetGeosMsg ();
3741 if (!geom)
3742 return NULL;
3743 if (gaiaIsToxic (geom))
3744 return NULL;
3745 g1 = gaiaToGeos (geom);
3746 /* setting up Buffer params */
3747 params = GEOSBufferParams_create ();
3748 GEOSBufferParams_setEndCapStyle (params, GEOSBUF_CAP_ROUND);
3749 GEOSBufferParams_setJoinStyle (params, GEOSBUF_JOIN_ROUND);
3750 GEOSBufferParams_setMitreLimit (params, 5.0);
3751 GEOSBufferParams_setQuadrantSegments (params, points);
3752 GEOSBufferParams_setSingleSided (params, 0);
3753
3754 g2 = GEOSBufferWithParams (g1, params, radius);
3755 GEOSGeom_destroy (g1);
3756 GEOSBufferParams_destroy (params);
3757 if (!g2)
3758 return NULL;
3759 if (GEOSisEmpty (g2) == 1)
3760 {
3761 GEOSGeom_destroy (g2);
3762 return NULL;
3763 }
3764 if (geom->DimensionModel == GAIA_XY_Z)
3765 geo = gaiaFromGeos_XYZ (g2);
3766 else if (geom->DimensionModel == GAIA_XY_M)
3767 geo = gaiaFromGeos_XYM (g2);
3768 else if (geom->DimensionModel == GAIA_XY_Z_M)
3769 geo = gaiaFromGeos_XYZM (g2);
3770 else
3771 geo = gaiaFromGeos_XY (g2);
3772 GEOSGeom_destroy (g2);
3773 if (geo == NULL)
3774 return NULL;
3775 geo->Srid = geom->Srid;
3776 #else
3777 if (geom == NULL || radius == 0.0 || points == 0)
3778 geom = NULL; /* silencing stupid compiler warnings */
3779 #endif
3780 return geo;
3781 }
3782
3783 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaGeomCollBuffer_r(const void * p_cache,gaiaGeomCollPtr geom,double radius,int points)3784 gaiaGeomCollBuffer_r (const void *p_cache, gaiaGeomCollPtr geom, double radius,
3785 int points)
3786 {
3787 /* builds a geometry that is the GIS buffer of GEOM */
3788 gaiaGeomCollPtr geo;
3789 GEOSGeometry *g1;
3790 GEOSGeometry *g2;
3791 GEOSBufferParams *params = NULL;
3792 struct splite_internal_cache *cache =
3793 (struct splite_internal_cache *) p_cache;
3794 GEOSContextHandle_t handle = NULL;
3795 int quadsegs = 30;
3796 if (cache == NULL)
3797 return NULL;
3798 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3799 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3800 return NULL;
3801 handle = cache->GEOS_handle;
3802 if (handle == NULL)
3803 return NULL;
3804 gaiaResetGeosMsg_r (cache);
3805 if (!geom)
3806 return NULL;
3807 if (gaiaIsToxic_r (cache, geom))
3808 return NULL;
3809 g1 = gaiaToGeos_r (cache, geom);
3810 /* setting up Buffer params */
3811 params = GEOSBufferParams_create_r (handle);
3812 GEOSBufferParams_setEndCapStyle_r (handle, params,
3813 cache->buffer_end_cap_style);
3814 GEOSBufferParams_setJoinStyle_r (handle, params, cache->buffer_join_style);
3815 GEOSBufferParams_setMitreLimit_r (handle, params,
3816 cache->buffer_mitre_limit);
3817 if (points > 0)
3818 quadsegs = points;
3819 else if (cache->buffer_quadrant_segments > 0)
3820 quadsegs = cache->buffer_quadrant_segments;
3821 GEOSBufferParams_setQuadrantSegments_r (handle, params, quadsegs);
3822 GEOSBufferParams_setSingleSided_r (handle, params, 0);
3823
3824 g2 = GEOSBufferWithParams_r (handle, g1, params, radius);
3825 GEOSGeom_destroy_r (handle, g1);
3826 GEOSBufferParams_destroy_r (handle, params);
3827 if (!g2)
3828 return NULL;
3829 if (GEOSisEmpty_r (handle, g2) == 1)
3830 {
3831 GEOSGeom_destroy_r (handle, g2);
3832 return NULL;
3833 }
3834 if (geom->DimensionModel == GAIA_XY_Z)
3835 geo = gaiaFromGeos_XYZ_r (cache, g2);
3836 else if (geom->DimensionModel == GAIA_XY_M)
3837 geo = gaiaFromGeos_XYM_r (cache, g2);
3838 else if (geom->DimensionModel == GAIA_XY_Z_M)
3839 geo = gaiaFromGeos_XYZM_r (cache, g2);
3840 else
3841 geo = gaiaFromGeos_XY_r (cache, g2);
3842 GEOSGeom_destroy_r (handle, g2);
3843 if (geo == NULL)
3844 return NULL;
3845 geo->Srid = geom->Srid;
3846 return geo;
3847 }
3848
3849 static void
auxFromGeosPolygon(GEOSContextHandle_t handle,const GEOSGeometry * geos,gaiaGeomCollPtr result)3850 auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos,
3851 gaiaGeomCollPtr result)
3852 {
3853 /* converting a Polygon from GEOS to SpatiaLite */
3854 const GEOSGeometry *geos_ring;
3855 const GEOSCoordSequence *coords;
3856 unsigned int pts;
3857 unsigned int geos_dims;
3858 int interiors;
3859 int iv;
3860 int ib;
3861 double x;
3862 double y;
3863 double z;
3864 gaiaPolygonPtr pg;
3865 gaiaRingPtr rng;
3866
3867 #ifdef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3868 if (handle == NULL)
3869 return;
3870 #endif
3871
3872 if (handle != NULL)
3873 {
3874 geos_ring = GEOSGetExteriorRing_r (handle, geos);
3875 interiors = GEOSGetNumInteriorRings_r (handle, geos);
3876 coords = GEOSGeom_getCoordSeq_r (handle, geos_ring);
3877 GEOSCoordSeq_getDimensions_r (handle, coords, &geos_dims);
3878 GEOSCoordSeq_getSize_r (handle, coords, &pts);
3879 }
3880 else
3881 {
3882 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3883 geos_ring = GEOSGetExteriorRing (geos);
3884 interiors = GEOSGetNumInteriorRings (geos);
3885 coords = GEOSGeom_getCoordSeq (geos_ring);
3886 GEOSCoordSeq_getDimensions (coords, &geos_dims);
3887 GEOSCoordSeq_getSize (coords, &pts);
3888 #endif
3889 }
3890
3891 pg = gaiaAddPolygonToGeomColl (result, pts, interiors);
3892 /* setting up the Exterior ring */
3893 rng = pg->Exterior;
3894 for (iv = 0; iv < (int) pts; iv++)
3895 {
3896 if (geos_dims == 3)
3897 {
3898 if (handle != NULL)
3899 {
3900 GEOSCoordSeq_getX_r (handle, coords, iv, &x);
3901 GEOSCoordSeq_getY_r (handle, coords, iv, &y);
3902 GEOSCoordSeq_getZ_r (handle, coords, iv, &z);
3903 }
3904 else
3905 {
3906 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3907 GEOSCoordSeq_getX (coords, iv, &x);
3908 GEOSCoordSeq_getY (coords, iv, &y);
3909 GEOSCoordSeq_getZ (coords, iv, &z);
3910 #endif
3911 }
3912 }
3913 else
3914 {
3915 if (handle != NULL)
3916 {
3917 GEOSCoordSeq_getX_r (handle, coords, iv, &x);
3918 GEOSCoordSeq_getY_r (handle, coords, iv, &y);
3919 }
3920 else
3921 {
3922 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3923 GEOSCoordSeq_getX (coords, iv, &x);
3924 GEOSCoordSeq_getY (coords, iv, &y);
3925 #endif
3926 }
3927 z = 0.0;
3928 }
3929 if (rng->DimensionModel == GAIA_XY_Z)
3930 {
3931 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
3932 }
3933 else if (rng->DimensionModel == GAIA_XY_M)
3934 {
3935 gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0);
3936 }
3937 else if (rng->DimensionModel == GAIA_XY_Z_M)
3938 {
3939 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0);
3940 }
3941 else
3942 {
3943 gaiaSetPoint (rng->Coords, iv, x, y);
3944 }
3945 }
3946
3947 for (ib = 0; ib < interiors; ib++)
3948 {
3949 /* setting up any interior ring */
3950 if (handle != NULL)
3951 {
3952 geos_ring = GEOSGetInteriorRingN_r (handle, geos, ib);
3953 coords = GEOSGeom_getCoordSeq_r (handle, geos_ring);
3954 GEOSCoordSeq_getDimensions_r (handle, coords, &geos_dims);
3955 GEOSCoordSeq_getSize_r (handle, coords, &pts);
3956 }
3957 else
3958 {
3959 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3960 geos_ring = GEOSGetInteriorRingN (geos, ib);
3961 coords = GEOSGeom_getCoordSeq (geos_ring);
3962 GEOSCoordSeq_getDimensions (coords, &geos_dims);
3963 GEOSCoordSeq_getSize (coords, &pts);
3964 #endif
3965 }
3966 rng = gaiaAddInteriorRing (pg, ib, pts);
3967 for (iv = 0; iv < (int) pts; iv++)
3968 {
3969 if (geos_dims == 3)
3970 {
3971 if (handle != NULL)
3972 {
3973 GEOSCoordSeq_getX_r (handle, coords, iv, &x);
3974 GEOSCoordSeq_getY_r (handle, coords, iv, &y);
3975 GEOSCoordSeq_getZ_r (handle, coords, iv, &z);
3976 }
3977 else
3978 {
3979 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3980 GEOSCoordSeq_getX (coords, iv, &x);
3981 GEOSCoordSeq_getY (coords, iv, &y);
3982 GEOSCoordSeq_getZ (coords, iv, &z);
3983 #endif
3984 }
3985 }
3986 else
3987 {
3988 if (handle != NULL)
3989 {
3990 GEOSCoordSeq_getX_r (handle, coords, iv, &x);
3991 GEOSCoordSeq_getY_r (handle, coords, iv, &y);
3992 }
3993 else
3994 {
3995 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
3996 GEOSCoordSeq_getX (coords, iv, &x);
3997 GEOSCoordSeq_getY (coords, iv, &y);
3998 #endif
3999 }
4000 z = 0.0;
4001 }
4002 if (rng->DimensionModel == GAIA_XY_Z)
4003 {
4004 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
4005 }
4006 else if (rng->DimensionModel == GAIA_XY_M)
4007 {
4008 gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0);
4009 }
4010 else if (rng->DimensionModel == GAIA_XY_Z_M)
4011 {
4012 gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0);
4013 }
4014 else
4015 {
4016 gaiaSetPoint (rng->Coords, iv, x, y);
4017 }
4018 }
4019 }
4020 }
4021
4022 static void
auxGeosMbr(GEOSContextHandle_t handle,const GEOSCoordSequence * cs,unsigned int pts,double * min_x,double * min_y,double * max_x,double * max_y)4023 auxGeosMbr (GEOSContextHandle_t handle, const GEOSCoordSequence * cs,
4024 unsigned int pts, double *min_x, double *min_y, double *max_x,
4025 double *max_y)
4026 {
4027 /* computing the MBR */
4028 int iv;
4029 double x;
4030 double y;
4031 *min_x = DBL_MAX;
4032 *min_y = DBL_MAX;
4033 *max_x = 0 - DBL_MAX;
4034 *max_y = 0 - DBL_MAX;
4035 for (iv = 0; iv < (int) pts; iv++)
4036 {
4037 if (handle != NULL)
4038 {
4039 GEOSCoordSeq_getX_r (handle, cs, iv, &x);
4040 GEOSCoordSeq_getY_r (handle, cs, iv, &y);
4041 }
4042 else
4043 {
4044 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4045 GEOSCoordSeq_getX (cs, iv, &x);
4046 GEOSCoordSeq_getY (cs, iv, &y);
4047 #endif
4048 }
4049 if (x < *min_x)
4050 *min_x = x;
4051 if (x > *max_x)
4052 *max_x = x;
4053 if (y < *min_y)
4054 *min_y = y;
4055 if (y > *max_y)
4056 *max_y = y;
4057 }
4058 }
4059
4060 static gaiaGeomCollPtr
gaiaPolygonizeCommon(const void * cache,GEOSContextHandle_t handle,gaiaGeomCollPtr geom,int force_multi)4061 gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle,
4062 gaiaGeomCollPtr geom, int force_multi)
4063 {
4064 /* attempts to rearrange a generic Geometry into a (multi)polygon */
4065 int ig;
4066 int ib;
4067 int iv;
4068 int interiors;
4069 int geos_dims = 2;
4070 int pts = 0;
4071 int lns = 0;
4072 int pgs = 0;
4073 int items;
4074 int error = 0;
4075 double x;
4076 double y;
4077 double z;
4078 double m;
4079 gaiaGeomCollPtr result = NULL;
4080 gaiaPointPtr pt;
4081 gaiaLinestringPtr ln;
4082 gaiaPolygonPtr pg;
4083 GEOSCoordSequence *cs;
4084 const GEOSGeometry *const *geos_list = NULL;
4085 GEOSGeometry **p_item;
4086 GEOSGeometry *geos;
4087 const GEOSGeometry *geos_item;
4088 const GEOSGeometry *geos_item2;
4089 const GEOSGeometry *geos_ring;
4090 char *valid_polygons = NULL;
4091 const GEOSCoordSequence *coords;
4092 unsigned int pts1;
4093 unsigned int pts2;
4094 double min_x1;
4095 double max_x1;
4096 double min_y1;
4097 double max_y1;
4098 double min_x2;
4099 double max_x2;
4100 double min_y2;
4101 double max_y2;
4102 int ret;
4103
4104 #ifdef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4105 if (handle == NULL)
4106 return NULL;
4107 #endif
4108 if (!geom)
4109 return NULL;
4110
4111 if (cache != NULL)
4112 ret = gaiaIsToxic_r (cache, geom);
4113 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4114 else
4115 ret = gaiaIsToxic (geom);
4116 #endif
4117 if (ret)
4118 return NULL;
4119
4120 pt = geom->FirstPoint;
4121 while (pt)
4122 {
4123 pts++;
4124 pt = pt->Next;
4125 }
4126 pg = geom->FirstPolygon;
4127 while (pg)
4128 {
4129 pgs++;
4130 pg = pg->Next;
4131 }
4132 if (pts || pgs)
4133 return NULL;
4134 ln = geom->FirstLinestring;
4135 while (ln)
4136 {
4137 lns++;
4138 ln = ln->Next;
4139 }
4140 if (!lns)
4141 return NULL;
4142 if (geom->DimensionModel == GAIA_XY_Z
4143 || geom->DimensionModel == GAIA_XY_Z_M)
4144 geos_dims = 3;
4145
4146 /* allocating GEOS linestrings */
4147 geos_list = malloc (sizeof (const GEOSGeometry * const *) * lns);
4148 p_item = (GEOSGeometry **) geos_list;
4149 for (iv = 0; iv < lns; iv++)
4150 {
4151 /* initializing to NULL */
4152 *p_item++ = NULL;
4153 }
4154 p_item = (GEOSGeometry **) geos_list;
4155
4156 /* initializing GEOS linestrings */
4157 ln = geom->FirstLinestring;
4158 while (ln)
4159 {
4160 if (handle != NULL)
4161 cs = GEOSCoordSeq_create_r (handle, ln->Points, geos_dims);
4162 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4163 else
4164 cs = GEOSCoordSeq_create (ln->Points, geos_dims);
4165 #endif
4166 for (iv = 0; iv < ln->Points; iv++)
4167 {
4168 /* exterior ring segments */
4169 z = 0.0;
4170 if (ln->DimensionModel == GAIA_XY_Z)
4171 {
4172 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4173 }
4174 else if (ln->DimensionModel == GAIA_XY_M)
4175 {
4176 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4177 }
4178 else if (ln->DimensionModel == GAIA_XY_Z_M)
4179 {
4180 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4181 }
4182 else
4183 {
4184 gaiaGetPoint (ln->Coords, iv, &x, &y);
4185 }
4186 if (geos_dims == 3)
4187 {
4188 if (handle != NULL)
4189 {
4190 GEOSCoordSeq_setX_r (handle, cs, iv, x);
4191 GEOSCoordSeq_setY_r (handle, cs, iv, y);
4192 GEOSCoordSeq_setZ_r (handle, cs, iv, z);
4193 }
4194 else
4195 {
4196 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4197 GEOSCoordSeq_setX (cs, iv, x);
4198 GEOSCoordSeq_setY (cs, iv, y);
4199 GEOSCoordSeq_setZ (cs, iv, z);
4200 #endif
4201 }
4202 }
4203 else
4204 {
4205 if (handle != NULL)
4206 {
4207 GEOSCoordSeq_setX_r (handle, cs, iv, x);
4208 GEOSCoordSeq_setY_r (handle, cs, iv, y);
4209 }
4210 else
4211 {
4212 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4213 GEOSCoordSeq_setX (cs, iv, x);
4214 GEOSCoordSeq_setY (cs, iv, y);
4215 #endif
4216 }
4217 }
4218 }
4219 if (handle != NULL)
4220 *p_item++ = GEOSGeom_createLineString_r (handle, cs);
4221 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4222 else
4223 *p_item++ = GEOSGeom_createLineString (cs);
4224 #endif
4225 ln = ln->Next;
4226 }
4227
4228 /* calling GEOSPolygonize */
4229 if (handle != NULL)
4230 geos = GEOSPolygonize_r (handle, geos_list, lns);
4231 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4232 else
4233 geos = GEOSPolygonize (geos_list, lns);
4234 #endif
4235 if (geos == NULL)
4236 goto cleanup;
4237
4238 /*
4239 /
4240 / GEOSPolygonize is expected to return a collection of Polygons
4241 /
4242 / CAVEAT: internal holes are returned as such (interior rings in
4243 / some Polygon), but are returned as distinct Polygons too
4244 /
4245 / we must check this, so to *not* return Polygons representing holes
4246 /
4247 */
4248 error = 0;
4249 if (handle != NULL)
4250 items = GEOSGetNumGeometries_r (handle, geos);
4251 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4252 else
4253 items = GEOSGetNumGeometries (geos);
4254 #endif
4255 for (ig = 0; ig < items; ig++)
4256 {
4257 /* looping on elementaty GEOS geometries */
4258 if (handle != NULL)
4259 {
4260 geos_item = GEOSGetGeometryN_r (handle, geos, ig);
4261 if (GEOSGeomTypeId_r (handle, geos_item) != GEOS_POLYGON)
4262 {
4263 /* not a Polygon ... ouch ... */
4264 error = 1;
4265 goto cleanup;
4266 }
4267 }
4268 else
4269 {
4270 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4271 geos_item = GEOSGetGeometryN (geos, ig);
4272 if (GEOSGeomTypeId (geos_item) != GEOS_POLYGON)
4273 {
4274 /* not a Polygon ... ouch ... */
4275 error = 1;
4276 goto cleanup;
4277 }
4278 #endif
4279 }
4280 }
4281
4282 /* identifying valid Polygons [excluding holes] */
4283 valid_polygons = malloc (sizeof (char *) * items);
4284 for (ig = 0; ig < items; ig++)
4285 valid_polygons[ig] = 'Y';
4286 for (ig = 0; ig < items; ig++)
4287 {
4288 /* looping on elementaty GEOS Polygons */
4289 if (handle != NULL)
4290 {
4291 geos_item = GEOSGetGeometryN_r (handle, geos, ig);
4292 interiors = GEOSGetNumInteriorRings_r (handle, geos_item);
4293 }
4294 else
4295 {
4296 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4297 geos_item = GEOSGetGeometryN (geos, ig);
4298 interiors = GEOSGetNumInteriorRings (geos_item);
4299 #endif
4300 }
4301 for (ib = 0; ib < interiors; ib++)
4302 {
4303 /* looping on any interior ring */
4304 if (handle != NULL)
4305 {
4306 geos_ring =
4307 GEOSGetInteriorRingN_r (handle, geos_item, ib);
4308 coords = GEOSGeom_getCoordSeq_r (handle, geos_ring);
4309 GEOSCoordSeq_getSize_r (handle, coords, &pts1);
4310 }
4311 else
4312 {
4313 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4314 geos_ring = GEOSGetInteriorRingN (geos_item, ib);
4315 coords = GEOSGeom_getCoordSeq (geos_ring);
4316 GEOSCoordSeq_getSize (coords, &pts1);
4317 #endif
4318 }
4319 auxGeosMbr (handle, coords, pts1, &min_x1, &min_y1, &max_x1,
4320 &max_y1);
4321 for (iv = 0; iv < items; iv++)
4322 {
4323 if (iv == ig)
4324 {
4325 /* skipping the Polygon itself */
4326 continue;
4327 }
4328 if (valid_polygons[iv] == 'N')
4329 {
4330 /* skipping any already invalid Polygon */
4331 continue;
4332 }
4333 if (handle != NULL)
4334 {
4335 geos_item2 = GEOSGetGeometryN_r (handle, geos, iv);
4336 if (GEOSGetNumInteriorRings_r (handle, geos_item2) >
4337 0)
4338 {
4339 /* this Polygon contains holes [surely valid] */
4340 continue;
4341 }
4342 geos_ring =
4343 GEOSGetExteriorRing_r (handle, geos_item2);
4344 coords = GEOSGeom_getCoordSeq_r (handle, geos_ring);
4345 GEOSCoordSeq_getSize_r (handle, coords, &pts2);
4346 }
4347 else
4348 {
4349 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4350 geos_item2 = GEOSGetGeometryN (geos, iv);
4351 if (GEOSGetNumInteriorRings (geos_item2) > 0)
4352 {
4353 /* this Polygon contains holes [surely valid] */
4354 continue;
4355 }
4356 geos_ring = GEOSGetExteriorRing (geos_item2);
4357 coords = GEOSGeom_getCoordSeq (geos_ring);
4358 GEOSCoordSeq_getSize (coords, &pts2);
4359 #endif
4360 }
4361 if (pts1 == pts2)
4362 {
4363 auxGeosMbr (handle, coords, pts2, &min_x2, &min_y2,
4364 &max_x2, &max_y2);
4365 if (min_x1 == min_x2 && min_y1 == min_y2
4366 && max_x1 == max_x2 && max_y1 == max_y2)
4367 {
4368 /* same #points, same MBRs: invalidating */
4369 valid_polygons[iv] = 'N';
4370 }
4371 }
4372 }
4373 }
4374 }
4375
4376 /* creating the Geometry to be returned */
4377 if (geom->DimensionModel == GAIA_XY_Z)
4378 result = gaiaAllocGeomCollXYZ ();
4379 else if (geom->DimensionModel == GAIA_XY_M)
4380 result = gaiaAllocGeomCollXYM ();
4381 else if (geom->DimensionModel == GAIA_XY_Z_M)
4382 result = gaiaAllocGeomCollXYZM ();
4383 else
4384 result = gaiaAllocGeomColl ();
4385 if (result == NULL)
4386 return NULL;
4387 result->Srid = geom->Srid;
4388 if (force_multi)
4389 result->DeclaredType = GAIA_MULTIPOLYGON;
4390
4391 for (ig = 0; ig < items; ig++)
4392 {
4393 /* looping on GEOS Polygons */
4394 if (handle != NULL)
4395 geos_item = GEOSGetGeometryN_r (handle, geos, ig);
4396 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4397 else
4398 geos_item = GEOSGetGeometryN (geos, ig);
4399 #endif
4400 if (valid_polygons[ig] == 'Y')
4401 auxFromGeosPolygon (handle, geos_item, result);
4402 }
4403
4404 cleanup:
4405 if (valid_polygons != NULL)
4406 free (valid_polygons);
4407 if (geos_list != NULL)
4408 {
4409 /* memory cleanup */
4410 p_item = (GEOSGeometry **) geos_list;
4411 for (iv = 0; iv < lns; iv++)
4412 {
4413 if (*p_item != NULL)
4414 {
4415 if (handle != NULL)
4416 GEOSGeom_destroy_r (handle, *p_item);
4417 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4418 else
4419 GEOSGeom_destroy (*p_item);
4420 #endif
4421 }
4422 p_item++;
4423 }
4424 p_item = (GEOSGeometry **) geos_list;
4425 free (p_item);
4426 }
4427 if (geos != NULL)
4428 {
4429 if (handle != NULL)
4430 GEOSGeom_destroy_r (handle, geos);
4431 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4432 else
4433 GEOSGeom_destroy (geos);
4434 #endif
4435 }
4436 if (error || result->FirstPolygon == NULL)
4437 {
4438 gaiaFreeGeomColl (result);
4439 return NULL;
4440 }
4441 return result;
4442 }
4443
4444 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaPolygonize(gaiaGeomCollPtr geom,int force_multi)4445 gaiaPolygonize (gaiaGeomCollPtr geom, int force_multi)
4446 {
4447 /* attempts to rearrange a generic Geometry into a (multi)polygon */
4448 gaiaResetGeosMsg ();
4449 return gaiaPolygonizeCommon (NULL, NULL, geom, force_multi);
4450 }
4451
4452 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaPolygonize_r(const void * p_cache,gaiaGeomCollPtr geom,int force_multi)4453 gaiaPolygonize_r (const void *p_cache, gaiaGeomCollPtr geom, int force_multi)
4454 {
4455 /* attempts to rearrange a generic Geometry into a (multi)polygon */
4456 struct splite_internal_cache *cache =
4457 (struct splite_internal_cache *) p_cache;
4458 GEOSContextHandle_t handle = NULL;
4459 if (cache == NULL)
4460 return NULL;
4461 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4462 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4463 return NULL;
4464 handle = cache->GEOS_handle;
4465 if (handle == NULL)
4466 return NULL;
4467 gaiaResetGeosMsg_r (cache);
4468 return gaiaPolygonizeCommon (cache, handle, geom, force_multi);
4469 }
4470
4471 GAIAGEO_DECLARE int
gaiaGeomCollCovers(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4472 gaiaGeomCollCovers (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
4473 {
4474 /* checks if geom1 "spatially covers" geom2 */
4475 int ret = -1;
4476 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4477 GEOSGeometry *g1;
4478 GEOSGeometry *g2;
4479 gaiaResetGeosMsg ();
4480 if (!geom1 || !geom2)
4481 return -1;
4482
4483 /* quick check based on MBRs comparison */
4484 if (!splite_mbr_contains (geom1, geom2))
4485 return 0;
4486
4487 g1 = gaiaToGeos (geom1);
4488 g2 = gaiaToGeos (geom2);
4489 ret = GEOSCovers (g1, g2);
4490 GEOSGeom_destroy (g1);
4491 GEOSGeom_destroy (g2);
4492 if (ret == 2)
4493 return -1;
4494 #else
4495 if (geom1 == NULL || geom2 == NULL)
4496 geom1 = NULL; /* silencing stupid compiler warnings */
4497 #endif
4498 return ret;
4499 }
4500
4501 GAIAGEO_DECLARE int
gaiaGeomCollCovers_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4502 gaiaGeomCollCovers_r (const void *p_cache, gaiaGeomCollPtr geom1,
4503 gaiaGeomCollPtr geom2)
4504 {
4505 /* checks if geom1 "spatially covers" geom2 */
4506 int ret;
4507 GEOSGeometry *g1;
4508 GEOSGeometry *g2;
4509 struct splite_internal_cache *cache =
4510 (struct splite_internal_cache *) p_cache;
4511 GEOSContextHandle_t handle = NULL;
4512 if (cache == NULL)
4513 return -1;
4514 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4515 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4516 return -1;
4517 handle = cache->GEOS_handle;
4518 if (handle == NULL)
4519 return -1;
4520 gaiaResetGeosMsg_r (cache);
4521 if (!geom1 || !geom2)
4522 return -1;
4523
4524 /* quick check based on MBRs comparison */
4525 if (!splite_mbr_contains (geom1, geom2))
4526 return 0;
4527
4528 g1 = gaiaToGeos_r (cache, geom1);
4529 g2 = gaiaToGeos_r (cache, geom2);
4530 ret = GEOSCovers_r (handle, g1, g2);
4531 GEOSGeom_destroy_r (handle, g1);
4532 GEOSGeom_destroy_r (handle, g2);
4533 if (ret == 2)
4534 return -1;
4535 return ret;
4536 }
4537
4538 GAIAGEO_DECLARE int
gaiaGeomCollPreparedCovers(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)4539 gaiaGeomCollPreparedCovers (const void *p_cache, gaiaGeomCollPtr geom1,
4540 unsigned char *blob1, int size1,
4541 gaiaGeomCollPtr geom2, unsigned char *blob2,
4542 int size2)
4543 {
4544 /* checks if geom1 "spatially covers" geom2 */
4545 int ret;
4546 struct splite_internal_cache *cache =
4547 (struct splite_internal_cache *) p_cache;
4548 GEOSPreparedGeometry *gPrep;
4549 GEOSGeometry *g1;
4550 GEOSGeometry *g2;
4551 gaiaGeomCollPtr geom;
4552 GEOSContextHandle_t handle = NULL;
4553 if (cache == NULL)
4554 return -1;
4555 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4556 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4557 return -1;
4558 handle = cache->GEOS_handle;
4559 if (handle == NULL)
4560 return -1;
4561 gaiaResetGeosMsg_r (cache);
4562 if (!geom1 || !geom2)
4563 return -1;
4564
4565 /* quick check based on MBRs comparison */
4566 if (!splite_mbr_contains (geom1, geom2))
4567 return 0;
4568
4569 /* handling the internal GEOS cache */
4570 if (evalGeosCache
4571 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
4572 {
4573 g2 = gaiaToGeos_r (cache, geom);
4574 if (geom == geom2)
4575 ret = GEOSPreparedCovers_r (handle, gPrep, g2);
4576 else
4577 ret = GEOSPreparedCoveredBy_r (handle, gPrep, g2);
4578 GEOSGeom_destroy_r (handle, g2);
4579 if (ret == 2)
4580 return -1;
4581 return ret;
4582 }
4583
4584 g1 = gaiaToGeos_r (cache, geom1);
4585 g2 = gaiaToGeos_r (cache, geom2);
4586 ret = GEOSCovers_r (handle, g1, g2);
4587 GEOSGeom_destroy_r (handle, g1);
4588 GEOSGeom_destroy_r (handle, g2);
4589 if (ret == 2)
4590 return -1;
4591 return ret;
4592 }
4593
4594 GAIAGEO_DECLARE int
gaiaGeomCollCoveredBy(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4595 gaiaGeomCollCoveredBy (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
4596 {
4597 /* checks if geom1 is "spatially covered by" geom2 */
4598 int ret = -1;
4599 #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */
4600 GEOSGeometry *g1;
4601 GEOSGeometry *g2;
4602 gaiaResetGeosMsg ();
4603 if (!geom1 || !geom2)
4604 return -1;
4605
4606 /* quick check based on MBRs comparison */
4607 if (!splite_mbr_within (geom1, geom2))
4608 return 0;
4609
4610 g1 = gaiaToGeos (geom1);
4611 g2 = gaiaToGeos (geom2);
4612 ret = GEOSCoveredBy (g1, g2);
4613 GEOSGeom_destroy (g1);
4614 GEOSGeom_destroy (g2);
4615 if (ret == 2)
4616 return -1;
4617 #else
4618 if (geom1 == NULL || geom2 == NULL)
4619 geom1 = NULL; /* silencing stupid compiler warnings */
4620 #endif
4621 return ret;
4622 }
4623
4624 GAIAGEO_DECLARE int
gaiaGeomCollCoveredBy_r(const void * p_cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4625 gaiaGeomCollCoveredBy_r (const void *p_cache, gaiaGeomCollPtr geom1,
4626 gaiaGeomCollPtr geom2)
4627 {
4628 /* checks if geom1 is "spatially covered by" geom2 */
4629 int ret;
4630 GEOSGeometry *g1;
4631 GEOSGeometry *g2;
4632 struct splite_internal_cache *cache =
4633 (struct splite_internal_cache *) p_cache;
4634 GEOSContextHandle_t handle = NULL;
4635 if (cache == NULL)
4636 return -1;
4637 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4638 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4639 return -1;
4640 handle = cache->GEOS_handle;
4641 if (handle == NULL)
4642 return -1;
4643 gaiaResetGeosMsg_r (cache);
4644 if (!geom1 || !geom2)
4645 return -1;
4646
4647 /* quick check based on MBRs comparison */
4648 if (!splite_mbr_within (geom1, geom2))
4649 return 0;
4650
4651 g1 = gaiaToGeos_r (cache, geom1);
4652 g2 = gaiaToGeos_r (cache, geom2);
4653 ret = GEOSCoveredBy_r (handle, g1, g2);
4654 GEOSGeom_destroy_r (handle, g1);
4655 GEOSGeom_destroy_r (handle, g2);
4656 if (ret == 2)
4657 return -1;
4658 return ret;
4659 }
4660
4661 GAIAGEO_DECLARE int
gaiaGeomCollPreparedCoveredBy(const void * p_cache,gaiaGeomCollPtr geom1,unsigned char * blob1,int size1,gaiaGeomCollPtr geom2,unsigned char * blob2,int size2)4662 gaiaGeomCollPreparedCoveredBy (const void *p_cache, gaiaGeomCollPtr geom1,
4663 unsigned char *blob1, int size1,
4664 gaiaGeomCollPtr geom2, unsigned char *blob2,
4665 int size2)
4666 {
4667 /* checks if geom1 is "spatially covered by" geom2 */
4668 int ret;
4669 struct splite_internal_cache *cache =
4670 (struct splite_internal_cache *) p_cache;
4671 GEOSPreparedGeometry *gPrep;
4672 GEOSGeometry *g1;
4673 GEOSGeometry *g2;
4674 GEOSContextHandle_t handle = NULL;
4675 gaiaGeomCollPtr geom;
4676 gaiaResetGeosMsg ();
4677 if (cache == NULL)
4678 return -1;
4679 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4680 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4681 return -1;
4682 handle = cache->GEOS_handle;
4683 if (handle == NULL)
4684 return -1;
4685 gaiaResetGeosMsg_r (cache);
4686 if (!geom1 || !geom2)
4687 return -1;
4688
4689 /* quick check based on MBRs comparison */
4690 if (!splite_mbr_within (geom1, geom2))
4691 return 0;
4692
4693 /* handling the internal GEOS cache */
4694 if (evalGeosCache
4695 (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
4696 {
4697 g2 = gaiaToGeos_r (cache, geom);
4698 if (geom == geom2)
4699 ret = GEOSPreparedCoveredBy_r (handle, gPrep, g2);
4700 else
4701 ret = GEOSPreparedCovers_r (handle, gPrep, g2);
4702 GEOSGeom_destroy_r (handle, g2);
4703 if (ret == 2)
4704 return -1;
4705 return ret;
4706 }
4707
4708 g1 = gaiaToGeos_r (cache, geom1);
4709 g2 = gaiaToGeos_r (cache, geom2);
4710 ret = GEOSCoveredBy_r (handle, g1, g2);
4711 GEOSGeom_destroy_r (handle, g1);
4712 GEOSGeom_destroy_r (handle, g2);
4713 if (ret == 2)
4714 return -1;
4715 return ret;
4716 }
4717
4718 #endif /* end including GEOS */
4719