/* gg_relations.c -- Gaia spatial relations version 5.0, 2020 August 1 Author: Sandro Furieri a.furieri@lqt.it ------------------------------------------------------------------------------ Version: MPL 1.1/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is the SpatiaLite library The Initial Developer of the Original Code is Alessandro Furieri Portions created by the Initial Developer are Copyright (C) 2008-2021 the Initial Developer. All Rights Reserved. Contributor(s): Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. */ #include #include #include #include #include #if defined(_WIN32) && !defined(__MINGW32__) #include "config-msvc.h" #else #include "config.h" #endif #ifndef OMIT_GEOS /* including GEOS */ #ifdef GEOS_REENTRANT #ifdef GEOS_ONLY_REENTRANT #define GEOS_USE_ONLY_R_API /* only fully thread-safe GEOS API */ #endif #endif #include #endif #include #include #include /* GLOBAL variables */ char *gaia_geos_error_msg = NULL; char *gaia_geos_warning_msg = NULL; char *gaia_geosaux_error_msg = NULL; SPATIALITE_PRIVATE void splite_free_geos_cache_item (struct splite_geos_cache_item *p) { #ifndef OMIT_GEOS /* including GEOS */ #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ if (p->preparedGeosGeom) GEOSPreparedGeom_destroy (p->preparedGeosGeom); if (p->geosGeom) GEOSGeom_destroy (p->geosGeom); #endif #endif p->geosGeom = NULL; p->preparedGeosGeom = NULL; } SPATIALITE_PRIVATE void splite_free_geos_cache_item_r (const void *p_cache, struct splite_geos_cache_item *p) { #ifndef OMIT_GEOS /* including GEOS */ struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) { splite_free_geos_cache_item (p); return; } if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) { splite_free_geos_cache_item (p); return; } handle = cache->GEOS_handle; if (handle == NULL) { splite_free_geos_cache_item (p); return; } if (p->preparedGeosGeom) GEOSPreparedGeom_destroy_r (handle, p->preparedGeosGeom); if (p->geosGeom) GEOSGeom_destroy_r (handle, p->geosGeom); #endif p->geosGeom = NULL; p->preparedGeosGeom = NULL; } GAIAGEO_DECLARE void gaiaResetGeosMsg () { /* resets the GEOS error and warning messages */ if (gaia_geos_error_msg != NULL) free (gaia_geos_error_msg); if (gaia_geos_warning_msg != NULL) free (gaia_geos_warning_msg); if (gaia_geosaux_error_msg != NULL) free (gaia_geosaux_error_msg); gaia_geos_error_msg = NULL; gaia_geos_warning_msg = NULL; gaia_geosaux_error_msg = NULL; } GAIAGEO_DECLARE const char * gaiaGetGeosErrorMsg () { /* return the latest GEOS error message */ return gaia_geos_error_msg; } GAIAGEO_DECLARE const char * gaiaGetGeosWarningMsg () { /* return the latest GEOS error message */ return gaia_geos_warning_msg; } GAIAGEO_DECLARE const char * gaiaGetGeosAuxErrorMsg () { /* return the latest GEOS (auxialiary) error message */ return gaia_geosaux_error_msg; } GAIAGEO_DECLARE void gaiaSetGeosErrorMsg (const char *msg) { /* setting the latest GEOS error message */ int len; if (gaia_geos_error_msg != NULL) free (gaia_geos_error_msg); gaia_geos_error_msg = NULL; if (msg == NULL) return; len = strlen (msg); gaia_geos_error_msg = malloc (len + 1); strcpy (gaia_geos_error_msg, msg); } GAIAGEO_DECLARE void gaiaSetGeosWarningMsg (const char *msg) { /* setting the latest GEOS error message */ int len; if (gaia_geos_warning_msg != NULL) free (gaia_geos_warning_msg); gaia_geos_warning_msg = NULL; if (msg == NULL) return; len = strlen (msg); gaia_geos_warning_msg = malloc (len + 1); strcpy (gaia_geos_warning_msg, msg); } GAIAGEO_DECLARE void gaiaSetGeosAuxErrorMsg (const char *msg) { /* setting the latest GEOS (auxiliary) error message */ int len; if (gaia_geosaux_error_msg != NULL) free (gaia_geosaux_error_msg); gaia_geosaux_error_msg = NULL; if (msg == NULL) return; len = strlen (msg); gaia_geosaux_error_msg = malloc (len + 1); strcpy (gaia_geosaux_error_msg, msg); } static int check_point (double *coords, int points, double x, double y) { /* checks if [X,Y] point is defined into this coordinate array [Linestring or Ring] */ int iv; double xx; double yy; for (iv = 0; iv < points; iv++) { gaiaGetPoint (coords, iv, &xx, &yy); if (xx == x && yy == y) return 1; } return 0; } GAIAGEO_DECLARE int gaiaLinestringEquals (gaiaLinestringPtr line1, gaiaLinestringPtr line2) { /* checks if two Linestrings are "spatially equal" */ int iv; double x; double y; if (line1->Points != line2->Points) return 0; for (iv = 0; iv < line1->Points; iv++) { gaiaGetPoint (line1->Coords, iv, &x, &y); if (!check_point (line2->Coords, line2->Points, x, y)) return 0; } return 1; } GAIAGEO_DECLARE int gaiaPolygonEquals (gaiaPolygonPtr polyg1, gaiaPolygonPtr polyg2) { /* checks if two Polygons are "spatially equal" */ int ib; int ib2; int iv; int ok2; double x; double y; gaiaRingPtr ring1; gaiaRingPtr ring2; if (polyg1->NumInteriors != polyg2->NumInteriors) return 0; /* checking the EXTERIOR RINGs */ ring1 = polyg1->Exterior; ring2 = polyg2->Exterior; if (ring1->Points != ring2->Points) return 0; for (iv = 0; iv < ring1->Points; iv++) { gaiaGetPoint (ring1->Coords, iv, &x, &y); if (!check_point (ring2->Coords, ring2->Points, x, y)) return 0; } for (ib = 0; ib < polyg1->NumInteriors; ib++) { /* checking the INTERIOR RINGS */ int ok = 0; ring1 = polyg1->Interiors + ib; for (ib2 = 0; ib2 < polyg2->NumInteriors; ib2++) { ok2 = 1; ring2 = polyg2->Interiors + ib2; for (iv = 0; iv < ring1->Points; iv++) { gaiaGetPoint (ring1->Coords, iv, &x, &y); if (!check_point (ring2->Coords, ring2->Points, x, y)) { ok2 = 0; break; } } if (ok2) { ok = 1; break; } } if (!ok) return 0; } return 1; } #ifndef OMIT_GEOS /* including GEOS */ static int splite_mbr_overlaps (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2) { /* checks if two MBRs do overlap */ if (g1->MaxX < g2->MinX) return 0; if (g1->MinX > g2->MaxX) return 0; if (g1->MaxY < g2->MinY) return 0; if (g1->MinY > g2->MaxY) return 0; return 1; } static int splite_mbr_contains (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2) { /* checks if MBR#1 fully contains MBR#2 */ if (g2->MinX < g1->MinX) return 0; if (g2->MaxX > g1->MaxX) return 0; if (g2->MinY < g1->MinY) return 0; if (g2->MaxY > g1->MaxY) return 0; return 1; } static int splite_mbr_within (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2) { /* checks if MBR#1 is fully contained within MBR#2 */ if (g1->MinX < g2->MinX) return 0; if (g1->MaxX > g2->MaxX) return 0; if (g1->MinY < g2->MinY) return 0; if (g1->MaxY > g2->MaxY) return 0; return 1; } static int splite_mbr_equals (gaiaGeomCollPtr g1, gaiaGeomCollPtr g2) { /* checks if MBR#1 equals MBR#2 */ if (g1->MinX != g2->MinX) return 0; if (g1->MaxX != g2->MaxX) return 0; if (g1->MinY != g2->MinY) return 0; if (g1->MaxY != g2->MaxY) return 0; return 1; } static int evalGeosCacheItem (unsigned char *blob, int blob_size, uLong crc, struct splite_geos_cache_item *p) { /* evaluting if this one could be a valid cache hit */ if (blob_size != p->gaiaBlobSize) { /* surely not a match; different size */ return 0; } if (crc != p->crc32) { /* surely not a match: different CRC32 */ return 0; } /* the first 46 bytes of the BLOB contain the MBR, the SRID and the Type; so are assumed to represent a valid signature */ if (memcmp (blob, p->gaiaBlob, 46) == 0) return 1; return 0; } static int sniffTinyPointBlob (const unsigned char *blob, const int size) { /* sniffing for a possible TinyPoint BLOB */ if (size == 24 || size == 32 || size == 40) ; else return 0; if (*(blob + 0) != GAIA_MARK_START) return 0; if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN) ; else return 0; if (*(blob + (size - 1)) != GAIA_MARK_END) return 0; return 1; } static void tinyPoint2Geom (const unsigned char *tiny, unsigned char **geom, int *geom_sz) { /* quickly converting from BLOB-TinyPoint to BLOB-Geometry */ int little_endian; int endian_arch = gaiaEndianArch (); int srid; int type; double x; double y; double z; double m; unsigned char *blob; int blob_sz; /* parsing the BLOB-TinyPoint */ if (*(tiny + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN) little_endian = 1; else little_endian = 0; srid = gaiaImport32 (tiny + 2, little_endian, endian_arch); if (*(tiny + 6) == GAIA_TINYPOINT_XYZ) type = GAIA_POINTZ; else if (*(tiny + 6) == GAIA_TINYPOINT_XYM) type = GAIA_POINTM; else if (*(tiny + 6) == GAIA_TINYPOINT_XYZM) type = GAIA_POINTZM; else type = GAIA_POINT; x = gaiaImport64 (tiny + 7, little_endian, endian_arch); y = gaiaImport64 (tiny + 15, little_endian, endian_arch); if (type == GAIA_POINTZ) z = gaiaImport64 (tiny + 23, little_endian, endian_arch); if (type == GAIA_POINTM) m = gaiaImport64 (tiny + 23, little_endian, endian_arch); if (type == GAIA_POINTZM) { z = gaiaImport64 (tiny + 23, little_endian, endian_arch); m = gaiaImport64 (tiny + 31, little_endian, endian_arch); } /* allocating and initializing the BLOB-Geometry */ switch (type) { case GAIA_POINT: blob_sz = 60; break; case GAIA_POINTZ: case GAIA_POINTM: blob_sz = 68; break; case GAIA_POINTZM: blob_sz = 76; break; }; blob = malloc (blob_sz); *geom = blob; *geom_sz = blob_sz; switch (type) { case GAIA_POINT: *blob = GAIA_MARK_START; /* START signature */ *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */ gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */ *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (blob + 39, GAIA_POINT, 1, endian_arch); /* class POINT */ gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */ gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */ *(blob + 59) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZ: *blob = GAIA_MARK_START; /* START signature */ *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */ gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */ *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (blob + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */ gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */ gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */ gaiaExport64 (blob + 59, z, 1, endian_arch); /* Z */ *(blob + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTM: *blob = GAIA_MARK_START; /* START signature */ *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */ gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */ *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (blob + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */ gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */ gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */ gaiaExport64 (blob + 59, m, 1, endian_arch); /* M */ *(blob + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZM: *blob = GAIA_MARK_START; /* START signature */ *(blob + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (blob + 2, srid, 1, endian_arch); /* the SRID */ gaiaExport64 (blob + 6, x, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (blob + 14, y, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (blob + 22, x, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (blob + 30, y, 1, endian_arch); /* MBR - maximum Y */ *(blob + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (blob + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */ gaiaExport64 (blob + 43, x, 1, endian_arch); /* X */ gaiaExport64 (blob + 51, y, 1, endian_arch); /* Y */ gaiaExport64 (blob + 59, z, 1, endian_arch); /* M */ gaiaExport64 (blob + 67, m, 1, endian_arch); /* Z */ *(blob + 75) = GAIA_MARK_END; /* END signature */ break; }; } 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) { /* handling the internal GEOS cache */ struct splite_geos_cache_item *p1 = &(cache->cacheItem1); struct splite_geos_cache_item *p2 = &(cache->cacheItem2); uLong crc1; uLong crc2; unsigned char *tiny1 = NULL; unsigned char *tiny2 = NULL; unsigned char *p_blob1; unsigned char *p_blob2; int sz1; int sz2; int tiny_sz; int retcode; GEOSContextHandle_t handle = NULL; if (cache == NULL) return 0; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return 0; handle = cache->GEOS_handle; if (handle == NULL) return 0; if (sniffTinyPointBlob (blob1, size1)) { tinyPoint2Geom (blob1, &tiny1, &tiny_sz); p_blob1 = tiny1; sz1 = tiny_sz; } else { p_blob1 = (unsigned char *) blob1; sz1 = size1; } if (sniffTinyPointBlob (blob2, size2)) { tinyPoint2Geom (blob2, &tiny2, &tiny_sz); p_blob2 = tiny2; sz2 = tiny_sz; } else { p_blob2 = (unsigned char *) blob2; sz2 = size2; } crc1 = crc32 (0L, p_blob1, sz1); crc2 = crc32 (0L, p_blob2, sz2); /* checking the first cache item */ if (evalGeosCacheItem (p_blob1, sz1, crc1, p1)) { /* found a matching item */ if (p1->preparedGeosGeom == NULL) { /* preparing the GeosGeometries */ p1->geosGeom = gaiaToGeos_r (cache, geom1); if (p1->geosGeom) { p1->preparedGeosGeom = (void *) GEOSPrepare_r (handle, p1->geosGeom); if (p1->preparedGeosGeom == NULL) { /* unexpected failure */ GEOSGeom_destroy_r (handle, p1->geosGeom); p1->geosGeom = NULL; } } } if (p1->preparedGeosGeom) { /* returning the corresponding GeosPreparedGeometry */ *gPrep = p1->preparedGeosGeom; *geom = geom2; retcode = 1; goto end; } retcode = 0; goto end; } /* checking the second cache item */ if (evalGeosCacheItem (p_blob2, sz2, crc2, p2)) { /* found a matching item */ if (p2->preparedGeosGeom == NULL) { /* preparing the GeosGeometries */ p2->geosGeom = gaiaToGeos_r (cache, geom2); if (p2->geosGeom) { p2->preparedGeosGeom = (void *) GEOSPrepare_r (handle, p2->geosGeom); if (p2->preparedGeosGeom == NULL) { /* unexpected failure */ GEOSGeom_destroy_r (handle, p2->geosGeom); p2->geosGeom = NULL; } } } if (p2->preparedGeosGeom) { /* returning the corresponding GeosPreparedGeometry */ *gPrep = p2->preparedGeosGeom; *geom = geom1; retcode = 1; goto end; } retcode = 0; goto end; } /* updating the GEOS cache item#1 */ memcpy (p1->gaiaBlob, p_blob1, 46); p1->gaiaBlobSize = sz1; p1->crc32 = crc1; if (p1->preparedGeosGeom) GEOSPreparedGeom_destroy_r (handle, p1->preparedGeosGeom); if (p1->geosGeom) GEOSGeom_destroy_r (handle, p1->geosGeom); p1->geosGeom = NULL; p1->preparedGeosGeom = NULL; /* updating the GEOS cache item#2 */ memcpy (p2->gaiaBlob, p_blob2, 46); p2->gaiaBlobSize = sz2; p2->crc32 = crc2; if (p2->preparedGeosGeom) GEOSPreparedGeom_destroy_r (handle, p2->preparedGeosGeom); if (p2->geosGeom) GEOSGeom_destroy_r (handle, p2->geosGeom); p2->geosGeom = NULL; p2->preparedGeosGeom = NULL; retcode = 0; end: if (tiny1 != NULL) free (tiny1); if (tiny2 != NULL) free (tiny2); return retcode; } GAIAGEO_DECLARE int gaiaGeomCollEquals (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries are "spatially equal" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_equals (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSEquals (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollEquals_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries are "spatially equal" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_equals (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSEquals_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollIntersects (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially intersects" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSIntersects (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollIntersects_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially intersects" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSIntersects_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedIntersects (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if two Geometries do "spatially intersects" */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); ret = GEOSPreparedIntersects_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSIntersects_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollDisjoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries are "spatially disjoint" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 1; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSDisjoint (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollDisjoint_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries are "spatially disjoint" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 1; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSDisjoint_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedDisjoint (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if two Geometries are "spatially disjoint" */ int ret; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 1; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); ret = GEOSPreparedDisjoint_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSDisjoint_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollOverlaps (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially overlaps" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSOverlaps (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollOverlaps_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially overlaps" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSOverlaps_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedOverlaps (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if two Geometries do "spatially overlaps" */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); ret = GEOSPreparedOverlaps_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSOverlaps_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollCrosses (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially crosses" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSCrosses (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollCrosses_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially crosses" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCrosses_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedCrosses (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if two Geometries do "spatially crosses" */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); ret = GEOSPreparedCrosses_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCrosses_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollTouches (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially touches" */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSTouches (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollTouches_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if two Geometries do "spatially touches" */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSTouches_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedTouches (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if two Geometries do "spatially touches" */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSGeometry *g1; GEOSGeometry *g2; GEOSPreparedGeometry *gPrep; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); ret = GEOSPreparedTouches_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSTouches_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollWithin (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if GEOM-1 is completely contained within GEOM-2 */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSWithin (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollWithin_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if GEOM-1 is completely contained within GEOM-2 */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSWithin_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedWithin (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if GEOM-1 is completely contained within GEOM-2 */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); if (geom == geom2) ret = GEOSPreparedWithin_r (handle, gPrep, g2); else ret = GEOSPreparedContains_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSWithin_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollContains (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if GEOM-1 completely contains GEOM-2 */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSContains (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollContains_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if GEOM-1 completely contains GEOM-2 */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSContains_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedContains (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if GEOM-1 completely contains GEOM-2 */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); if (geom == geom2) ret = GEOSPreparedContains_r (handle, gPrep, g2); else ret = GEOSPreparedWithin_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSContains_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); return ret; } GAIAGEO_DECLARE int gaiaGeomCollRelate (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, const char *pattern) { /* checks if if GEOM-1 and GEOM-2 have a spatial relationship as specified by the pattern Matrix */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return -1; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSRelatePattern (g1, g2, pattern); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (ret == 2) return -1; #else if (geom1 == NULL || geom2 == NULL || pattern == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollRelate_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, const char *pattern) { /* checks if if GEOM-1 and GEOM-2 have a spatial relationship as specified by the pattern Matrix */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return -1; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSRelatePattern_r (handle, g1, g2, pattern); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE char * gaiaGeomCollRelateBoundaryNodeRule (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, int mode) { /* return the intesection matrix [DE-9IM] of GEOM-1 and GEOM-2 */ #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; int bnr; char *retMatrix; char *matrix; int len; gaiaResetGeosMsg (); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return NULL; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); switch (mode) { case 2: bnr = GEOSRELATE_BNR_ENDPOINT; break; case 3: bnr = GEOSRELATE_BNR_MULTIVALENT_ENDPOINT; break; case 4: bnr = GEOSRELATE_BNR_MONOVALENT_ENDPOINT; break; default: bnr = GEOSRELATE_BNR_MOD2; break; }; retMatrix = GEOSRelateBoundaryNodeRule (g1, g2, bnr); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (retMatrix == NULL) return NULL; len = strlen (retMatrix); matrix = malloc (len + 1); strcpy (matrix, retMatrix); GEOSFree (retMatrix); return matrix; #else if (geom1 == NULL || geom2 == NULL || mode == 0) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return NULL; } GAIAGEO_DECLARE char * gaiaGeomCollRelateBoundaryNodeRule_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, int mode) { /* return the intesection matrix [DE-9IM] of GEOM-1 and GEOM-2 */ GEOSGeometry *g1; GEOSGeometry *g2; int bnr; char *retMatrix; char *matrix; int len; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return NULL; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); switch (mode) { case 2: bnr = GEOSRELATE_BNR_ENDPOINT; break; case 3: bnr = GEOSRELATE_BNR_MULTIVALENT_ENDPOINT; break; case 4: bnr = GEOSRELATE_BNR_MONOVALENT_ENDPOINT; break; default: bnr = GEOSRELATE_BNR_MOD2; break; }; retMatrix = GEOSRelateBoundaryNodeRule_r (handle, g1, g2, bnr); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (retMatrix == NULL) return NULL; len = strlen (retMatrix); matrix = malloc (len + 1); strcpy (matrix, retMatrix); GEOSFree_r (handle, retMatrix); return matrix; } GAIAGEO_DECLARE int gaiaIntersectionMatrixPatternMatch (const char *matrix, const char *pattern) { /* evalutes if an intersection matrix [DE-9IM] matches a matrix pattern */ #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ int ret; gaiaResetGeosMsg (); if (matrix == NULL || pattern == NULL) return -1; ret = GEOSRelatePatternMatch (matrix, pattern); if (ret == 0 || ret == 1) return ret; #else if (matrix == NULL || pattern == NULL) matrix = NULL; /* silencing stupid compiler warnings */ #endif return -1; } GAIAGEO_DECLARE int gaiaIntersectionMatrixPatternMatch_r (const void *p_cache, const char *matrix, const char *pattern) { /* evalutes is an intersection matrix [DE-9IM] matches a matrix pattern */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (matrix == NULL || pattern == NULL) return -1; ret = GEOSRelatePatternMatch_r (handle, matrix, pattern); if (ret == 0 || ret == 1) return ret; return -1; } GAIAGEO_DECLARE int gaiaGeomCollLength (gaiaGeomCollPtr geom, double *xlength) { /* computes the total length for this Geometry */ int ret = 0; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ double length; GEOSGeometry *g; gaiaResetGeosMsg (); if (!geom) return 0; if (gaiaIsToxic (geom)) return 0; g = gaiaToGeos (geom); ret = GEOSLength (g, &length); GEOSGeom_destroy (g); if (ret) *xlength = length; #else if (geom == NULL || xlength == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollLength_r (const void *p_cache, gaiaGeomCollPtr geom, double *xlength) { /* computes the total length for this Geometry */ double length; int ret; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom) return 0; if (gaiaIsToxic_r (cache, geom)) return 0; g = gaiaToGeos_r (cache, geom); ret = GEOSLength_r (handle, g, &length); GEOSGeom_destroy_r (handle, g); if (ret) *xlength = length; return ret; } GAIAGEO_DECLARE int gaiaGeomCollLengthOrPerimeter (gaiaGeomCollPtr geom, int perimeter, double *xlength) { /* computes the total length or perimeter for this Geometry */ int ret = 0; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ double length; GEOSGeometry *g; int mode = GAIA2GEOS_ONLY_LINESTRINGS; if (perimeter) mode = GAIA2GEOS_ONLY_POLYGONS; gaiaResetGeosMsg (); if (!geom) return 0; if (gaiaIsToxic (geom)) return 0; g = gaiaToGeosSelective (geom, mode); if (g == NULL) { *xlength = 0.0; return 1; } ret = GEOSLength (g, &length); GEOSGeom_destroy (g); if (ret) *xlength = length; #else if (geom == NULL || perimeter == 0 || xlength == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollLengthOrPerimeter_r (const void *p_cache, gaiaGeomCollPtr geom, int perimeter, double *xlength) { /* computes the total length or perimeter for this Geometry */ double length; int ret; int mode = GAIA2GEOS_ONLY_LINESTRINGS; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; if (perimeter) mode = GAIA2GEOS_ONLY_POLYGONS; gaiaResetGeosMsg_r (cache); if (!geom) return 0; if (gaiaIsToxic_r (cache, geom)) return 0; g = gaiaToGeosSelective_r (cache, geom, mode); if (g == NULL) { *xlength = 0.0; return 1; } ret = GEOSLength_r (handle, g, &length); GEOSGeom_destroy_r (handle, g); if (ret) *xlength = length; return ret; } GAIAGEO_DECLARE int gaiaGeomCollArea (gaiaGeomCollPtr geom, double *xarea) { /* computes the total area for this Geometry */ int ret = 0; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ double area; GEOSGeometry *g; gaiaResetGeosMsg (); if (!geom) return 0; if (gaiaIsToxic (geom)) return 0; g = gaiaToGeos (geom); ret = GEOSArea (g, &area); GEOSGeom_destroy (g); if (ret) *xarea = area; #else if (geom == NULL || xarea == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollArea_r (const void *p_cache, gaiaGeomCollPtr geom, double *xarea) { /* computes the total area for this Geometry */ double area; int ret; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom) return 0; if (gaiaIsToxic_r (cache, geom)) return 0; g = gaiaToGeos_r (cache, geom); ret = GEOSArea_r (handle, g, &area); GEOSGeom_destroy_r (handle, g); if (ret) *xarea = area; return ret; } GAIAGEO_DECLARE int gaiaGeomCollDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double *xdist) { /* computes the minimum distance intercurring between GEOM-1 and GEOM-2 */ int ret = 0; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ double dist; GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return 0; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSDistance (g1, g2, &dist); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (ret) *xdist = dist; #else if (geom1 == NULL || geom2 == NULL || xdist == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollDistance_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double *xdist) { /* computes the minimum distance intercurring between GEOM-1 and GEOM-2 */ double dist; int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return 0; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSDistance_r (handle, g1, g2, &dist); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret) *xdist = dist; return ret; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryIntersection (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial intersection" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; gaiaResetGeosMsg (); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return NULL; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return NULL; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); g3 = GEOSIntersection (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (!g3) return NULL; if (GEOSisEmpty (g3) == 1) { GEOSGeom_destroy (g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g3); else geo = gaiaFromGeos_XY (g3); GEOSGeom_destroy (g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryIntersection_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial intersection" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return NULL; /* quick check based on MBRs comparison */ if (!splite_mbr_overlaps (geom1, geom2)) return NULL; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); g3 = GEOSIntersection_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (!g3) return NULL; if (GEOSisEmpty_r (handle, g3) == 1) { GEOSGeom_destroy_r (handle, g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g3); else geo = gaiaFromGeos_XY_r (cache, g3); GEOSGeom_destroy_r (handle, g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryUnion (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial union" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; gaiaResetGeosMsg (); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return NULL; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); g3 = GEOSUnion (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (g3 == NULL) return NULL; if (GEOSisEmpty (g3) == 1) { GEOSGeom_destroy (g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g3); else geo = gaiaFromGeos_XY (g3); GEOSGeom_destroy (g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; if (geo->DeclaredType == GAIA_POINT && geom1->DeclaredType == GAIA_MULTIPOINT) geo->DeclaredType = GAIA_MULTIPOINT; if (geo->DeclaredType == GAIA_LINESTRING && geom1->DeclaredType == GAIA_MULTILINESTRING) geo->DeclaredType = GAIA_MULTILINESTRING; if (geo->DeclaredType == GAIA_POLYGON && geom1->DeclaredType == GAIA_MULTIPOLYGON) geo->DeclaredType = GAIA_MULTIPOLYGON; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryUnion_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial union" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return NULL; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); g3 = GEOSUnion_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (g3 == NULL) return NULL; if (GEOSisEmpty_r (handle, g3) == 1) { GEOSGeom_destroy_r (handle, g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g3); else geo = gaiaFromGeos_XY_r (cache, g3); GEOSGeom_destroy_r (handle, g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; if (geo->DeclaredType == GAIA_POINT && geom1->DeclaredType == GAIA_MULTIPOINT) geo->DeclaredType = GAIA_MULTIPOINT; if (geo->DeclaredType == GAIA_LINESTRING && geom1->DeclaredType == GAIA_MULTILINESTRING) geo->DeclaredType = GAIA_MULTILINESTRING; if (geo->DeclaredType == GAIA_POLYGON && geom1->DeclaredType == GAIA_MULTIPOLYGON) geo->DeclaredType = GAIA_MULTIPOLYGON; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaUnionCascaded (gaiaGeomCollPtr geom) { /* UnionCascaded (single Collection of polygons) */ gaiaGeomCollPtr result = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; int pts = 0; int lns = 0; int pgs = 0; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; /* testing if geom only contains Polygons */ pt = geom->FirstPoint; while (pt) { pts++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { lns++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { pgs++; pg = pg->Next; } if (pts || lns) return NULL; if (!pgs) return NULL; g1 = gaiaToGeos (geom); g2 = GEOSUnionCascaded (g1); GEOSGeom_destroy (g1); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) result = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) result = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) result = gaiaFromGeos_XYZM (g2); else result = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (result == NULL) return NULL; result->Srid = geom->Srid; #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return result; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaUnionCascaded_r (const void *p_cache, gaiaGeomCollPtr geom) { /* UnionCascaded (single Collection of polygons) */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr result; int pts = 0; int lns = 0; int pgs = 0; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; /* testing if geom only contains Polygons */ pt = geom->FirstPoint; while (pt) { pts++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { lns++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { pgs++; pg = pg->Next; } if (pts || lns) return NULL; if (!pgs) return NULL; g1 = gaiaToGeos_r (cache, geom); g2 = GEOSUnionCascaded_r (handle, g1); GEOSGeom_destroy_r (handle, g1); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) result = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) result = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) result = gaiaFromGeos_XYZM_r (cache, g2); else result = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (result == NULL) return NULL; result->Srid = geom->Srid; return result; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial difference" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; gaiaResetGeosMsg (); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return NULL; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); g3 = GEOSDifference (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (!g3) return NULL; if (GEOSisEmpty (g3) == 1) { GEOSGeom_destroy (g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g3); else geo = gaiaFromGeos_XY (g3); GEOSGeom_destroy (g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometryDifference_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial difference" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return NULL; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); g3 = GEOSDifference_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (!g3) return NULL; if (GEOSisEmpty_r (handle, g3) == 1) { GEOSGeom_destroy_r (handle, g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g3); else geo = gaiaFromGeos_XY_r (cache, g3); GEOSGeom_destroy_r (handle, g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometrySymDifference (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial symmetric difference" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; gaiaResetGeosMsg (); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic (geom1) || gaiaIsToxic (geom2)) return NULL; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); g3 = GEOSSymDifference (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (!g3) return NULL; if (GEOSisEmpty (g3) == 1) { GEOSGeom_destroy (g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g3); else geo = gaiaFromGeos_XY (g3); GEOSGeom_destroy (g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeometrySymDifference_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* builds a new geometry representing the "spatial symmetric difference" of GEOM-1 and GEOM-2 */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; GEOSGeometry *g3; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return NULL; if (gaiaIsToxic_r (cache, geom1) || gaiaIsToxic_r (cache, geom2)) return NULL; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); g3 = GEOSSymDifference_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (!g3) return NULL; if (GEOSisEmpty_r (handle, g3) == 1) { GEOSGeom_destroy_r (handle, g3); return NULL; } if (geom1->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g3); else if (geom1->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g3); else geo = gaiaFromGeos_XY_r (cache, g3); GEOSGeom_destroy_r (handle, g3); if (geo == NULL) return NULL; geo->Srid = geom1->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaBoundary (gaiaGeomCollPtr geom) { /* builds a new geometry representing the combinatorial boundary of GEOM */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; g1 = gaiaToGeos (geom); g2 = GEOSBoundary (g1); GEOSGeom_destroy (g1); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaBoundary_r (const void *p_cache, gaiaGeomCollPtr geom) { /* builds a new geometry representing the combinatorial boundary of GEOM */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; g1 = gaiaToGeos_r (cache, geom); g2 = GEOSBoundary_r (handle, g1); GEOSGeom_destroy_r (handle, g1); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; return geo; } GAIAGEO_DECLARE int gaiaGeomCollCentroid (gaiaGeomCollPtr geom, double *x, double *y) { /* returns a Point representing the centroid for this Geometry */ #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return 0; if (gaiaIsToxic (geom)) { return 0; } g1 = gaiaToGeos (geom); g2 = GEOSGetCentroid (g1); GEOSGeom_destroy (g1); if (!g2) return 0; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return 0; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return 0; if (geo->FirstPoint) { *x = geo->FirstPoint->X; *y = geo->FirstPoint->Y; gaiaFreeGeomColl (geo); return 1; } gaiaFreeGeomColl (geo); #else if (geom == NULL || x == NULL || y == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return 0; } GAIAGEO_DECLARE int gaiaGeomCollCentroid_r (const void *p_cache, gaiaGeomCollPtr geom, double *x, double *y) { /* returns a Point representing the centroid for this Geometry */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return 0; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return 0; handle = cache->GEOS_handle; if (handle == NULL) return 0; gaiaResetGeosMsg_r (cache); if (!geom) return 0; if (gaiaIsToxic_r (cache, geom)) { return 0; } g1 = gaiaToGeos_r (cache, geom); g2 = GEOSGetCentroid_r (handle, g1); GEOSGeom_destroy_r (handle, g1); if (!g2) return 0; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return 0; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return 0; if (geo->FirstPoint) { *x = geo->FirstPoint->X; *y = geo->FirstPoint->Y; gaiaFreeGeomColl (geo); return 1; } gaiaFreeGeomColl (geo); return 0; } GAIAGEO_DECLARE int gaiaGetPointOnSurface (gaiaGeomCollPtr geom, double *x, double *y) { /* returns a Point guaranteed to lie on the Surface */ #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return 0; if (gaiaIsToxic (geom)) { return 0; } g1 = gaiaToGeos (geom); g2 = GEOSPointOnSurface (g1); GEOSGeom_destroy (g1); if (!g2) return 0; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return 0; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return 0; if (geo->FirstPoint) { *x = geo->FirstPoint->X; *y = geo->FirstPoint->Y; gaiaFreeGeomColl (geo); return 1; } gaiaFreeGeomColl (geo); #else if (geom == NULL || x == NULL || y == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return 0; } GAIAGEO_DECLARE int gaiaGetPointOnSurface_r (const void *p_cache, gaiaGeomCollPtr geom, double *x, double *y) { /* returns a Point guaranteed to lie on the Surface */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return 0; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return 0; handle = cache->GEOS_handle; if (handle == NULL) return 0; gaiaResetGeosMsg_r (cache); if (!geom) return 0; if (gaiaIsToxic_r (cache, geom)) { return 0; } g1 = gaiaToGeos_r (cache, geom); g2 = GEOSPointOnSurface_r (handle, g1); GEOSGeom_destroy_r (handle, g1); if (!g2) return 0; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return 0; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XYZ_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return 0; if (geo->FirstPoint) { *x = geo->FirstPoint->X; *y = geo->FirstPoint->Y; gaiaFreeGeomColl (geo); return 1; } gaiaFreeGeomColl (geo); return 0; } GAIAGEO_DECLARE int gaiaIsSimple (gaiaGeomCollPtr geom) { /* checks if this GEOMETRYCOLLECTION is a simple one */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g; gaiaResetGeosMsg (); if (!geom) return -1; if (gaiaIsToxic (geom)) return 0; g = gaiaToGeos (geom); ret = GEOSisSimple (g); GEOSGeom_destroy (g); if (ret == 2) return -1; #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaIsSimple_r (const void *p_cache, gaiaGeomCollPtr geom) { /* checks if this GEOMETRYCOLLECTION is a simple one */ int ret; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom) return -1; if (gaiaIsToxic_r (cache, geom)) return -1; g = gaiaToGeos_r (cache, geom); ret = GEOSisSimple_r (handle, g); GEOSGeom_destroy_r (handle, g); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaIsRing (gaiaLinestringPtr line) { /* checks if this LINESTRING can be a valid RING */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ gaiaGeomCollPtr geo; gaiaLinestringPtr line2; int iv; double x; double y; double z; double m; GEOSGeometry *g; gaiaResetGeosMsg (); if (!line) return -1; if (line->DimensionModel == GAIA_XY_Z) geo = gaiaAllocGeomCollXYZ (); else if (line->DimensionModel == GAIA_XY_M) geo = gaiaAllocGeomCollXYM (); else if (line->DimensionModel == GAIA_XY_Z_M) geo = gaiaAllocGeomCollXYZM (); else geo = gaiaAllocGeomColl (); line2 = gaiaAddLinestringToGeomColl (geo, line->Points); for (iv = 0; iv < line2->Points; iv++) { z = 0.0; m = 0.0; if (line->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (line->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (line->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } if (line2->DimensionModel == GAIA_XY_Z) { gaiaSetPointXYZ (line2->Coords, iv, x, y, z); } else if (line2->DimensionModel == GAIA_XY_M) { gaiaSetPointXYM (line2->Coords, iv, x, y, m); } else if (line2->DimensionModel == GAIA_XY_Z_M) { gaiaSetPointXYZM (line2->Coords, iv, x, y, z, m); } else { gaiaSetPoint (line2->Coords, iv, x, y); } } if (gaiaIsToxic (geo)) { gaiaFreeGeomColl (geo); return -1; } g = gaiaToGeos (geo); gaiaFreeGeomColl (geo); ret = GEOSisRing (g); GEOSGeom_destroy (g); if (ret == 2) return -1; #else if (line == NULL) line = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaIsRing_r (const void *p_cache, gaiaLinestringPtr line) { /* checks if this LINESTRING can be a valid RING */ gaiaGeomCollPtr geo; gaiaLinestringPtr line2; int ret; int iv; double x; double y; double z; double m; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!line) return -1; if (line->DimensionModel == GAIA_XY_Z) geo = gaiaAllocGeomCollXYZ (); else if (line->DimensionModel == GAIA_XY_M) geo = gaiaAllocGeomCollXYM (); else if (line->DimensionModel == GAIA_XY_Z_M) geo = gaiaAllocGeomCollXYZM (); else geo = gaiaAllocGeomColl (); line2 = gaiaAddLinestringToGeomColl (geo, line->Points); for (iv = 0; iv < line2->Points; iv++) { z = 0.0; m = 0.0; if (line->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (line->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (line->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } if (line2->DimensionModel == GAIA_XY_Z) { gaiaSetPointXYZ (line2->Coords, iv, x, y, z); } else if (line2->DimensionModel == GAIA_XY_M) { gaiaSetPointXYM (line2->Coords, iv, x, y, m); } else if (line2->DimensionModel == GAIA_XY_Z_M) { gaiaSetPointXYZM (line2->Coords, iv, x, y, z, m); } else { gaiaSetPoint (line2->Coords, iv, x, y); } } if (gaiaIsToxic_r (cache, geo)) { gaiaFreeGeomColl (geo); return -1; } g = gaiaToGeos_r (cache, geo); gaiaFreeGeomColl (geo); ret = GEOSisRing_r (handle, g); GEOSGeom_destroy_r (handle, g); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaIsValid (gaiaGeomCollPtr geom) { /* checks if this GEOMETRYCOLLECTION is a valid one */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g; gaiaResetGeosMsg (); if (!geom) return -1; if (gaiaIsToxic (geom)) return 0; if (gaiaIsNotClosedGeomColl (geom)) return 0; g = gaiaToGeos (geom); ret = GEOSisValid (g); GEOSGeom_destroy (g); if (ret == 2) return -1; #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaIsValid_r (const void *p_cache, gaiaGeomCollPtr geom) { /* checks if this GEOMETRYCOLLECTION is a valid one */ int ret; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom) return -1; if (gaiaIsToxic_r (cache, geom)) return 0; if (gaiaIsNotClosedGeomColl_r (cache, geom)) return 0; g = gaiaToGeos_r (cache, geom); ret = GEOSisValid_r (handle, g); GEOSGeom_destroy_r (handle, g); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE char * gaiaIsValidReason (gaiaGeomCollPtr geom) { /* return a TEXT string stating if a Geometry is valid / and if not valid, a reason why */ char *text = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ int len; const char *str; char *gstr; GEOSGeometry *g; gaiaResetGeosMsg (); if (!geom) { str = "Invalid: NULL Geometry"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } if (gaiaIsToxic (geom)) { str = "Invalid: Toxic Geometry ... too few points"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } if (gaiaIsNotClosedGeomColl (geom)) { str = "Invalid: Unclosed Rings were detected"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } g = gaiaToGeos (geom); gstr = GEOSisValidReason (g); GEOSGeom_destroy (g); if (gstr == NULL) return NULL; len = strlen (gstr); text = malloc (len + 1); strcpy (text, gstr); GEOSFree (gstr); #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return text; } GAIAGEO_DECLARE char * gaiaIsValidReason_r (const void *p_cache, gaiaGeomCollPtr geom) { /* return a TEXT string stating if a Geometry is valid / and if not valid, a reason why */ char *text; int len; const char *str; char *gstr; GEOSGeometry *g; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) { str = "Invalid: NULL Geometry"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } if (gaiaIsToxic_r (cache, geom)) { str = "Invalid: Toxic Geometry ... too few points"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } if (gaiaIsNotClosedGeomColl_r (cache, geom)) { str = "Invalid: Unclosed Rings were detected"; len = strlen (str); text = malloc (len + 1); strcpy (text, str); return text; } g = gaiaToGeos_r (cache, geom); gstr = GEOSisValidReason_r (handle, g); GEOSGeom_destroy_r (handle, g); if (gstr == NULL) return NULL; len = strlen (gstr); text = malloc (len + 1); strcpy (text, gstr); GEOSFree_r (handle, gstr); return text; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaIsValidDetailEx (gaiaGeomCollPtr geom, int esri_flag) { /* return a Geometry detail causing a Geometry to be invalid */ gaiaGeomCollPtr detail = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ char *reason = NULL; GEOSGeometry *g; GEOSGeometry *d = NULL; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; if (gaiaIsNotClosedGeomColl (geom)) return NULL; g = gaiaToGeos (geom); if (esri_flag) esri_flag = GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE; GEOSisValidDetail (g, esri_flag, &reason, &d); GEOSGeom_destroy (g); if (reason != NULL) GEOSFree (reason); if (d == NULL) return NULL; detail = gaiaFromGeos_XY (d); GEOSGeom_destroy (d); #else if (geom == NULL && esri_flag == 0) geom = NULL; /* silencing stupid compiler warnings */ #endif return detail; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaIsValidDetail (gaiaGeomCollPtr geom) { /* return a Geometry detail causing a Geometry to be invalid */ return gaiaIsValidDetailEx (geom, 0); } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaIsValidDetailEx_r (const void *p_cache, gaiaGeomCollPtr geom, int esri_flag) { /* return a Geometry detail causing a Geometry to be invalid */ char *reason = NULL; GEOSGeometry *g; GEOSGeometry *d = NULL; gaiaGeomCollPtr detail; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; if (gaiaIsNotClosedGeomColl_r (cache, geom)) return NULL; g = gaiaToGeos_r (cache, geom); if (esri_flag) esri_flag = GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE; GEOSisValidDetail_r (handle, g, esri_flag, &reason, &d); GEOSGeom_destroy_r (handle, g); if (reason != NULL) GEOSFree_r (handle, reason); if (d == NULL) return NULL; detail = gaiaFromGeos_XY_r (cache, d); GEOSGeom_destroy_r (handle, d); return detail; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaIsValidDetail_r (const void *p_cache, gaiaGeomCollPtr geom) { /* return a Geometry detail causing a Geometry to be invalid */ return gaiaIsValidDetailEx_r (p_cache, geom, 0); } GAIAGEO_DECLARE int gaiaIsClosedGeom_r (const void *cache, gaiaGeomCollPtr geom) { /* checks if this geometry is a closed linestring (or multilinestring) */ int ret = 0; gaiaLinestringPtr ln; if (cache != NULL) gaiaResetGeosMsg_r (cache); if (!geom) return -1; if (cache != NULL) ret = gaiaIsToxic_r (cache, geom); else ret = gaiaIsToxic (geom); if (ret) return 0; ln = geom->FirstLinestring; while (ln) { /* unhappily GEOS v3.2.2 [system package on Debian Lenny and Ubuntu 12.04] * doesn't exposes the GEOSisClosed() API at all !!!! * GEOSGeometry *g; gaiaGeomCollPtr geoColl = gaiaAllocGeomColl(); gaiaInsertLinestringInGeomColl(geoColl, gaiaCloneLinestring(ln)); g = gaiaToGeos (geoColl); ret = GEOSisClosed (g); GEOSGeom_destroy (g); gaiaFreeGeomColl(geoColl); */ /* so we'll use this internal default in order to circumvent the above issue */ double x1; double y1; double z1; double m1; double x2; double y2; double z2; double m2; gaiaLineGetPoint (ln, 0, &x1, &y1, &z1, &m1); gaiaLineGetPoint (ln, ln->Points - 1, &x2, &y2, &z2, &m2); if (x1 == x2 && y1 == y2 && z1 == z2) ret = 1; else ret = 0; if (ret == 0) { /* this line isn't closed, so we don't need to continue */ break; } ln = ln->Next; } if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaIsClosedGeom (gaiaGeomCollPtr geom) { gaiaResetGeosMsg (); return gaiaIsClosedGeom_r (NULL, geom); } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollSimplify (gaiaGeomCollPtr geom, double tolerance) { /* builds a simplified geometry using the Douglas-Peuker algorihtm */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; g1 = gaiaToGeos (geom); g2 = GEOSSimplify (g1, tolerance); GEOSGeom_destroy (g1); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; #else if (geom == NULL || tolerance == 0.0) geom = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollSimplify_r (const void *p_cache, gaiaGeomCollPtr geom, double tolerance) { /* builds a simplified geometry using the Douglas-Peuker algorihtm */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; g1 = gaiaToGeos_r (cache, geom); g2 = GEOSSimplify_r (handle, g1, tolerance); GEOSGeom_destroy_r (handle, g1); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollSimplifyPreserveTopology (gaiaGeomCollPtr geom, double tolerance) { /* builds a simplified geometry using the Douglas-Peuker algorihtm [preserving topology] */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; g1 = gaiaToGeos (geom); g2 = GEOSTopologyPreserveSimplify (g1, tolerance); GEOSGeom_destroy (g1); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; #else if (geom == NULL || tolerance == 0.0) geom = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollSimplifyPreserveTopology_r (const void *p_cache, gaiaGeomCollPtr geom, double tolerance) { /* builds a simplified geometry using the Douglas-Peuker algorihtm [preserving topology] */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; g1 = gaiaToGeos_r (cache, geom); g2 = GEOSTopologyPreserveSimplify_r (handle, g1, tolerance); GEOSGeom_destroy_r (handle, g1); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaConvexHull (gaiaGeomCollPtr geom) { /* builds a geometry that is the convex hull of GEOM */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; g1 = gaiaToGeos (geom); g2 = GEOSConvexHull (g1); GEOSGeom_destroy (g1); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; #else if (geom == NULL) geom = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaConvexHull_r (const void *p_cache, gaiaGeomCollPtr geom) { /* builds a geometry that is the convex hull of GEOM */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; g1 = gaiaToGeos_r (cache, geom); g2 = GEOSConvexHull_r (handle, g1); GEOSGeom_destroy_r (handle, g1); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollBuffer (gaiaGeomCollPtr geom, double radius, int points) { /* builds a geometry that is the GIS buffer of GEOM */ gaiaGeomCollPtr geo = NULL; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; GEOSBufferParams *params = NULL; gaiaResetGeosMsg (); if (!geom) return NULL; if (gaiaIsToxic (geom)) return NULL; g1 = gaiaToGeos (geom); /* setting up Buffer params */ params = GEOSBufferParams_create (); GEOSBufferParams_setEndCapStyle (params, GEOSBUF_CAP_ROUND); GEOSBufferParams_setJoinStyle (params, GEOSBUF_JOIN_ROUND); GEOSBufferParams_setMitreLimit (params, 5.0); GEOSBufferParams_setQuadrantSegments (params, points); GEOSBufferParams_setSingleSided (params, 0); g2 = GEOSBufferWithParams (g1, params, radius); GEOSGeom_destroy (g1); GEOSBufferParams_destroy (params); if (!g2) return NULL; if (GEOSisEmpty (g2) == 1) { GEOSGeom_destroy (g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ (g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM (g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM (g2); else geo = gaiaFromGeos_XY (g2); GEOSGeom_destroy (g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; #else if (geom == NULL || radius == 0.0 || points == 0) geom = NULL; /* silencing stupid compiler warnings */ #endif return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaGeomCollBuffer_r (const void *p_cache, gaiaGeomCollPtr geom, double radius, int points) { /* builds a geometry that is the GIS buffer of GEOM */ gaiaGeomCollPtr geo; GEOSGeometry *g1; GEOSGeometry *g2; GEOSBufferParams *params = NULL; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; int quadsegs = 30; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); if (!geom) return NULL; if (gaiaIsToxic_r (cache, geom)) return NULL; g1 = gaiaToGeos_r (cache, geom); /* setting up Buffer params */ params = GEOSBufferParams_create_r (handle); GEOSBufferParams_setEndCapStyle_r (handle, params, cache->buffer_end_cap_style); GEOSBufferParams_setJoinStyle_r (handle, params, cache->buffer_join_style); GEOSBufferParams_setMitreLimit_r (handle, params, cache->buffer_mitre_limit); if (points > 0) quadsegs = points; else if (cache->buffer_quadrant_segments > 0) quadsegs = cache->buffer_quadrant_segments; GEOSBufferParams_setQuadrantSegments_r (handle, params, quadsegs); GEOSBufferParams_setSingleSided_r (handle, params, 0); g2 = GEOSBufferWithParams_r (handle, g1, params, radius); GEOSGeom_destroy_r (handle, g1); GEOSBufferParams_destroy_r (handle, params); if (!g2) return NULL; if (GEOSisEmpty_r (handle, g2) == 1) { GEOSGeom_destroy_r (handle, g2); return NULL; } if (geom->DimensionModel == GAIA_XY_Z) geo = gaiaFromGeos_XYZ_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_M) geo = gaiaFromGeos_XYM_r (cache, g2); else if (geom->DimensionModel == GAIA_XY_Z_M) geo = gaiaFromGeos_XYZM_r (cache, g2); else geo = gaiaFromGeos_XY_r (cache, g2); GEOSGeom_destroy_r (handle, g2); if (geo == NULL) return NULL; geo->Srid = geom->Srid; return geo; } static void auxFromGeosPolygon (GEOSContextHandle_t handle, const GEOSGeometry * geos, gaiaGeomCollPtr result) { /* converting a Polygon from GEOS to SpatiaLite */ const GEOSGeometry *geos_ring; const GEOSCoordSequence *coords; unsigned int pts; unsigned int geos_dims; int interiors; int iv; int ib; double x; double y; double z; gaiaPolygonPtr pg; gaiaRingPtr rng; #ifdef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ if (handle == NULL) return; #endif if (handle != NULL) { geos_ring = GEOSGetExteriorRing_r (handle, geos); interiors = GEOSGetNumInteriorRings_r (handle, geos); coords = GEOSGeom_getCoordSeq_r (handle, geos_ring); GEOSCoordSeq_getDimensions_r (handle, coords, &geos_dims); GEOSCoordSeq_getSize_r (handle, coords, &pts); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_ring = GEOSGetExteriorRing (geos); interiors = GEOSGetNumInteriorRings (geos); coords = GEOSGeom_getCoordSeq (geos_ring); GEOSCoordSeq_getDimensions (coords, &geos_dims); GEOSCoordSeq_getSize (coords, &pts); #endif } pg = gaiaAddPolygonToGeomColl (result, pts, interiors); /* setting up the Exterior ring */ rng = pg->Exterior; for (iv = 0; iv < (int) pts; iv++) { if (geos_dims == 3) { if (handle != NULL) { GEOSCoordSeq_getX_r (handle, coords, iv, &x); GEOSCoordSeq_getY_r (handle, coords, iv, &y); GEOSCoordSeq_getZ_r (handle, coords, iv, &z); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_getX (coords, iv, &x); GEOSCoordSeq_getY (coords, iv, &y); GEOSCoordSeq_getZ (coords, iv, &z); #endif } } else { if (handle != NULL) { GEOSCoordSeq_getX_r (handle, coords, iv, &x); GEOSCoordSeq_getY_r (handle, coords, iv, &y); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_getX (coords, iv, &x); GEOSCoordSeq_getY (coords, iv, &y); #endif } z = 0.0; } if (rng->DimensionModel == GAIA_XY_Z) { gaiaSetPointXYZ (rng->Coords, iv, x, y, z); } else if (rng->DimensionModel == GAIA_XY_M) { gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0); } else if (rng->DimensionModel == GAIA_XY_Z_M) { gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0); } else { gaiaSetPoint (rng->Coords, iv, x, y); } } for (ib = 0; ib < interiors; ib++) { /* setting up any interior ring */ if (handle != NULL) { geos_ring = GEOSGetInteriorRingN_r (handle, geos, ib); coords = GEOSGeom_getCoordSeq_r (handle, geos_ring); GEOSCoordSeq_getDimensions_r (handle, coords, &geos_dims); GEOSCoordSeq_getSize_r (handle, coords, &pts); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_ring = GEOSGetInteriorRingN (geos, ib); coords = GEOSGeom_getCoordSeq (geos_ring); GEOSCoordSeq_getDimensions (coords, &geos_dims); GEOSCoordSeq_getSize (coords, &pts); #endif } rng = gaiaAddInteriorRing (pg, ib, pts); for (iv = 0; iv < (int) pts; iv++) { if (geos_dims == 3) { if (handle != NULL) { GEOSCoordSeq_getX_r (handle, coords, iv, &x); GEOSCoordSeq_getY_r (handle, coords, iv, &y); GEOSCoordSeq_getZ_r (handle, coords, iv, &z); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_getX (coords, iv, &x); GEOSCoordSeq_getY (coords, iv, &y); GEOSCoordSeq_getZ (coords, iv, &z); #endif } } else { if (handle != NULL) { GEOSCoordSeq_getX_r (handle, coords, iv, &x); GEOSCoordSeq_getY_r (handle, coords, iv, &y); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_getX (coords, iv, &x); GEOSCoordSeq_getY (coords, iv, &y); #endif } z = 0.0; } if (rng->DimensionModel == GAIA_XY_Z) { gaiaSetPointXYZ (rng->Coords, iv, x, y, z); } else if (rng->DimensionModel == GAIA_XY_M) { gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0); } else if (rng->DimensionModel == GAIA_XY_Z_M) { gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0); } else { gaiaSetPoint (rng->Coords, iv, x, y); } } } } static void auxGeosMbr (GEOSContextHandle_t handle, const GEOSCoordSequence * cs, unsigned int pts, double *min_x, double *min_y, double *max_x, double *max_y) { /* computing the MBR */ int iv; double x; double y; *min_x = DBL_MAX; *min_y = DBL_MAX; *max_x = 0 - DBL_MAX; *max_y = 0 - DBL_MAX; for (iv = 0; iv < (int) pts; iv++) { if (handle != NULL) { GEOSCoordSeq_getX_r (handle, cs, iv, &x); GEOSCoordSeq_getY_r (handle, cs, iv, &y); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_getX (cs, iv, &x); GEOSCoordSeq_getY (cs, iv, &y); #endif } if (x < *min_x) *min_x = x; if (x > *max_x) *max_x = x; if (y < *min_y) *min_y = y; if (y > *max_y) *max_y = y; } } static gaiaGeomCollPtr gaiaPolygonizeCommon (const void *cache, GEOSContextHandle_t handle, gaiaGeomCollPtr geom, int force_multi) { /* attempts to rearrange a generic Geometry into a (multi)polygon */ int ig; int ib; int iv; int interiors; int geos_dims = 2; int pts = 0; int lns = 0; int pgs = 0; int items; int error = 0; double x; double y; double z; double m; gaiaGeomCollPtr result = NULL; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; GEOSCoordSequence *cs; const GEOSGeometry *const *geos_list = NULL; GEOSGeometry **p_item; GEOSGeometry *geos; const GEOSGeometry *geos_item; const GEOSGeometry *geos_item2; const GEOSGeometry *geos_ring; char *valid_polygons = NULL; const GEOSCoordSequence *coords; unsigned int pts1; unsigned int pts2; double min_x1; double max_x1; double min_y1; double max_y1; double min_x2; double max_x2; double min_y2; double max_y2; int ret; #ifdef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ if (handle == NULL) return NULL; #endif if (!geom) return NULL; if (cache != NULL) ret = gaiaIsToxic_r (cache, geom); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else ret = gaiaIsToxic (geom); #endif if (ret) return NULL; pt = geom->FirstPoint; while (pt) { pts++; pt = pt->Next; } pg = geom->FirstPolygon; while (pg) { pgs++; pg = pg->Next; } if (pts || pgs) return NULL; ln = geom->FirstLinestring; while (ln) { lns++; ln = ln->Next; } if (!lns) return NULL; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_Z_M) geos_dims = 3; /* allocating GEOS linestrings */ geos_list = malloc (sizeof (const GEOSGeometry * const *) * lns); p_item = (GEOSGeometry **) geos_list; for (iv = 0; iv < lns; iv++) { /* initializing to NULL */ *p_item++ = NULL; } p_item = (GEOSGeometry **) geos_list; /* initializing GEOS linestrings */ ln = geom->FirstLinestring; while (ln) { if (handle != NULL) cs = GEOSCoordSeq_create_r (handle, ln->Points, geos_dims); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else cs = GEOSCoordSeq_create (ln->Points, geos_dims); #endif for (iv = 0; iv < ln->Points; iv++) { /* exterior ring segments */ z = 0.0; if (ln->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z); } else if (ln->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m); } else if (ln->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (ln->Coords, iv, &x, &y); } if (geos_dims == 3) { if (handle != NULL) { GEOSCoordSeq_setX_r (handle, cs, iv, x); GEOSCoordSeq_setY_r (handle, cs, iv, y); GEOSCoordSeq_setZ_r (handle, cs, iv, z); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_setX (cs, iv, x); GEOSCoordSeq_setY (cs, iv, y); GEOSCoordSeq_setZ (cs, iv, z); #endif } } else { if (handle != NULL) { GEOSCoordSeq_setX_r (handle, cs, iv, x); GEOSCoordSeq_setY_r (handle, cs, iv, y); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSCoordSeq_setX (cs, iv, x); GEOSCoordSeq_setY (cs, iv, y); #endif } } } if (handle != NULL) *p_item++ = GEOSGeom_createLineString_r (handle, cs); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else *p_item++ = GEOSGeom_createLineString (cs); #endif ln = ln->Next; } /* calling GEOSPolygonize */ if (handle != NULL) geos = GEOSPolygonize_r (handle, geos_list, lns); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else geos = GEOSPolygonize (geos_list, lns); #endif if (geos == NULL) goto cleanup; /* / / GEOSPolygonize is expected to return a collection of Polygons / / CAVEAT: internal holes are returned as such (interior rings in / some Polygon), but are returned as distinct Polygons too / / we must check this, so to *not* return Polygons representing holes / */ error = 0; if (handle != NULL) items = GEOSGetNumGeometries_r (handle, geos); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else items = GEOSGetNumGeometries (geos); #endif for (ig = 0; ig < items; ig++) { /* looping on elementaty GEOS geometries */ if (handle != NULL) { geos_item = GEOSGetGeometryN_r (handle, geos, ig); if (GEOSGeomTypeId_r (handle, geos_item) != GEOS_POLYGON) { /* not a Polygon ... ouch ... */ error = 1; goto cleanup; } } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_item = GEOSGetGeometryN (geos, ig); if (GEOSGeomTypeId (geos_item) != GEOS_POLYGON) { /* not a Polygon ... ouch ... */ error = 1; goto cleanup; } #endif } } /* identifying valid Polygons [excluding holes] */ valid_polygons = malloc (sizeof (char *) * items); for (ig = 0; ig < items; ig++) valid_polygons[ig] = 'Y'; for (ig = 0; ig < items; ig++) { /* looping on elementaty GEOS Polygons */ if (handle != NULL) { geos_item = GEOSGetGeometryN_r (handle, geos, ig); interiors = GEOSGetNumInteriorRings_r (handle, geos_item); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_item = GEOSGetGeometryN (geos, ig); interiors = GEOSGetNumInteriorRings (geos_item); #endif } for (ib = 0; ib < interiors; ib++) { /* looping on any interior ring */ if (handle != NULL) { geos_ring = GEOSGetInteriorRingN_r (handle, geos_item, ib); coords = GEOSGeom_getCoordSeq_r (handle, geos_ring); GEOSCoordSeq_getSize_r (handle, coords, &pts1); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_ring = GEOSGetInteriorRingN (geos_item, ib); coords = GEOSGeom_getCoordSeq (geos_ring); GEOSCoordSeq_getSize (coords, &pts1); #endif } auxGeosMbr (handle, coords, pts1, &min_x1, &min_y1, &max_x1, &max_y1); for (iv = 0; iv < items; iv++) { if (iv == ig) { /* skipping the Polygon itself */ continue; } if (valid_polygons[iv] == 'N') { /* skipping any already invalid Polygon */ continue; } if (handle != NULL) { geos_item2 = GEOSGetGeometryN_r (handle, geos, iv); if (GEOSGetNumInteriorRings_r (handle, geos_item2) > 0) { /* this Polygon contains holes [surely valid] */ continue; } geos_ring = GEOSGetExteriorRing_r (handle, geos_item2); coords = GEOSGeom_getCoordSeq_r (handle, geos_ring); GEOSCoordSeq_getSize_r (handle, coords, &pts2); } else { #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ geos_item2 = GEOSGetGeometryN (geos, iv); if (GEOSGetNumInteriorRings (geos_item2) > 0) { /* this Polygon contains holes [surely valid] */ continue; } geos_ring = GEOSGetExteriorRing (geos_item2); coords = GEOSGeom_getCoordSeq (geos_ring); GEOSCoordSeq_getSize (coords, &pts2); #endif } if (pts1 == pts2) { auxGeosMbr (handle, coords, pts2, &min_x2, &min_y2, &max_x2, &max_y2); if (min_x1 == min_x2 && min_y1 == min_y2 && max_x1 == max_x2 && max_y1 == max_y2) { /* same #points, same MBRs: invalidating */ valid_polygons[iv] = 'N'; } } } } } /* creating the Geometry to be returned */ if (geom->DimensionModel == GAIA_XY_Z) result = gaiaAllocGeomCollXYZ (); else if (geom->DimensionModel == GAIA_XY_M) result = gaiaAllocGeomCollXYM (); else if (geom->DimensionModel == GAIA_XY_Z_M) result = gaiaAllocGeomCollXYZM (); else result = gaiaAllocGeomColl (); if (result == NULL) return NULL; result->Srid = geom->Srid; if (force_multi) result->DeclaredType = GAIA_MULTIPOLYGON; for (ig = 0; ig < items; ig++) { /* looping on GEOS Polygons */ if (handle != NULL) geos_item = GEOSGetGeometryN_r (handle, geos, ig); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else geos_item = GEOSGetGeometryN (geos, ig); #endif if (valid_polygons[ig] == 'Y') auxFromGeosPolygon (handle, geos_item, result); } cleanup: if (valid_polygons != NULL) free (valid_polygons); if (geos_list != NULL) { /* memory cleanup */ p_item = (GEOSGeometry **) geos_list; for (iv = 0; iv < lns; iv++) { if (*p_item != NULL) { if (handle != NULL) GEOSGeom_destroy_r (handle, *p_item); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else GEOSGeom_destroy (*p_item); #endif } p_item++; } p_item = (GEOSGeometry **) geos_list; free (p_item); } if (geos != NULL) { if (handle != NULL) GEOSGeom_destroy_r (handle, geos); #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ else GEOSGeom_destroy (geos); #endif } if (error || result->FirstPolygon == NULL) { gaiaFreeGeomColl (result); return NULL; } return result; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaPolygonize (gaiaGeomCollPtr geom, int force_multi) { /* attempts to rearrange a generic Geometry into a (multi)polygon */ gaiaResetGeosMsg (); return gaiaPolygonizeCommon (NULL, NULL, geom, force_multi); } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaPolygonize_r (const void *p_cache, gaiaGeomCollPtr geom, int force_multi) { /* attempts to rearrange a generic Geometry into a (multi)polygon */ struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return NULL; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return NULL; handle = cache->GEOS_handle; if (handle == NULL) return NULL; gaiaResetGeosMsg_r (cache); return gaiaPolygonizeCommon (cache, handle, geom, force_multi); } GAIAGEO_DECLARE int gaiaGeomCollCovers (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if geom1 "spatially covers" geom2 */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSCovers (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (ret == 2) return -1; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollCovers_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if geom1 "spatially covers" geom2 */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCovers_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedCovers (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if geom1 "spatially covers" geom2 */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; gaiaGeomCollPtr geom; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_contains (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); if (geom == geom2) ret = GEOSPreparedCovers_r (handle, gPrep, g2); else ret = GEOSPreparedCoveredBy_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCovers_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaGeomCollCoveredBy (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if geom1 is "spatially covered by" geom2 */ int ret = -1; #ifndef GEOS_USE_ONLY_R_API /* obsolete versions non fully thread-safe */ GEOSGeometry *g1; GEOSGeometry *g2; gaiaResetGeosMsg (); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; g1 = gaiaToGeos (geom1); g2 = gaiaToGeos (geom2); ret = GEOSCoveredBy (g1, g2); GEOSGeom_destroy (g1); GEOSGeom_destroy (g2); if (ret == 2) return -1; #else if (geom1 == NULL || geom2 == NULL) geom1 = NULL; /* silencing stupid compiler warnings */ #endif return ret; } GAIAGEO_DECLARE int gaiaGeomCollCoveredBy_r (const void *p_cache, gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2) { /* checks if geom1 is "spatially covered by" geom2 */ int ret; GEOSGeometry *g1; GEOSGeometry *g2; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSContextHandle_t handle = NULL; if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCoveredBy_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } GAIAGEO_DECLARE int gaiaGeomCollPreparedCoveredBy (const void *p_cache, gaiaGeomCollPtr geom1, unsigned char *blob1, int size1, gaiaGeomCollPtr geom2, unsigned char *blob2, int size2) { /* checks if geom1 is "spatially covered by" geom2 */ int ret; struct splite_internal_cache *cache = (struct splite_internal_cache *) p_cache; GEOSPreparedGeometry *gPrep; GEOSGeometry *g1; GEOSGeometry *g2; GEOSContextHandle_t handle = NULL; gaiaGeomCollPtr geom; gaiaResetGeosMsg (); if (cache == NULL) return -1; if (cache->magic1 != SPATIALITE_CACHE_MAGIC1 || cache->magic2 != SPATIALITE_CACHE_MAGIC2) return -1; handle = cache->GEOS_handle; if (handle == NULL) return -1; gaiaResetGeosMsg_r (cache); if (!geom1 || !geom2) return -1; /* quick check based on MBRs comparison */ if (!splite_mbr_within (geom1, geom2)) return 0; /* handling the internal GEOS cache */ if (evalGeosCache (cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom)) { g2 = gaiaToGeos_r (cache, geom); if (geom == geom2) ret = GEOSPreparedCoveredBy_r (handle, gPrep, g2); else ret = GEOSPreparedCovers_r (handle, gPrep, g2); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } g1 = gaiaToGeos_r (cache, geom1); g2 = gaiaToGeos_r (cache, geom2); ret = GEOSCoveredBy_r (handle, g1, g2); GEOSGeom_destroy_r (handle, g1); GEOSGeom_destroy_r (handle, g2); if (ret == 2) return -1; return ret; } #endif /* end including GEOS */