static VALUE method_geometry_envelope(VALUE self) { VALUE result; RGeo_GeometryData* self_data; const GEOSGeometry* self_geom; GEOSContextHandle_t geos_context; GEOSGeometry* envelope; result = Qnil; self_data = RGEO_GEOMETRY_DATA_PTR(self); self_geom = self_data->geom; if (self_geom) { geos_context = self_data->geos_context; envelope = GEOSEnvelope_r(geos_context, self_geom); // GEOS returns an "empty" point for an empty collection's envelope. // We don't allow that type, so we replace it with an empty collection. if (!envelope || GEOSGeomTypeId_r(geos_context, envelope) == GEOS_POINT && GEOSGetNumCoordinates_r(geos_context, envelope) == 0) { if (envelope) { GEOSGeom_destroy_r(geos_context, envelope); } envelope = GEOSGeom_createCollection_r(geos_context, GEOS_GEOMETRYCOLLECTION, NULL, 0); } result = rgeo_wrap_geos_geometry(self_data->factory, envelope, Qnil); } return result; }
SEXP rgeos_geospoint2SpatialPoints(SEXP env, GEOSGeom geom, SEXP p4s, SEXP id, int n) { GEOSContextHandle_t GEOShandle = getContextHandle(env); int type = GEOSGeomTypeId_r(GEOShandle, geom); if ( type != GEOS_POINT && type != GEOS_MULTIPOINT && type != GEOS_GEOMETRYCOLLECTION ) error("rgeos_geospoint2SpatialPoints: invalid geometry type"); int pc=0; SEXP bbox, crdmat; if (GEOSisEmpty_r(GEOShandle, geom)) error("rgeos_geospoint2SpatialPoints: empty point found"); //if (GEOSisEmpty_r(GEOShandle, geom)==0) { PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++; PROTECT(crdmat = rgeos_geospoint2crdMat(env, geom, id, n, type)); pc++; //} else { // bbox = R_NilValue; // crdmat = R_NilValue; //} SEXP ans; PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialPoints"))); pc++; SET_SLOT(ans, install("coords"), crdmat); SET_SLOT(ans, install("bbox"), bbox); SET_SLOT(ans, install("proj4string"), p4s); UNPROTECT(pc); return(ans); }
void object::test<3>() { geom1_ = GEOSGeom_createEmptyPolygon_r(handle_); ensure(0 != GEOSisEmpty_r(handle_, geom1_)); ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_POLYGON); GEOSGeom_destroy(geom1_); geom1_=0; }
BOX3D Polygon::bounds() const { uint32_t numInputDims; BOX3D output; GEOSGeometry* boundary = GEOSGeom_clone_r(m_ctx, m_geom); // Smash out multi* if (GEOSGeomTypeId_r(m_ctx, m_geom) > 3) boundary = GEOSEnvelope_r(m_ctx, m_geom); GEOSGeometry const* ring = GEOSGetExteriorRing_r(m_ctx, boundary); GEOSCoordSequence const* coords = GEOSGeom_getCoordSeq_r(m_ctx, ring); GEOSCoordSeq_getDimensions_r(m_ctx, coords, &numInputDims); uint32_t count(0); GEOSCoordSeq_getSize_r(m_ctx, coords, &count); double x(0.0); double y(0.0); double z(0.0); for (unsigned i = 0; i < count; ++i) { GEOSCoordSeq_getOrdinate_r(m_ctx, coords, i, 0, &x); GEOSCoordSeq_getOrdinate_r(m_ctx, coords, i, 1, &y); if (numInputDims > 2) GEOSCoordSeq_getOrdinate_r(m_ctx, coords, i, 2, &z); output.grow(x, y, z); } GEOSGeom_destroy_r(m_ctx, boundary); return output; }
SEXP rgeos_miscfunc(SEXP env, SEXP obj, SEXP byid, p_miscfunc miscfunc) { SEXP ans; GEOSContextHandle_t GEOShandle = getContextHandle(env); GEOSGeom geom = rgeos_convert_R2geos(env, obj); int type = GEOSGeomTypeId_r(GEOShandle, geom); int n = (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION) ? GEOSGetNumGeometries_r(GEOShandle, geom) : 1; int pc=0; PROTECT(ans = NEW_NUMERIC(n)); pc++; GEOSGeom curgeom = geom; for(int i=0; i<n; i++) { if ( n > 1) { curgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i); if (curgeom == NULL) error("rgeos_miscfunc: unable to get subgeometries"); } double val; if (!miscfunc(GEOShandle, curgeom, &val)) error("rgeos_miscfunc: unable to calculate"); NUMERIC_POINTER(ans)[i] = val; } GEOSGeom_destroy_r(GEOShandle, geom); UNPROTECT(pc); return(ans); }
void object::test<4>() { geom1_ = GEOSGeom_createEmptyCollection_r(handle_, GEOS_MULTIPOINT); ensure(0 != GEOSisEmpty_r(handle_, geom1_)); ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_MULTIPOINT); GEOSGeom_destroy(geom1_); geom1_=0; }
void object::test<1>() { geom1_ = GEOSGeom_createEmptyPoint_r(handle_); ensure(0 != GEOSisEmpty_r(handle_, geom1_)); ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_POINT); GEOSGeom_destroy(geom1_); geom1_=0; }
void object::test<2>() { geom1_ = GEOSGeom_createEmptyLineString_r(handle_); ensure(0 != GEOSisEmpty_r(handle_, geom1_)); ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_LINESTRING); GEOSGeom_destroy(geom1_); geom1_=0; }
void object::test<7>() { geom1_ = GEOSGeom_createEmptyCollection_r(handle_, GEOS_GEOMETRYCOLLECTION); ensure(0 != GEOSisEmpty_r(handle_, geom1_)); ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_GEOMETRYCOLLECTION); GEOSGeom_destroy(geom1_); geom1_=0; }
bool Polygon::valid() const { int gtype = GEOSGeomTypeId_r(m_ctx, m_geom); if (gtype != GEOS_POLYGON && gtype != GEOS_MULTIPOLYGON) return false; return (bool)GEOSisValid_r(m_ctx, m_geom); }
RGEO_BEGIN_C /**** INTERNAL UTILITY FUNCTIONS ****/ // Determine the dimension of the given geometry. Empty collections have dimension -1. // Recursively checks collection elemenets. static int compute_dimension(GEOSContextHandle_t context, const GEOSGeometry* geom) { int result; int size; int i; int dim; result = -1; if (geom) { switch (GEOSGeomTypeId_r(context, geom)) { case GEOS_POINT: result = 0; break; case GEOS_MULTIPOINT: if (!GEOSisEmpty_r(context, geom)) { result = 0; } break; case GEOS_LINESTRING: case GEOS_LINEARRING: result = 1; break; case GEOS_MULTILINESTRING: if (!GEOSisEmpty_r(context, geom)) { result = 1; } break; case GEOS_POLYGON: result = 2; break; case GEOS_MULTIPOLYGON: if (!GEOSisEmpty_r(context, geom)) { result = 2; } break; case GEOS_GEOMETRYCOLLECTION: size = GEOSGetNumGeometries_r(context, geom); for (i=0; i<size; ++i) { dim = compute_dimension(context, GEOSGetGeometryN_r(context, geom, i)); if (dim > result) { result = dim; } } break; } } return result; }
std::string Polygon::validReason() const { int gtype = GEOSGeomTypeId_r(m_ctx, m_geom); if (gtype != GEOS_POLYGON && gtype != GEOS_MULTIPOLYGON) return std::string("Geometry is not Polygon or MultiPolygon"); char *reason = GEOSisValidReason_r(m_ctx, m_geom); std::string output(reason); GEOSFree_r(m_ctx, reason); return output; }
SEXP rgeos_topologyfunc(SEXP env, SEXP obj, SEXP id, SEXP byid, p_topofunc topofunc) { GEOSContextHandle_t GEOShandle = getContextHandle(env); SEXP p4s = GET_SLOT(obj, install("proj4string")); GEOSGeom geom = rgeos_convert_R2geos(env, obj); int type = GEOSGeomTypeId_r(GEOShandle, geom); int n = 1; if (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION) n = GEOSGetNumGeometries_r(GEOShandle, geom); if (n < 1) error("rgeos_topologyfunc: invalid number of geometries"); GEOSGeom *resgeoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom)); for(int i=0; i<n; i++) { const GEOSGeometry *curgeom = (n > 1) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i) : geom; if (curgeom == NULL) error("rgeos_topologyfunc: unable to get subgeometries"); if ( topofunc == GEOSUnionCascaded_r && GEOSGeomTypeId_r(GEOShandle, curgeom) == GEOS_POLYGON) { resgeoms[i] = GEOSGeom_clone_r(GEOShandle, curgeom); } else { resgeoms[i] = topofunc(GEOShandle, curgeom); if (resgeoms[i] == NULL) error("rgeos_topologyfunc: unable to calculate"); } } GEOSGeom_destroy_r(GEOShandle, geom); GEOSGeom res = (n == 1) ? resgeoms[0] : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, resgeoms, (unsigned int) n); return( rgeos_convert_geos2R(env, res, p4s, id) ); // releases res }
static GEOSGeometry *LWGEOM_GEOS_makeValid( const GEOSGeometry *gin, QString &errorMessage ) { GEOSContextHandle_t handle = QgsGeos::getGEOSHandler(); // return what we got so far if already valid Q_NOWARN_UNREACHABLE_PUSH try { if ( GEOSisValid_r( handle, gin ) ) { // It's valid at this step, return what we have return GEOSGeom_clone_r( handle, gin ); } } catch ( GEOSException &e ) { // I don't think should ever happen errorMessage = QStringLiteral( "GEOSisValid(): %1" ).arg( e.what() ); return nullptr; } Q_NOWARN_UNREACHABLE_POP // make what we got valid switch ( GEOSGeomTypeId_r( handle, gin ) ) { case GEOS_MULTIPOINT: case GEOS_POINT: // points are always valid, but we might have invalid ordinate values QgsDebugMsg( QStringLiteral( "PUNTUAL geometry resulted invalid to GEOS -- dunno how to clean that up" ) ); return nullptr; case GEOS_LINESTRING: return LWGEOM_GEOS_makeValidLine( gin, errorMessage ); case GEOS_MULTILINESTRING: return LWGEOM_GEOS_makeValidMultiLine( gin, errorMessage ); case GEOS_POLYGON: case GEOS_MULTIPOLYGON: return LWGEOM_GEOS_makeValidPolygon( gin, errorMessage ); case GEOS_GEOMETRYCOLLECTION: return LWGEOM_GEOS_makeValidCollection( gin, errorMessage ); default: errorMessage = QStringLiteral( "ST_MakeValid: doesn't support geometry type: %1" ).arg( GEOSGeomTypeId_r( handle, gin ) ); return nullptr; } }
void Crop::ready(PointContext ctx) { #ifdef PDAL_HAVE_GEOS if (!m_poly.empty()) { m_geosEnvironment = initGEOS_r(pdal::geos::_GEOSWarningHandler, pdal::geos::_GEOSErrorHandler); m_geosGeometry = GEOSGeomFromWKT_r(m_geosEnvironment, m_poly.c_str()); if (!m_geosGeometry) throw pdal_error("unable to import polygon WKT"); int gtype = GEOSGeomTypeId_r(m_geosEnvironment, m_geosGeometry); if (!(gtype == GEOS_POLYGON || gtype == GEOS_MULTIPOLYGON)) throw pdal_error("input WKT was not a POLYGON or MULTIPOLYGON"); char* out_wkt = GEOSGeomToWKT_r(m_geosEnvironment, m_geosGeometry); log()->get(LogLevel::Debug2) << "Ingested WKT for filters.crop: " << std::string(out_wkt) <<std::endl; GEOSFree_r(m_geosEnvironment, out_wkt); if (!GEOSisValid_r(m_geosEnvironment, m_geosGeometry)) { char* reason = GEOSisValidReason_r(m_geosEnvironment, m_geosGeometry); std::ostringstream oss; oss << "WKT is invalid: " << std::string(reason) << std::endl; GEOSFree_r(m_geosEnvironment, reason); throw pdal_error(oss.str()); } m_geosPreparedGeometry = GEOSPrepare_r(m_geosEnvironment, m_geosGeometry); if (!m_geosPreparedGeometry) throw pdal_error("unable to prepare geometry for " "index-accelerated intersection"); m_bounds = computeBounds(m_geosGeometry); log()->get(LogLevel::Debug) << "Computed bounds from given WKT: " << m_bounds <<std::endl; } else { log()->get(LogLevel::Debug) << "Using simple bounds for " "filters.crop: " << m_bounds << std::endl; } #endif }
QLinkedList<const GEOSGeometry *>* pal::Util::unmulti( const GEOSGeometry *the_geom ) { QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>; QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>; const GEOSGeometry *geom; queue->append( the_geom ); int nGeom; int i; GEOSContextHandle_t geosctxt = geosContext(); while ( !queue->isEmpty() ) { geom = queue->takeFirst(); int type = GEOSGeomTypeId_r( geosctxt, geom ); switch ( type ) { case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: nGeom = GEOSGetNumGeometries_r( geosctxt, geom ); for ( i = 0; i < nGeom; i++ ) { queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) ); } break; case GEOS_POINT: case GEOS_LINESTRING: case GEOS_POLYGON: final_queue->append( geom ); break; default: QgsDebugMsg( QString( "unexpected geometry type:%1" ).arg( type ) ); delete final_queue; delete queue; return nullptr; } } delete queue; return final_queue; }
QLinkedList<const GEOSGeometry *> *unmulti( const GEOSGeometry *the_geom ) { QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>; QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>; const GEOSGeometry *geom; queue->append( the_geom ); int nGeom; int i; while ( !queue->isEmpty() ) { geom = queue->takeFirst(); GEOSContextHandle_t geosctxt = geosContext(); switch ( GEOSGeomTypeId_r( geosctxt, geom ) ) { case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: nGeom = GEOSGetNumGeometries_r( geosctxt, geom ); for ( i = 0; i < nGeom; i++ ) { queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) ); } break; case GEOS_POINT: case GEOS_LINESTRING: case GEOS_POLYGON: final_queue->append( geom ); break; default: delete final_queue; delete queue; return NULL; } } delete queue; return final_queue; }
SEXP rgeos_simplify(SEXP env, SEXP obj, SEXP tol, SEXP id, SEXP byid, SEXP topPres) { GEOSContextHandle_t GEOShandle = getContextHandle(env); SEXP p4s = GET_SLOT(obj, install("proj4string")); GEOSGeom geom = rgeos_convert_R2geos(env, obj); int type = GEOSGeomTypeId_r(GEOShandle, geom); int preserve = LOGICAL_POINTER(topPres)[0]; double tolerance = NUMERIC_POINTER(tol)[0]; int n = 1; if (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION) n = GEOSGetNumGeometries_r(GEOShandle, geom); if (n < 1) error("rgeos_simplify: invalid number of geometries"); GEOSGeom *resgeoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom)); for(int i=0; i<n; i++) { const GEOSGeometry *curgeom = (n > 1) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i) : geom; if (curgeom == NULL) error("rgeos_topologyfunc: unable to get subgeometries"); resgeoms[i] = (preserve) ? GEOSTopologyPreserveSimplify_r(GEOShandle, curgeom, tolerance) : GEOSSimplify_r(GEOShandle, curgeom, tolerance); } GEOSGeom_destroy_r(GEOShandle, geom); GEOSGeom res = (n == 1) ? resgeoms[0] : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, resgeoms, (unsigned int) n); return( rgeos_convert_geos2R(env, res, p4s, id) ); }
void Point::update(const std::string& wkt_or_json, SpatialReference ref) { Geometry::update(wkt_or_json, ref); int t = GEOSGeomTypeId_r(m_geoserr.ctx(), m_geom.get()); if (t == -1) throw pdal_error("Unable to fetch geometry point type"); if (t > 0) throw pdal_error("Geometry type is not point!"); int nGeometries = GEOSGetNumGeometries_r(m_geoserr.ctx(), m_geom.get()); if (nGeometries > 1) throw pdal_error("Geometry count is > 1!"); const GEOSGeometry* g = GEOSGetGeometryN_r(m_geoserr.ctx(), m_geom.get(), 0); GEOSCoordSequence const* coords = GEOSGeom_getCoordSeq_r(m_geoserr.ctx(), g); uint32_t numInputDims; GEOSCoordSeq_getDimensions_r(m_geoserr.ctx(), coords, &numInputDims); uint32_t count(0); GEOSCoordSeq_getSize_r(m_geoserr.ctx(), coords, &count); if (count == 0) throw pdal_error("No coordinates in geometry!"); for (unsigned i = 0; i < count; ++i) { GEOSCoordSeq_getOrdinate_r(m_geoserr.ctx(), coords, i, 0, &x); GEOSCoordSeq_getOrdinate_r(m_geoserr.ctx(), coords, i, 1, &y); if (numInputDims > 2) GEOSCoordSeq_getOrdinate_r(m_geoserr.ctx(), coords, i, 2, &z); } }
SEXP rgeos_distancefunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_distfunc distfunc) { GEOSContextHandle_t GEOShandle = getContextHandle(env); GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1); int type1 = GEOSGeomTypeId_r(GEOShandle, geom1); GEOSGeom geom2; int type2; int sym_ans = FALSE; if (spgeom2 == R_NilValue) { sym_ans = TRUE; geom2 = geom1; type2 = GEOSGeomTypeId_r(GEOShandle, geom2); } else { geom2 = rgeos_convert_R2geos(env, spgeom2); type2 = GEOSGeomTypeId_r(GEOShandle, geom2); } int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ? GEOSGetNumGeometries_r(GEOShandle, geom1) : 1; int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ? GEOSGetNumGeometries_r(GEOShandle, geom2) : 1; if (m == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 1"); if (n == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 2"); int pc=0; SEXP ans; PROTECT(ans = NEW_NUMERIC(m*n)); pc++; GEOSGeom curgeom1 = geom1; GEOSGeom curgeom2 = geom2; for(int i=0; i<m; i++) { if ( m > 1) { curgeom1 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom1, i); if (curgeom1 == NULL) error("rgeos_binpredfunc: unable to get subgeometries from geometry 1"); } for(int j=0; j<n; j++) { if(sym_ans && j > i) break; if ( n > 1) { curgeom2 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom2, j); if (curgeom2 == NULL) error("rgeos_binpredfunc: unable to get subgeometries from geometry 2"); } double dist; if (!distfunc(GEOShandle, curgeom1, curgeom2, &dist)) error("rgeos_distancefunc: unable to calculate distance"); NUMERIC_POINTER(ans)[n*i+j] = dist; if (sym_ans) NUMERIC_POINTER(ans)[n*j+i] = dist; } } if (LOGICAL_POINTER(byid)[0] || LOGICAL_POINTER(byid)[1]) { SEXP dims; PROTECT(dims = NEW_INTEGER(2)); pc++; INTEGER_POINTER(dims)[0] = n; INTEGER_POINTER(dims)[1] = m; setAttrib(ans, R_DimSymbol, dims); } GEOSGeom_destroy_r(GEOShandle, geom1); if (!sym_ans) GEOSGeom_destroy_r(GEOShandle, geom2); UNPROTECT(pc); return(ans); }
bool QgsGeometryAnalyzer::createOffsetGeometry( QgsGeometry* geom, QgsGeometry* lineGeom, double offset ) { if ( !geom || !lineGeom ) { return false; } QList<QgsGeometry*> inputGeomList; if ( geom->isMultipart() ) { inputGeomList = geom->asGeometryCollection(); } else { inputGeomList.push_back( geom ); } QList<GEOSGeometry*> outputGeomList; QList<QgsGeometry*>::const_iterator inputGeomIt = inputGeomList.constBegin(); GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler(); for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt ) { if ( geom->type() == QGis::Line ) { //geos 3.3 needed for line offsets #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \ ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3))) GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( geosctxt, ( *inputGeomIt )->asGeos(), -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ ); if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) ) { return false; } if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 ) { GEOSGeom_destroy_r( geosctxt, offsetGeom ); return false; } outputGeomList.push_back( offsetGeom ); #else outputGeomList.push_back( GEOSGeom_clone_r( geosctxt, ( *inputGeomIt )->asGeos() ) ); #endif } else if ( geom->type() == QGis::Point ) { QgsPoint p = ( *inputGeomIt )->asPoint(); p = createPointOffset( p.x(), p.y(), offset, lineGeom ); GEOSCoordSequence* ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 ); GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() ); GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() ); GEOSGeometry* geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq ); outputGeomList.push_back( geosPt ); } } if ( !geom->isMultipart() ) { GEOSGeometry* outputGeom = outputGeomList.at( 0 ); if ( outputGeom ) { geom->fromGeos( outputGeom ); } } else { GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()]; for ( int i = 0; i < outputGeomList.size(); ++i ) { geomArray[i] = outputGeomList.at( i ); } GEOSGeometry* collection = 0; if ( geom->type() == QGis::Point ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() ); } else if ( geom->type() == QGis::Line ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() ); } geom->fromGeos( collection ); delete[] geomArray; } return true; }
bool Layer::registerFeature( const QString& geom_id, PalGeometry *userGeom, double label_x, double label_y, const QString &labelText, double labelPosX, double labelPosY, bool fixedPos, double angle, bool fixedAngle, int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow, double repeatDistance ) { if ( geom_id.isEmpty() || label_x < 0 || label_y < 0 ) return false; mMutex.lock(); if ( hashtable->contains( geom_id ) ) { mMutex.unlock(); //A feature with this id already exists. Don't throw an exception as sometimes, //the same feature is added twice (dateline split with otf-reprojection) return false; } // Split MULTI GEOM and Collection in simple geometries const GEOSGeometry *the_geom = userGeom->getGeosGeometry(); Feature* f = new Feature( this, geom_id, userGeom, label_x, label_y ); if ( fixedPos ) { f->setFixedPosition( labelPosX, labelPosY ); } if ( xQuadOffset != 0 || yQuadOffset != 0 ) { f->setQuadOffset( xQuadOffset, yQuadOffset ); } if ( xOffset != 0.0 || yOffset != 0.0 ) { f->setPosOffset( xOffset, yOffset ); } if ( fixedAngle ) { f->setFixedAngle( angle ); } // use layer-level defined rotation, but not if position fixed if ( !fixedPos && angle != 0.0 ) { f->setFixedAngle( angle ); } f->setRepeatDistance( repeatDistance ); f->setAlwaysShow( alwaysShow ); bool first_feat = true; double geom_size = -1, biggest_size = -1; FeaturePart* biggest_part = NULL; // break the (possibly multi-part) geometry into simple geometries QLinkedList<const GEOSGeometry*>* simpleGeometries = unmulti( the_geom ); if ( simpleGeometries == NULL ) // unmulti() failed? { mMutex.unlock(); throw InternalException::UnknownGeometry(); } GEOSContextHandle_t geosctxt = geosContext(); while ( simpleGeometries->size() > 0 ) { const GEOSGeometry* geom = simpleGeometries->takeFirst(); // ignore invalid geometries (e.g. polygons with self-intersecting rings) if ( GEOSisValid_r( geosctxt, geom ) != 1 ) // 0=invalid, 1=valid, 2=exception { // std::cerr << "ignoring invalid feature " << geom_id << std::endl; continue; } int type = GEOSGeomTypeId_r( geosctxt, geom ); if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON ) { mMutex.unlock(); throw InternalException::UnknownGeometry(); } FeaturePart* fpart = new FeaturePart( f, geom ); // ignore invalid geometries if (( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) || ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) ) { delete fpart; continue; } // polygons: reorder coordinates if ( type == GEOS_POLYGON && reorderPolygon( fpart->nbPoints, fpart->x, fpart->y ) != 0 ) { delete fpart; continue; } if ( mMode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) ) { if ( type == GEOS_LINESTRING ) GEOSLength_r( geosctxt, geom, &geom_size ); else if ( type == GEOS_POLYGON ) GEOSArea_r( geosctxt, geom, &geom_size ); if ( geom_size > biggest_size ) { biggest_size = geom_size; delete biggest_part; // safe with NULL part biggest_part = fpart; } continue; // don't add the feature part now, do it later // TODO: we should probably add also other parts to act just as obstacles } // feature part is ready! addFeaturePart( fpart, labelText ); first_feat = false; } delete simpleGeometries; userGeom->releaseGeosGeometry( the_geom ); mMutex.unlock(); // if using only biggest parts... if (( mMode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL ) { addFeaturePart( biggest_part, labelText ); first_feat = false; } // add feature to layer if we have added something if ( !first_feat ) { features->append( f ); hashtable->insert( geom_id, f ); } else { delete f; } return !first_feat; // true if we've added something }
VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass) { VALUE result; RGeo_FactoryData* factory_data; GEOSContextHandle_t factory_context; VALUE klasses; RGeo_Globals* globals; VALUE inferred_klass; char is_collection; RGeo_GeometryData* data; result = Qnil; if (geom || !NIL_P(klass)) { factory_data = NIL_P(factory) ? NULL : RGEO_FACTORY_DATA_PTR(factory); factory_context = factory_data ? factory_data->geos_context : NULL; globals = factory_data ? factory_data->globals : NULL; // We don't allow "empty" points, so replace such objects with // an empty collection. if (geom && factory) { if (GEOSGeomTypeId_r(factory_context, geom) == GEOS_POINT && GEOSGetNumCoordinates_r(factory_context, geom) == 0) { GEOSGeom_destroy_r(factory_context, geom); geom = GEOSGeom_createCollection_r(factory_context, GEOS_GEOMETRYCOLLECTION, NULL, 0); klass = globals->geos_geometry_collection; } } klasses = Qnil; if (TYPE(klass) != T_CLASS) { inferred_klass = Qnil; is_collection = 0; switch (GEOSGeomTypeId_r(factory_context, geom)) { case GEOS_POINT: inferred_klass = globals->geos_point; break; case GEOS_LINESTRING: inferred_klass = globals->geos_line_string; break; case GEOS_LINEARRING: inferred_klass = globals->geos_linear_ring; break; case GEOS_POLYGON: inferred_klass = globals->geos_polygon; break; case GEOS_MULTIPOINT: inferred_klass = globals->geos_multi_point; is_collection = 1; break; case GEOS_MULTILINESTRING: inferred_klass = globals->geos_multi_line_string; is_collection = 1; break; case GEOS_MULTIPOLYGON: inferred_klass = globals->geos_multi_polygon; is_collection = 1; break; case GEOS_GEOMETRYCOLLECTION: inferred_klass = globals->geos_geometry_collection; is_collection = 1; break; default: inferred_klass = globals->geos_geometry; break; } if (TYPE(klass) == T_ARRAY && is_collection) { klasses = klass; } klass = inferred_klass; } data = ALLOC(RGeo_GeometryData); if (data) { if (geom) { GEOSSetSRID_r(factory_context, geom, factory_data->srid); } data->geos_context = factory_context; data->geom = geom; data->prep = factory_data && ((factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC) != 0) ? (GEOSPreparedGeometry*)1 : NULL; data->factory = factory; data->klasses = klasses; result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data); } } return result; }
static GEOSGeometry *LWGEOM_GEOS_makeValidMultiLine( const GEOSGeometry *gin, QString &errorMessage ) { GEOSContextHandle_t handle = QgsGeos::getGEOSHandler(); int ngeoms = GEOSGetNumGeometries_r( handle, gin ); uint32_t nlines_alloc = ngeoms; QVector<GEOSGeometry *> lines; QVector<GEOSGeometry *> points; lines.reserve( nlines_alloc ); points.reserve( ngeoms ); for ( int i = 0; i < ngeoms; ++i ) { const GEOSGeometry *g = GEOSGetGeometryN_r( handle, gin, i ); GEOSGeometry *vg = LWGEOM_GEOS_makeValidLine( g, errorMessage ); if ( GEOSisEmpty_r( handle, vg ) ) { // we don't care about this one GEOSGeom_destroy_r( handle, vg ); } if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_POINT ) { points.append( vg ); } else if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_LINESTRING ) { lines.append( vg ); } else if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_MULTILINESTRING ) { int nsubgeoms = GEOSGetNumGeometries_r( handle, vg ); nlines_alloc += nsubgeoms; lines.reserve( nlines_alloc ); for ( int j = 0; j < nsubgeoms; ++j ) { // NOTE: ownership of the cloned geoms will be taken by final collection lines.append( GEOSGeom_clone_r( handle, GEOSGetGeometryN_r( handle, vg, j ) ) ); } } else { // NOTE: return from GEOSGeomType will leak but we really don't expect this to happen errorMessage = QStringLiteral( "unexpected geom type returned by LWGEOM_GEOS_makeValid: %1" ).arg( GEOSGeomTypeId_r( handle, vg ) ); } } GEOSGeometry *mpoint_out = nullptr; if ( points.count() ) { if ( points.count() > 1 ) { mpoint_out = GEOSGeom_createCollection_r( handle, GEOS_MULTIPOINT, points.data(), points.count() ); } else { mpoint_out = points[0]; } } GEOSGeometry *mline_out = nullptr; if ( lines.count() ) { if ( lines.count() > 1 ) { mline_out = GEOSGeom_createCollection_r( handle, GEOS_MULTILINESTRING, lines.data(), lines.count() ); } else { mline_out = lines[0]; } } if ( mline_out && mpoint_out ) { GEOSGeometry *collection[2]; collection[0] = mline_out; collection[1] = mpoint_out; return GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, collection, 2 ); } else if ( mline_out ) { return mline_out; } else if ( mpoint_out ) { return mpoint_out; } else { return nullptr; } }
void Layer::chopFeaturesAtRepeatDistance() { GEOSContextHandle_t geosctxt = geosContext(); QLinkedList<FeaturePart*> * newFeatureParts = new QLinkedList<FeaturePart*>; while ( !featureParts->isEmpty() ) { FeaturePart* fpart = featureParts->takeFirst(); const GEOSGeometry* geom = fpart->geos(); double chopInterval = fpart->getFeature()->repeatDistance(); if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING ) { double bmin[2], bmax[2]; fpart->getBoundingBox( bmin, bmax ); rtree->Remove( bmin, bmax, fpart ); const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom ); // get number of points unsigned int n; GEOSCoordSeq_getSize_r( geosctxt, cs, &n ); // Read points std::vector<Point> points( n ); for ( unsigned int i = 0; i < n; ++i ) { GEOSCoordSeq_getX_r( geosctxt, cs, i, &points[i].x ); GEOSCoordSeq_getY_r( geosctxt, cs, i, &points[i].y ); } // Cumulative length vector std::vector<double> len( n, 0 ); for ( unsigned int i = 1; i < n; ++i ) { double dx = points[i].x - points[i - 1].x; double dy = points[i].y - points[i - 1].y; len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy ); } // Walk along line unsigned int cur = 0; double lambda = 0; std::vector<Point> part; for ( ;; ) { lambda += chopInterval; for ( ; cur < n && lambda > len[cur]; ++cur ) { part.push_back( points[cur] ); } if ( cur >= n ) { break; } double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] ); Point p; p.x = points[cur - 1].x + c * ( points[cur].x - points[cur - 1].x ); p.y = points[cur - 1].y + c * ( points[cur].y - points[cur - 1].y ); part.push_back( p ); GEOSCoordSequence* cooSeq = GEOSCoordSeq_create_r( geosctxt, part.size(), 2 ); for ( std::size_t i = 0; i < part.size(); ++i ) { GEOSCoordSeq_setX_r( geosctxt, cooSeq, i, part[i].x ); GEOSCoordSeq_setY_r( geosctxt, cooSeq, i, part[i].y ); } GEOSGeometry* newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq ); FeaturePart* newfpart = new FeaturePart( fpart->getFeature(), newgeom ); newFeatureParts->append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); rtree->Insert( bmin, bmax, newfpart ); part.clear(); part.push_back( p ); } // Create final part part.push_back( points[n - 1] ); GEOSCoordSequence* cooSeq = GEOSCoordSeq_create_r( geosctxt, part.size(), 2 ); for ( std::size_t i = 0; i < part.size(); ++i ) { GEOSCoordSeq_setX_r( geosctxt, cooSeq, i, part[i].x ); GEOSCoordSeq_setY_r( geosctxt, cooSeq, i, part[i].y ); } GEOSGeometry* newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq ); FeaturePart* newfpart = new FeaturePart( fpart->getFeature(), newgeom ); newFeatureParts->append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); rtree->Insert( bmin, bmax, newfpart ); } else { newFeatureParts->append( fpart ); } } delete featureParts; featureParts = newFeatureParts; }
SEXP rgeos_geosline2SpatialLines(SEXP env, GEOSGeom geom, SEXP p4s, SEXP idlist, int nlines) { GEOSContextHandle_t GEOShandle = getContextHandle(env); GEOSGeom curgeom; GEOSGeom subgeom; GEOSCoordSeq s; int type = GEOSGeomTypeId_r(GEOShandle, geom); if (type != GEOS_LINESTRING && type != GEOS_MULTILINESTRING && type != GEOS_LINEARRING && type != GEOS_GEOMETRYCOLLECTION ) { error("rgeos_geosline2SpatialLines: invalid type"); } if (nlines < 1) error("rgeos_geosline2SpatialLines: invalid number of geometries"); int pc=0; if (nlines > length(idlist)) error("rgeos_geosline2SpatialLines: nlines > length(idlist)"); SEXP bbox, lines_list; PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++; PROTECT(lines_list = NEW_LIST(nlines)); pc++; for(int j = 0; j < nlines; j++) { curgeom = (type == GEOS_GEOMETRYCOLLECTION) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, j) : geom; if (curgeom == NULL) error("rgeos_geosline2SpatialLines: unable to get geometry collection geometry"); int curtype = GEOSGeomTypeId_r(GEOShandle, curgeom); int n = GEOSGetNumGeometries_r(GEOShandle, curgeom); if (n == -1) error("rgeos_geosline2SpatialLines: invalid number of geometries in current geometry"); n = n ? n : 1; SEXP line_list; PROTECT(line_list = NEW_LIST(n)); for(int i = 0; i < n; i++) { subgeom = (curtype == GEOS_MULTILINESTRING && !GEOSisEmpty_r(GEOShandle, curgeom)) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, curgeom, i) : curgeom; if(subgeom == NULL) error("rgeos_geosline2SpatialLines: unable to get subgeometry"); SEXP crdmat; if (GEOSisEmpty_r(GEOShandle, subgeom) == 0) { s = (GEOSCoordSeq) GEOSGeom_getCoordSeq_r(GEOShandle, subgeom); if (s == NULL) error("rgeos_geosline2SpatialLines: unable to generate coordinate sequence"); PROTECT( crdmat = rgeos_CoordSeq2crdMat(env, s, FALSE, FALSE)); } else { error("rgeos_geosline2SpatialLines: empty line found"); // PROTECT( crdmat = R_NilValue); } SEXP line; PROTECT(line = NEW_OBJECT(MAKE_CLASS("Line"))); SET_SLOT(line, install("coords"), crdmat); SET_VECTOR_ELT(line_list, i, line ); UNPROTECT(2); } SEXP lines; PROTECT( lines = NEW_OBJECT(MAKE_CLASS("Lines")) ); SET_SLOT(lines, install("Lines"), line_list); char idbuf[BUFSIZ]; strcpy(idbuf, CHAR( STRING_ELT(idlist, j) )); SEXP id; PROTECT( id = NEW_CHARACTER(1) ); SET_STRING_ELT(id, 0, COPY_TO_USER_STRING(idbuf)); SET_SLOT(lines, install("ID"), id); SET_VECTOR_ELT( lines_list, j, lines ); UNPROTECT(3); } SEXP ans; PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialLines"))); pc++; SET_SLOT(ans, install("lines"), lines_list); SET_SLOT(ans, install("bbox"), bbox); SET_SLOT(ans, install("proj4string"), p4s); UNPROTECT(pc); return(ans); }
Q_NOWARN_UNREACHABLE_POP // Return Nth vertex in GEOSGeometry as a POINT. // May return NULL if the geometry has NO vertexex. static GEOSGeometry *LWGEOM_GEOS_getPointN( const GEOSGeometry *g_in, uint32_t n ) { GEOSContextHandle_t handle = QgsGeos::getGEOSHandler(); uint32_t dims; const GEOSCoordSequence *seq_in = nullptr; GEOSCoordSeq seq_out; double val; uint32_t sz; int gn; GEOSGeometry *ret = nullptr; switch ( GEOSGeomTypeId_r( handle, g_in ) ) { case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: case GEOS_GEOMETRYCOLLECTION: { for ( gn = 0; gn < GEOSGetNumGeometries_r( handle, g_in ); ++gn ) { const GEOSGeometry *g = GEOSGetGeometryN_r( handle, g_in, gn ); ret = LWGEOM_GEOS_getPointN( g, n ); if ( ret ) return ret; } break; } case GEOS_POLYGON: { ret = LWGEOM_GEOS_getPointN( GEOSGetExteriorRing_r( handle, g_in ), n ); if ( ret ) return ret; for ( gn = 0; gn < GEOSGetNumInteriorRings_r( handle, g_in ); ++gn ) { const GEOSGeometry *g = GEOSGetInteriorRingN_r( handle, g_in, gn ); ret = LWGEOM_GEOS_getPointN( g, n ); if ( ret ) return ret; } break; } case GEOS_POINT: case GEOS_LINESTRING: case GEOS_LINEARRING: break; } seq_in = GEOSGeom_getCoordSeq_r( handle, g_in ); if ( ! seq_in ) return nullptr; if ( ! GEOSCoordSeq_getSize_r( handle, seq_in, &sz ) ) return nullptr; if ( ! sz ) return nullptr; if ( ! GEOSCoordSeq_getDimensions_r( handle, seq_in, &dims ) ) return nullptr; seq_out = GEOSCoordSeq_create_r( handle, 1, dims ); if ( ! seq_out ) return nullptr; if ( ! GEOSCoordSeq_getX_r( handle, seq_in, n, &val ) ) return nullptr; if ( ! GEOSCoordSeq_setX_r( handle, seq_out, n, val ) ) return nullptr; if ( ! GEOSCoordSeq_getY_r( handle, seq_in, n, &val ) ) return nullptr; if ( ! GEOSCoordSeq_setY_r( handle, seq_out, n, val ) ) return nullptr; if ( dims > 2 ) { if ( ! GEOSCoordSeq_getZ_r( handle, seq_in, n, &val ) ) return nullptr; if ( ! GEOSCoordSeq_setZ_r( handle, seq_out, n, val ) ) return nullptr; } return GEOSGeom_createPoint_r( handle, seq_out ); }
SEXP rgeos_geosring2SpatialRings(SEXP env, GEOSGeom geom, SEXP p4s, SEXP idlist, int nrings) { GEOSContextHandle_t GEOShandle = getContextHandle(env); int type = GEOSGeomTypeId_r(GEOShandle, geom); if (type != GEOS_LINEARRING && type != GEOS_GEOMETRYCOLLECTION ) error("rgeos_geosring2SpatialRings: invalid type"); if (nrings < 1) error("rgeos_geosring2SpatialRings: invalid number of geometries"); int pc=0; SEXP bbox, rings_list; PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++; PROTECT(rings_list = NEW_LIST(nrings)); pc++; for(int j = 0; j < nrings; j++) { GEOSGeom curgeom = (type == GEOS_GEOMETRYCOLLECTION) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, j) : geom; if (curgeom == NULL) error("rgeos_geosring2SpatialRings: unable to get geometry collection geometry"); SEXP crdmat; if (GEOSisEmpty_r(GEOShandle, curgeom) == 0) { GEOSCoordSeq s = (GEOSCoordSeq) GEOSGeom_getCoordSeq_r(GEOShandle, curgeom); if (s == NULL) error("rgeos_geosring2SpatialRings: unable to generate coordinate sequence"); PROTECT(crdmat = rgeos_crdMatFixDir(PROTECT(rgeos_CoordSeq2crdMat(env, s, FALSE, FALSE)), FALSE)); pc += 2; } else { PROTECT( crdmat = R_NilValue); pc++; } SEXP ring; PROTECT(ring = NEW_OBJECT(MAKE_CLASS("Ring"))); pc++; SET_SLOT(ring, install("coords"), crdmat); SEXP id; PROTECT( id = NEW_CHARACTER(1) ); pc++; char idbuf[BUFSIZ]; strcpy(idbuf, CHAR( STRING_ELT(idlist, j) )); SET_STRING_ELT(id, 0, COPY_TO_USER_STRING(idbuf)); SET_SLOT(ring, install("ID"), id); SET_VECTOR_ELT(rings_list, j, ring ); UNPROTECT(pc); } SEXP ans; PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialRings"))); pc++; SET_SLOT(ans, install("rings"), rings_list); SET_SLOT(ans, install("bbox"), bbox); SET_SLOT(ans, install("proj4string"), p4s); UNPROTECT(pc); return(ans); }
QgsGeometry QgsGeometryAnalyzer::createOffsetGeometry( const QgsGeometry& geom, const QgsGeometry& lineGeom, double offset ) { if ( !geom || lineGeom.isEmpty() ) { return QgsGeometry(); } QList<QgsGeometry> inputGeomList; if ( geom.isMultipart() ) { inputGeomList = geom.asGeometryCollection(); } else { inputGeomList.push_back( geom ); } QList<GEOSGeometry*> outputGeomList; QList<QgsGeometry>::const_iterator inputGeomIt = inputGeomList.constBegin(); GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler(); for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt ) { if ( geom.type() == QgsWkbTypes::LineGeometry ) { GEOSGeometry* inputGeomItGeos = inputGeomIt->exportToGeos(); GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( geosctxt, inputGeomItGeos, -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ ); GEOSGeom_destroy_r( geosctxt, inputGeomItGeos ); if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) ) { return QgsGeometry(); } if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 ) { GEOSGeom_destroy_r( geosctxt, offsetGeom ); return QgsGeometry(); } outputGeomList.push_back( offsetGeom ); } else if ( geom.type() == QgsWkbTypes::PointGeometry ) { QgsPoint p = ( *inputGeomIt ).asPoint(); p = createPointOffset( p.x(), p.y(), offset, lineGeom ); GEOSCoordSequence* ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 ); GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() ); GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() ); GEOSGeometry* geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq ); outputGeomList.push_back( geosPt ); } } QgsGeometry outGeometry; if ( !geom.isMultipart() ) { GEOSGeometry* outputGeom = outputGeomList.at( 0 ); if ( outputGeom ) { outGeometry.fromGeos( outputGeom ); } } else { GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()]; for ( int i = 0; i < outputGeomList.size(); ++i ) { geomArray[i] = outputGeomList.at( i ); } GEOSGeometry* collection = nullptr; if ( geom.type() == QgsWkbTypes::PointGeometry ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() ); } else if ( geom.type() == QgsWkbTypes::LineGeometry ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() ); } outGeometry.fromGeos( collection ); delete[] geomArray; } return outGeometry; }
// Will return NULL on error (expect error handler being called by then) Q_NOWARN_UNREACHABLE_PUSH static GEOSGeometry *LWGEOM_GEOS_makeValidPolygon( const GEOSGeometry *gin, QString &errorMessage ) { GEOSContextHandle_t handle = QgsGeos::getGEOSHandler(); GEOSGeom gout; GEOSGeom geos_bound; GEOSGeom geos_cut_edges, geos_area, collapse_points; GEOSGeometry *vgeoms[3]; // One for area, one for cut-edges unsigned int nvgeoms = 0; Q_ASSERT( GEOSGeomTypeId_r( handle, gin ) == GEOS_POLYGON || GEOSGeomTypeId_r( handle, gin ) == GEOS_MULTIPOLYGON ); geos_bound = GEOSBoundary_r( handle, gin ); if ( !geos_bound ) return nullptr; // Use noded boundaries as initial "cut" edges geos_cut_edges = LWGEOM_GEOS_nodeLines( geos_bound ); if ( !geos_cut_edges ) { GEOSGeom_destroy_r( handle, geos_bound ); errorMessage = QStringLiteral( "LWGEOM_GEOS_nodeLines() failed" ); return nullptr; } // NOTE: the noding process may drop lines collapsing to points. // We want to retrieve any of those { GEOSGeometry *pi = nullptr; GEOSGeometry *po = nullptr; try { pi = GEOSGeom_extractUniquePoints_r( handle, geos_bound ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_bound ); errorMessage = QStringLiteral( "GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() ); return nullptr; } try { po = GEOSGeom_extractUniquePoints_r( handle, geos_cut_edges ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_bound ); GEOSGeom_destroy_r( handle, pi ); errorMessage = QStringLiteral( "GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() ); return nullptr; } try { collapse_points = GEOSDifference_r( handle, pi, po ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_bound ); GEOSGeom_destroy_r( handle, pi ); GEOSGeom_destroy_r( handle, po ); errorMessage = QStringLiteral( "GEOSDifference(): %1" ).arg( e.what() ); return nullptr; } GEOSGeom_destroy_r( handle, pi ); GEOSGeom_destroy_r( handle, po ); } GEOSGeom_destroy_r( handle, geos_bound ); // And use an empty geometry as initial "area" try { geos_area = GEOSGeom_createEmptyPolygon_r( handle ); } catch ( GEOSException &e ) { errorMessage = QStringLiteral( "GEOSGeom_createEmptyPolygon(): %1" ).arg( e.what() ); GEOSGeom_destroy_r( handle, geos_cut_edges ); return nullptr; } // See if an area can be build with the remaining edges // and if it can, symdifference with the original area. // Iterate this until no more polygons can be created // with left-over edges. while ( GEOSGetNumGeometries_r( handle, geos_cut_edges ) ) { GEOSGeometry *new_area = nullptr; GEOSGeometry *new_area_bound = nullptr; GEOSGeometry *symdif = nullptr; GEOSGeometry *new_cut_edges = nullptr; // ASSUMPTION: cut_edges should already be fully noded try { new_area = LWGEOM_GEOS_buildArea( geos_cut_edges, errorMessage ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_cut_edges ); GEOSGeom_destroy_r( handle, geos_area ); errorMessage = QStringLiteral( "LWGEOM_GEOS_buildArea() threw an error: %1" ).arg( e.what() ); return nullptr; } if ( GEOSisEmpty_r( handle, new_area ) ) { // no more rings can be build with thes edges GEOSGeom_destroy_r( handle, new_area ); break; } // We succeeded in building a ring ! // Save the new ring boundaries first (to compute // further cut edges later) try { new_area_bound = GEOSBoundary_r( handle, new_area ); } catch ( GEOSException &e ) { // We did check for empty area already so // this must be some other error errorMessage = QStringLiteral( "GEOSBoundary() threw an error: %1" ).arg( e.what() ); GEOSGeom_destroy_r( handle, new_area ); GEOSGeom_destroy_r( handle, geos_area ); return nullptr; } // Now symdiff new and old area try { symdif = GEOSSymDifference_r( handle, geos_area, new_area ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_cut_edges ); GEOSGeom_destroy_r( handle, new_area ); GEOSGeom_destroy_r( handle, new_area_bound ); GEOSGeom_destroy_r( handle, geos_area ); errorMessage = QStringLiteral( "GEOSSymDifference() threw an error: %1" ).arg( e.what() ); return nullptr; } GEOSGeom_destroy_r( handle, geos_area ); GEOSGeom_destroy_r( handle, new_area ); geos_area = symdif; symdif = nullptr; // Now let's re-set geos_cut_edges with what's left // from the original boundary. // ASSUMPTION: only the previous cut-edges can be // left, so we don't need to reconsider // the whole original boundaries // // NOTE: this is an expensive operation. try { new_cut_edges = GEOSDifference_r( handle, geos_cut_edges, new_area_bound ); } catch ( GEOSException &e ) { GEOSGeom_destroy_r( handle, geos_cut_edges ); GEOSGeom_destroy_r( handle, new_area_bound ); GEOSGeom_destroy_r( handle, geos_area ); errorMessage = QStringLiteral( "GEOSDifference() threw an error: %1" ).arg( e.what() ); return nullptr; } GEOSGeom_destroy_r( handle, geos_cut_edges ); GEOSGeom_destroy_r( handle, new_area_bound ); geos_cut_edges = new_cut_edges; } if ( !GEOSisEmpty_r( handle, geos_area ) ) { vgeoms[nvgeoms++] = geos_area; } else { GEOSGeom_destroy_r( handle, geos_area ); } if ( !GEOSisEmpty_r( handle, geos_cut_edges ) ) { vgeoms[nvgeoms++] = geos_cut_edges; } else { GEOSGeom_destroy_r( handle, geos_cut_edges ); } if ( !GEOSisEmpty_r( handle, collapse_points ) ) { vgeoms[nvgeoms++] = collapse_points; } else { GEOSGeom_destroy_r( handle, collapse_points ); } if ( 1 == nvgeoms ) { // Return cut edges gout = vgeoms[0]; } else { // Collect areas and lines (if any line) try { gout = GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, vgeoms, nvgeoms ); } catch ( GEOSException &e ) { errorMessage = QStringLiteral( "GEOSGeom_createCollection() threw an error: %1" ).arg( e.what() ); // TODO: cleanup! return nullptr; } } return gout; }