/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2020 Sandro Santilli * Copyright (C) 2020 Paul Ramsey * * 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. * ********************************************************************** * * Last Port: operation/overlayng/OverlayNG.java 4c88fea52 * **********************************************************************/ #pragma once #include #include #include #include #include #include // Forward declarations namespace geos { namespace geom { class GeometryFactory; class PrecisionModel; } namespace noding { class Noder; } namespace operation { namespace overlayng { } } } namespace geos { // geos. namespace operation { // geos.operation namespace overlayng { // geos.operation.overlayng /** * Computes the geometric overlay of two {@link geom::Geometry}s, * using an explicit precision model to allow robust computation. * The overlay can be used to determine any of the * following set-theoretic operations (boolean combinations) of the geometries: * * * INTERSECTION - all points which lie in both geometries * * UNION - all points which lie in at least one geometry * * DIFFERENCE - all points which lie in the first geometry but not the second * * SYMDIFFERENCE - all points which lie in one geometry but not both * * The requirements for overlay input are: * * Input collections must be homogeneous * (all elements must have the same dimension). * * Inputs may be simple link GeometryCollections. * A GeometryCollection is simple if it can be flattened into a valid Multi-geometry; * i.e. it is homogeneous and does not contain any overlapping Polygons. * * In general, inputs must be valid geometries. * However, polygonal inputs may contain the following two kinds of "mild" invalid topology: * (i) rings which self-touch at discrete points (sometimes called inverted shells and exverted holes). * (ii) rings which touch along line segments (i.e. topology collapse). * * The precision model used for the computation can be supplied * independent of the precision model of the input geometry. * The main use for this is to allow using a fixed precision * for geometry with a floating precision model. * This does two things: ensures robust computation; * and forces the output to be validly rounded to the precision model. * * For fixed precision models noding is performed using a {@link noding::snapround::SnapRoundingNoder}. * This provides robust computation (as long as precision is limited to * around 13 decimal digits). * * For floating precision an {@link noding::MCIndexNoder} is used. * This is not fully robust, so can sometimes result in * {@link util::TopologyException}s being thrown. * For robust full-precision overlay see {@link OverlayNGRobust}. * * Note: If a {@link noding::snap::SnappingNoder} is used * it is best to specify a fairly small snap tolerance, * since the intersection clipping optimization can * interact with the snapping to alter the result. * * Optionally the overlay computation can process using strict mode * (via setStrictMode(boolean). In strict mode result semantics are: * * - Lines and Points resulting from topology collapses are not included * in the result * - Result geometry is homogeneous for the * INTERSECTION and DIFFERENCE operations. * - Result geometry is homogeneous for the * UNION and SYMDIFFERENCE operations if * the inputs have the same dimension. * * Strict mode has the following benefits: * * - Results are simpler * - Overlay operations are chainable without needing to remove * lower-dimension elements * * The original JTS overlay semantics correspond to non-strict mode. * * If a robustness error occurs, a TopologyException is thrown. * These are usually caused by numerical rounding causing the noding * output to not be fully noded. * For robust computation with full-precision {@link OverlayNGRobust} * can be used. * * @author mdavis * @see OverlayNGRobust * */ class GEOS_DLL OverlayNG { private: // Members const geom::PrecisionModel* pm; InputGeometry inputGeom; const geom::GeometryFactory* geomFact; int opCode; noding::Noder* noder; bool isStrictMode; bool isOptimized; bool isAreaResultOnly; bool isOutputEdges; bool isOutputResultEdges; bool isOutputNodedEdges; // Methods std::unique_ptr computeEdgeOverlay(); void labelGraph(OverlayGraph* graph); /** * Extracts the result geometry components from the fully labelled topology graph. * * This method implements the semantic that the result of an * intersection operation is homogeneous with highest dimension. * In other words, * if an intersection has components of a given dimension * no lower-dimension components are output. * For example, if two polygons intersect in an area, * no linestrings or points are included in the result, * even if portions of the input do meet in lines or points. * This semantic choice makes more sense for typical usage, * in which only the highest dimension components are of interest. */ std::unique_ptr extractResult(int opCode, OverlayGraph* graph); std::unique_ptr createEmptyResult(); public: /** * The default setting for Strict Mode. * * The original JTS overlay semantics used non-strict result * semantics, including; * - An Intersection result can be mixed-dimension, * due to inclusion of intersection components of all dimensions * - Results can include lines caused by Area topology collapse */ static constexpr bool STRICT_MODE_DEFAULT = false; static constexpr int INTERSECTION = 1; static constexpr int UNION = 2; static constexpr int DIFFERENCE = 3; static constexpr int SYMDIFFERENCE = 4; /** * Creates an overlay operation on the given geometries, * with a defined precision model. * The noding strategy is determined by the precision model. */ OverlayNG(const geom::Geometry* geom0, const geom::Geometry* geom1, const geom::GeometryFactory* p_geomFact, int p_opCode) : pm(p_geomFact->getPrecisionModel()) , inputGeom(geom0, geom1) , geomFact(p_geomFact) , opCode(p_opCode) , noder(nullptr) , isStrictMode(STRICT_MODE_DEFAULT) , isOptimized(true) , isAreaResultOnly(false) , isOutputEdges(false) , isOutputResultEdges(false) , isOutputNodedEdges(false) {} /** * Creates an overlay operation on the given geometries, * with a defined precision model. * The noding strategy is determined by the precision model. */ OverlayNG(const geom::Geometry* geom0, const geom::Geometry* geom1, const geom::PrecisionModel* p_pm, int p_opCode) : pm(p_pm) , inputGeom(geom0, geom1) , geomFact(geom0->getFactory()) , opCode(p_opCode) , noder(nullptr) , isStrictMode(STRICT_MODE_DEFAULT) , isOptimized(true) , isAreaResultOnly(false) , isOutputEdges(false) , isOutputResultEdges(false) , isOutputNodedEdges(false) {} /** * Creates an overlay operation on the given geometries * using the precision model of the geometries. * * The noder is chosen according to the precision model specified. * * - For {@link PrecisionModel#FIXED} * a snap-rounding noder is used, and the computation is robust. * - For {@link PrecisionModel#FLOATING} * a non-snapping noder is used, * and this computation may not be robust. * If errors occur a {@link util::TopologyException} is thrown. */ OverlayNG(const geom::Geometry* geom0, const geom::Geometry* geom1, int p_opCode) : OverlayNG(geom0, geom1, geom0->getFactory()->getPrecisionModel(), p_opCode) {} OverlayNG(const geom::Geometry* geom0, const geom::PrecisionModel* p_pm) : OverlayNG(geom0, nullptr, p_pm, UNION) {} /** * Sets whether overlay processing optimizations are enabled. * It may be useful to disable optimizations * for testing purposes. * Default is TRUE (optimization enabled). * * @param p_isOptimized whether to optimize processing */ void setOptimized(bool p_isOptimized) { isOptimized = p_isOptimized; } void setStrictMode(bool p_isStrictMode) { isStrictMode = p_isStrictMode; } void setAreaResultOnly(bool p_areaResultOnly) { isAreaResultOnly = p_areaResultOnly; } void setOutputEdges(bool p_isOutputEdges) { isOutputEdges = p_isOutputEdges; } void setOutputResultEdges(bool p_isOutputResultEdges) { isOutputResultEdges = p_isOutputResultEdges; } void setNoder(noding::Noder* p_noder) { noder = p_noder; } void setOutputNodedEdges(bool p_isOutputNodedEdges) { isOutputEdges = true; isOutputNodedEdges = p_isOutputNodedEdges; } /** * Gets the result of the overlay operation. * * @return the result of the overlay operation. * * @throws IllegalArgumentException if the input is not supported (e.g. a mixed-dimension geometry) * @throws TopologyException if a robustness error occurs */ std::unique_ptr getResult(); /** * Tests whether a point with a given topological {@link OverlayLabel} * relative to two geometries is contained in * the result of overlaying the geometries using * a given overlay operation. * * The method handles arguments of {@link geom::Location::NONE} correctly */ static bool isResultOfOpPoint(const OverlayLabel* label, int opCode); /** * Tests whether a point with given {@link geom::Location}s * relative to two geometries would be contained in * the result of overlaying the geometries using * a given overlay operation. * This is used to determine whether components * computed during the overlay process should be * included in the result geometry. * * The method handles arguments of {@link geom::Location::NONE} correctly. */ static bool isResultOfOp(int overlayOpCode, Location loc0, Location loc1); /** * Computes an overlay operation for * the given geometry operands, with the * noding strategy determined by the precision model. * * @param geom0 the first geometry argument * @param geom1 the second geometry argument * @param opCode the code for the desired overlay operation * @param pm the precision model to use * @return the result of the overlay operation */ static std::unique_ptr overlay(const Geometry* geom0, const Geometry* geom1, int opCode, const PrecisionModel* pm); /** * Computes an overlay operation on the given geometry operands, * using a supplied {@link noding::Noder}. * * @param geom0 the first geometry argument * @param geom1 the second geometry argument * @param opCode the code for the desired overlay operation * @param pm the precision model to use (which may be null if the noder does not use one) * @param noder the noder to use * @return the result of the overlay operation */ static std::unique_ptr overlay(const Geometry* geom0, const Geometry* geom1, int opCode, const PrecisionModel* pm, noding::Noder* noder); /** * Computes an overlay operation on the given geometry operands, * using a supplied {@link noding::Noder}. * * @param geom0 the first geometry argument * @param geom1 the second geometry argument * @param opCode the code for the desired overlay operation * @param noder the noder to use * @return the result of the overlay operation */ static std::unique_ptr overlay(const Geometry* geom0, const Geometry* geom1, int opCode, noding::Noder* noder); /** * Computes an overlay operation on * the given geometry operands, * using the precision model of the geometry. * and an appropriate noder. * * The noder is chosen according to the precision model specified. * * - For {@link geom::PrecisionModel#FIXED} * a snap-rounding noder is used, and the computation is robust. * - For {@link geom::PrecisionModel#FLOATING} * a non-snapping noder is used, * and this computation may not be robust. * If errors occur a {@link util::TopologyException} is thrown. * * @param geom0 the first argument geometry * @param geom1 the second argument geometry * @param opCode the code for the desired overlay operation * @return the result of the overlay operation */ static std::unique_ptr overlay(const Geometry* geom0, const Geometry* geom1, int opCode); /** * Computes a union operation on * the given geometry, with the supplied precision model. * The primary use for this is to perform precision reduction * (round the geometry to the supplied precision). * * The input must be a valid geometry. * Collections must be homogeneous. * IMPORTANT: You probably want OverlayNGUnaryUnion, not this. * * @param geom the geometry * @param pm the precision model to use * @return the result of the union operation * * @see OverlayMixedPoints * @see PrecisionReducer * @see UnaryUnionNG * @see CoverageUnion */ static std::unique_ptr geomunion(const Geometry* geom, const PrecisionModel* pm); /** * Computes a union of a single geometry using a custom noder. * * The primary use of this is to support coverage union. * * The input must be a valid geometry. * Collections must be homogeneous. * IMPORTANT: You probably want OverlayNGUnaryUnion, not this. * * @param geom the geometry to union * @param pm the precision model to use (maybe be null) * @param noder the noder to use * @return the result geometry * * @see CoverageUnion */ static std::unique_ptr geomunion(const Geometry* geom, const PrecisionModel* pm, noding::Noder* noder); }; } // namespace geos.operation.overlayng } // namespace geos.operation } // namespace geos