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) ); }
Polygon Polygon::simplify(double distance_tolerance, double area_tolerance) const { GEOSGeometry *smoothed = GEOSTopologyPreserveSimplify_r(m_ctx, m_geom, distance_tolerance); if (!smoothed) throw pdal_error("Unable to simplify input geometry!"); std::vector<GEOSGeometry*> geometries; int numGeom = GEOSGetNumGeometries_r(m_ctx, smoothed); for (int n = 0; n < numGeom; ++n) { const GEOSGeometry* m = GEOSGetGeometryN_r(m_ctx, smoothed, n); if (!m) throw pdal::pdal_error("Unable to Get GeometryN"); const GEOSGeometry* ering = GEOSGetExteriorRing_r(m_ctx, m); if (!ering) throw pdal::pdal_error("Unable to Get Exterior Ring"); GEOSGeometry* exterior = GEOSGeom_clone_r(m_ctx, GEOSGetExteriorRing_r(m_ctx, m)); if (!exterior) throw pdal::pdal_error("Unable to clone exterior ring!"); std::vector<GEOSGeometry*> keep_rings; int numRings = GEOSGetNumInteriorRings_r(m_ctx, m); for (int i = 0; i < numRings; ++i) { double area(0.0); const GEOSGeometry* iring = GEOSGetInteriorRingN_r(m_ctx, m, i); if (!iring) throw pdal::pdal_error("Unable to Get Interior Ring"); GEOSGeometry* cring = GEOSGeom_clone_r(m_ctx, iring); if (!cring) throw pdal::pdal_error("Unable to clone interior ring!"); GEOSGeometry* aring = GEOSGeom_createPolygon_r(m_ctx, cring, NULL, 0); int errored = GEOSArea_r(m_ctx, aring, &area); if (errored == 0) throw pdal::pdal_error("Unable to get area of ring!"); if (area > area_tolerance) { keep_rings.push_back(cring); } } GEOSGeometry* p = GEOSGeom_createPolygon_r(m_ctx, exterior, keep_rings.data(), keep_rings.size()); if (p == NULL) throw pdal::pdal_error("smooth polygon could not be created!" ); geometries.push_back(p); } GEOSGeometry* o = GEOSGeom_createCollection_r(m_ctx, GEOS_MULTIPOLYGON, geometries.data(), geometries.size()); Polygon p(o, m_srs, m_ctx); GEOSGeom_destroy_r(m_ctx, smoothed); GEOSGeom_destroy_r(m_ctx, o); return p; }