515 lines
18 KiB
C++
515 lines
18 KiB
C++
/**********************************************************************
|
|
*
|
|
* GEOS - Geometry Engine Open Source
|
|
* http://geos.osgeo.org
|
|
*
|
|
* Copyright (C) 2012 Excensus LLC.
|
|
* Copyright (C) 2019 Daniel Baston
|
|
*
|
|
* This is free software; you can redistribute and/or modify it under
|
|
* the terms of the GNU Lesser General Licence as published
|
|
* by the Free Software Foundation.
|
|
* See the COPYING file for more information.
|
|
*
|
|
**********************************************************************
|
|
*
|
|
* Last port: triangulate/quadedge/QuadEdgeSubdivision.java r524
|
|
*
|
|
**********************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <list>
|
|
#include <stack>
|
|
#include <unordered_set>
|
|
#include <array>
|
|
#include <vector>
|
|
|
|
#include <geos/geom/MultiLineString.h>
|
|
#include <geos/triangulate/quadedge/QuadEdge.h>
|
|
#include <geos/triangulate/quadedge/QuadEdgeLocator.h>
|
|
#include <geos/triangulate/quadedge/QuadEdgeQuartet.h>
|
|
#include <geos/triangulate/quadedge/Vertex.h>
|
|
|
|
namespace geos {
|
|
|
|
namespace geom {
|
|
|
|
class CoordinateSequence;
|
|
class GeometryCollection;
|
|
class MultiLineString;
|
|
class GeometryFactory;
|
|
class Coordinate;
|
|
class Geometry;
|
|
class Envelope;
|
|
}
|
|
|
|
namespace triangulate { //geos.triangulate
|
|
namespace quadedge { //geos.triangulate.quadedge
|
|
|
|
class TriangleVisitor;
|
|
|
|
/** \brief
|
|
* A class that contains the [QuadEdges](@ref QuadEdge) representing a planar
|
|
* subdivision that models a triangulation.
|
|
*
|
|
* The subdivision is constructed using the quadedge algebra defined in the class QuadEdge.
|
|
*
|
|
* All metric calculations are done in the Vertex class.
|
|
* In addition to a triangulation, subdivisions support extraction of Voronoi diagrams.
|
|
* This is easily accomplished, since the Voronoi diagram is the dual
|
|
* of the Delaunay triangulation.
|
|
*
|
|
* Subdivisions can be provided with a tolerance value. Inserted vertices which
|
|
* are closer than this value to vertices already in the subdivision will be
|
|
* ignored. Using a suitable tolerance value can prevent robustness failures
|
|
* from happening during Delaunay triangulation.
|
|
*
|
|
* Subdivisions maintain a **frame** triangle around the client-created
|
|
* edges. The frame is used to provide a bounded "container" for all edges
|
|
* within a TIN. Normally the frame edges, frame connecting edges, and frame
|
|
* triangles are not included in client processing.
|
|
*
|
|
* @author JTS: David Skea
|
|
* @author JTS: Martin Davis
|
|
* @author Benjamin Campbell
|
|
*/
|
|
class GEOS_DLL QuadEdgeSubdivision {
|
|
public:
|
|
typedef std::vector<QuadEdge*> QuadEdgeList;
|
|
|
|
/** \brief
|
|
* Gets the edges for the triangle to the left of the given QuadEdge.
|
|
*
|
|
* @param startQE
|
|
* @param triEdge
|
|
*
|
|
* @throws IllegalArgumentException if the edges do not form a triangle
|
|
*/
|
|
static void getTriangleEdges(const QuadEdge& startQE,
|
|
const QuadEdge* triEdge[3]);
|
|
|
|
private:
|
|
/**
|
|
* Use a deque to ensure QuadEdge pointers are stable.
|
|
* Note that it is NOT safe to erase entries from the deque.
|
|
*/
|
|
std::deque<QuadEdgeQuartet> quadEdges;
|
|
std::array<QuadEdge*, 3> startingEdges;
|
|
double tolerance;
|
|
double edgeCoincidenceTolerance;
|
|
std::array<Vertex, 3> frameVertex;
|
|
geom::Envelope frameEnv;
|
|
std::unique_ptr<QuadEdgeLocator> locator;
|
|
bool visit_state_clean;
|
|
|
|
public:
|
|
/** \brief
|
|
* Creates a new instance of a quad-edge subdivision based on a frame triangle
|
|
* that encloses a supplied bounding box.
|
|
* A new super-bounding box that contains the triangle is computed and stored.
|
|
*
|
|
* @param env the bounding box to surround
|
|
* @param tolerance the tolerance value for determining if two sites are equal
|
|
*/
|
|
QuadEdgeSubdivision(const geom::Envelope& env, double tolerance);
|
|
|
|
virtual ~QuadEdgeSubdivision() = default;
|
|
|
|
private:
|
|
virtual void createFrame(const geom::Envelope& env);
|
|
|
|
virtual void initSubdiv();
|
|
|
|
public:
|
|
/** \brief
|
|
* Gets the vertex-equality tolerance value used in this subdivision
|
|
*
|
|
* @return the tolerance value
|
|
*/
|
|
inline double
|
|
getTolerance() const
|
|
{
|
|
return tolerance;
|
|
}
|
|
|
|
/** \brief
|
|
* Gets the envelope of the Subdivision (including the frame).
|
|
*
|
|
* @return the envelope
|
|
*/
|
|
inline const geom::Envelope&
|
|
getEnvelope() const
|
|
{
|
|
return frameEnv;
|
|
}
|
|
|
|
/** \brief
|
|
* Gets the collection of base {@link QuadEdge}s (one for every pair of
|
|
* vertices which is connected).
|
|
*
|
|
* @return a QuadEdgeList
|
|
*/
|
|
inline std::deque<QuadEdgeQuartet>&
|
|
getEdges()
|
|
{
|
|
return quadEdges;
|
|
}
|
|
|
|
/** \brief
|
|
* Sets the QuadEdgeLocator to use for locating containing triangles
|
|
* in this subdivision.
|
|
*
|
|
* @param p_locator
|
|
* a QuadEdgeLocator
|
|
*/
|
|
inline void
|
|
setLocator(std::unique_ptr<QuadEdgeLocator> p_locator)
|
|
{
|
|
this->locator = std::move(p_locator);
|
|
}
|
|
|
|
/** \brief
|
|
* Creates a new quadedge, recording it in the edges list.
|
|
*
|
|
* @param o
|
|
* @param d
|
|
* @return
|
|
*/
|
|
virtual QuadEdge& makeEdge(const Vertex& o, const Vertex& d);
|
|
|
|
/** \brief
|
|
* Creates a new QuadEdge connecting the destination of a to the origin of b,
|
|
* in such a way that all three have the same left face after the connection
|
|
* is complete.
|
|
* The quadedge is recorded in the edges list.
|
|
*
|
|
* @param a
|
|
* @param b
|
|
* @return
|
|
*/
|
|
virtual QuadEdge& connect(QuadEdge& a, QuadEdge& b);
|
|
|
|
/** \brief
|
|
* Deletes a quadedge from the subdivision. Linked quadedges are updated to
|
|
* reflect the deletion.
|
|
*
|
|
* @param e the quadedge to delete
|
|
*/
|
|
void remove(QuadEdge& e);
|
|
|
|
/** \brief
|
|
* Locates an edge of a triangle which contains a location
|
|
* specified by a Vertex `v`.
|
|
*
|
|
* The edge returned has the property that either v is on e,
|
|
* or e is an edge of a triangle containing v.
|
|
* The search starts from startEdge and proceeds on the general direction of v.
|
|
*
|
|
* This locate algorithm relies on the subdivision being Delaunay. For
|
|
* non-Delaunay subdivisions, this may loop for ever.
|
|
*
|
|
* @param v the location to search for
|
|
* @param startEdge an edge of the subdivision to start searching at
|
|
* @return a QuadEdge which contains v, or is on the edge of a triangle containing v
|
|
* @throws LocateFailureException if the location algorithm fails to converge in a
|
|
* reasonable number of iterations.
|
|
*
|
|
* @note The returned pointer **should not** be freed be the caller.
|
|
*/
|
|
QuadEdge* locateFromEdge(const Vertex& v,
|
|
const QuadEdge& startEdge) const;
|
|
|
|
/** \brief
|
|
* Finds a quadedge of a triangle containing a location
|
|
* specified by a [Vertex](@ref triangulate::quadedge::Vertex), if one exists.
|
|
*
|
|
* @param v the vertex to locate
|
|
* @return a QuadEdge on the edge of a triangle which touches or contains the location
|
|
* @return `null` if no such triangle exists.
|
|
*
|
|
* @note The returned pointer **should not** be freed be the caller.
|
|
*/
|
|
inline QuadEdge*
|
|
locate(const Vertex& v) const
|
|
{
|
|
return locator->locate(v);
|
|
}
|
|
|
|
/** \brief
|
|
* Finds a quadedge of a triangle containing a location
|
|
* specified by a geom::Coordinate, if one exists.
|
|
*
|
|
* @param p the Coordinate to locate
|
|
* @return a QuadEdge on the edge of a triangle which touches or contains the location
|
|
* @return `null` if no such triangle exists.
|
|
*
|
|
* @note The returned pointer **should not** be freed be the caller.
|
|
*/
|
|
inline QuadEdge*
|
|
locate(const geom::Coordinate& p)
|
|
{
|
|
return locator->locate(Vertex(p));
|
|
}
|
|
|
|
/** \brief
|
|
* Locates the edge between the given vertices, if it exists in the
|
|
* subdivision.
|
|
*
|
|
* @param p0 a coordinate
|
|
* @param p1 another coordinate
|
|
* @return the edge joining the coordinates, if present
|
|
* @return `null` if no such edge exists
|
|
*
|
|
* @note the caller **should not** free the returned pointer
|
|
*/
|
|
QuadEdge* locate(const geom::Coordinate& p0, const geom::Coordinate& p1);
|
|
|
|
/** \brief
|
|
* Inserts a new site into the Subdivision, connecting it to the vertices of
|
|
* the containing triangle (or quadrilateral, if the split point falls on an
|
|
* existing edge).
|
|
*
|
|
* This method does NOT maintain the Delaunay condition. If desired, this must
|
|
* be checked and enforced by the caller.
|
|
*
|
|
* This method does NOT check if the inserted vertex falls on an edge. This
|
|
* must be checked by the caller, since this situation may cause erroneous
|
|
* triangulation
|
|
*
|
|
* @param v the vertex to insert
|
|
* @return a new quad edge terminating in v
|
|
*/
|
|
QuadEdge& insertSite(const Vertex& v);
|
|
|
|
/** \brief
|
|
* Tests whether a QuadEdge is an edge incident on a frame triangle vertex.
|
|
*
|
|
* @param e the edge to test
|
|
* @return `true` if the edge is connected to the frame triangle
|
|
*/
|
|
bool isFrameEdge(const QuadEdge& e) const;
|
|
|
|
/** \brief
|
|
* Tests whether a QuadEdge is an edge on the border of the frame facets and
|
|
* the internal facets. E.g. an edge which does not itself touch a frame
|
|
* vertex, but which touches an edge which does.
|
|
*
|
|
* @param e the edge to test
|
|
* @return `true` if the edge is on the border of the frame
|
|
*/
|
|
bool isFrameBorderEdge(const QuadEdge& e) const;
|
|
|
|
/** \brief
|
|
* Tests whether a vertex is a vertex of the outer triangle.
|
|
*
|
|
* @param v the vertex to test
|
|
* @return `true` if the vertex is an outer triangle vertex
|
|
*/
|
|
bool isFrameVertex(const Vertex& v) const;
|
|
|
|
|
|
/** \brief
|
|
* Tests whether a [Coordinate](@ref geom::Coordinate) lies on a QuadEdge,
|
|
* up to a tolerance determined by the subdivision tolerance.
|
|
*
|
|
* @param e a QuadEdge
|
|
* @param p a point
|
|
* @return `true` if the vertex lies on the edge
|
|
*/
|
|
bool isOnEdge(const QuadEdge& e, const geom::Coordinate& p) const;
|
|
|
|
/** \brief
|
|
* Tests whether a Vertex is the start or end vertex of a
|
|
* QuadEdge, up to the subdivision tolerance distance.
|
|
*
|
|
* @param e
|
|
* @param v
|
|
* @return `true` if the vertex is a endpoint of the edge
|
|
*/
|
|
bool isVertexOfEdge(const QuadEdge& e, const Vertex& v) const;
|
|
|
|
/** \brief
|
|
* Gets all primary quadedges in the subdivision.
|
|
*
|
|
* A primary edge is a QuadEdge which occupies the 0'th position in its
|
|
* array of associated quadedges. These provide the unique geometric
|
|
* edges of the triangulation.
|
|
*
|
|
* @param includeFrame `true` if the frame edges are to be included
|
|
* @return a List of QuadEdges. The caller takes ownership of the returned QuadEdgeList but not the
|
|
* items it contains.
|
|
*/
|
|
std::unique_ptr<QuadEdgeList> getPrimaryEdges(bool includeFrame);
|
|
|
|
/*****************************************************************************
|
|
* Visitors
|
|
****************************************************************************/
|
|
|
|
void visitTriangles(TriangleVisitor* triVisitor, bool includeFrame);
|
|
|
|
private:
|
|
typedef std::stack<QuadEdge*> QuadEdgeStack;
|
|
typedef std::vector<std::unique_ptr<geom::CoordinateSequence>> TriList;
|
|
|
|
/** \brief
|
|
* The quadedges forming a single triangle.
|
|
*
|
|
* Only one visitor is allowed to be active at a time, so this is safe.
|
|
*/
|
|
std::array<QuadEdge*, 3> m_triEdges;
|
|
|
|
/** \brief
|
|
* Resets the `visited` flag of each `QuadEdge` prior to iteration, if necessary.
|
|
*/
|
|
void prepareVisit();
|
|
|
|
/** \brief
|
|
* Stores the edges for a visited triangle. Also pushes sym (neighbour) edges
|
|
* on stack to visit later.
|
|
*
|
|
* @param edge
|
|
* @param edgeStack
|
|
* @param includeFrame
|
|
* @return the visited triangle edges
|
|
* @return `null` if the triangle should not be visited (for instance, if it is
|
|
* outer)
|
|
*/
|
|
std::array<QuadEdge*, 3>* fetchTriangleToVisit(QuadEdge* edge, QuadEdgeStack& edgeStack, bool includeFrame);
|
|
|
|
/** \brief
|
|
* Gets the coordinates for each triangle in the subdivision as an array.
|
|
*
|
|
* @param includeFrame true if the frame triangles should be included
|
|
* @param triList a list of Coordinate[4] representing each triangle
|
|
*/
|
|
void getTriangleCoordinates(TriList* triList, bool includeFrame);
|
|
|
|
private:
|
|
class TriangleCoordinatesVisitor;
|
|
class TriangleCircumcentreVisitor;
|
|
|
|
public:
|
|
/** \brief
|
|
* Gets the geometry for the edges in the subdivision as a [MultiLineString](@ref geom::MultiLineString)
|
|
* containing 2-point lines.
|
|
*
|
|
* @param geomFact the GeometryFactory to use
|
|
* @return a MultiLineString
|
|
* @note The caller takes ownership of the returned object.
|
|
*/
|
|
std::unique_ptr<geom::MultiLineString> getEdges(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets the geometry for the triangles in a triangulated subdivision as a
|
|
* [GeometryCollection](@ref geos::geom::GeometryCollection)
|
|
* of triangular [Polygons](@ref geos::geom::Polygon).
|
|
*
|
|
* @param geomFact the GeometryFactory to use
|
|
* @return a GeometryCollection of triangular polygons.
|
|
*
|
|
* @note The caller takes ownership of the returned object.
|
|
*/
|
|
std::unique_ptr<geom::GeometryCollection> getTriangles(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets the cells in the Voronoi diagram for this triangulation.
|
|
* The cells are returned as a [GeometryCollection](@ref geom::GeometryCollection)
|
|
* of [Polygons](@ref geom::Polygon).
|
|
*
|
|
* The userData of each polygon is set to be the [Coordinate](@ref geom::Coordinate)
|
|
* of the cell site. This allows easily associating external
|
|
* data associated with the sites to the cells.
|
|
*
|
|
* @param geomFact a geometry factory
|
|
* @return a GeometryCollection of Polygons
|
|
*/
|
|
std::unique_ptr<geom::GeometryCollection> getVoronoiDiagram(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets the cells in the Voronoi diagram for this triangulation.
|
|
*
|
|
* The cells are returned as a [GeometryCollection](@ref geom::GeometryCollection) of
|
|
* [LineStrings](@ref geom::LineString). The userData of each polygon is set to be the
|
|
* [Coordinate](@ref geom::Coordinate) of the cell site. This allows easily associating external
|
|
* data associated with the sites to the cells.
|
|
*
|
|
* @param geomFact a geometry factory
|
|
* @return a MultiLineString
|
|
*/
|
|
std::unique_ptr<geom::MultiLineString> getVoronoiDiagramEdges(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets a List of [Polygons](@ref geom::Polygon) for the Voronoi cells
|
|
* of this triangulation.
|
|
*
|
|
* The userData of each polygon is set to be the [Coordinate](@ref geom::Coordinate)
|
|
* of the cell site. This allows easily associating external data associated
|
|
* with the sites to the cells.
|
|
*
|
|
* @param geomFact a geometry factory
|
|
* @return a List of Polygons
|
|
*/
|
|
std::vector<std::unique_ptr<geom::Geometry>> getVoronoiCellPolygons(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets a List of [LineStrings](@ref geom::LineString) for the Voronoi cells
|
|
* of this triangulation.
|
|
*
|
|
* The userData of each LineString is set to be the [Coordinate](@ref geom::Coordinate)
|
|
* of the cell site. This allows easily associating external
|
|
* data associated with the sites to the cells.
|
|
*
|
|
* @param geomFact a geometry factory
|
|
* @return a List of LineString
|
|
*/
|
|
std::vector<std::unique_ptr<geom::Geometry>> getVoronoiCellEdges(const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets a collection of [QuadEdges](@ref QuadEdge) whose origin vertices are a unique set
|
|
* which includes all vertices in the subdivision.
|
|
*
|
|
* The frame vertices can be included if required. This is useful for algorithms which require
|
|
* traversing the subdivision starting at all vertices.
|
|
* Returning a quadedge for each vertex is more efficient than the alternative
|
|
* of finding the actual vertices using `getVertices()` and then locating
|
|
* quadedges attached to them.
|
|
*
|
|
* @param includeFrame `true` if the frame vertices should be included
|
|
* @return a collection of QuadEdge with the vertices of the subdivision as their origins
|
|
*/
|
|
std::unique_ptr<QuadEdgeSubdivision::QuadEdgeList> getVertexUniqueEdges(bool includeFrame);
|
|
|
|
/** \brief
|
|
* Gets the Voronoi cell around a site specified by the origin of a QuadEdge.
|
|
*
|
|
* The userData of the polygon is set to be the [Coordinate](@ref geom::Coordinate)
|
|
* of the site. This allows attaching external data associated with the site
|
|
* to this cell polygon.
|
|
*
|
|
* @param qe a quadedge originating at the cell site
|
|
* @param geomFact a factory for building the polygon
|
|
* @return a polygon indicating the cell extent
|
|
*/
|
|
std::unique_ptr<geom::Geometry> getVoronoiCellPolygon(const QuadEdge* qe, const geom::GeometryFactory& geomFact);
|
|
|
|
/** \brief
|
|
* Gets the Voronoi cell edge around a site specified by the origin of a QuadEdge.
|
|
*
|
|
* The userData of the LineString is set to be the [Coordinate](@ref geom::Coordinate)
|
|
* of the site. This allows attaching external data associated with
|
|
* the site to this cell polygon.
|
|
*
|
|
* @param qe a quadedge originating at the cell site
|
|
* @param geomFact a factory for building the polygon
|
|
* @return a polygon indicating the cell extent
|
|
*/
|
|
std::unique_ptr<geom::Geometry> getVoronoiCellEdge(const QuadEdge* qe, const geom::GeometryFactory& geomFact);
|
|
|
|
};
|
|
|
|
} //namespace geos.triangulate.quadedge
|
|
} //namespace geos.triangulate
|
|
} //namespace goes
|