351 lines
10 KiB
C++
351 lines
10 KiB
C++
/**********************************************************************
|
|
*
|
|
* GEOS - Geometry Engine Open Source
|
|
* http://geos.osgeo.org
|
|
*
|
|
* Copyright (C) 2006 Refractions Research Inc.
|
|
* Copyright (C) 2001-2002 Vivid Solutions Inc.
|
|
*
|
|
* 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/polygonize/EdgeRing.java 0b3c7e3eb0d3e
|
|
*
|
|
**********************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <geos/export.h>
|
|
#include <geos/algorithm/locate/IndexedPointInAreaLocator.h>
|
|
#include <geos/operation/polygonize/PolygonizeDirectedEdge.h>
|
|
#include <geos/geom/Geometry.h>
|
|
#include <geos/geom/LinearRing.h>
|
|
#include <geos/geom/Polygon.h>
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <geos/geom/Location.h>
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
|
|
#endif
|
|
|
|
// Forward declarations
|
|
namespace geos {
|
|
namespace geom {
|
|
class LineString;
|
|
class CoordinateSequence;
|
|
class GeometryFactory;
|
|
class Coordinate;
|
|
}
|
|
namespace planargraph {
|
|
class DirectedEdge;
|
|
}
|
|
}
|
|
|
|
namespace geos {
|
|
namespace operation { // geos::operation
|
|
namespace polygonize { // geos::operation::polygonize
|
|
|
|
/** \brief
|
|
* Represents a ring of PolygonizeDirectedEdge which form
|
|
* a ring of a polygon. The ring may be either an outer shell or a hole.
|
|
*/
|
|
class GEOS_DLL EdgeRing {
|
|
private:
|
|
const geom::GeometryFactory* factory;
|
|
|
|
typedef std::vector<const PolygonizeDirectedEdge*> DeList;
|
|
DeList deList;
|
|
|
|
// cache the following data for efficiency
|
|
std::unique_ptr<geom::LinearRing> ring;
|
|
std::unique_ptr<geom::CoordinateSequence> ringPts;
|
|
std::unique_ptr<algorithm::locate::PointOnGeometryLocator> ringLocator;
|
|
|
|
std::unique_ptr<std::vector<std::unique_ptr<geom::LinearRing>>> holes;
|
|
|
|
EdgeRing* shell = nullptr;
|
|
bool is_hole;
|
|
bool is_valid = false;
|
|
bool is_processed = false;
|
|
bool is_included_set = false;
|
|
bool is_included = false;
|
|
bool visitedByUpdateIncludedRecursive = false;
|
|
|
|
/** \brief
|
|
* Computes the list of coordinates which are contained in this ring.
|
|
* The coordinates are computed once only and cached.
|
|
*
|
|
* @return an array of the Coordinate in this ring
|
|
*/
|
|
const geom::CoordinateSequence* getCoordinates();
|
|
|
|
static void addEdge(const geom::CoordinateSequence* coords,
|
|
bool isForward,
|
|
geom::CoordinateSequence* coordList);
|
|
|
|
algorithm::locate::PointOnGeometryLocator* getLocator() {
|
|
if (ringLocator == nullptr) {
|
|
ringLocator.reset(new algorithm::locate::IndexedPointInAreaLocator(*getRingInternal()));
|
|
}
|
|
return ringLocator.get();
|
|
}
|
|
|
|
public:
|
|
/** \brief
|
|
* Adds a DirectedEdge which is known to form part of this ring.
|
|
*
|
|
* @param de the DirectedEdge to add. Ownership to the caller.
|
|
*/
|
|
void add(const PolygonizeDirectedEdge* de);
|
|
|
|
/**
|
|
* \brief
|
|
* Find the innermost enclosing shell EdgeRing
|
|
* containing this, if any.
|
|
*
|
|
* The innermost enclosing ring is the <i>smallest</i> enclosing ring.
|
|
* The algorithm used depends on the fact that:
|
|
*
|
|
* ring A contains ring B iff envelope(ring A) contains envelope(ring B)
|
|
*
|
|
* This routine is only safe to use if the chosen point of the hole
|
|
* is known to be properly contained in a shell
|
|
* (which is guaranteed to be the case if the hole does not touch
|
|
* its shell)
|
|
*
|
|
* @return containing EdgeRing, if there is one
|
|
* @return null if no containing EdgeRing is found
|
|
*/
|
|
EdgeRing* findEdgeRingContaining(const std::vector<EdgeRing*> & erList);
|
|
|
|
/**
|
|
* \brief
|
|
* Traverses a ring of DirectedEdges, accumulating them into a list.
|
|
*
|
|
* This assumes that all dangling directed edges have been removed from
|
|
* the graph, so that there is always a next dirEdge.
|
|
*
|
|
* @param startDE the DirectedEdge to start traversing at
|
|
* @return a vector of DirectedEdges that form a ring
|
|
*/
|
|
static std::vector<PolygonizeDirectedEdge*> findDirEdgesInRing(PolygonizeDirectedEdge* startDE);
|
|
|
|
/**
|
|
* \brief
|
|
* Finds a point in a list of points which is not contained in
|
|
* another list of points.
|
|
*
|
|
* @param testPts the CoordinateSequence to test
|
|
* @param pts the CoordinateSequence to test the input points against
|
|
* @return a Coordinate reference from <code>testPts</code> which is
|
|
* not in <code>pts</code>, or <code>Coordinate::nullCoord</code>
|
|
*/
|
|
static const geom::Coordinate& ptNotInList(
|
|
const geom::CoordinateSequence* testPts,
|
|
const geom::CoordinateSequence* pts);
|
|
|
|
/** \brief
|
|
* Tests whether a given point is in an array of points.
|
|
* Uses a value-based test.
|
|
*
|
|
* @param pt a Coordinate for the test point
|
|
* @param pts an array of Coordinate to test
|
|
* @return <code>true</code> if the point is in the array
|
|
*/
|
|
static bool isInList(const geom::Coordinate& pt,
|
|
const geom::CoordinateSequence* pts);
|
|
|
|
explicit EdgeRing(const geom::GeometryFactory* newFactory);
|
|
|
|
~EdgeRing() = default;
|
|
|
|
void build(PolygonizeDirectedEdge* startDE);
|
|
|
|
void computeHole();
|
|
|
|
const DeList& getEdges() const {
|
|
return deList;
|
|
}
|
|
|
|
/** \brief
|
|
* Tests whether this ring is a hole.
|
|
*
|
|
* Due to the way the edges in the polyongization graph are linked,
|
|
* a ring is a hole if it is oriented counter-clockwise.
|
|
* @return <code>true</code> if this ring is a hole
|
|
*/
|
|
bool isHole() const {
|
|
return is_hole;
|
|
}
|
|
|
|
/* Indicates whether we know if the ring should be included in a polygonizer
|
|
* output of only polygons.
|
|
*/
|
|
bool isIncludedSet() const {
|
|
return is_included_set;
|
|
}
|
|
|
|
/* Indicates whether the ring should be included in a polygonizer output of
|
|
* only polygons.
|
|
*/
|
|
bool isIncluded() const {
|
|
return is_included;
|
|
}
|
|
|
|
void setIncluded(bool included) {
|
|
is_included = included;
|
|
is_included_set = true;
|
|
}
|
|
|
|
bool isProcessed() const {
|
|
return is_processed;
|
|
}
|
|
|
|
void setProcessed(bool processed) {
|
|
is_processed = processed;
|
|
}
|
|
|
|
/** \brief
|
|
* Sets the containing shell ring of a ring that has been determined to be a hole.
|
|
*
|
|
* @param shellRing the shell ring
|
|
*/
|
|
void setShell(EdgeRing* shellRing) {
|
|
shell = shellRing;
|
|
}
|
|
|
|
/** \brief
|
|
* Tests whether this ring has a shell assigned to it.
|
|
*
|
|
* @return true if the ring has a shell
|
|
*/
|
|
bool hasShell() const {
|
|
return shell != nullptr;
|
|
}
|
|
|
|
/** \brief
|
|
* Gets the shell for this ring. The shell is the ring itself if it is
|
|
* not a hole, otherwise it is the parent shell.
|
|
*
|
|
* @return the shell for the ring
|
|
*/
|
|
EdgeRing* getShell() {
|
|
return isHole() ? shell : this;
|
|
}
|
|
|
|
/** \brief
|
|
* Tests whether this ring is an outer hole.
|
|
* A hole is an outer hole if it is not contained by any shell.
|
|
*
|
|
* @return true if the ring is an outer hole.
|
|
*/
|
|
bool isOuterHole() const {
|
|
if (!isHole()) {
|
|
return false;
|
|
}
|
|
|
|
return !hasShell();
|
|
}
|
|
|
|
/** \brief
|
|
* Tests whether this ring is an outer shell.
|
|
*
|
|
* @return true if the ring is an outer shell.
|
|
*/
|
|
bool isOuterShell() const {
|
|
return getOuterHole() != nullptr;
|
|
}
|
|
|
|
/** \brief
|
|
* Gets the outer hole of a shell, if it has one.
|
|
* An outer hole is one that is not contained in any other shell.
|
|
*
|
|
* Each disjoint connected group of shells is surrounded by
|
|
* an outer hole.
|
|
*
|
|
* @return the outer hole edge ring, or nullptr
|
|
*/
|
|
EdgeRing* getOuterHole() const;
|
|
|
|
/** \brief
|
|
* Updates the included status for currently non-included shells
|
|
* based on whether they are adjacent to an included shell.
|
|
*/
|
|
void updateIncludedRecursive();
|
|
|
|
/** \brief
|
|
* Adds a hole to the polygon formed by this ring.
|
|
*
|
|
* @param hole the LinearRing forming the hole.
|
|
*/
|
|
void addHole(geom::LinearRing* hole);
|
|
|
|
void addHole(EdgeRing* holeER);
|
|
|
|
/** \brief
|
|
* Computes the Polygon formed by this ring and any contained holes.
|
|
*
|
|
* LinearRings ownership is transferred to returned polygon.
|
|
* Subsequent calls to the function will return NULL.
|
|
*
|
|
* @return the Polygon formed by this ring and its holes.
|
|
*/
|
|
std::unique_ptr<geom::Polygon> getPolygon();
|
|
|
|
/** \brief
|
|
* Tests if the LinearRing ring formed by this edge ring
|
|
* is topologically valid.
|
|
*/
|
|
bool isValid() const;
|
|
|
|
void computeValid();
|
|
|
|
/** \brief
|
|
* Gets the coordinates for this ring as a LineString.
|
|
*
|
|
* Used to return the coordinates in this ring
|
|
* as a valid geometry, when it has been detected that the ring
|
|
* is topologically invalid.
|
|
* @return a LineString containing the coordinates in this ring
|
|
*/
|
|
std::unique_ptr<geom::LineString> getLineString();
|
|
|
|
/** \brief
|
|
* Returns this ring as a LinearRing, or null if an Exception
|
|
* occurs while creating it (such as a topology problem).
|
|
*
|
|
* Ownership of ring is retained by the object.
|
|
* Details of problems are written to standard output.
|
|
*/
|
|
geom::LinearRing* getRingInternal();
|
|
|
|
/** \brief
|
|
* Returns this ring as a LinearRing, or null if an Exception
|
|
* occurs while creating it (such as a topology problem).
|
|
*
|
|
* Details of problems are written to standard output.
|
|
* Caller gets ownership of ring.
|
|
*/
|
|
std::unique_ptr<geom::LinearRing> getRingOwnership();
|
|
|
|
bool isInRing(const geom::Coordinate & pt) {
|
|
return geom::Location::EXTERIOR != getLocator()->locate(&pt);
|
|
}
|
|
};
|
|
|
|
} // namespace geos::operation::polygonize
|
|
} // namespace geos::operation
|
|
} // namespace geos
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
|