Commit a10d918c authored by Maciej Suminski's avatar Maciej Suminski

Thread-safe version of Delaunay triangulation.

parent fe97521b
......@@ -51,8 +51,6 @@ using namespace hed;
using namespace std;
Triangulation* TTLtraits::triang_ = NULL;
#ifdef TTL_USE_NODE_ID
int Node::id_count = 0;
#endif
......@@ -164,11 +162,30 @@ EdgePtr Triangulation::initTwoEnclosingTriangles(NodesContainer::iterator first,
}
//--------------------------------------------------------------------------------------------------
Triangulation::Triangulation() {
helper = new ttl::TriangulationHelper( *this );
}
//--------------------------------------------------------------------------------------------------
Triangulation::Triangulation(const Triangulation& tr) {
std::cout << "Triangulation: Copy constructor not present - EXIT.";
exit(-1);
}
//--------------------------------------------------------------------------------------------------
Triangulation::~Triangulation() {
cleanAll();
delete helper;
}
//--------------------------------------------------------------------------------------------------
void Triangulation::createDelaunay(NodesContainer::iterator first,
NodesContainer::iterator last) {
TTLtraits::triang_ = this;
cleanAll();
EdgePtr bedge = initTwoEnclosingTriangles(first, last);
......@@ -178,7 +195,7 @@ void Triangulation::createDelaunay(NodesContainer::iterator first,
NodesContainer::iterator it;
for (it = first; it != last; ++it) {
ttl::insertNode<TTLtraits>(d_iter, *it);
helper->insertNode<TTLtraits>(d_iter, *it);
}
// In general (e.g. for the triangle based data structure), the initial dart
......@@ -189,7 +206,7 @@ void Triangulation::createDelaunay(NodesContainer::iterator first,
// triangle "outside" the triangulation.)
// Assumes rectangular domain
ttl::removeRectangularBoundary<TTLtraits>(dc);
helper->removeRectangularBoundary<TTLtraits>(dc);
}
......@@ -269,7 +286,7 @@ cout << "Iterate boundary 2" << endl;
Dart dart_iter = dart;
do {
if (ttl::isBoundaryEdge(dart_iter))
if (helper->isBoundaryEdge(dart_iter))
dart_iter.alpha0().alpha1();
else
dart_iter.alpha2().alpha1();
......@@ -322,6 +339,31 @@ void Triangulation::cleanAll() {
}
//--------------------------------------------------------------------------------------------------
void Triangulation::swapEdge(Dart& dart) {
if (!dart.getEdge()->isConstrained()) swapEdge(dart.getEdge());
}
//--------------------------------------------------------------------------------------------------
void Triangulation::splitTriangle(Dart& dart, NodePtr point) {
EdgePtr edge = splitTriangle(dart.getEdge(), point);
dart.init(edge);
}
//--------------------------------------------------------------------------------------------------
void Triangulation::reverse_splitTriangle(Dart& dart) {
reverse_splitTriangle(dart.getEdge());
}
//--------------------------------------------------------------------------------------------------
void Triangulation::removeBoundaryTriangle(Dart& d) {
removeTriangle(d.getEdge());
}
#ifdef TTL_USE_NODE_FLAG
//--------------------------------------------------------------------------------------------------
// This is a "template" for accessing all nodes (but multiple tests)
......@@ -486,7 +528,7 @@ void Triangulation::swapEdge(EdgePtr& diagonal) {
// Note that diagonal is both input and output and it is always
// kept in counterclockwise direction (this is not required by all
// finctions in ttl:: now)
// functions in TriangulationHelper now)
// Swap by rotating counterclockwise
// Use the same objects - no deletion or new objects
......@@ -567,7 +609,7 @@ bool Triangulation::checkDelaunay() const {
// only one of the half-edges
if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) {
Dart dart(edge);
if (ttl::swapTestDelaunay<TTLtraits>(dart)) {
if (helper->swapTestDelaunay<TTLtraits>(dart)) {
noNotDelaunay++;
//printEdge(dart,os); os << "\n";
......@@ -610,7 +652,7 @@ void Triangulation::optimizeDelaunay() {
Dart dart(edge);
// Constrained edges should not be swapped
if (!edge->isConstrained() && ttl::swapTestDelaunay<TTLtraits>(dart, cycling_check)) {
if (!edge->isConstrained() && helper->swapTestDelaunay<TTLtraits>(dart, cycling_check)) {
optimal = false;
swapEdge(edge);
}
......@@ -632,7 +674,7 @@ EdgePtr Triangulation::getInteriorNode() const {
for (int i = 0; i < 3; ++i) {
if (edge->getTwinEdge()) {
if (!ttl::isBoundaryNode(Dart(edge)))
if (!helper->isBoundaryNode(Dart(edge)))
return edge;
}
edge = edge->getNextEdgeInFace();
......@@ -643,18 +685,18 @@ EdgePtr Triangulation::getInteriorNode() const {
//--------------------------------------------------------------------------------------------------
static EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) {
EdgePtr Triangulation::getBoundaryEdgeInTriangle(const EdgePtr& e) const {
EdgePtr edge = e;
if (ttl::isBoundaryEdge(Dart(edge)))
if (helper->isBoundaryEdge(Dart(edge)))
return edge;
edge = edge->getNextEdgeInFace();
if (ttl::isBoundaryEdge(Dart(edge)))
if (helper->isBoundaryEdge(Dart(edge)))
return edge;
edge = edge->getNextEdgeInFace();
if (ttl::isBoundaryEdge(Dart(edge)))
if (helper->isBoundaryEdge(Dart(edge)))
return edge;
return EdgePtr();
......
......@@ -69,9 +69,6 @@ namespace hed {
struct TTLtraits {
// The actual triangulation object
static Triangulation* triang_;
/** The floating point type used in calculations
* involving scalar products and cross products.
*/
......@@ -172,127 +169,6 @@ namespace hed {
}
//@} // End of Geometric Predicates Group
// A rationale for directing these functions to traits is:
// e.g., constraints
//----------------------------------------------------------------------------------------------
/* Checks if the edge associated with \e dart should be swapped
* according to the Delaunay criterion.<br>
*
* \note
* This function is also present in the TTL as ttl::swapTestDelaunay.<br>
* Thus, the function can be implemented simply as:
* \code
* { return ttl::swapTestDelaunay<TTLtraits>(dart); }
* \endcode
*/
//static bool swapTestDelaunay(const Dart& dart) {
// return ttl::swapTestDelaunay<TTLtraits>(dart);
//}
//----------------------------------------------------------------------------------------------
/* Checks if the edge associated with \e dart can be swapped, i.e.,
* if the edge is a diagonal in a (strictly) convex quadrilateral.
* This function is also present as ttl::swappableEdge.
*/
//static bool swappableEdge(const Dart& dart) {
// return ttl::swappableEdge<TTLtraits>(dart);
//}
//----------------------------------------------------------------------------------------------
/* Checks if the edge associated with \e dart should be \e fixed, meaning
* that it should never be swapped. ??? Use when constraints.
*/
//static bool fixedEdge(const Dart& dart) {
// return dart.getEdge()->isConstrained();
//}
//----------------------------------------------------------------------------------------------
// ----------------------- Functions for Delaunay Triangulation Group -------------------------
//----------------------------------------------------------------------------------------------
/** @name Functions for Delaunay Triangulation */
//@{
//----------------------------------------------------------------------------------------------
/** Swaps the edge associated with \e dart in the actual data structure.
*
* <center>
* \image html swapEdge.gif
* </center>
*
* \param dart
* Some of the functions require a dart as output.
* If this is required by the actual function, the dart should be delivered
* back in a position as seen if it was glued to the edge when swapping (rotating)
* the edge CCW; see the figure.
*
* \note
* - If the edge is \e constrained, or if it should not be swapped for
* some other reason, this function need not do the actual swap of the edge.
* - Some functions in TTL require that \c swapEdge is implemented such that
* darts outside the quadrilateral are not affected by the swap.
*/
static void swapEdge(Dart& dart) {
if (!dart.getEdge()->isConstrained()) triang_->swapEdge(dart.getEdge());
}
//----------------------------------------------------------------------------------------------
/** Splits the triangle associated with \e dart in the actual data structure into
* three new triangles joining at \e point.
*
* <center>
* \image html splitTriangle.gif
* </center>
*
* \param dart
* Output: A CCW dart incident with the new node; see the figure.
*/
static void splitTriangle(Dart& dart, NodePtr point) {
EdgePtr edge = triang_->splitTriangle(dart.getEdge(), point);
dart.init(edge);
}
//@} // End of Functions for Delaunay Triangulation group
//----------------------------------------------------------------------------------------------
// --------------------------- Functions for removing nodes Group -----------------------------
//----------------------------------------------------------------------------------------------
/** @name Functions for removing nodes */
//@{
//----------------------------------------------------------------------------------------------
/** The reverse operation of TTLtraits::splitTriangle.
* This function is only required for functions that involve
* removal of interior nodes; see for example ttl::removeInteriorNode.
*
* <center>
* \image html reverse_splitTriangle.gif
* </center>
*/
static void reverse_splitTriangle(Dart& dart) {
triang_->reverse_splitTriangle(dart.getEdge());
}
//----------------------------------------------------------------------------------------------
/** Removes a triangle with an edge at the boundary of the triangulation
* in the actual data structure
*/
static void removeBoundaryTriangle(Dart& d) {
triang_->removeTriangle(d.getEdge());
}
//@} // End of Functions for removing nodes Group
};
}; // End of hed namespace
......
......@@ -51,10 +51,13 @@
#include <vector>
#include <iostream>
#include <fstream>
#include <ttl/ttl.h>
#include <ttl/ttl_util.h>
#include <boost/shared_ptr.hpp>
namespace ttl {
class TriangulationHelper;
};
//--------------------------------------------------------------------------------------------------
// The half-edge data structure
//--------------------------------------------------------------------------------------------------
......@@ -242,26 +245,75 @@ public:
class Triangulation {
protected:
list<EdgePtr> leadingEdges_; // one half-edge for each arc
std::list<EdgePtr> leadingEdges_; // one half-edge for each arc
ttl::TriangulationHelper* helper;
void addLeadingEdge(EdgePtr& edge) {
edge->setAsLeadingEdge();
leadingEdges_.push_front( edge );
}
bool removeLeadingEdgeFromList(EdgePtr& leadingEdge);
void cleanAll();
/** Swaps the edge associated with \e dart in the actual data structure.
*
* <center>
* \image html swapEdge.gif
* </center>
*
* \param dart
* Some of the functions require a dart as output.
* If this is required by the actual function, the dart should be delivered
* back in a position as seen if it was glued to the edge when swapping (rotating)
* the edge CCW; see the figure.
*
* \note
* - If the edge is \e constrained, or if it should not be swapped for
* some other reason, this function need not do the actual swap of the edge.
* - Some functions in TTL require that \c swapEdge is implemented such that
* darts outside the quadrilateral are not affected by the swap.
*/
void swapEdge(Dart& dart);
/** Splits the triangle associated with \e dart in the actual data structure into
* three new triangles joining at \e point.
*
* <center>
* \image html splitTriangle.gif
* </center>
*
* \param dart
* Output: A CCW dart incident with the new node; see the figure.
*/
void splitTriangle(Dart& dart, NodePtr point);
/** The reverse operation of TTLtraits::splitTriangle.
* This function is only required for functions that involve
* removal of interior nodes; see for example TrinagulationHelper::removeInteriorNode.
*
* <center>
* \image html reverse_splitTriangle.gif
* </center>
*/
void reverse_splitTriangle(Dart& dart);
/** Removes a triangle with an edge at the boundary of the triangulation
* in the actual data structure
*/
void removeBoundaryTriangle(Dart& d);
public:
/// Default constructor
Triangulation() {}
Triangulation();
/// Copy constructor
Triangulation(const Triangulation& tr) {
std::cout << "Triangulation: Copy constructor not present - EXIT.";
exit(-1);
}
Triangulation(const Triangulation& tr);
/// Destructor
~Triangulation() { cleanAll(); }
~Triangulation();
/// Creates a Delaunay triangulation from a set of points
void createDelaunay(NodesContainer::iterator first,
......@@ -295,20 +347,20 @@ public:
Dart createDart();
/// Returns a list of "triangles" (one leading half-edge for each triangle)
const list<EdgePtr>& getLeadingEdges() const { return leadingEdges_; }
const std::list<EdgePtr>& getLeadingEdges() const { return leadingEdges_; }
/// Returns the number of triangles
int noTriangles() const { return (int)leadingEdges_.size(); }
/// Returns a list of half-edges (one half-edge for each arc)
list<EdgePtr>* getEdges(bool skip_boundary_edges = false) const;
std::list<EdgePtr>* getEdges(bool skip_boundary_edges = false) const;
#ifdef TTL_USE_NODE_FLAG
/// Sets flag in all the nodes
void flagNodes(bool flag) const;
/// Returns a list of nodes. This function requires TTL_USE_NODE_FLAG to be defined. \see Node.
list<NodePtr>* getNodes() const;
std::list<NodePtr>* getNodes() const;
#endif
/// Swaps edges until the triangulation is Delaunay (constrained edges are not swapped)
......@@ -320,12 +372,16 @@ public:
/// Returns an arbitrary interior node (as the source node of the returned edge)
EdgePtr getInteriorNode() const;
EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) const;
/// Returns an arbitrary boundary edge
EdgePtr getBoundaryEdge() const;
/// Print edges for plotting with, e.g., gnuplot
void printEdges(std::ofstream& os) const;
friend class ttl::TriangulationHelper;
}; // End of class Triangulation
......
This diff is collapsed.
......@@ -51,9 +51,6 @@
static ofstream ofile_constr("qweCons.dat");
#endif
//using namespace std;
/** \brief Constrained Delaunay triangulation
*
* Basic generic algorithms in TTL for inserting a constrained edge between two existing nodes.\n
......@@ -61,7 +58,7 @@
* See documentation for the namespace ttl for general requirements and assumptions.
*
* \author
* Øyvind Hjelle, oyvindhj@ifi.uio.no
* yvind Hjelle, oyvindhj@ifi.uio.no
*/
namespace ttl_constr {
......@@ -73,6 +70,9 @@ namespace ttl_constr {
#endif
class ConstrainedTriangulation
{
public:
//------------------------------------------------------------------------------------------------
/* Checks if \e dart has start and end points in \e dstart and \e dend.
*
......@@ -89,14 +89,14 @@ namespace ttl_constr {
* A bool confirming that it's the constraint or not
*
* \using
* ttl::same_0_orbit
* same_0_orbit
*/
template <class DartType>
bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) {
static bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) {
DartType d0 = dart;
d0.alpha0(); // CW
if ((ttl::same_0_orbit(dstart, dart) && ttl::same_0_orbit(dend, d0)) ||
(ttl::same_0_orbit(dstart, d0) && ttl::same_0_orbit(dend, dart))) {
if ((ttl::TriangulationHelper::same_0_orbit(dstart, dart) && ttl::TriangulationHelper::same_0_orbit(dend, d0)) ||
(ttl::TriangulationHelper::same_0_orbit(dstart, d0) && ttl::TriangulationHelper::same_0_orbit(dend, dart))) {
return true;
}
return false;
......@@ -123,7 +123,7 @@ namespace ttl_constr {
* TraitsType::orient2d
*/
template <class TraitsType, class DartType>
bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) {
static bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) {
typename TraitsType::real_type orient_1 = TraitsType::orient2d(dstart,d1,dend);
typename TraitsType::real_type orient_2 = TraitsType::orient2d(dstart,d2,dend);
......@@ -156,12 +156,12 @@ namespace ttl_constr {
* The dart \e d making the smallest positive (or == 0) angle
*
* \using
* ttl::isBoundaryNode
* ttl::positionAtNextBoundaryEdge
* isBoundaryNode
* positionAtNextBoundaryEdge
* TraitsType::orient2d
*/
template <class TraitsType, class DartType>
DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) {
static DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) {
// - Must boundary be convex???
// - Handle the case where the constraint is already present???
......@@ -169,9 +169,9 @@ namespace ttl_constr {
// (dstart and dend may define a boundary edge)
DartType d_iter = dstart;
if (ttl::isBoundaryNode(d_iter)) {
if (ttl::TriangulationHelper::isBoundaryNode(d_iter)) {
d_iter.alpha1(); // CW
ttl::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary)
ttl::TriangulationHelper::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary)
}
// assume convex boundary; see comments
......@@ -273,7 +273,7 @@ namespace ttl_constr {
* Returns the next "collinear" starting node such that dend is returned when done.
*/
template <class TraitsType, class DartType, class ListType>
DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) {
static DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) {
const DartType my_start = getAtSmallestAngle<TraitsType>(dstart, dend);
DartType my_end = getAtSmallestAngle<TraitsType>(dend, dstart);
......@@ -387,15 +387,16 @@ namespace ttl_constr {
* A list containing all the edges crossing the spesified constraint
*
* \using
* ttl::swappableEdge
* ttl::swapEdgeInList
* ttl::crossesConstraint
* ttl::isTheConstraint
* swappableEdge
* swapEdgeInList
* crossesConstraint
* isTheConstraint
*/
template <class TraitsType, class DartType>
void transformToConstraint(DartType& dstart, DartType& dend, std::list<DartType>& elist) {
void transformToConstraint(ttl::TriangulationHelper helper, DartType& dstart, DartType& dend,
std::list<DartType>& elist) const {
typename list<DartType>::iterator it, used;
typename std::list<DartType>::iterator it, used;
// We may enter in a situation where dstart and dend are altered because of a swap.
// (The general rule is that darts inside the actual quadrilateral can be changed,
......@@ -423,7 +424,7 @@ namespace ttl_constr {
if (counter > dartsInList)
break;
if (ttl::swappableEdge<TraitsType, DartType>(*it, true)) {
if (ttl::TriangulationHelper::swappableEdge<TraitsType, DartType>(*it, true)) {
// Dyn & Goren & Rippa 's notation:
// The node assosiated with dart *it is denoted u_m. u_m has edges crossing the constraint
// named w_1, ... , w_r . The other node to the edge assosiated with dart *it is w_s.
......@@ -456,7 +457,7 @@ namespace ttl_constr {
end = true;
// This is the only place swapping is called when inserting a constraint
ttl::swapEdgeInList<TraitsType, DartType>(it,elist);
helper.swapEdgeInList<TraitsType, DartType>(it,elist);
// If we, during look-ahead, found that dstart and/or dend were in the quadrilateral,
// we update them.
......@@ -512,6 +513,8 @@ namespace ttl_constr {
}
}; // End of ConstrainedTriangulation class
}; // End of ttl_constr namespace scope
......@@ -546,14 +549,14 @@ namespace ttl { // (extension)
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&)
*
* \using
* - ttl::optimizeDelaunay if \e optimize_delaunay is set to \c true
* - optimizeDelaunay if \e optimize_delaunay is set to \c true
*
* \par Assumes:
* - The constrained edge must be inside the existing triangulation (and it cannot
* cross the boundary of the triangulation).
*/
template <class TraitsType, class DartType>
DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) {
DartType TriangulationHelper::insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) {
// Assumes:
// - It is the users responsibility to avoid crossing constraints
......@@ -567,8 +570,8 @@ namespace ttl { // (extension)
// calls itself recursively.
// RECURSION
list<DartType> elist;
DartType next_start = ttl_constr::findCrossingEdges<TraitsType>(dstart, dend, elist);
std::list<DartType> elist;
DartType next_start = ttl_constr::ConstrainedTriangulation::findCrossingEdges<TraitsType>(dstart, dend, elist);
// If there are no crossing edges (elist is empty), we assume that the constraint
// is an existing edge.
......@@ -583,7 +586,7 @@ namespace ttl { // (extension)
// findCrossingEdges stops if it finds a node lying on the constraint.
// A dart with this node as start node is returned
// We call insertConstraint recursivly until the received dart is dend
if (!ttl::same_0_orbit(next_start, dend)) {
if (!same_0_orbit(next_start, dend)) {
#ifdef DEBUG_TTL_CONSTR_PLOT
cout << "RECURSION due to collinearity along constraint" << endl;
......@@ -594,7 +597,7 @@ namespace ttl { // (extension)
// Swap edges such that the constraint edge is present in the transformed triangulation.
if (elist.size() > 0) // by Thomas Sevaldrud
ttl_constr::transformToConstraint<TraitsType>(dstart, next_start, elist);
ttl_constr::ConstrainedTriangulation::transformToConstraint<TraitsType>(dstart, next_start, elist);
#ifdef DEBUG_TTL_CONSTR_PLOT
cout << "size of elist = " << elist.size() << endl;
......@@ -607,13 +610,13 @@ namespace ttl { // (extension)
#endif
// Optimize to constrained Delaunay triangulation if required.
typename list<DartType>::iterator end_opt = elist.end();
typename std::list<DartType>::iterator end_opt = elist.end();
if (optimize_delaunay) {
// Indicate that the constrained edge, which is the last element in the list,
// should not be swapped
--end_opt;
ttl::optimizeDelaunay<TraitsType, DartType>(elist, end_opt);
optimizeDelaunay<TraitsType, DartType>(elist, end_opt);
}
if(elist.size() == 0) // by Thomas Sevaldrud
......
......@@ -240,7 +240,7 @@ void RN_NET::compute()
return;
}
else if( boardNodes.size() == 1 ) // This case is even simpler
else if( boardNodes.size() <= 1 ) // This case is even simpler
{
m_rnEdges.reset( new std::vector<RN_EDGE_PTR>( 0 ) );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment