~test_capigeospreparedgeometry_data() { GEOSGeom_destroy(geom1_); GEOSGeom_destroy(geom2_); GEOSPreparedGeom_destroy(prepGeom1_); GEOSPreparedGeom_destroy(prepGeom2_); geom1_ = nullptr; geom2_ = nullptr; prepGeom1_ = nullptr; prepGeom2_ = nullptr; finishGEOS(); }
Geometry::~Geometry() { // FIXME we also need to release any char* returned from GEOS functions if (geos_geom_ != NULL) GEOSGeom_destroy(geos_geom_); if (geos_geom_ != NULL) GEOSPreparedGeom_destroy(geos_pg_); }
void object::test<11> () { // Coincident vertext at -753.167968418005 93709.4279185742 //POLYGON ((-753.167968418005 93754.0955183194,-816.392328351464 93754.0955183194,-816.392328351464 93709.4279185742,-753.167968418005 93709.4279185742,-753.167968418005 93754.0955183194)) std::string const outer("01030000800100000005000000bd70d3ff578987c09e373e87a1e3f6400000000000000000a9f60b7d238389c09e373e87a1e3f6400000000000000000a9f60b7d238389c09625c1d8d6e0f6400000000000000000bd70d3ff578987c09625c1d8d6e0f6400000000000000000bd70d3ff578987c09e373e87a1e3f6400000000000000000"); //POLYGON ((-753.167968418005 93747.6909727677,-799.641978447015 93747.6909727677,-799.641978447015 93709.4279185742,-753.167968418005 93709.4279185742,-753.167968418005 93747.6909727677)) std::string const inner("01030000800100000005000000bd70d3ff578987c0f875390e3be3f6400000000000000000579598c522fd88c0f875390e3be3f6400000000000000000579598c522fd88c09625c1d8d6e0f6400000000000000000bd70d3ff578987c09625c1d8d6e0f6400000000000000000bd70d3ff578987c0f875390e3be3f6400000000000000000"); // A contains B if precision is limited to 1e+10 { geos::geom::PrecisionModel pm(1e+10); geos::geom::GeometryFactory::Ptr factory = geos::geom::GeometryFactory::create(&pm); geos::io::WKBReader reader(*factory); std::istringstream sOuter(outer); geom1_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sOuter)); std::istringstream sInner(inner); geom2_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sInner)); ensure(nullptr != geom1_); ensure(nullptr != geom2_); prepGeom1_ = GEOSPrepare(geom1_); ensure(nullptr != prepGeom1_); int ret = GEOSPreparedContains(prepGeom1_, geom2_); ensure_equals(ret, 1); ret = GEOSPreparedContainsProperly(prepGeom1_, geom2_); ensure_equals(ret, 0); GEOSGeom_destroy(geom1_); GEOSGeom_destroy(geom2_); GEOSPreparedGeom_destroy(prepGeom1_); } // A contains B if FLOATING PM is used with extended precision { geos::geom::PrecisionModel pm; geos::geom::GeometryFactory::Ptr factory = geos::geom::GeometryFactory::create(&pm); geos::io::WKBReader reader(*factory); std::istringstream sOuter(outer); geom1_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sOuter)); std::istringstream sInner(inner); geom2_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sInner)); ensure(nullptr != geom1_); ensure(nullptr != geom2_); prepGeom1_ = GEOSPrepare(geom1_); ensure(nullptr != prepGeom1_); int ret = GEOSPreparedContains(prepGeom1_, geom2_); ensure_equals(ret, 1); ret = GEOSPreparedContainsProperly(prepGeom1_, geom2_); ensure_equals(ret, 0); } }
void object::test<10> () { // Coincident vertives of both polygons at // -700.67089999181 93743.4218587986, -713.450135807349 93754.1677576647, std::string const outer("01030000800100000009000000af9dd0005ee585c0f802efbff6e2f6400000000000000000955acde0994b86c039a922afa2e3f64000000000000000002af6fb4f5d1887c07adb1c4071e3f6400000000000000000e5962b388d4f87c0bd3aeda7bae2f640000000000000000087c61344030887c07d585e6ff6e1f6400000000000000000fc8a31b5166186c0230588b20ae1f640000000000000000034733daf050186c0ed9f3ac98ae1f6400000000000000000f190aef659b385c0df2876538ce2f6400000000000000000af9dd0005ee585c0f802efbff6e2f6400000000000000000"); std::string const inner("0103000080010000000a000000ac21f88bbaff86c05f45d8c7b4e2f6400000000000000000467f1177ebf386c05de1971187e2f6400000000000000000fcf677888fc886c04e855a544be2f6400000000000000000c61226e540b686c0c0662d1fe7e1f640000000000000000042dc1bece8a486c09b85529f8ae1f6400000000000000000891047cde55e86c038cfa59c4ee1f6400000000000000000ae9dd0005ee585c0fa02efbff6e2f6400000000000000000975acde0994b86c038a922afa2e3f6400000000000000000287e339b09f986c01b1a083a10e3f6400000000000000000ac21f88bbaff86c05f45d8c7b4e2f6400000000000000000"); // A contains B if precision is limited to 1e+10 { geos::geom::PrecisionModel pm(1e+10); // NOTE: higher precision fails this test case geos::geom::GeometryFactory::Ptr factory = geos::geom::GeometryFactory::create(&pm); geos::io::WKBReader reader(*factory); std::istringstream sOuter(outer); geom1_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sOuter)); std::istringstream sInner(inner); geom2_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sInner)); ensure(nullptr != geom1_); ensure(nullptr != geom2_); prepGeom1_ = GEOSPrepare(geom1_); ensure(nullptr != prepGeom1_); int ret = GEOSPreparedContains(prepGeom1_, geom2_); ensure_equals(ret, 1); ret = GEOSPreparedContainsProperly(prepGeom1_, geom2_); ensure_equals(ret, 0); GEOSGeom_destroy(geom1_); GEOSGeom_destroy(geom2_); GEOSPreparedGeom_destroy(prepGeom1_); } // A does NOT contain B if precision is extended to 1e+11 or beyond { geos::geom::PrecisionModel pm(1e+11); geos::geom::GeometryFactory::Ptr factory = geos::geom::GeometryFactory::create(&pm); geos::io::WKBReader reader(*factory); std::istringstream sOuter(outer); geom1_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sOuter)); std::istringstream sInner(inner); geom2_ = reinterpret_cast<GEOSGeometry*>(reader.readHEX(sInner)); ensure(nullptr != geom1_); ensure(nullptr != geom2_); prepGeom1_ = GEOSPrepare(geom1_); ensure(nullptr != prepGeom1_); int ret = GEOSPreparedContains(prepGeom1_, geom2_); ensure_equals(ret, 0); ret = GEOSPreparedContainsProperly(prepGeom1_, geom2_); ensure_equals(ret, 0); } }
static void PreparedCacheDelete(MemoryContext context) { PrepGeomHashEntry* pghe; /* Lookup the hash entry pointer in the global hash table so we can free it */ pghe = GetPrepGeomHashEntry(context); if (!pghe) elog(ERROR, "PreparedCacheDelete: Trying to delete non-existant hash entry object with MemoryContext key (%p)", (void *)context); POSTGIS_DEBUGF(3, "deleting geom object (%p) and prepared geom object (%p) with MemoryContext key (%p)", pghe->geom, pghe->prepared_geom, context); /* Free them */ if ( pghe->prepared_geom ) GEOSPreparedGeom_destroy( pghe->prepared_geom ); if ( pghe->geom ) GEOSGeom_destroy( (GEOSGeometry *)pghe->geom ); /* Remove the hash entry as it is no longer needed */ DeletePrepGeomHashEntry(context); }
/* ** GetPrepGeomCache ** ** Pull the current prepared geometry from the cache or make ** one if there is not one available. Only prepare geometry ** if we are seeing a key for the second time. That way rapidly ** cycling keys don't cause too much preparing. */ PrepGeomCache* GetPrepGeomCache(FunctionCallInfoData *fcinfo, GSERIALIZED *pg_geom1, GSERIALIZED *pg_geom2) { MemoryContext old_context; PrepGeomCache* cache = fcinfo->flinfo->fn_extra; int copy_keys = 1; size_t pg_geom1_size = 0; size_t pg_geom2_size = 0; /* Make sure this isn't someone else's cache object. */ if ( cache && cache->type != 2 ) cache = NULL; if (!PrepGeomHash) CreatePrepGeomHash(); if ( pg_geom1 ) pg_geom1_size = VARSIZE(pg_geom1) + VARHDRSZ; if ( pg_geom2 ) pg_geom2_size = VARSIZE(pg_geom2) + VARHDRSZ; if ( cache == NULL) { /* ** Cache requested, but the cache isn't set up yet. ** Set it up, but don't prepare the geometry yet. ** That way if the next call is a cache miss we haven't ** wasted time preparing a geometry we don't need. */ PrepGeomHashEntry pghe; old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); cache = palloc(sizeof(PrepGeomCache)); MemoryContextSwitchTo(old_context); cache->type = 2; cache->prepared_geom = 0; cache->geom = 0; cache->argnum = 0; cache->pg_geom1 = 0; cache->pg_geom2 = 0; cache->pg_geom1_size = 0; cache->pg_geom2_size = 0; cache->context = MemoryContextCreate(T_AllocSetContext, 8192, &PreparedCacheContextMethods, fcinfo->flinfo->fn_mcxt, "PostGIS Prepared Geometry Context"); POSTGIS_DEBUGF(3, "GetPrepGeomCache: creating cache: %p", cache); pghe.context = cache->context; pghe.geom = 0; pghe.prepared_geom = 0; AddPrepGeomHashEntry( pghe ); fcinfo->flinfo->fn_extra = cache; POSTGIS_DEBUGF(3, "GetPrepGeomCache: adding context to hash: %p", cache); } else if ( pg_geom1 && cache->argnum != 2 && cache->pg_geom1_size == pg_geom1_size && memcmp(cache->pg_geom1, pg_geom1, pg_geom1_size) == 0) { if ( !cache->prepared_geom ) { /* ** Cache hit, but we haven't prepared our geometry yet. ** Prepare it. */ PrepGeomHashEntry* pghe; cache->geom = POSTGIS2GEOS( pg_geom1 ); cache->prepared_geom = GEOSPrepare( cache->geom ); cache->argnum = 1; POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 1"); pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = cache->geom; pghe->prepared_geom = cache->prepared_geom; POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 1"); } else { /* ** Cache hit, and we're good to go. Do nothing. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 1"); } /* We don't need new keys until we have a cache miss */ copy_keys = 0; } else if ( pg_geom2 && cache->argnum != 1 && cache->pg_geom2_size == pg_geom2_size && memcmp(cache->pg_geom2, pg_geom2, pg_geom2_size) == 0) { if ( !cache->prepared_geom ) { /* ** Cache hit on arg2, but we haven't prepared our geometry yet. ** Prepare it. */ PrepGeomHashEntry* pghe; cache->geom = POSTGIS2GEOS( pg_geom2 ); cache->prepared_geom = GEOSPrepare( cache->geom ); cache->argnum = 2; POSTGIS_DEBUG(3, "GetPrepGeomCache: preparing obj in argument 2"); pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = cache->geom; pghe->prepared_geom = cache->prepared_geom; POSTGIS_DEBUG(3, "GetPrepGeomCache: storing references to prepared obj in argument 2"); } else { /* ** Cache hit, and we're good to go. Do nothing. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: cache hit, argument 2"); } /* We don't need new keys until we have a cache miss */ copy_keys = 0; } else if ( cache->prepared_geom ) { /* ** No cache hits, so this must be a miss. ** Destroy the GEOS objects, empty the cache. */ PrepGeomHashEntry* pghe; pghe = GetPrepGeomHashEntry(cache->context); pghe->geom = 0; pghe->prepared_geom = 0; POSTGIS_DEBUGF(3, "GetPrepGeomCache: cache miss, argument %d", cache->argnum); GEOSPreparedGeom_destroy( cache->prepared_geom ); GEOSGeom_destroy( (GEOSGeometry *)cache->geom ); cache->prepared_geom = 0; cache->geom = 0; cache->argnum = 0; } if ( copy_keys && pg_geom1 ) { /* ** If this is a new key (cache miss) we flip into the function ** manager memory context and make a copy. We can't just store a pointer ** because this copy will be pfree'd at the end of this function ** call. */ POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom1 into cache"); old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); if ( cache->pg_geom1 ) pfree(cache->pg_geom1); cache->pg_geom1 = palloc(pg_geom1_size); MemoryContextSwitchTo(old_context); memcpy(cache->pg_geom1, pg_geom1, pg_geom1_size); cache->pg_geom1_size = pg_geom1_size; } if ( copy_keys && pg_geom2 ) { POSTGIS_DEBUG(3, "GetPrepGeomCache: copying pg_geom2 into cache"); old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); if ( cache->pg_geom2 ) pfree(cache->pg_geom2); cache->pg_geom2 = palloc(pg_geom2_size); MemoryContextSwitchTo(old_context); memcpy(cache->pg_geom2, pg_geom2, pg_geom2_size); cache->pg_geom2_size = pg_geom2_size; } return cache; }