Commit a10d918c authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Thread-safe version of Delaunay triangulation.

parent fe97521b
Loading
Loading
Loading
Loading
+57 −15
Original line number Diff line number Diff line
@@ -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();
+0 −124
Original line number Diff line number Diff line
@@ -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
+67 −11
Original line number Diff line number Diff line
@@ -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


Loading