Skip to content

Commit

Permalink
Improve Delaunay/Voronoi performance
Browse files Browse the repository at this point in the history
- Introduce a QuadEdgeQuartet structure to store four QuadEdges. This
reduces the number of memory allocations needed to create the QuadEdges,
and allows them to refer to each other by their relative memory
addresses. (This follows the Graphics Gems implementation.) For now, we
still require QuadEdgeQuartets to have stable addresses, so we store
them in a std::deque. If this requirement can be relaxed, better
performance may come from using a std::vector.
- Reduce the size of a Vertex and a QuadEdge by eliminating unnecessary
virtual methods and associated vtable storage.

Overall performance improvement of about 25% observed on benchmark.
  • Loading branch information
dbaston committed Oct 24, 2019
1 parent 26c0b56 commit 8b433f0
Show file tree
Hide file tree
Showing 14 changed files with 250 additions and 251 deletions.
6 changes: 6 additions & 0 deletions benchmarks/ClassSizes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#include <geos/constants.h>
#include <iostream>
#include <geos/geomgraph/index/SweepLineEvent.h>
#include <geos/triangulate/quadedge/QuadEdge.h>
#include <geos/triangulate/quadedge/QuadEdgeQuartet.h>
#include <geos/triangulate/quadedge/Vertex.h>

using namespace std;
using namespace geos;
Expand Down Expand Up @@ -71,6 +74,9 @@ main()
check(geom::CoordinateArraySequence);
check(geom::FixedSizeCoordinateSequence<1>);
check(geom::FixedSizeCoordinateSequence<2>);
check(triangulate::quadedge::QuadEdge);
check(triangulate::quadedge::QuadEdgeQuartet);
check(triangulate::quadedge::Vertex);
check(int64);
}

1 change: 1 addition & 0 deletions include/geos/triangulate/quadedge/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ geos_HEADERS = \
QuadEdge.h \
Vertex.h \
TrianglePredicate.h \
QuadEdgeQuartet.h \
QuadEdgeSubdivision.h \
QuadEdgeLocator.h \
LastFoundQuadEdgeLocator.h \
Expand Down
147 changes: 90 additions & 57 deletions include/geos/triangulate/quadedge/QuadEdge.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 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
Expand All @@ -28,15 +29,17 @@ namespace geos {
namespace triangulate { //geos.triangulate
namespace quadedge { //geos.triangulate.quadedge


class GEOS_DLL QuadEdgeQuartet;

/** \brief
* A class that represents the edge data structure which implements the quadedge algebra.
*
* The quadedge algebra was described in a well-known paper by Guibas and Stolfi,
* "Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams",
* *ACM Transactions on Graphics*, 4(2), 1985, 75-123.
*
* Each edge object is part of a quartet of 4 edges, linked via their `_rot` references.
* Any edge in the group may be accessed using a series of {@link #rot()} operations.
* Each edge object is part of a QuadEdgeQuartet of 4 edges, linked via relative memory addresses.
* Quadedges in a subdivision are linked together via their `next` references.
* The linkage between the quadedge quartets determines the topology
* of the subdivision.
Expand All @@ -49,16 +52,17 @@ namespace quadedge { //geos.triangulate.quadedge
* @author Benjamin Campbell
* */
class GEOS_DLL QuadEdge {
friend class QuadEdgeQuartet;
public:
/** \brief
* Creates a new QuadEdge quartet from {@link Vertex} o to {@link Vertex} d.
*
* @param o the origin Vertex
* @param d the destination Vertex
* @return the new QuadEdge* The caller is reponsible for
* freeing the returned pointer
* @param edges a container in which to store the newly created quartet
* @return the new QuadEdge*,
*/
static std::unique_ptr<QuadEdge> makeEdge(const Vertex& o, const Vertex& d);
static QuadEdge* makeEdge(const Vertex& o, const Vertex & d, std::deque<QuadEdgeQuartet> & edges);

/** \brief
* Creates a new QuadEdge connecting the destination of a to the origin of
Expand All @@ -67,10 +71,9 @@ class GEOS_DLL QuadEdge {
*
* Additionally, the data pointers of the new edge are set.
*
* @return the new QuadEdge* The caller is reponsible for
* freeing the returned pointer
* @return the new QuadEdge*
*/
static std::unique_ptr<QuadEdge> connect(QuadEdge& a, QuadEdge& b);
static QuadEdge* connect(QuadEdge& a, QuadEdge& b, std::deque<QuadEdgeQuartet> & edges);

/** \brief
* Splices two edges together or apart.
Expand All @@ -97,31 +100,26 @@ class GEOS_DLL QuadEdge {

private:
//// the dual of this edge, directed from right to left
QuadEdge* _rot;
Vertex vertex; // The vertex that this edge represents
QuadEdge* next; // A reference to a connected edge
void* data;
Vertex vertex; // The vertex that this edge represents
QuadEdge* next; // A reference to a connected edge

int8_t num; // the position of the QuadEdge in the quartet (0-3)

bool isAlive;
bool visited;

/**
* Quadedges must be made using {@link makeEdge},
* Quadedges must be made using {@link QuadEdgeQuartet::makeEdge},
* to ensure proper construction.
*/
QuadEdge();
explicit QuadEdge(int8_t _num) :
next(nullptr),
num(_num),
isAlive(true),
visited(false) {
}

public:
virtual ~QuadEdge();

/** \brief
* Free the QuadEdge quartet associated with this QuadEdge by a connect()
* or makeEdge() call.
*
* @note DO NOT call this function on a QuadEdge that was not returned
* by connect() or makeEdge().
*/
virtual void free();

/** \brief
* Gets the primary edge of this quadedge and its `sym`.
*
Expand All @@ -131,21 +129,7 @@ class GEOS_DLL QuadEdge {
*
* @return the primary quadedge
*/
const QuadEdge& getPrimary() const;

/** \brief
* Sets the external data value for this edge.
*
* @param data an object containing external data
*/
virtual void setData(void* data);

/** \brief
* Gets the external data value for this edge.
*
* @return the data object
*/
virtual void* getData();
const QuadEdge& getPrimary();

/** \brief
* Marks this quadedge as being deleted.
Expand Down Expand Up @@ -203,62 +187,92 @@ class GEOS_DLL QuadEdge {
*
* @return the rotated edge
*/
inline QuadEdge&
inline const QuadEdge&
rot() const
{
return *_rot;
return (num < 3) ? *(this + 1) : *(this - 3);
}

inline QuadEdge&
rot()
{
return (num < 3) ? *(this + 1) : *(this - 3);
}

/** \brief
* Gets the dual of this edge, directed from its left to its right.
*
* @return the inverse rotated edge.
*/
inline QuadEdge&
inline const QuadEdge&
invRot() const
{
return rot().sym();
return (num > 0) ? *(this - 1) : *(this + 3);
}

inline QuadEdge&
invRot()
{
return (num > 0) ? *(this - 1) : *(this + 3);
}

/** \brief
* Gets the edge from the destination to the origin of this edge.
*
* @return the sym of the edge
*/
inline QuadEdge&
inline const QuadEdge&
sym() const
{
return rot().rot();
return (num < 2) ? *(this + 2) : *(this - 2);
}

inline QuadEdge&
sym()
{
return (num < 2) ? *(this + 2) : *(this - 2);
}

/** \brief
* Gets the next CCW edge around the origin of this edge.
*
* @return the next linked edge.
*/
inline QuadEdge&
inline const QuadEdge&
oNext() const
{
return *next;
}

inline QuadEdge&
oNext()
{
return *next;
}

/** \brief
* Gets the next CW edge around (from) the origin of this edge.
*
* @return the previous edge.
*/
inline QuadEdge&
inline const QuadEdge&
oPrev() const
{
return rot().oNext().rot();
}

inline QuadEdge&
oPrev()
{
return rot().oNext().rot();
}

/** \brief
* Gets the next CCW edge around (into) the destination of this edge.
*
* @return the next destination edge.
*/
inline QuadEdge&
inline const QuadEdge&
dNext() const
{
return sym().oNext().sym();
Expand All @@ -269,41 +283,59 @@ class GEOS_DLL QuadEdge {
*
* @return the previous destination edge.
*/
inline QuadEdge&
inline const QuadEdge&
dPrev() const
{
return invRot().oNext().invRot();
}

inline QuadEdge&
dPrev()
{
return invRot().oNext().invRot();
}

/** \brief
* Gets the CCW edge around the left face following this edge.
*
* @return the next left face edge.
*/
inline QuadEdge&
inline const QuadEdge&
lNext() const
{
return invRot().oNext().rot();
}

inline QuadEdge&
lNext()
{
return invRot().oNext().rot();
}

/** \brief
* Gets the CCW edge around the left face before this edge.
*
* @return the previous left face edge.
*/
inline QuadEdge&
inline const QuadEdge&
lPrev() const
{
return oNext().sym();
}

inline QuadEdge&
lPrev()
{
return oNext().sym();
}

/** \brief
* Gets the edge around the right face ccw following this edge.
*
* @return the next right face edge.
*/
inline QuadEdge&
rNext()
inline const QuadEdge&
rNext() const
{
return rot().oNext().invRot();
}
Expand All @@ -313,8 +345,8 @@ class GEOS_DLL QuadEdge {
*
* @return the previous right face edge.
*/
inline QuadEdge&
rPrev()
inline const QuadEdge&
rPrev() const
{
return sym().oNext();
}
Expand Down Expand Up @@ -404,9 +436,10 @@ class GEOS_DLL QuadEdge {
std::unique_ptr<geom::LineSegment> toLineSegment() const;
};


} //namespace geos.triangulate.quadedge
} //namespace geos.triangulate
} //namespace goes
} //namespace geos

#endif //GEOS_TRIANGULATE_QUADEDGE_QUADEDGE_H

Loading

0 comments on commit 8b433f0

Please sign in to comment.