OGRMultiPolygon* OGRILI1Layer::Polygonize( OGRGeometryCollection* poLines, bool fix_crossing_lines ) { OGRMultiPolygon *poPolygon = new OGRMultiPolygon(); if (poLines->getNumGeometries() == 0) return poPolygon; #if defined(HAVE_GEOS) GEOSGeom *ahInGeoms = NULL; int i = 0; OGRGeometryCollection *poNoncrossingLines = poLines; GEOSGeom hResultGeom = NULL; OGRGeometry *poMP = NULL; if (fix_crossing_lines && poLines->getNumGeometries() > 0) { CPLDebug( "OGR_ILI", "Fixing crossing lines"); //A union of the geometry collection with one line fixes invalid geometries poNoncrossingLines = (OGRGeometryCollection*)poLines->Union(poLines->getGeometryRef(0)); CPLDebug( "OGR_ILI", "Fixed lines: %d", poNoncrossingLines->getNumGeometries()-poLines->getNumGeometries()); } GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext(); ahInGeoms = (GEOSGeom *) CPLCalloc(sizeof(void*),poNoncrossingLines->getNumGeometries()); for( i = 0; i < poNoncrossingLines->getNumGeometries(); i++ ) ahInGeoms[i] = poNoncrossingLines->getGeometryRef(i)->exportToGEOS(hGEOSCtxt); hResultGeom = GEOSPolygonize_r( hGEOSCtxt, ahInGeoms, poNoncrossingLines->getNumGeometries() ); for( i = 0; i < poNoncrossingLines->getNumGeometries(); i++ ) GEOSGeom_destroy_r( hGEOSCtxt, ahInGeoms[i] ); CPLFree( ahInGeoms ); if (poNoncrossingLines != poLines) delete poNoncrossingLines; if( hResultGeom == NULL ) { OGRGeometry::freeGEOSContext( hGEOSCtxt ); return NULL; } poMP = OGRGeometryFactory::createFromGEOS( hGEOSCtxt, hResultGeom ); GEOSGeom_destroy_r( hGEOSCtxt, hResultGeom ); OGRGeometry::freeGEOSContext( hGEOSCtxt ); return (OGRMultiPolygon *) poMP; #endif return poPolygon; }
SEXP rgeos_polygonize(SEXP env, SEXP obj, SEXP id, SEXP p4s, SEXP cutEdges) { GEOSContextHandle_t GEOShandle = getContextHandle(env); int getCutEdges = LOGICAL_POINTER(cutEdges)[0]; int n = length(obj); GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom)); for(int i=0; i<n; i++) { geoms[i] = rgeos_convert_R2geos(env, VECTOR_ELT(obj,i)); } GEOSGeom res = (getCutEdges) ? GEOSPolygonizer_getCutEdges_r(GEOShandle, (const GEOSGeometry *const *) geoms, (unsigned int) n) : GEOSPolygonize_r(GEOShandle, (const GEOSGeometry *const *) geoms, (unsigned int) n); return( rgeos_convert_geos2R(env, res, p4s, id) ); }
Q_NOWARN_UNREACHABLE_PUSH static GEOSGeometry *LWGEOM_GEOS_buildArea( const GEOSGeometry *geom_in, QString &errorMessage ) { GEOSContextHandle_t handle = QgsGeos::getGEOSHandler(); GEOSGeometry *tmp = nullptr; GEOSGeometry *shp = nullptr; GEOSGeometry *geos_result = nullptr; int srid = GEOSGetSRID_r( handle, geom_in ); GEOSGeometry const *vgeoms[1]; vgeoms[0] = geom_in; try { geos_result = GEOSPolygonize_r( handle, vgeoms, 1 ); } catch ( GEOSException &e ) { errorMessage = QStringLiteral( "GEOSPolygonize(): %1" ).arg( e.what() ); return nullptr; } // We should now have a collection #if PARANOIA_LEVEL > 0 if ( GEOSGeometryTypeId_r( handle, geos_result ) != COLLECTIONTYPE ) { GEOSGeom_destroy_r( handle, geos_result ); errorMessage = "Unexpected return from GEOSpolygonize"; return nullptr; } #endif int ngeoms = GEOSGetNumGeometries_r( handle, geos_result ); // No geometries in collection, early out if ( ngeoms == 0 ) { GEOSSetSRID_r( handle, geos_result, srid ); return geos_result; } // Return first geometry if we only have one in collection, // to avoid the unnecessary Geometry clone below. if ( ngeoms == 1 ) { tmp = ( GEOSGeometry * )GEOSGetGeometryN_r( handle, geos_result, 0 ); if ( ! tmp ) { GEOSGeom_destroy_r( handle, geos_result ); return nullptr; } shp = GEOSGeom_clone_r( handle, tmp ); GEOSGeom_destroy_r( handle, geos_result ); // only safe after the clone above GEOSSetSRID_r( handle, shp, srid ); return shp; } /* * Polygonizer returns a polygon for each face in the built topology. * * This means that for any face with holes we'll have other faces * representing each hole. We can imagine a parent-child relationship * between these faces. * * In order to maximize the number of visible rings in output we * only use those faces which have an even number of parents. * * Example: * * +---------------+ * | L0 | L0 has no parents * | +---------+ | * | | L1 | | L1 is an hole of L0 * | | +---+ | | * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0) * | | | | | | * | | +---+ | | * | +---------+ | * | | * +---------------+ * * See http://trac.osgeo.org/postgis/ticket/1806 * */ // Prepare face structures for later analysis Face **geoms = new Face*[ngeoms]; for ( int i = 0; i < ngeoms; ++i ) geoms[i] = newFace( GEOSGetGeometryN_r( handle, geos_result, i ) ); // Find faces representing other faces holes findFaceHoles( geoms, ngeoms ); // Build a MultiPolygon composed only by faces with an // even number of ancestors tmp = collectFacesWithEvenAncestors( geoms, ngeoms ); // Cleanup face structures for ( int i = 0; i < ngeoms; ++i ) delFace( geoms[i] ); delete [] geoms; // Faces referenced memory owned by geos_result. // It is safe to destroy geos_result after deleting them. GEOSGeom_destroy_r( handle, geos_result ); // Run a single overlay operation to dissolve shared edges shp = GEOSUnionCascaded_r( handle, tmp ); if ( !shp ) { GEOSGeom_destroy_r( handle, tmp ); return nullptr; } GEOSGeom_destroy_r( handle, tmp ); GEOSSetSRID_r( handle, shp, srid ); return shp; }
OGRMultiPolygon* OGRILI1Layer::Polygonize( OGRGeometryCollection* poLines, bool fix_crossing_lines ) { if (poLines->getNumGeometries() == 0) { return new OGRMultiPolygon(); } #if defined(HAVE_GEOS) GEOSGeom *ahInGeoms = NULL; OGRGeometryCollection *poNoncrossingLines = poLines; GEOSGeom hResultGeom = NULL; OGRGeometry *poMP = NULL; if (fix_crossing_lines && poLines->getNumGeometries() > 0) { CPLDebug( "OGR_ILI", "Fixing crossing lines"); //A union of the geometry collection with one line fixes invalid geometries OGRGeometry* poUnion = poLines->Union(poLines->getGeometryRef(0)); if( poUnion != NULL ) { if( wkbFlatten(poUnion->getGeometryType()) == wkbGeometryCollection || wkbFlatten(poUnion->getGeometryType()) == wkbMultiLineString ) { poNoncrossingLines = dynamic_cast<OGRGeometryCollection*>(poUnion); CPLDebug( "OGR_ILI", "Fixed lines: %d", poNoncrossingLines->getNumGeometries()-poLines->getNumGeometries()); } else { delete poUnion; } } } GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext(); ahInGeoms = (GEOSGeom *) CPLCalloc(sizeof(void*),poNoncrossingLines->getNumGeometries()); for( int i = 0; i < poNoncrossingLines->getNumGeometries(); i++ ) ahInGeoms[i] = poNoncrossingLines->getGeometryRef(i)->exportToGEOS(hGEOSCtxt); hResultGeom = GEOSPolygonize_r( hGEOSCtxt, ahInGeoms, poNoncrossingLines->getNumGeometries() ); for( int i = 0; i < poNoncrossingLines->getNumGeometries(); i++ ) GEOSGeom_destroy_r( hGEOSCtxt, ahInGeoms[i] ); CPLFree( ahInGeoms ); if (poNoncrossingLines != poLines) delete poNoncrossingLines; if( hResultGeom == NULL ) { OGRGeometry::freeGEOSContext( hGEOSCtxt ); return new OGRMultiPolygon(); } poMP = OGRGeometryFactory::createFromGEOS( hGEOSCtxt, hResultGeom ); GEOSGeom_destroy_r( hGEOSCtxt, hResultGeom ); OGRGeometry::freeGEOSContext( hGEOSCtxt ); poMP = OGRGeometryFactory::forceToMultiPolygon( poMP ); if( poMP && wkbFlatten(poMP->getGeometryType()) == wkbMultiPolygon ) return dynamic_cast<OGRMultiPolygon *>(poMP); else { delete poMP; return new OGRMultiPolygon(); } #else return new OGRMultiPolygon(); #endif }