EVOLUTION-MANAGER
Edit File: CoverageUnion.cpp
/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2019 Daniel Baston <dbaston@gmail.com> * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * **********************************************************************/ #include <geos/operation/union/CoverageUnion.h> #include <geos/geom/GeometryCollection.h> #include <geos/geom/GeometryFactory.h> #include <geos/geom/LineString.h> #include <geos/geom/Polygon.h> #include <geos/operation/polygonize/Polygonizer.h> #include <geos/util/IllegalArgumentException.h> #include <geos/util/TopologyException.h> namespace geos { namespace operation { namespace geounion { using geos::geom::Geometry; using geos::geom::LineSegment; using geos::geom::LineString; using geos::geom::Polygon; using geos::geom::GeometryCollection; using geos::geom::GeometryFactory; using geos::operation::polygonize::Polygonizer; void CoverageUnion::extractSegments(const Geometry* geom) { const Polygon* p = dynamic_cast<const Polygon*>(geom); if (p != nullptr) { extractSegments(p); } else { auto gc = dynamic_cast<const GeometryCollection*>(geom); if (gc == nullptr) { throw geos::util::IllegalArgumentException("Unhandled geometry type in CoverageUnion."); } for (size_t i = 0; i < gc->getNumGeometries(); i++) { extractSegments(gc->getGeometryN(i)); } } } void CoverageUnion::extractSegments(const Polygon* p) { const LineString* ring = p->getExteriorRing(); extractSegments(ring); for (size_t i = 0; i < p->getNumInteriorRing(); i++) { extractSegments(p->getInteriorRingN(i)); } } void CoverageUnion::extractSegments(const LineString* ls) { auto coords = ls->getCoordinatesRO(); if (coords->isEmpty()) return; for (size_t i = 1; i < coords->size(); i++) { LineSegment segment{coords->getAt(i), coords->getAt(i-1)}; segment.normalize(); if (!segments.erase(segment)) { segments.emplace(std::move(segment)); } } } std::unique_ptr<Geometry> CoverageUnion::polygonize(const GeometryFactory* gf) { Polygonizer p{true}; // Create a vector to manage the lifecycle of a geometry corresponding to each line segment. // Polygonizer needs these to stay alive until it does its work. std::unique_ptr<std::vector<std::unique_ptr<Geometry>>> segment_geoms; segment_geoms.reset(new std::vector<std::unique_ptr<Geometry>>()); segment_geoms->reserve(segments.size()); for (const LineSegment& segment : segments) { auto seg_geom = segment.toGeometry(*gf); p.add(static_cast<Geometry*>(seg_geom.get())); segment_geoms->emplace_back(std::move(seg_geom)); } if (!p.allInputsFormPolygons()) { throw geos::util::TopologyException("CoverageUnion cannot process incorrectly noded inputs."); } auto polygons = p.getPolygons(); segment_geoms.reset(); if (polygons->size() == 1) { return std::unique_ptr<Geometry>((*polygons)[0].release()); } return gf->createMultiPolygon(std::move(*polygons)); } std::unique_ptr<geom::Geometry> CoverageUnion::Union(const geom::Geometry* geom) { CoverageUnion cu; cu.extractSegments(geom); double area_in = geom->getArea(); auto ret = cu.polygonize(geom->getFactory()); double area_out = ret->getArea(); if (std::abs((area_out - area_in)/area_in) > AREA_PCT_DIFF_TOL) { throw geos::util::TopologyException("CoverageUnion cannot process overlapping inputs."); } return ret; } } } }