From 2b328721d4f20f92ceca7f61f34ea1139e737e8f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 7 Apr 2014 13:32:09 +0200 Subject: [PATCH] Formatted ttl library to comply with KiCad coding policy. --- common/geometry/hetriang.cpp | 1246 +++++++------ include/ttl/halfedge/hedart.h | 175 +- include/ttl/halfedge/hetraits.h | 223 +-- include/ttl/halfedge/hetriang.h | 484 ++--- include/ttl/ttl.h | 2979 ++++++++++++++++--------------- include/ttl/ttl_util.h | 118 +- pcbnew/ratsnest_data.cpp | 34 +- pcbnew/ratsnest_data.h | 14 +- pcbnew/ratsnest_viewitem.cpp | 4 +- 9 files changed, 2707 insertions(+), 2570 deletions(-) diff --git a/common/geometry/hetriang.cpp b/common/geometry/hetriang.cpp index eb5e59ecf7..2172413966 100644 --- a/common/geometry/hetriang.cpp +++ b/common/geometry/hetriang.cpp @@ -48,685 +48,681 @@ #include #include - using namespace hed; -using namespace std; - #ifdef TTL_USE_NODE_ID - int Node::id_count = 0; + int NODE::id_count = 0; #endif //#define DEBUG_HE #ifdef DEBUG_HE #include - static void errorAndExit(char* message) { - cout << "\n!!! ERROR: "<< message << " !!!\n" << endl; exit(-1); - } +static void errorAndExit( char* aMessage ) +{ + cout << "\n!!! ERROR: "<< aMessage << " !!!\n" << endl; + exit( -1 ); +} #endif -//-------------------------------------------------------------------------------------------------- -static EdgePtr getLeadingEdgeInTriangle(const EdgePtr& e) { - EdgePtr edge = e; - - // Code: 3EF (assumes triangle) - if (!edge->isLeadingEdge()) { - edge = edge->getNextEdgeInFace(); - if (!edge->isLeadingEdge()) - edge = edge->getNextEdgeInFace(); - } - - if (!edge->isLeadingEdge()) { - return EdgePtr(); - } - - return edge; -} +static EDGE_PTR getLeadingEdgeInTriangle( const EDGE_PTR& aEdge ) +{ + EDGE_PTR edge = aEdge; + // Code: 3EF (assumes triangle) + if( !edge->IsLeadingEdge() ) + { + edge = edge->GetNextEdgeInFace(); -//-------------------------------------------------------------------------------------------------- -static void getLimits(NodesContainer::iterator first, - NodesContainer::iterator last, - int& xmin, int& ymin, - int& xmax, int& ymax) { - - xmin = ymin = std::numeric_limits::min(); - xmax = ymax = std::numeric_limits::max(); - - NodesContainer::iterator it; - for (it = first; it != last; ++it) { - xmin = min(xmin, (*it)->GetX()); - ymin = min(ymin, (*it)->GetY()); - xmax = max(xmax, (*it)->GetX()); - ymax = max(ymax, (*it)->GetY()); - } -} - - -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::initTwoEnclosingTriangles(NodesContainer::iterator first, - NodesContainer::iterator last) { - - int xmin, ymin, xmax, ymax; - getLimits(first, last, xmin, ymin, xmax, ymax); - - // Add 10% of range: - double fac = 10.0; - double dx = (xmax-xmin)/fac; - double dy = (ymax-ymin)/fac; - - NodePtr n1 = boost::make_shared(xmin-dx, ymin-dy); - NodePtr n2 = boost::make_shared(xmax+dx, ymin-dy); - NodePtr n3 = boost::make_shared(xmax+dx, ymax+dy); - NodePtr n4 = boost::make_shared(xmin-dx, ymax+dy); - - // diagonal - EdgePtr e1d = boost::make_shared(); - EdgePtr e2d = boost::make_shared(); - - // lower triangle - EdgePtr e11 = boost::make_shared(); - EdgePtr e12 = boost::make_shared(); - - // upper triangle - EdgePtr e21 = boost::make_shared(); - EdgePtr e22 = boost::make_shared(); - - // lower triangle - e1d->setSourceNode(n3); - e1d->setNextEdgeInFace(e11); - e1d->setTwinEdge(e2d); - addLeadingEdge(e1d); - - e11->setSourceNode(n1); - e11->setNextEdgeInFace(e12); - - e12->setSourceNode(n2); - e12->setNextEdgeInFace(e1d); - - // upper triangle - e2d->setSourceNode(n1); - e2d->setNextEdgeInFace(e21); - e2d->setTwinEdge(e1d); - addLeadingEdge(e2d); - - e21->setSourceNode(n3); - e21->setNextEdgeInFace(e22); - - e22->setSourceNode(n4); - e22->setNextEdgeInFace(e2d); - - return e11; -} - - -//-------------------------------------------------------------------------------------------------- -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) { - - cleanAll(); - - EdgePtr bedge = initTwoEnclosingTriangles(first, last); - Dart dc(bedge); - - Dart d_iter = dc; - - NodesContainer::iterator it; - for (it = first; it != last; ++it) { - helper->insertNode(d_iter, *it); - } - - // In general (e.g. for the triangle based data structure), the initial dart - // may have been changed. - // It is the users responsibility to get a valid boundary dart here. - // The half-edge data structure preserves the initial dart. - // (A dart at the boundary can also be found by trying to locate a - // triangle "outside" the triangulation.) - - // Assumes rectangular domain - helper->removeRectangularBoundary(dc); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::removeTriangle(EdgePtr& edge) { - - EdgePtr e1 = getLeadingEdgeInTriangle(edge); - -#ifdef DEBUG_HE - if (!e1) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - - removeLeadingEdgeFromList(e1); - // cout << "No leading edges = " << leadingEdges_.size() << endl; - // Remove the triangle - EdgePtr e2(e1->getNextEdgeInFace()); - EdgePtr e3(e2->getNextEdgeInFace()); - - e1->clear(); - e2->clear(); - e3->clear(); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::reverse_splitTriangle(EdgePtr& edge) { - - // Reverse operation of splitTriangle - - EdgePtr e1(edge->getNextEdgeInFace()); - EdgePtr le(getLeadingEdgeInTriangle(e1)); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - EdgePtr e2(e1->getNextEdgeInFace()->getTwinEdge()->getNextEdgeInFace()); - le = getLeadingEdgeInTriangle(e2); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - EdgePtr e3(edge->getTwinEdge()->getNextEdgeInFace()->getNextEdgeInFace()); - le = getLeadingEdgeInTriangle(e3); -#ifdef DEBUG_HE - if (!le) - errorAndExit("Triangulation::removeTriangle: could not find leading edge"); -#endif - removeLeadingEdgeFromList(le); - - // The three triangles at the node have now been removed - // from the triangulation, but the arcs have not been deleted. - // Next delete the 6 half edges radiating from the node - // The node is maintained by handle and need not be deleted explicitly - EdgePtr estar = edge; - EdgePtr enext = estar->getTwinEdge()->getNextEdgeInFace(); - estar->getTwinEdge()->clear(); - estar->clear(); - - estar = enext; - enext = estar->getTwinEdge()->getNextEdgeInFace(); - estar->getTwinEdge()->clear(); - estar->clear(); - - enext->getTwinEdge()->clear(); - enext->clear(); - - - // Create the new triangle - e1->setNextEdgeInFace(e2); - e2->setNextEdgeInFace(e3); - e3->setNextEdgeInFace(e1); - addLeadingEdge(e1); -} - - -//-------------------------------------------------------------------------------------------------- -Dart Triangulation::createDart() { - - // Return an arbitrary CCW dart - return Dart(*leadingEdges_.begin()); -} - - -//-------------------------------------------------------------------------------------------------- -bool Triangulation::removeLeadingEdgeFromList(EdgePtr& leadingEdge) { - - // Remove the edge from the list of leading edges, - // but don't delete it. - // Also set flag for leading edge to false. - // Must search from start of list. Since edges are added to the - // start of the list during triangulation, this operation will - // normally be fast (when used in the triangulation algorithm) - list::iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - - EdgePtr edge = *it; - if (edge == leadingEdge) { - - edge->setAsLeadingEdge(false); - it = leadingEdges_.erase(it); - - return true; + if( !edge->IsLeadingEdge() ) + edge = edge->GetNextEdgeInFace(); } - } - - return false; + + if( !edge->IsLeadingEdge() ) + { + return EDGE_PTR(); + } + + return edge; } -//-------------------------------------------------------------------------------------------------- -void Triangulation::cleanAll() { - BOOST_FOREACH(EdgePtr& edge, leadingEdges_) - edge->setNextEdgeInFace(EdgePtr()); +static void getLimits( NODES_CONTAINER::iterator aFirst, NODES_CONTAINER::iterator aLast, + int& aXmin, int& aYmin, int& aXmax, int& aYmax) +{ + aXmin = aYmin = std::numeric_limits::min(); + aXmax = aYmax = std::numeric_limits::max(); + + NODES_CONTAINER::iterator it; + + for( it = aFirst; it != aLast; ++it ) + { + aXmin = std::min( aXmin, ( *it )->GetX() ); + aYmin = std::min( aYmin, ( *it )->GetY() ); + aXmax = std::max( aXmax, ( *it )->GetX() ); + aYmax = std::max( aYmax, ( *it )->GetY() ); + } } -//-------------------------------------------------------------------------------------------------- -void Triangulation::swapEdge(Dart& dart) { - swapEdge(dart.getEdge()); +EDGE_PTR TRIANGULATION::InitTwoEnclosingTriangles( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast) +{ + int xmin, ymin, xmax, ymax; + getLimits( aFirst, aLast, xmin, ymin, xmax, ymax ); + + // Add 10% of range: + double fac = 10.0; + double dx = ( xmax - xmin ) / fac; + double dy = ( ymax - ymin ) / fac; + + NODE_PTR n1 = boost::make_shared( xmin - dx, ymin - dy ); + NODE_PTR n2 = boost::make_shared( xmax + dx, ymin - dy ); + NODE_PTR n3 = boost::make_shared( xmax + dx, ymax + dy ); + NODE_PTR n4 = boost::make_shared( xmin - dx, ymax + dy ); + + // diagonal + EDGE_PTR e1d = boost::make_shared(); + EDGE_PTR e2d = boost::make_shared(); + + // lower triangle + EDGE_PTR e11 = boost::make_shared(); + EDGE_PTR e12 = boost::make_shared(); + + // upper triangle + EDGE_PTR e21 = boost::make_shared(); + EDGE_PTR e22 = boost::make_shared(); + + // lower triangle + e1d->SetSourceNode( n3 ); + e1d->SetNextEdgeInFace( e11 ); + e1d->SetTwinEdge( e2d ); + addLeadingEdge( e1d ); + + e11->SetSourceNode( n1 ); + e11->SetNextEdgeInFace( e12 ); + + e12->SetSourceNode( n2 ); + e12->SetNextEdgeInFace( e1d ); + + // upper triangle + e2d->SetSourceNode( n1 ); + e2d->SetNextEdgeInFace( e21 ); + e2d->SetTwinEdge( e1d ); + addLeadingEdge( e2d ); + + e21->SetSourceNode( n3 ); + e21->SetNextEdgeInFace( e22 ); + + e22->SetSourceNode( n4 ); + e22->SetNextEdgeInFace( e2d ); + + return e11; } -//-------------------------------------------------------------------------------------------------- -void Triangulation::splitTriangle(Dart& dart, const NodePtr& point) { - EdgePtr edge = splitTriangle(dart.getEdge(), point); - dart.init(edge); +TRIANGULATION::TRIANGULATION() +{ + m_helper = new ttl::TRIANGULATION_HELPER( *this ); } -//-------------------------------------------------------------------------------------------------- -void Triangulation::reverse_splitTriangle(Dart& dart) { - reverse_splitTriangle(dart.getEdge()); +TRIANGULATION::TRIANGULATION( const TRIANGULATION& aTriangulation ) +{ + // Triangulation: Copy constructor not present + assert( false ); } -//-------------------------------------------------------------------------------------------------- -void Triangulation::removeBoundaryTriangle(Dart& d) { - removeTriangle(d.getEdge()); +TRIANGULATION::~TRIANGULATION() +{ + cleanAll(); + delete m_helper; +} + + +void TRIANGULATION::CreateDelaunay( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast ) +{ + cleanAll(); + + EDGE_PTR bedge = InitTwoEnclosingTriangles( aFirst, aLast ); + DART dc( bedge ); + + DART d_iter = dc; + + NODES_CONTAINER::iterator it; + for( it = aFirst; it != aLast; ++it ) + { + m_helper->InsertNode( d_iter, *it ); + } + + // In general (e.g. for the triangle based data structure), the initial dart + // may have been changed. + // It is the users responsibility to get a valid boundary dart here. + // The half-edge data structure preserves the initial dart. + // (A dart at the boundary can also be found by trying to locate a + // triangle "outside" the triangulation.) + + // Assumes rectangular domain + m_helper->RemoveRectangularBoundary( dc ); +} + + +void TRIANGULATION::RemoveTriangle( EDGE_PTR& aEdge ) +{ + EDGE_PTR e1 = getLeadingEdgeInTriangle( aEdge ); + +#ifdef DEBUG_HE + if( !e1 ) + errorAndExit( "Triangulation::removeTriangle: could not find leading aEdge" ); +#endif + + removeLeadingEdgeFromList( e1 ); + // cout << "No leading edges = " << leadingEdges_.size() << endl; + // Remove the triangle + EDGE_PTR e2( e1->GetNextEdgeInFace() ); + EDGE_PTR e3( e2->GetNextEdgeInFace() ); + + e1->Clear(); + e2->Clear(); + e3->Clear(); +} + + +void TRIANGULATION::ReverseSplitTriangle( EDGE_PTR& aEdge ) +{ + // Reverse operation of splitTriangle + EDGE_PTR e1( aEdge->GetNextEdgeInFace() ); + EDGE_PTR le( getLeadingEdgeInTriangle( e1 ) ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + EDGE_PTR e2( e1->GetNextEdgeInFace()->GetTwinEdge()->GetNextEdgeInFace() ); + le = getLeadingEdgeInTriangle( e2 ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + EDGE_PTR e3( aEdge->GetTwinEdge()->GetNextEdgeInFace()->GetNextEdgeInFace() ); + le = getLeadingEdgeInTriangle( e3 ); +#ifdef DEBUG_HE + if (!le) + errorAndExit("Triangulation::removeTriangle: could not find leading edge"); +#endif + removeLeadingEdgeFromList( le ); + + // The three triangles at the node have now been removed + // from the triangulation, but the arcs have not been deleted. + // Next delete the 6 half edges radiating from the node + // The node is maintained by handle and need not be deleted explicitly + EDGE_PTR estar = aEdge; + EDGE_PTR enext = estar->GetTwinEdge()->GetNextEdgeInFace(); + estar->GetTwinEdge()->Clear(); + estar->Clear(); + + estar = enext; + enext = estar->GetTwinEdge()->GetNextEdgeInFace(); + estar->GetTwinEdge()->Clear(); + estar->Clear(); + + enext->GetTwinEdge()->Clear(); + enext->Clear(); + + // Create the new triangle + e1->SetNextEdgeInFace( e2 ); + e2->SetNextEdgeInFace( e3 ); + e3->SetNextEdgeInFace( e1 ); + addLeadingEdge( e1 ); +} + + +DART TRIANGULATION::CreateDart() +{ + // Return an arbitrary CCW dart + return DART( *m_leadingEdges.begin() ); +} + + +bool TRIANGULATION::removeLeadingEdgeFromList( EDGE_PTR& aLeadingEdge ) +{ + // Remove the edge from the list of leading edges, + // but don't delete it. + // Also set flag for leading edge to false. + // Must search from start of list. Since edges are added to the + // start of the list during triangulation, this operation will + // normally be fast (when used in the triangulation algorithm) + std::list::iterator it; + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + if( edge == aLeadingEdge ) + { + edge->SetAsLeadingEdge( false ); + it = m_leadingEdges.erase( it ); + + return true; + } + } + + return false; +} + + +void TRIANGULATION::cleanAll() +{ + BOOST_FOREACH( EDGE_PTR& edge, m_leadingEdges ) + edge->SetNextEdgeInFace( EDGE_PTR() ); +} + + +void TRIANGULATION::swapEdge( DART& aDart ) +{ + SwapEdge( aDart.GetEdge() ); +} + + +void TRIANGULATION::splitTriangle( DART& aDart, const NODE_PTR& aPoint ) +{ + EDGE_PTR edge = SplitTriangle( aDart.GetEdge(), aPoint ); + aDart.Init( edge ); +} + + +void TRIANGULATION::reverseSplitTriangle( DART& aDart ) +{ + ReverseSplitTriangle( aDart.GetEdge() ); +} + + +void TRIANGULATION::removeBoundaryTriangle( DART& aDart ) +{ + RemoveTriangle( aDart.GetEdge() ); } #ifdef TTL_USE_NODE_FLAG -//-------------------------------------------------------------------------------------------------- -// This is a "template" for accessing all nodes (but multiple tests) -void Triangulation::flagNodes(bool flag) const { - - list::const_iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - edge->getSourceNode()->SetFlag(flag); - edge = edge->getNextEdgeInFace(); - } - } -} +void TRIANGULATION::FlagNodes( bool aFlag ) const +{ + std::list::const_iterator it; + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; - -//-------------------------------------------------------------------------------------------------- -list* Triangulation::getNodes() const { - - flagNodes(false); - list* nodeList = new list; - - list::const_iterator it; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - const NodePtr& node = edge->getSourceNode(); - - if (node->GetFlag() == false) { - nodeList->push_back(node); - node->SetFlag(true); - } - edge = edge->getNextEdgeInFace(); - } - } - return nodeList; -} -#endif - - -//-------------------------------------------------------------------------------------------------- -list* Triangulation::getEdges(bool skip_boundary_edges) const { - - // collect all arcs (one half edge for each arc) - // (boundary edges are also collected). - - list::const_iterator it; - list* elist = new list; - for (it = leadingEdges_.begin(); it != leadingEdges_.end(); ++it) { - EdgePtr edge = *it; - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - // only one of the half-edges - - if ( (!twinedge && !skip_boundary_edges) || - (twinedge && ((size_t)edge.get() > (size_t)twinedge.get())) ) - elist->push_front(edge); - - edge = edge->getNextEdgeInFace(); - } - } - return elist; -} - - -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::splitTriangle(EdgePtr& edge, const NodePtr& point) { - - // Add a node by just splitting a triangle into three triangles - // Assumes the half edge is located in the triangle - // Returns a half edge with source node as the new node - -// double x, y, z; -// x = point.x(); -// y = point.y(); -// z = point.z(); - - // e#_n are new edges - // e# are existing edges - // e#_n and e##_n are new twin edges - // e##_n are edges incident to the new node - - // Add the node to the structure - //NodePtr new_node(new Node(x,y,z)); - - NodePtr n1(edge->getSourceNode()); - EdgePtr e1(edge); - - EdgePtr e2(edge->getNextEdgeInFace()); - NodePtr n2(e2->getSourceNode()); - - EdgePtr e3(e2->getNextEdgeInFace()); - NodePtr n3(e3->getSourceNode()); - - EdgePtr e1_n = boost::make_shared(); - EdgePtr e11_n = boost::make_shared(); - EdgePtr e2_n = boost::make_shared(); - EdgePtr e22_n = boost::make_shared(); - EdgePtr e3_n = boost::make_shared(); - EdgePtr e33_n = boost::make_shared(); - - e1_n->setSourceNode(n1); - e11_n->setSourceNode(point); - e2_n->setSourceNode(n2); - e22_n->setSourceNode(point); - e3_n->setSourceNode(n3); - e33_n->setSourceNode(point); - - e1_n->setTwinEdge(e11_n); - e11_n->setTwinEdge(e1_n); - e2_n->setTwinEdge(e22_n); - e22_n->setTwinEdge(e2_n); - e3_n->setTwinEdge(e33_n); - e33_n->setTwinEdge(e3_n); - - e1_n->setNextEdgeInFace(e33_n); - e2_n->setNextEdgeInFace(e11_n); - e3_n->setNextEdgeInFace(e22_n); - - e11_n->setNextEdgeInFace(e1); - e22_n->setNextEdgeInFace(e2); - e33_n->setNextEdgeInFace(e3); - - // and update old's next edge - e1->setNextEdgeInFace(e2_n); - e2->setNextEdgeInFace(e3_n); - e3->setNextEdgeInFace(e1_n); - - // add the three new leading edges, - // Must remove the old leading edge from the list. - // Use the field telling if an edge is a leading edge - // NOTE: Must search in the list!!! - - if (e1->isLeadingEdge()) - removeLeadingEdgeFromList(e1); - else if (e2->isLeadingEdge()) - removeLeadingEdgeFromList(e2); - else if(e3->isLeadingEdge()) - removeLeadingEdgeFromList(e3); - else - assert( false ); // one of the edges should be leading - - addLeadingEdge(e1_n); - addLeadingEdge(e2_n); - addLeadingEdge(e3_n); - - // Return a half edge incident to the new node (with the new node as source node) - - return e11_n; -} - - -//-------------------------------------------------------------------------------------------------- -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 - // functions in TriangulationHelper now) - - // Swap by rotating counterclockwise - // Use the same objects - no deletion or new objects - EdgePtr eL(diagonal); - EdgePtr eR(eL->getTwinEdge()); - EdgePtr eL_1(eL->getNextEdgeInFace()); - EdgePtr eL_2(eL_1->getNextEdgeInFace()); - EdgePtr eR_1(eR->getNextEdgeInFace()); - EdgePtr eR_2(eR_1->getNextEdgeInFace()); - - // avoid node to be dereferenced to zero and deleted - NodePtr nR(eR_2->getSourceNode()); - NodePtr nL(eL_2->getSourceNode()); - - eL->setSourceNode(nR); - eR->setSourceNode(nL); - - // and now 6 1-sewings - eL->setNextEdgeInFace(eL_2); - eL_2->setNextEdgeInFace(eR_1); - eR_1->setNextEdgeInFace(eL); - - eR->setNextEdgeInFace(eR_2); - eR_2->setNextEdgeInFace(eL_1); - eL_1->setNextEdgeInFace(eR); - - if (eL->isLeadingEdge()) - removeLeadingEdgeFromList(eL); - else if (eL_1->isLeadingEdge()) - removeLeadingEdgeFromList(eL_1); - else if (eL_2->isLeadingEdge()) - removeLeadingEdgeFromList(eL_2); - - if (eR->isLeadingEdge()) - removeLeadingEdgeFromList(eR); - else if (eR_1->isLeadingEdge()) - removeLeadingEdgeFromList(eR_1); - else if (eR_2->isLeadingEdge()) - removeLeadingEdgeFromList(eR_2); - - addLeadingEdge(eL); - addLeadingEdge(eR); -} - - -////-------------------------------------------------------------------------- -//static void printEdge(const Dart& dart, ostream& ofile) { -// -// Dart d0 = dart; -// d0.alpha0(); -// -// ofile << dart.x() << " " << dart.y() << endl; -// ofile << d0.x() << " " << d0.y() << endl; -//} - - -//-------------------------------------------------------------------------- -bool Triangulation::checkDelaunay() const { - - // ???? outputs !!!! - // ofstream os("qweND.dat"); - const list& leadingEdges = getLeadingEdges(); - - list::const_iterator it; - bool ok = true; - int noNotDelaunay = 0; - - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - - // only one of the half-edges - if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) { - Dart dart(edge); - if (helper->swapTestDelaunay(dart)) { - noNotDelaunay++; - - //printEdge(dart,os); os << "\n"; - ok = false; - //cout << "............. not Delaunay .... " << endl; + for( int i = 0; i < 3; ++i ) + { + edge->GetSourceNode()->SetFlag( aFlag ); + edge = edge->GetNextEdgeInFace(); } - } - edge = edge->getNextEdgeInFace(); } - } - -#ifdef DEBUG_HE - cout << "!!! Triangulation is NOT Delaunay: " << noNotDelaunay << " edges\n" << endl; +} + + +std::list* TRIANGULATION::GetNodes() const +{ + FlagNodes( false ); + std::list* nodeList = new std::list; + std::list::const_iterator it; + + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + const NODE_PTR& node = edge->GetSourceNode(); + + if( node->GetFlag() == false ) + { + nodeList->push_back( node ); + node->SetFlag( true ); + } + edge = edge->GetNextEdgeInFace(); + } + } + return nodeList; +} #endif - - return ok; -} -//-------------------------------------------------------------------------------------------------- -void Triangulation::optimizeDelaunay() { +std::list* TRIANGULATION::GetEdges( bool aSkipBoundaryEdges ) const +{ + // collect all arcs (one half edge for each arc) + // (boundary edges are also collected). + std::list::const_iterator it; + std::list* elist = new std::list; - // This function is also present in ttl where it is implemented - // generically. - // The implementation below is tailored for the half-edge data structure, - // and is thus more efficient + for( it = m_leadingEdges.begin(); it != m_leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + // only one of the half-edges - // Collect all interior edges (one half edge for each arc) - bool skip_boundary_edges = true; - list* elist = getEdges(skip_boundary_edges); - - // Assumes that elist has only one half-edge for each arc. - bool cycling_check = true; - bool optimal = false; - list::const_iterator it; - while(!optimal) { - optimal = true; - for (it = elist->begin(); it != elist->end(); ++it) { - EdgePtr edge = *it; - - Dart dart(edge); - // Constrained edges should not be swapped - if (helper->swapTestDelaunay(dart, cycling_check)) { - optimal = false; - swapEdge(edge); - } + if( ( !twinedge && !aSkipBoundaryEdges ) + || ( twinedge && ( (size_t) edge.get() > (size_t) twinedge.get() ) ) ) + elist->push_front( edge ); + + edge = edge->GetNextEdgeInFace(); + } } - } - delete elist; + + return elist; } -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getInteriorNode() const { - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - // multiple checks, but only until found - for (int i = 0; i < 3; ++i) { - if (edge->getTwinEdge()) { - - if (!helper->isBoundaryNode(Dart(edge))) - return edge; - } - edge = edge->getNextEdgeInFace(); +EDGE_PTR TRIANGULATION::SplitTriangle( EDGE_PTR& aEdge, const NODE_PTR& aPoint ) +{ + // Add a node by just splitting a triangle into three triangles + // Assumes the half aEdge is located in the triangle + // Returns a half aEdge with source node as the new node + + // e#_n are new edges + // e# are existing edges + // e#_n and e##_n are new twin edges + // e##_n are edges incident to the new node + + // Add the node to the structure + //NODE_PTR new_node(new Node(x,y,z)); + + NODE_PTR n1( aEdge->GetSourceNode() ); + EDGE_PTR e1( aEdge ); + + EDGE_PTR e2( aEdge->GetNextEdgeInFace() ); + NODE_PTR n2( e2->GetSourceNode() ); + + EDGE_PTR e3( e2->GetNextEdgeInFace() ); + NODE_PTR n3( e3->GetSourceNode() ); + + EDGE_PTR e1_n = boost::make_shared(); + EDGE_PTR e11_n = boost::make_shared(); + EDGE_PTR e2_n = boost::make_shared(); + EDGE_PTR e22_n = boost::make_shared(); + EDGE_PTR e3_n = boost::make_shared(); + EDGE_PTR e33_n = boost::make_shared(); + + e1_n->SetSourceNode( n1 ); + e11_n->SetSourceNode( aPoint ); + e2_n->SetSourceNode( n2 ); + e22_n->SetSourceNode( aPoint ); + e3_n->SetSourceNode( n3 ); + e33_n->SetSourceNode( aPoint ); + + e1_n->SetTwinEdge( e11_n ); + e11_n->SetTwinEdge( e1_n ); + e2_n->SetTwinEdge( e22_n ); + e22_n->SetTwinEdge( e2_n ); + e3_n->SetTwinEdge( e33_n ); + e33_n->SetTwinEdge( e3_n ); + + e1_n->SetNextEdgeInFace( e33_n ); + e2_n->SetNextEdgeInFace( e11_n ); + e3_n->SetNextEdgeInFace( e22_n ); + + e11_n->SetNextEdgeInFace( e1 ); + e22_n->SetNextEdgeInFace( e2 ); + e33_n->SetNextEdgeInFace( e3 ); + + // and update old's next aEdge + e1->SetNextEdgeInFace( e2_n ); + e2->SetNextEdgeInFace( e3_n ); + e3->SetNextEdgeInFace( e1_n ); + + // add the three new leading edges, + // Must remove the old leading aEdge from the list. + // Use the field telling if an aEdge is a leading aEdge + // NOTE: Must search in the list!!! + + if( e1->IsLeadingEdge() ) + removeLeadingEdgeFromList( e1 ); + else if( e2->IsLeadingEdge() ) + removeLeadingEdgeFromList( e2 ); + else if( e3->IsLeadingEdge() ) + removeLeadingEdgeFromList( e3 ); + else + assert( false ); // one of the edges should be leading + + addLeadingEdge( e1_n ); + addLeadingEdge( e2_n ); + addLeadingEdge( e3_n ); + + // Return a half aEdge incident to the new node (with the new node as source node) + + return e11_n; +} + + +void TRIANGULATION::SwapEdge( EDGE_PTR& aDiagonal ) +{ + // Note that diagonal is both input and output and it is always + // kept in counterclockwise direction (this is not required by all + // functions in TriangulationHelper now) + + // Swap by rotating counterclockwise + // Use the same objects - no deletion or new objects + EDGE_PTR eL( aDiagonal ); + EDGE_PTR eR( eL->GetTwinEdge() ); + EDGE_PTR eL_1( eL->GetNextEdgeInFace() ); + EDGE_PTR eL_2( eL_1->GetNextEdgeInFace() ); + EDGE_PTR eR_1( eR->GetNextEdgeInFace() ); + EDGE_PTR eR_2( eR_1->GetNextEdgeInFace() ); + + // avoid node to be dereferenced to zero and deleted + NODE_PTR nR( eR_2->GetSourceNode() ); + NODE_PTR nL( eL_2->GetSourceNode() ); + + eL->SetSourceNode( nR ); + eR->SetSourceNode( nL ); + + // and now 6 1-sewings + eL->SetNextEdgeInFace( eL_2 ); + eL_2->SetNextEdgeInFace( eR_1 ); + eR_1->SetNextEdgeInFace( eL ); + + eR->SetNextEdgeInFace( eR_2 ); + eR_2->SetNextEdgeInFace( eL_1 ); + eL_1->SetNextEdgeInFace( eR ); + + if( eL->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL ); + else if( eL_1->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL_1 ); + else if( eL_2->IsLeadingEdge() ) + removeLeadingEdgeFromList( eL_2 ); + + if( eR->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR ); + else if( eR_1->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR_1 ); + else if( eR_2->IsLeadingEdge() ) + removeLeadingEdgeFromList( eR_2 ); + + addLeadingEdge( eL ); + addLeadingEdge( eR ); +} + + +bool TRIANGULATION::CheckDelaunay() const +{ + // ???? outputs !!!! + // ofstream os("qweND.dat"); + const std::list& leadingEdges = GetLeadingEdges(); + + std::list::const_iterator it; + bool ok = true; + int noNotDelaunay = 0; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + + // only one of the half-edges + if( !twinedge || (size_t) edge.get() > (size_t) twinedge.get() ) + { + DART dart( edge ); + if( m_helper->SwapTestDelaunay( dart ) ) + { + noNotDelaunay++; + + //printEdge(dart,os); os << "\n"; + ok = false; + //cout << "............. not Delaunay .... " << endl; + } + } + + edge = edge->GetNextEdgeInFace(); + } } - } - return EdgePtr(); // no boundary nodes + +#ifdef DEBUG_HE + cout << "!!! Triangulation is NOT Delaunay: " << noNotDelaunay << " edges\n" << endl; +#endif + + return ok; } -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getBoundaryEdgeInTriangle(const EdgePtr& e) const { - EdgePtr edge = e; - - if (helper->isBoundaryEdge(Dart(edge))) - return edge; +void TRIANGULATION::OptimizeDelaunay() +{ + // This function is also present in ttl where it is implemented + // generically. + // The implementation below is tailored for the half-edge data structure, + // and is thus more efficient - edge = edge->getNextEdgeInFace(); - if (helper->isBoundaryEdge(Dart(edge))) - return edge; + // Collect all interior edges (one half edge for each arc) + bool skip_boundary_edges = true; + std::list* elist = GetEdges( skip_boundary_edges ); - edge = edge->getNextEdgeInFace(); - if (helper->isBoundaryEdge(Dart(edge))) - return edge; - - return EdgePtr(); -} + // Assumes that elist has only one half-edge for each arc. + bool cycling_check = true; + bool optimal = false; + std::list::const_iterator it; + while( !optimal ) + { + optimal = true; -//-------------------------------------------------------------------------------------------------- -EdgePtr Triangulation::getBoundaryEdge() const { + for( it = elist->begin(); it != elist->end(); ++it ) + { + EDGE_PTR edge = *it; - // Get an arbitrary (CCW) boundary edge - // If the triangulation is closed, NULL is returned - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - EdgePtr edge; - - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - edge = getBoundaryEdgeInTriangle(*it); - - if (edge) - return edge; - } - return EdgePtr(); -} - - -//-------------------------------------------------------------------------------------------------- -void Triangulation::printEdges(ofstream& os) const { - - // Print source node and target node for each edge face by face, - // but only one of the half-edges. - - const list& leadingEdges = getLeadingEdges(); - list::const_iterator it; - for (it = leadingEdges.begin(); it != leadingEdges.end(); ++it) { - EdgePtr edge = *it; - - for (int i = 0; i < 3; ++i) { - EdgePtr twinedge = edge->getTwinEdge(); - - // Print only one edge (the highest value of the pointer) - if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) { - // Print source node and target node - NodePtr node = edge->getSourceNode(); - os << node->GetX() << " " << node->GetY() << endl; - node = edge->getTargetNode(); - os << node->GetX() << " " << node->GetY() << endl; - os << '\n'; // blank line - } - edge = edge->getNextEdgeInFace(); + DART dart( edge ); + // Constrained edges should not be swapped + if( m_helper->SwapTestDelaunay( dart, cycling_check ) ) + { + optimal = false; + SwapEdge( edge ); + } + } + } + + delete elist; +} + + +EDGE_PTR TRIANGULATION::GetInteriorNode() const +{ + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + // multiple checks, but only until found + for( int i = 0; i < 3; ++i ) + { + if( edge->GetTwinEdge() ) + { + if( !m_helper->IsBoundaryNode( DART( edge ) ) ) + return edge; + } + + edge = edge->GetNextEdgeInFace(); + } + } + + return EDGE_PTR(); // no boundary nodes +} + + +EDGE_PTR TRIANGULATION::GetBoundaryEdgeInTriangle( const EDGE_PTR& aEdge ) const +{ + EDGE_PTR edge = aEdge; + + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + edge = edge->GetNextEdgeInFace(); + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + edge = edge->GetNextEdgeInFace(); + if( m_helper->IsBoundaryEdge( DART( edge ) ) ) + return edge; + + return EDGE_PTR(); +} + + +EDGE_PTR TRIANGULATION::GetBoundaryEdge() const +{ + // Get an arbitrary (CCW) boundary edge + // If the triangulation is closed, NULL is returned + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + EDGE_PTR edge; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + edge = GetBoundaryEdgeInTriangle( *it ); + + if( edge ) + return edge; + } + return EDGE_PTR(); +} + + +void TRIANGULATION::PrintEdges( std::ofstream& aOutput ) const +{ + // Print source node and target node for each edge face by face, + // but only one of the half-edges. + const std::list& leadingEdges = GetLeadingEdges(); + std::list::const_iterator it; + + for( it = leadingEdges.begin(); it != leadingEdges.end(); ++it ) + { + EDGE_PTR edge = *it; + + for( int i = 0; i < 3; ++i ) + { + EDGE_PTR twinedge = edge->GetTwinEdge(); + + // Print only one edge (the highest value of the pointer) + if( !twinedge || (size_t) edge.get() > (size_t) twinedge.get() ) + { + // Print source node and target node + NODE_PTR node = edge->GetSourceNode(); + aOutput << node->GetX() << " " << node->GetY() << std::endl; + node = edge->GetTargetNode(); + aOutput << node->GetX() << " " << node->GetY() << std::endl; + aOutput << '\n'; // blank line + } + + edge = edge->GetNextEdgeInFace(); + } } - } } diff --git a/include/ttl/halfedge/hedart.h b/include/ttl/halfedge/hedart.h index f85678963a..2749c5087c 100644 --- a/include/ttl/halfedge/hedart.h +++ b/include/ttl/halfedge/hedart.h @@ -40,111 +40,152 @@ #ifndef _HALF_EDGE_DART_ #define _HALF_EDGE_DART_ - #include +namespace hed +{ +/** + * \class Dart + * \brief \b %Dart class for the half-edge data structure. + * + * See \ref api for a detailed description of how the member functions + * should be implemented. + */ +class DART +{ + EDGE_PTR m_edge; -namespace hed { + /// Dart direction: true if dart is counterclockwise in face + bool m_dir; - - //------------------------------------------------------------------------------------------------ - // Dart class for the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \class Dart - * \brief \b %Dart class for the half-edge data structure. - * - * See \ref api for a detailed description of how the member functions - * should be implemented. - */ - - class Dart { - - EdgePtr edge_; - bool dir_; // true if dart is counterclockwise in face - - public: +public: /// Default constructor - Dart() { dir_ = true; } + DART() + { + m_dir = true; + } /// Constructor - Dart(const EdgePtr& edge, bool dir = true) { edge_ = edge; dir_ = dir; } + DART( const EDGE_PTR& aEdge, bool aDir = true ) + { + m_edge = aEdge; + m_dir = aDir; + } /// Copy constructor - Dart(const Dart& dart) { edge_ = dart.edge_; dir_ = dart.dir_; } + DART( const DART& aDart ) + { + m_edge = aDart.m_edge; + m_dir = aDart.m_dir; + } /// Destructor - ~Dart() {} + ~DART() + { + } /// Assignment operator - Dart& operator = (const Dart& dart) { - if (this == &dart) + DART& operator=( const DART& aDart ) + { + if( this == &aDart ) + return *this; + + m_edge = aDart.m_edge; + m_dir = aDart.m_dir; + return *this; - edge_ = dart.edge_; - dir_ = dart.dir_; - return *this; } /// Comparing dart objects - bool operator==(const Dart& dart) const { - if (dart.edge_ == edge_ && dart.dir_ == dir_) - return true; - return false; + bool operator==( const DART& aDart ) const + { + return ( aDart.m_edge == m_edge && aDart.m_dir == m_dir ); } /// Comparing dart objects - bool operator!=(const Dart& dart) const { - return !(dart==*this); + bool operator!=( const DART& aDart ) const + { + return !( aDart == *this ); } /// Maps the dart to a different node - Dart& alpha0() { dir_ = !dir_; return *this; } + DART& Alpha0() + { + m_dir = !m_dir; + return *this; + } /// Maps the dart to a different edge - Dart& alpha1() { - if (dir_) { - edge_ = edge_->getNextEdgeInFace()->getNextEdgeInFace(); - dir_ = false; - } - else { - edge_ = edge_->getNextEdgeInFace(); - dir_ = true; - } - return *this; + DART& Alpha1() + { + if( m_dir ) + { + m_edge = m_edge->GetNextEdgeInFace()->GetNextEdgeInFace(); + m_dir = false; + } + else + { + m_edge = m_edge->GetNextEdgeInFace(); + m_dir = true; + } + + return *this; } /// Maps the dart to a different triangle. \b Note: the dart is not changed if it is at the boundary! - Dart& alpha2() { - if (edge_->getTwinEdge()) { - edge_ = edge_->getTwinEdge(); - dir_ = !dir_; - } - // else, the dart is at the boundary and should not be changed - return *this; + DART& Alpha2() + { + if( m_edge->GetTwinEdge() ) + { + m_edge = m_edge->GetTwinEdge(); + m_dir = !m_dir; + } + + // else, the dart is at the boundary and should not be changed + return *this; } - - // Utilities not required by TTL - // ----------------------------- - /** @name Utilities not required by TTL */ //@{ + void Init( const EDGE_PTR& aEdge, bool aDir = true ) + { + m_edge = aEdge; + m_dir = aDir; + } - void init(const EdgePtr& edge, bool dir = true) { edge_ = edge; dir_ = dir; } + double X() const + { + return GetNode()->GetX(); + } - double x() const { return getNode()->GetX(); } // x-coordinate of source node - double y() const { return getNode()->GetY(); } // y-coordinate of source node + double Y() const + { + return GetNode()->GetY(); + } - bool isCounterClockWise() const { return dir_; } + bool IsCCW() const + { + return m_dir; + } - const NodePtr& getNode() const { return dir_ ? edge_->getSourceNode() : edge_->getTargetNode(); } - const NodePtr& getOppositeNode() const { return dir_ ? edge_->getTargetNode() : edge_->getSourceNode(); } - EdgePtr& getEdge() { return edge_; } + const NODE_PTR& GetNode() const + { + return m_dir ? m_edge->GetSourceNode() : m_edge->GetTargetNode(); + } + + const NODE_PTR& GetOppositeNode() const + { + return m_dir ? m_edge->GetTargetNode() : m_edge->GetSourceNode(); + } + + EDGE_PTR& GetEdge() + { + return m_edge; + } //@} // End of Utilities not required by TTL +}; - }; - -}; // End of hed namespace +} // End of hed namespace #endif diff --git a/include/ttl/halfedge/hetraits.h b/include/ttl/halfedge/hetraits.h index e24cd0697d..04288a0ba5 100644 --- a/include/ttl/halfedge/hetraits.h +++ b/include/ttl/halfedge/hetraits.h @@ -40,136 +40,149 @@ #ifndef _HALF_EDGE_TRAITS_ #define _HALF_EDGE_TRAITS_ - #include #include - -namespace hed { - - - //------------------------------------------------------------------------------------------------ - // Traits class for the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \struct TTLtraits - * \brief \b Traits class (static struct) for the half-edge data structure. - * - * The member functions are those required by different function templates - * in the TTL. Documentation is given here to explain what actions - * should be carried out on the actual data structure as required by the functions - * in the \ref ttl namespace. - * - * The source code of \c %HeTraits.h shows how the traits class is implemented for the - * half-edge data structure. - * - * \see \ref api - * - */ - - struct TTLtraits { +namespace hed +{ +/** + * \struct TTLtraits + * \brief \b Traits class (static struct) for the half-edge data structure. + * + * The member functions are those required by different function templates + * in the TTL. Documentation is given here to explain what actions + * should be carried out on the actual data structure as required by the functions + * in the \ref ttl namespace. + * + * The source code of \c %HeTraits.h shows how the traits class is implemented for the + * half-edge data structure. + * + * \see \ref api + */ +struct TTLtraits +{ + /** + * The floating point type used in calculations involving scalar products and cross products. + */ + typedef double REAL_TYPE; - /** The floating point type used in calculations - * involving scalar products and cross products. - */ - typedef double real_type; - - - //---------------------------------------------------------------------------------------------- - // ------------------------------- Geometric Predicates Group --------------------------------- - //---------------------------------------------------------------------------------------------- - /** @name Geometric Predicates */ //@{ + /** + * Scalar product between two 2D vectors represented as darts.\n + * + * ttl_util::scalarProduct2d can be used. + */ + static REAL_TYPE ScalarProduct2D( const DART& aV1, const DART& aV2 ) + { + DART v10 = aV1; + v10.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Scalar product between two 2D vectors represented as darts.\n - * - * ttl_util::scalarProduct2d can be used. - */ - static real_type scalarProduct2d(const Dart& v1, const Dart& v2) { - Dart v10 = v1; v10.alpha0(); - Dart v20 = v2; v20.alpha0(); - return ttl_util::scalarProduct2d(v10.x()-v1.x(), v10.y()-v1.y(), - v20.x()-v2.x(), v20.y()-v2.y()); + DART v20 = aV2; + v20.Alpha0(); + + return ttl_util::ScalarProduct2D( v10.X() - aV1.X(), v10.Y() - aV1.Y(), + v20.X() - aV2.X(), v20.Y() - aV2.Y() ); } + /** + * Scalar product between two 2D vectors. + * The first vector is represented by a dart \e v, and the second + * vector has direction from the source node of \e v to the point \e p.\n + * + * ttl_util::ScalarProduct2D can be used. + */ + static REAL_TYPE ScalarProduct2D( const DART& aV, const NODE_PTR& aP ) + { + DART d0 = aV; + d0.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Scalar product between two 2D vectors. - * The first vector is represented by a dart \e v, and the second - * vector has direction from the source node of \e v to the point \e p.\n - * - * ttl_util::scalarProduct2d can be used. - */ - static real_type scalarProduct2d(const Dart& v, const NodePtr& p) { - Dart d0 = v; d0.alpha0(); - return ttl_util::scalarProduct2d(d0.x() - v.x(), d0.y() - v.y(), - p->GetX() - v.x(), p->GetY() - v.y()); + return ttl_util::ScalarProduct2D( d0.X() - aV.X(), d0.Y() - aV.Y(), + aP->GetX() - aV.X(), aP->GetY() - aV.Y() ); } + /** + * Cross product between two vectors in the plane represented as darts. + * The z-component of the cross product is returned.\n + * + * ttl_util::CrossProduct2D can be used. + */ + static REAL_TYPE CrossProduct2D( const DART& aV1, const DART& aV2 ) + { + DART v10 = aV1; + v10.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Cross product between two vectors in the plane represented as darts. - * The z-component of the cross product is returned.\n - * - * ttl_util::crossProduct2d can be used. - */ - static real_type crossProduct2d(const Dart& v1, const Dart& v2) { - Dart v10 = v1; v10.alpha0(); - Dart v20 = v2; v20.alpha0(); - return ttl_util::crossProduct2d(v10.x()-v1.x(), v10.y()-v1.y(), - v20.x()-v2.x(), v20.y()-v2.y()); + DART v20 = aV2; + v20.Alpha0(); + + return ttl_util::CrossProduct2D( v10.X() - aV1.X(), v10.Y() - aV1.Y(), + v20.X() - aV2.X(), v20.Y() - aV2.Y() ); } + /** + * Cross product between two vectors in the plane. + * The first vector is represented by a dart \e v, and the second + * vector has direction from the source node of \e v to the point \e p. + * The z-component of the cross product is returned.\n + * + * ttl_util::CrossProduct2d can be used. + */ + static REAL_TYPE CrossProduct2D( const DART& aV, const NODE_PTR& aP ) + { + DART d0 = aV; + d0.Alpha0(); - //---------------------------------------------------------------------------------------------- - /** Cross product between two vectors in the plane. - * The first vector is represented by a dart \e v, and the second - * vector has direction from the source node of \e v to the point \e p. - * The z-component of the cross product is returned.\n - * - * ttl_util::crossProduct2d can be used. - */ - static real_type crossProduct2d(const Dart& v, const NodePtr& p) { - Dart d0 = v; d0.alpha0(); - return ttl_util::crossProduct2d(d0.x() - v.x(), d0.y() - v.y(), - p->GetX() - v.x(), p->GetY() - v.y()); + return ttl_util::CrossProduct2D( d0.X() - aV.X(), d0.Y() - aV.Y(), + aP->GetX() - aV.X(), aP->GetY() - aV.Y() ); } + /** + * Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p + * be a point in the plane. Return a positive value if \e n1, \e n2, + * and \e p occur in counterclockwise order; a negative value if they occur + * in clockwise order; and zero if they are collinear. + */ + static REAL_TYPE Orient2D( const DART& aN1, const DART& aN2, const NODE_PTR& aP ) + { + REAL_TYPE pa[2]; + REAL_TYPE pb[2]; + REAL_TYPE pc[2]; - //---------------------------------------------------------------------------------------------- - /** Let \e n1 and \e n2 be the nodes associated with two darts, and let \e p - * be a point in the plane. Return a positive value if \e n1, \e n2, - * and \e p occur in counterclockwise order; a negative value if they occur - * in clockwise order; and zero if they are collinear. - */ - static real_type orient2d(const Dart& n1, const Dart& n2, const NodePtr& p) { - real_type pa[2]; real_type pb[2]; real_type pc[2]; - pa[0] = n1.x(); pa[1] = n1.y(); - pb[0] = n2.x(); pb[1] = n2.y(); - pc[0] = p->GetX(); pc[1] = p->GetY(); - return ttl_util::orient2dfast(pa, pb, pc); + pa[0] = aN1.X(); + pa[1] = aN1.Y(); + pb[0] = aN2.X(); + pb[1] = aN2.Y(); + pc[0] = aP->GetX(); + pc[1] = aP->GetY(); + + return ttl_util::Orient2DFast( pa, pb, pc ); } + /** + * This is the same predicate as represented with the function above, + * but with a slighty different interface: + * The last parameter is given as a dart where the source node of the dart + * represents a point in the plane. + * This function is required for constrained triangulation. + */ + static REAL_TYPE Orient2D( const DART& aN1, const DART& aN2, const DART& aP ) + { + REAL_TYPE pa[2]; + REAL_TYPE pb[2]; + REAL_TYPE pc[2]; - //---------------------------------------------------------------------------------------------- - /** This is the same predicate as represented with the function above, - * but with a slighty different interface: - * The last parameter is given as a dart where the source node of the dart - * represents a point in the plane. - * This function is required for constrained triangulation. - */ - static real_type orient2d(const Dart& n1, const Dart& n2, const Dart& p) { - real_type pa[2]; real_type pb[2]; real_type pc[2]; - pa[0] = n1.x(); pa[1] = n1.y(); - pb[0] = n2.x(); pb[1] = n2.y(); - pc[0] = p.x(); pc[1] = p.y(); - return ttl_util::orient2dfast(pa, pb, pc); + pa[0] = aN1.X(); + pa[1] = aN1.Y(); + pb[0] = aN2.X(); + pb[1] = aN2.Y(); + pc[0] = aP.X(); + pc[1] = aP.Y(); + + return ttl_util::Orient2DFast( pa, pb, pc ); } //@} // End of Geometric Predicates Group - }; +}; }; // End of hed namespace diff --git a/include/ttl/halfedge/hetriang.h b/include/ttl/halfedge/hetriang.h index 2c5380864e..f84c542e5a 100644 --- a/include/ttl/halfedge/hetriang.h +++ b/include/ttl/halfedge/hetriang.h @@ -42,11 +42,9 @@ #ifndef _HE_TRIANG_H_ #define _HE_TRIANG_H_ - #define TTL_USE_NODE_ID // Each node gets it's own unique id #define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false) - #include #include #include @@ -55,43 +53,40 @@ #include #include -namespace ttl { - class TriangulationHelper; +namespace ttl +{ + class TRIANGULATION_HELPER; }; -//-------------------------------------------------------------------------------------------------- -// The half-edge data structure -//-------------------------------------------------------------------------------------------------- - -namespace hed { - // Helper typedefs - class Node; - class Edge; - typedef boost::shared_ptr NodePtr; - typedef boost::shared_ptr EdgePtr; - typedef boost::weak_ptr EdgeWeakPtr; - typedef std::vector NodesContainer; - - //------------------------------------------------------------------------------------------------ - // Node class for data structures - //------------------------------------------------------------------------------------------------ - - /** \class Node - * \brief \b Node class for data structures (Inherits from HandleId) - * - * \note - * - To enable node IDs, TTL_USE_NODE_ID must be defined. - * - To enable node flags, TTL_USE_NODE_FLAG must be defined. - * - TTL_USE_NODE_ID and TTL_USE_NODE_FLAG should only be enabled if this functionality is - * required by the application, because they increase the memory usage for each Node object. - */ - - class Node { +/** + * The half-edge data structure + */ +namespace hed +{ +// Helper typedefs +class NODE; +class EDGE; +typedef boost::shared_ptr NODE_PTR; +typedef boost::shared_ptr EDGE_PTR; +typedef boost::weak_ptr EDGE_WEAK_PTR; +typedef std::vector NODES_CONTAINER; +/** + * \class NODE + * \brief \b Node class for data structures (Inherits from HandleId) + * + * \note + * - To enable node IDs, TTL_USE_NODE_ID must be defined. + * - To enable node flags, TTL_USE_NODE_FLAG must be defined. + * - TTL_USE_NODE_ID and TTL_USE_NODE_FLAG should only be enabled if this functionality is + * required by the application, because they increase the memory usage for each Node object. + */ +class NODE +{ protected: #ifdef TTL_USE_NODE_FLAG /// TTL_USE_NODE_FLAG must be defined - bool flag_; + bool m_flag; #endif #ifdef TTL_USE_NODE_ID @@ -99,303 +94,378 @@ protected: static int id_count; /// A unique id for each node (TTL_USE_NODE_ID must be defined) - int id_; + int m_id; #endif - int x_, y_; + /// Node coordinates + int m_x, m_y; - unsigned int refCount_; + /// Reference count + unsigned int m_refCount; public: /// Constructor - Node( int x = 0, int y = 0 ) : + NODE( int aX = 0, int aY = 0 ) : #ifdef TTL_USE_NODE_FLAG - flag_( false ), + m_flag( false ), #endif #ifdef TTL_USE_NODE_ID - id_( id_count++ ), + m_id( id_count++ ), #endif - x_( x ), y_( y ), refCount_( 0 ) {} + m_x( aX ), m_y( aY ), m_refCount( 0 ) + { + } /// Destructor - ~Node() {} + ~NODE() {} /// Returns the x-coordinate - int GetX() const { return x_; } + int GetX() const + { + return m_x; + } /// Returns the y-coordinate - int GetY() const { return y_; } + int GetY() const + { + return m_y; + } #ifdef TTL_USE_NODE_ID /// Returns the id (TTL_USE_NODE_ID must be defined) - int Id() const { return id_; } + int Id() const + { + return m_id; + } #endif #ifdef TTL_USE_NODE_FLAG /// Sets the flag (TTL_USE_NODE_FLAG must be defined) - void SetFlag(bool aFlag) { flag_ = aFlag; } + void SetFlag( bool aFlag ) + { + m_flag = aFlag; + } /// Returns the flag (TTL_USE_NODE_FLAG must be defined) - const bool& GetFlag() const { return flag_; } + const bool& GetFlag() const + { + return m_flag; + } #endif - void IncRefCount() { refCount_++; } - void DecRefCount() { refCount_--; } - unsigned int GetRefCount() const { return refCount_; } - }; // End of class Node + void IncRefCount() + { + m_refCount++; + } + + void DecRefCount() + { + m_refCount--; + } + + unsigned int GetRefCount() const + { + return m_refCount; + } +}; - //------------------------------------------------------------------------------------------------ - // Edge class in the half-edge data structure - //------------------------------------------------------------------------------------------------ - - /** \class Edge - * \brief \b %Edge class in the in the half-edge data structure. - */ - - class Edge { - public: +/** + * \class EDGE + * \brief \b %Edge class in the in the half-edge data structure. + */ +class EDGE +{ +public: /// Constructor - Edge() : weight_(0), isLeadingEdge_(false) {} + EDGE() : m_weight( 0 ), m_isLeadingEdge( false ) + { + } /// Destructor - virtual ~Edge() {} + virtual ~EDGE() + { + } /// Sets the source node - void setSourceNode(const NodePtr& node) { sourceNode_ = node; } + void SetSourceNode( const NODE_PTR& aNode ) + { + m_sourceNode = aNode; + } /// Sets the next edge in face - void setNextEdgeInFace(const EdgePtr& edge) { nextEdgeInFace_ = edge; } + void SetNextEdgeInFace( const EDGE_PTR& aEdge ) + { + m_nextEdgeInFace = aEdge; + } /// Sets the twin edge - void setTwinEdge(const EdgePtr& edge) { twinEdge_ = edge; } + void SetTwinEdge( const EDGE_PTR& aEdge ) + { + m_twinEdge = aEdge; + } /// Sets the edge as a leading edge - void setAsLeadingEdge(bool val=true) { isLeadingEdge_ = val; } + void SetAsLeadingEdge( bool aLeading = true ) + { + m_isLeadingEdge = aLeading; + } /// Checks if an edge is a leading edge - bool isLeadingEdge() const { return isLeadingEdge_; } + bool IsLeadingEdge() const + { + return m_isLeadingEdge; + } /// Returns the twin edge - EdgePtr getTwinEdge() const { return twinEdge_.lock(); }; + EDGE_PTR GetTwinEdge() const + { + return m_twinEdge.lock(); + } - void clearTwinEdge() { twinEdge_.reset(); } + void ClearTwinEdge() + { + m_twinEdge.reset(); + } /// Returns the next edge in face - const EdgePtr& getNextEdgeInFace() const { return nextEdgeInFace_; } + const EDGE_PTR& GetNextEdgeInFace() const + { + return m_nextEdgeInFace; + } /// Retuns the source node - const NodePtr& getSourceNode() const { return sourceNode_; } + const NODE_PTR& GetSourceNode() const + { + return m_sourceNode; + } /// Returns the target node - virtual const NodePtr& getTargetNode() const { return nextEdgeInFace_->getSourceNode(); } - - void setWeight( unsigned int weight ) { weight_ = weight; } - - unsigned int getWeight() const { return weight_; } - - void clear() + virtual const NODE_PTR& GetTargetNode() const { - sourceNode_.reset(); - nextEdgeInFace_.reset(); + return m_nextEdgeInFace->GetSourceNode(); + } - if( !twinEdge_.expired() ) + void SetWeight( unsigned int weight ) + { + m_weight = weight; + } + + unsigned int GetWeight() const + { + return m_weight; + } + + void Clear() + { + m_sourceNode.reset(); + m_nextEdgeInFace.reset(); + + if( !m_twinEdge.expired() ) { - twinEdge_.lock()->clearTwinEdge(); - twinEdge_.reset(); + m_twinEdge.lock()->ClearTwinEdge(); + m_twinEdge.reset(); } } - protected: - NodePtr sourceNode_; - EdgeWeakPtr twinEdge_; - EdgePtr nextEdgeInFace_; - unsigned int weight_; - bool isLeadingEdge_; - }; // End of class Edge +protected: + NODE_PTR m_sourceNode; + EDGE_WEAK_PTR m_twinEdge; + EDGE_PTR m_nextEdgeInFace; + unsigned int m_weight; + bool m_isLeadingEdge; +}; - /** \class EdgeMST - * \brief \b Specialization of %Edge class to be used for Minimum Spanning Tree algorithm. + /** + * \class EDGE_MST + * \brief \b Specialization of %EDGE class to be used for Minimum Spanning Tree algorithm. */ - class EdgeMST : public Edge - { - private: - NodePtr target_; +class EDGE_MST : public EDGE +{ +private: + NODE_PTR m_target; - public: - EdgeMST( const NodePtr& source, const NodePtr& target, unsigned int weight = 0 ) : - target_(target) - { sourceNode_ = source; weight_ = weight; } - - EdgeMST( const Edge& edge ) +public: + EDGE_MST( const NODE_PTR& aSource, const NODE_PTR& aTarget, unsigned int aWeight = 0 ) : + m_target( aTarget ) { - sourceNode_ = edge.getSourceNode(); - target_ = edge.getTargetNode(); - weight_ = edge.getWeight(); + m_sourceNode = aSource; + m_weight = aWeight; } - ~EdgeMST() {}; + EDGE_MST( const EDGE& edge ) + { + m_sourceNode = edge.GetSourceNode(); + m_target = edge.GetTargetNode(); + m_weight = edge.GetWeight(); + } + + ~EDGE_MST() + { + } /// @copydoc Edge::setSourceNode() - virtual const NodePtr& getTargetNode() const { return target_; } - }; + virtual const NODE_PTR& GetTargetNode() const + { + return m_target; + } +}; +class DART; // Forward declaration (class in this namespace) - //------------------------------------------------------------------------------------------------ - class Dart; // Forward declaration (class in this namespace) +/** + * \class TRIANGULATION + * \brief \b %Triangulation class for the half-edge data structure with adaption to TTL. + */ +class TRIANGULATION +{ +protected: + /// One half-edge for each arc + std::list m_leadingEdges; - //------------------------------------------------------------------------------------------------ - // Triangulation class in the half-edge data structure - //------------------------------------------------------------------------------------------------ + ttl::TRIANGULATION_HELPER* m_helper; - /** \class Triangulation - * \brief \b %Triangulation class for the half-edge data structure with adaption to TTL. - */ - - class Triangulation { - - protected: - std::list leadingEdges_; // one half-edge for each arc - - ttl::TriangulationHelper* helper; - - void addLeadingEdge(EdgePtr& edge) { - edge->setAsLeadingEdge(); - leadingEdges_.push_front( edge ); + void addLeadingEdge( EDGE_PTR& aEdge ) + { + aEdge->SetAsLeadingEdge(); + m_leadingEdges.push_front( aEdge ); } - bool removeLeadingEdgeFromList(EdgePtr& leadingEdge); + bool removeLeadingEdgeFromList( EDGE_PTR& aLeadingEdge ); void cleanAll(); - + /** Swaps the edge associated with \e dart in the actual data structure. - * - *
- * \image html swapEdge.gif - *
- * - * \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); + * + *
+ * \image html swapEdge.gif + *
+ * + * \param aDart + * 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& aDart ); - /** Splits the triangle associated with \e dart in the actual data structure into - * three new triangles joining at \e point. - * - *
- * \image html splitTriangle.gif - *
- * - * \param dart - * Output: A CCW dart incident with the new node; see the figure. - */ - void splitTriangle(Dart& dart, const NodePtr& point); + /** + * Splits the triangle associated with \e dart in the actual data structure into + * three new triangles joining at \e point. + * + *
+ * \image html splitTriangle.gif + *
+ * + * \param aDart + * Output: A CCW dart incident with the new node; see the figure. + */ + void splitTriangle( DART& aDart, const NODE_PTR& aPoint ); - /** The reverse operation of TTLtraits::splitTriangle. - * This function is only required for functions that involve - * removal of interior nodes; see for example TrinagulationHelper::removeInteriorNode. - * - *
- * \image html reverse_splitTriangle.gif - *
- */ - void reverse_splitTriangle(Dart& dart); + /** + * The reverse operation of TTLtraits::splitTriangle. + * This function is only required for functions that involve + * removal of interior nodes; see for example TrinagulationHelper::RemoveInteriorNode. + * + *
+ * \image html reverse_splitTriangle.gif + *
+ */ + void reverseSplitTriangle( DART& aDart ); - /** Removes a triangle with an edge at the boundary of the triangulation - * in the actual data structure - */ - void removeBoundaryTriangle(Dart& d); + /** + * Removes a triangle with an edge at the boundary of the triangulation + * in the actual data structure + */ + void removeBoundaryTriangle( DART& aDart ); - public: +public: /// Default constructor - Triangulation(); - + TRIANGULATION(); + /// Copy constructor - Triangulation(const Triangulation& tr); + TRIANGULATION( const TRIANGULATION& aTriangulation ); /// Destructor - ~Triangulation(); - + ~TRIANGULATION(); + /// Creates a Delaunay triangulation from a set of points - void createDelaunay(NodesContainer::iterator first, - NodesContainer::iterator last); + void CreateDelaunay( NODES_CONTAINER::iterator aFirst, NODES_CONTAINER::iterator aLast ); /// Creates an initial Delaunay triangulation from two enclosing triangles // When using rectangular boundary - loop through all points and expand. // (Called from createDelaunay(...) when starting) - EdgePtr initTwoEnclosingTriangles(NodesContainer::iterator first, - NodesContainer::iterator last); - + EDGE_PTR InitTwoEnclosingTriangles( NODES_CONTAINER::iterator aFirst, + NODES_CONTAINER::iterator aLast ); // These two functions are required by TTL for Delaunay triangulation - + /// Swaps the edge associated with diagonal - void swapEdge(EdgePtr& diagonal); + void SwapEdge( EDGE_PTR& aDiagonal ); /// Splits the triangle associated with edge into three new triangles joining at point - EdgePtr splitTriangle(EdgePtr& edge, const NodePtr& point); - + EDGE_PTR SplitTriangle( EDGE_PTR& aEdge, const NODE_PTR& aPoint ); // Functions required by TTL for removing nodes in a Delaunay triangulation - + /// Removes the boundary triangle associated with edge - void removeTriangle(EdgePtr& edge); // boundary triangle required + void RemoveTriangle( EDGE_PTR& aEdge ); // boundary triangle required /// The reverse operation of removeTriangle - void reverse_splitTriangle(EdgePtr& edge); + void ReverseSplitTriangle( EDGE_PTR& aEdge ); /// Creates an arbitrary CCW dart - Dart createDart(); + DART CreateDart(); /// Returns a list of "triangles" (one leading half-edge for each triangle) - const std::list& getLeadingEdges() const { return leadingEdges_; } + const std::list& GetLeadingEdges() const + { + return m_leadingEdges; + } /// Returns the number of triangles - int noTriangles() const { return (int)leadingEdges_.size(); } - + int NoTriangles() const + { + return (int) m_leadingEdges.size(); + } + /// Returns a list of half-edges (one half-edge for each arc) - std::list* getEdges(bool skip_boundary_edges = false) const; + std::list* GetEdges( bool aSkipBoundaryEdges = false ) const; #ifdef TTL_USE_NODE_FLAG /// Sets flag in all the nodes - void flagNodes(bool flag) const; + void FlagNodes( bool aFlag ) const; /// Returns a list of nodes. This function requires TTL_USE_NODE_FLAG to be defined. \see Node. - std::list* getNodes() const; + std::list* GetNodes() const; #endif /// Swaps edges until the triangulation is Delaunay (constrained edges are not swapped) - void optimizeDelaunay(); + void OptimizeDelaunay(); /// Checks if the triangulation is Delaunay - bool checkDelaunay() const; + bool CheckDelaunay() const; /// Returns an arbitrary interior node (as the source node of the returned edge) - EdgePtr getInteriorNode() const; + EDGE_PTR GetInteriorNode() const; - EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) const; + EDGE_PTR GetBoundaryEdgeInTriangle( const EDGE_PTR& aEdge ) const; /// Returns an arbitrary boundary edge - EdgePtr getBoundaryEdge() const; + EDGE_PTR GetBoundaryEdge() const; /// Print edges for plotting with, e.g., gnuplot - void printEdges(std::ofstream& os) const; - - friend class ttl::TriangulationHelper; - - }; // End of class Triangulation - + void PrintEdges( std::ofstream& aOutput ) const; + friend class ttl::TRIANGULATION_HELPER; +}; }; // End of hed namespace #endif diff --git a/include/ttl/ttl.h b/include/ttl/ttl.h index 7de2e7b08d..fae9a8434d 100644 --- a/include/ttl/ttl.h +++ b/include/ttl/ttl.h @@ -40,19 +40,18 @@ #ifndef _TTL_H_ #define _TTL_H_ - #include #include // Debugging #ifdef DEBUG_TTL - static void errorAndExit(char* message) { - cout << "\n!!! ERROR: " << message << " !!!\n" << endl; +static void errorAndExit( char* aMessage ) +{ + cout << "\n!!! ERROR: " << aMessage << " !!!\n" << endl; exit(-1); - } +} #endif - // Next on TOPOLOGY: // - get triangle strips // - weighted graph, algorithms using a weight (real) for each edge, @@ -63,559 +62,557 @@ // - analyze in detail locateFace: e.g. detect 0-orbit in case of infinite loop // around a node etc. - -/** \brief Main interface to TTL +/** + * \brief Main interface to TTL * -* This namespace contains the basic generic algorithms for the TTL, -* the Triangulation Template Library.\n +* This namespace contains the basic generic algorithms for the TTL, +* the Triangulation Template Library.\n * -* Examples of functionality are: -* - Incremental Delaunay triangulation -* - Constrained triangulation -* - Insert/remove nodes and constrained edges -* - Traversal operations -* - Misc. queries for extracting information for visualisation systems etc. +* Examples of functionality are: +* - Incremental Delaunay triangulation +* - Constrained triangulation +* - Insert/remove nodes and constrained edges +* - Traversal operations +* - Misc. queries for extracting information for visualisation systems etc. * -* \par General requirements and assumptions: -* - \e DartType and \e TraitsType should be implemented in accordance with the description -* in \ref api. -* - A \b "Requires:" section in the documentation of a function template -* shows which functionality is required in \e TraitsType to -* support that specific function.\n -* Functionalty required in \e DartType is the same (almost) for all -* function templates; see \ref api and the example referred to. -* - When a reference to a \e dart object is passed to a function in TTL, -* it is assumed that it is oriented \e counterclockwise (CCW) in a triangle -* unless it is explicitly mentioned that it can also be \e clockwise (CW). -* The same applies for a dart that is passed from a function in TTL to -* the users TraitsType class (or struct). -* - When an edge (represented with a dart) is swapped, it is assumed that darts -* outside the quadrilateral where the edge is a diagonal are not affected by -* the swap. Thus, \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" -* must be implemented in accordance with this rule. +* \par General requirements and assumptions: +* - \e DART_TYPE and \e TRAITS_TYPE should be implemented in accordance with the description +* in \ref api. +* - A \b "Requires:" section in the documentation of a function template +* shows which functionality is required in \e TRAITS_TYPE to +* support that specific function.\n +* Functionalty required in \e DART_TYPE is the same (almost) for all +* function templates; see \ref api and the example referred to. +* - When a reference to a \e dart object is passed to a function in TTL, +* it is assumed that it is oriented \e counterclockwise (CCW) in a triangle +* unless it is explicitly mentioned that it can also be \e clockwise (CW). +* The same applies for a dart that is passed from a function in TTL to +* the users TRAITS_TYPE class (or struct). +* - When an edge (represented with a dart) is swapped, it is assumed that darts +* outside the quadrilateral where the edge is a diagonal are not affected by +* the swap. Thus, \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" +* must be implemented in accordance with this rule. * -* \par Glossary: -* - General terms are explained in \ref api. -* - \e CCW - counterclockwise -* - \e CW - clockwise -* - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around -* a node, around an edge and in a triangle respectively; -* see get_0_orbit_interior and get_0_orbit_boundary -* - \e arc - In a triangulation an arc is equivalent with an edge +* \par Glossary: +* - General terms are explained in \ref api. +* - \e CCW - counterclockwise +* - \e CW - clockwise +* - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around +* a node, around an edge and in a triangle respectively; +* see get_0_orbit_interior and get_0_orbit_boundary +* - \e arc - In a triangulation an arc is equivalent with an edge * -* \see -* \ref ttl_util and \ref api +* \see +* \ref ttl_util and \ref api * -* \author -* �yvind Hjelle, oyvindhj@ifi.uio.no +* \author +* �yvind Hjelle, oyvindhj@ifi.uio.no */ -namespace ttl { - -class TriangulationHelper +namespace ttl +{ +class TRIANGULATION_HELPER { #ifndef DOXYGEN_SHOULD_SKIP_THIS public: - TriangulationHelper(hed::Triangulation& triang) : triangulation(triang) - { - } + TRIANGULATION_HELPER( hed::TRIANGULATION& aTriang ) : + m_triangulation( aTriang ) + { + } - // Delaunay Triangulation - // ---------------------- - template - bool insertNode(DartType& dart, PointType& point); + // Delaunay Triangulation + template + bool InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint ); - template - void removeRectangularBoundary(DartType& dart); + template + void RemoveRectangularBoundary( DART_TYPE& aDart ); - template - void removeNode(DartType& dart); + template + void RemoveNode( DART_TYPE& aDart ); - template - void removeBoundaryNode(DartType& dart); + template + void RemoveBoundaryNode( DART_TYPE& aDart ); - template - void removeInteriorNode(DartType& dart); + template + void RemoveInteriorNode( DART_TYPE& aDart ); + // Topological and Geometric Queries + // --------------------------------- + template + static bool LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart ); - // Topological and Geometric Queries - // --------------------------------- - template - static bool locateFaceSimplest(const PointType& point, DartType& dart); + template + static bool LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart ); - template - static bool locateTriangle(const PointType& point, DartType& dart); + template + static bool InTriangleSimplest( const POINT_TYPE& aPoint, const DART_TYPE& aDart ); - template - static bool inTriangleSimplest(const PointType& point, const DartType& dart); + template + static bool InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart ); - template - static bool inTriangle(const PointType& point, const DartType& dart); + template + static void GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary ); - template - static void getBoundary(const DartType& dart, DartListType& boundary); + template + static bool IsBoundaryEdge( const DART_TYPE& aDart ); - template - static bool isBoundaryEdge(const DartType& dart); + template + static bool IsBoundaryFace( const DART_TYPE& aDart ); - template - static bool isBoundaryFace(const DartType& dart); + template + static bool IsBoundaryNode( const DART_TYPE& aDart ); - template - static bool isBoundaryNode(const DartType& dart); + template + static int GetDegreeOfNode( const DART_TYPE& aDart ); - template - static int getDegreeOfNode(const DartType& dart); + template + static void Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ); - template - static void get_0_orbit_interior(const DartType& dart, DartListType& orbit); + template + static void Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ); - template - static void get_0_orbit_boundary(const DartType& dart, DartListType& orbit); + template + static bool Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_0_orbit(const DartType& d1, const DartType& d2); + template + static bool Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_1_orbit(const DartType& d1, const DartType& d2); + template + static bool Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ); - template - static bool same_2_orbit(const DartType& d1, const DartType& d2); + template + static bool SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy = false ); - template - static bool swappableEdge(const DartType& dart, bool allowDegeneracy = false); + template + static void PositionAtNextBoundaryEdge( DART_TYPE& aDart ); - template - static void positionAtNextBoundaryEdge(DartType& dart); + template + static bool ConvexBoundary( const DART_TYPE& aDart ); - template - static bool convexBoundary(const DartType& dart); + // Utilities for Delaunay Triangulation + // ------------------------------------ + template + void OptimizeDelaunay( DART_LIST_TYPE& aElist ); + template + void OptimizeDelaunay( DART_LIST_TYPE& aElist, const typename DART_LIST_TYPE::iterator aEnd ); - // Utilities for Delaunay Triangulation - // ------------------------------------ - template - void optimizeDelaunay(DartListType& elist); + template + bool SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck = false ) const; - template - void optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end); + template + void RecSwapDelaunay( DART_TYPE& aDiagonal ); - template - bool swapTestDelaunay(const DartType& dart, bool cycling_check = false) const; + template + void SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges ); - template - void recSwapDelaunay(DartType& diagonal); + template + void SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges ); - template - void swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges); + template + void SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt, DART_LIST_TYPE& aElist ); - template - void swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges); - - template - void swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist); - - - // Constrained Triangulation - // ------------------------- - template - static DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay); + // Constrained Triangulation + // ------------------------- + template + static DART_TYPE InsertConstraint( DART_TYPE& aDStart, DART_TYPE& aDEnd, bool aOptimizeDelaunay ); private: - hed::Triangulation& triangulation; + hed::TRIANGULATION& m_triangulation; - template - void insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart); + template + void insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast, DART_TYPE& aDart ); - template - static bool isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart); + template + static bool isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement, const DART_TYPE& aDart ); - template - static bool locateFaceWithNode(const NodeType& node, DartType& dart_iter); + template + static bool locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter ); - template - static void getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3); + template + static void getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1, DART_TYPE& aT2, + DART_TYPE& aT3 ); - template - static void getNeighborNodes(const DartType& dart, std::list& node_list, bool& boundary); + template + static void getNeighborNodes( const DART_TYPE& aDart, std::list& aNodeList, + bool& aBoundary ); - template - static bool degenerateTriangle(const DartType& dart); + template + static bool degenerateTriangle( const DART_TYPE& aDart ); }; #endif // DOXYGEN_SHOULD_SKIP_THIS - //------------------------------------------------------------------------------------------------ - // ------------------------------- Delaunay Triangulation Group --------------------------------- - //------------------------------------------------------------------------------------------------ - /** @name Delaunay Triangulation */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Inserts a new node in an existing Delaunay triangulation and - * swaps edges to obtain a new Delaunay triangulation. - * This is the basic function for incremental Delaunay triangulation. - * When starting from a set of points, an initial Delaunay triangulation - * can be created as two triangles forming a rectangle that contains - * all the points. - * After \c insertNode has been called repeatedly with all the points, - * removeRectangularBoundary can be called to remove triangles - * at the boundary of the triangulation so that the boundary - * form the convex hull of the points. - * - * Note that this incremetal scheme will run much faster if the points - * have been sorted lexicographically on \e x and \e y. - * - * \param dart - * An arbitrary CCW dart in the tringulation.\n - * Output: A CCW dart incident to the new node. - * - * \param point - * A point (node) to be inserted in the triangulation. - * - * \retval bool - * \c true if \e point was inserted; \c false if not.\n - * If \e point is outside the triangulation, or the input dart is not valid, - * \c false is returned. - * - * \require - * - \ref hed::TTLtraits::splitTriangle "TraitsType::splitTriangle" (DartType&, const PointType&) - * - * \using - * - locateTriangle - * - recSwapDelaunay - * - * \note - * - For efficiency reasons \e dart should be close to the insertion \e point. - * - * \see - * removeRectangularBoundary - */ - template - bool TriangulationHelper::insertNode(DartType& dart, PointType& point) { +//@{ +/** + * Inserts a new node in an existing Delaunay triangulation and + * swaps edges to obtain a new Delaunay triangulation. + * This is the basic function for incremental Delaunay triangulation. + * When starting from a set of points, an initial Delaunay triangulation + * can be created as two triangles forming a rectangle that contains + * all the points. + * After \c insertNode has been called repeatedly with all the points, + * removeRectangularBoundary can be called to remove triangles + * at the boundary of the triangulation so that the boundary + * form the convex hull of the points. + * + * Note that this incremetal scheme will run much faster if the points + * have been sorted lexicographically on \e x and \e y. + * + * \param aDart + * An arbitrary CCW dart in the tringulation.\n + * Output: A CCW dart incident to the new node. + * + * \param aPoint + * A point (node) to be inserted in the triangulation. + * + * \retval bool + * \c true if \e point was inserted; \c false if not.\n + * If \e point is outside the triangulation, or the input dart is not valid, + * \c false is returned. + * + * \require + * - \ref hed::TTLtraits::splitTriangle "TRAITS_TYPE::splitTriangle" (DART_TYPE&, const POINT_TYPE&) + * + * \using + * - locateTriangle + * - RecSwapDelaunay + * + * \note + * - For efficiency reasons \e dart should be close to the insertion \e point. + * + * \see + * removeRectangularBoundary + */ +template +bool TRIANGULATION_HELPER::InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint ) +{ + bool found = LocateTriangle( aPoint, aDart ); - bool found = locateTriangle(point, dart); - if (!found) { + if( !found ) + { #ifdef DEBUG_TTL - cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; + cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; #endif - return false; + return false; } - + // ??? can we hide the dart? this is not possible if one triangle only - triangulation.splitTriangle(dart, point); - - DartType d1 = dart; - d1.alpha2().alpha1().alpha2().alpha0().alpha1(); - - DartType d2 = dart; - d2.alpha1().alpha0().alpha1(); - + m_triangulation.splitTriangle( aDart, aPoint ); + + DART_TYPE d1 = aDart; + d1.Alpha2().Alpha1().Alpha2().Alpha0().Alpha1(); + + DART_TYPE d2 = aDart; + d2.Alpha1().Alpha0().Alpha1(); + // Preserve a dart as output incident to the node and CCW - DartType d3 = dart; - d3.alpha2(); - dart = d3; // and see below - //DartType dsav = d3; - d3.alpha0().alpha1(); - - //if (!TraitsType::fixedEdge(d1) && !isBoundaryEdge(d1)) { - if (!isBoundaryEdge(d1)) { - d1.alpha2(); - recSwapDelaunay(d1); + DART_TYPE d3 = aDart; + d3.Alpha2(); + aDart = d3; // and see below + //DART_TYPE dsav = d3; + d3.Alpha0().Alpha1(); + + //if (!TRAITS_TYPE::fixedEdge(d1) && !IsBoundaryEdge(d1)) { + if( !IsBoundaryEdge( d1 ) ) + { + d1.Alpha2(); + RecSwapDelaunay( d1 ); } - - //if (!TraitsType::fixedEdge(d2) && !isBoundaryEdge(d2)) { - if (!isBoundaryEdge(d2)) { - d2.alpha2(); - recSwapDelaunay(d2); + + //if (!TRAITS_TYPE::fixedEdge(d2) && !IsBoundaryEdge(d2)) { + if( !IsBoundaryEdge( d2 ) ) + { + d2.Alpha2(); + RecSwapDelaunay( d2 ); } - + // Preserve the incoming dart as output incident to the node and CCW - //d = dsav.alpha2(); - dart.alpha2(); - //if (!TraitsType::fixedEdge(d3) && !isBoundaryEdge(d3)) { - if (!isBoundaryEdge(d3)) { - d3.alpha2(); - recSwapDelaunay(d3); + //d = dsav.Alpha2(); + aDart.Alpha2(); + //if (!TRAITS_TYPE::fixedEdge(d3) && !IsBoundaryEdge(d3)) { + if( !IsBoundaryEdge( d3 ) ) + { + d3.Alpha2(); + RecSwapDelaunay( d3 ); } - + return true; - } +} +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +void TRIANGULATION_HELPER::insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast, + DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - void TriangulationHelper::insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart) { - // Assumes that the dereferenced point objects are pointers. // References to the point objects are then passed to TTL. - - ForwardIterator it; - for (it = first; it != last; ++it) { - insertNode(dart, **it); + + FORWARD_ITERATOR it; + for( it = aFirst; it != aLast; ++it ) + { + InsertNode( aDart, **it ); } - } +} - //------------------------------------------------------------------------------------------------ - /** Removes the rectangular boundary of a triangulation as a final step of an - * incremental Delaunay triangulation. - * The four nodes at the corners will be removed and the resulting triangulation - * will have a convex boundary and be Delaunay. - * - * \param dart - * A CCW dart at the boundary of the triangulation\n - * Output: A CCW dart at the new boundary - * - * \using - * - removeBoundaryNode - * - * \note - * - This function requires that the boundary of the triangulation is - * a rectangle with four nodes (one in each corner). - */ - template - void TriangulationHelper::removeRectangularBoundary(DartType& dart) { - - DartType d_next = dart; - DartType d_iter; - - for (int i = 0; i < 4; i++) { - d_iter = d_next; - d_next.alpha0(); - positionAtNextBoundaryEdge(d_next); - removeBoundaryNode(d_iter); +/** Removes the rectangular boundary of a triangulation as a final step of an + * incremental Delaunay triangulation. + * The four nodes at the corners will be removed and the resulting triangulation + * will have a convex boundary and be Delaunay. + * + * \param dart + * A CCW dart at the boundary of the triangulation\n + * Output: A CCW dart at the new boundary + * + * \using + * - RemoveBoundaryNode + * + * \note + * - This function requires that the boundary of the m_triangulation is + * a rectangle with four nodes (one in each corner). + */ +template +void TRIANGULATION_HELPER::RemoveRectangularBoundary( DART_TYPE& aDart ) +{ + DART_TYPE d_next = aDart; + DART_TYPE d_iter; + + for( int i = 0; i < 4; i++ ) + { + d_iter = d_next; + d_next.Alpha0(); + PositionAtNextBoundaryEdge( d_next ); + RemoveBoundaryNode( d_iter ); } - - dart = d_next; // Return a dart at the new boundary - } + aDart = d_next; // Return a dart at the new boundary +} - //------------------------------------------------------------------------------------------------ - /** Removes the node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - removeBoundaryNode if \e dart represents a node at the boundary - * - removeInteriorNode if \e dart represents an interior node - * - * \note - * - The node cannot belong to a fixed (constrained) edge that is not - * swappable. (An endless loop is likely to occur in this case). - */ - template - void TriangulationHelper::removeNode(DartType& dart) { - - if (isBoundaryNode(dart)) - removeBoundaryNode(dart); +/** Removes the node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - RemoveBoundaryNode if \e dart represents a node at the boundary + * - RemoveInteriorNode if \e dart represents an interior node + * + * \note + * - The node cannot belong to a fixed (constrained) edge that is not + * swappable. (An endless loop is likely to occur in this case). + */ +template +void TRIANGULATION_HELPER::RemoveNode( DART_TYPE& aDart ) +{ + + if( isBoundaryNode( aDart ) ) + RemoveBoundaryNode( aDart ); else - removeInteriorNode(dart); - } + RemoveInteriorNode( aDart ); +} +/** Removes the boundary node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - SwapEdgesAwayFromBoundaryNode + * - OptimizeDelaunay + * + * \require + * - \ref hed::TTLtraits::removeBoundaryTriangle "TRAITS_TYPE::removeBoundaryTriangle" (Dart&) + */ +template +void TRIANGULATION_HELPER::RemoveBoundaryNode( DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - /** Removes the boundary node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - swapEdgesAwayFromBoundaryNode - * - optimizeDelaunay - * - * \require - * - \ref hed::TTLtraits::removeBoundaryTriangle "TraitsType::removeBoundaryTriangle" (Dart&) - */ - template - void TriangulationHelper::removeBoundaryNode(DartType& dart) { - // ... and update Delaunay // - CCW dart must be given (for remove) // - No dart is delivered back now (but this is possible if - // we assume that there is not only one triangle left in the triangulation. - + // we assume that there is not only one triangle left in the m_triangulation. + // Position at boundary edge and CCW - if (!isBoundaryEdge(dart)) { - dart.alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) - positionAtNextBoundaryEdge(dart); + if( !IsBoundaryEdge( aDart ) ) + { + aDart.Alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) + PositionAtNextBoundaryEdge( aDart ); } - std::list swapped_edges; - swapEdgesAwayFromBoundaryNode(dart, swapped_edges); - + std::list swapped_edges; + SwapEdgesAwayFromBoundaryNode( aDart, swapped_edges ); + // Remove boundary triangles and remove the new boundary from the list // of swapped edges, see below. - DartType d_iter = dart; - DartType dnext = dart; + DART_TYPE d_iter = aDart; + DART_TYPE dnext = aDart; bool bend = false; - while (bend == false) { - dnext.alpha1().alpha2(); - if (isBoundaryEdge(dnext)) - bend = true; // Stop when boundary - - // Generic: Also remove the new boundary from the list of swapped edges - DartType n_bedge = d_iter; - n_bedge.alpha1().alpha0().alpha1().alpha2(); // new boundary edge - - // ??? can we avoid find if we do this in swap away? - typename std::list::iterator it; - it = find(swapped_edges.begin(), swapped_edges.end(), n_bedge); - - if (it != swapped_edges.end()) - swapped_edges.erase(it); - - // Remove the boundary triangle - triangulation.removeBoundaryTriangle(d_iter); - d_iter = dnext; + while( bend == false ) + { + dnext.Alpha1().Alpha2(); + if( IsBoundaryEdge( dnext ) ) + bend = true; // Stop when boundary + + // Generic: Also remove the new boundary from the list of swapped edges + DART_TYPE n_bedge = d_iter; + n_bedge.Alpha1().Alpha0().Alpha1().Alpha2(); // new boundary edge + + // ??? can we avoid find if we do this in swap away? + typename std::list::iterator it; + it = find( swapped_edges.begin(), swapped_edges.end(), n_bedge ); + + if( it != swapped_edges.end() ) + swapped_edges.erase( it ); + + // Remove the boundary triangle + m_triangulation.removeBoundaryTriangle( d_iter ); + d_iter = dnext; } - + // Optimize Delaunay - typedef std::list DartListType; - optimizeDelaunay(swapped_edges); - } + typedef std::list DART_LIST_TYPE; + OptimizeDelaunay( swapped_edges ); +} - //------------------------------------------------------------------------------------------------ - /** Removes the interior node associated with \e dart and - * updates the triangulation to be Delaunay. - * - * \using - * - swapEdgesAwayFromInteriorNode - * - optimizeDelaunay - * - * \require - * - \ref hed::TTLtraits::reverse_splitTriangle "TraitsType::reverse_splitTriangle" (Dart&) - * - * \note - * - The node cannot belong to a fixed (constrained) edge that is not - * swappable. (An endless loop is likely to occur in this case). - */ - template - void TriangulationHelper::removeInteriorNode(DartType& dart) { - +/** Removes the interior node associated with \e dart and + * updates the triangulation to be Delaunay. + * + * \using + * - SwapEdgesAwayFromInteriorNode + * - OptimizeDelaunay + * + * \require + * - \ref hed::TTLtraits::reverse_splitTriangle "TRAITS_TYPE::reverse_splitTriangle" (Dart&) + * + * \note + * - The node cannot belong to a fixed (constrained) edge that is not + * swappable. (An endless loop is likely to occur in this case). + */ +template +void TRIANGULATION_HELPER::RemoveInteriorNode( DART_TYPE& aDart ) +{ // ... and update to Delaunay. // Must allow degeneracy temporarily, see comments in swap edges away // Assumes: // - revese_splitTriangle does not affect darts // outside the resulting triangle. - + // 1) Swaps edges away from the node until degree=3 (generic) // 2) Removes the remaining 3 triangles and creates a new to fill the hole // unsplitTriangle which is required - // 3) Runs LOP on the platelet to obtain a Delaunay triangulation + // 3) Runs LOP on the platelet to obtain a Delaunay m_triangulation // (No dart is delivered as output) - + // Assumes dart is counterclockwise - - std::list swapped_edges; - swapEdgesAwayFromInteriorNode(dart, swapped_edges); - + + std::list swapped_edges; + SwapEdgesAwayFromInteriorNode( aDart, swapped_edges ); + // The reverse operation of split triangle: // Make one triangle of the three triangles at the node associated with dart - // TraitsType:: - triangulation.reverse_splitTriangle(dart); - + // TRAITS_TYPE:: + m_triangulation.reverseSplitTriangle( aDart ); + // ???? Not generic yet if we are very strict: // When calling unsplit triangle, darts at the three opposite sides may // change! // Should we hide them longer away??? This is possible since they cannot // be boundary edges. // ----> Or should we just require that they are not changed??? - + // Make the swapped-away edges Delaunay. // Note the theoretical result: if there are no edges in the list, // the triangulation is Delaunay already - - optimizeDelaunay(swapped_edges); - } - //@} // End of Delaunay Triangulation Group + OptimizeDelaunay( swapped_edges ); +} +//@} // End of Delaunay Triangulation Group - //------------------------------------------------------------------------------------------------ - // -------------------------- Topological and Geometric Queries Group --------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Topological and Geometric Queries */ - //@{ - - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - bool TriangulationHelper::isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart) { - +/** @name Topological and Geometric Queries */ +//@{ +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +bool TRIANGULATION_HELPER::isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement, + const DART_TYPE& aDart ) +{ // Check if the given topology element (node, edge or face) is a member of the face // Assumes: - // - DartType::isMember(TopologyElementType) - - DartType dart_iter = dart; - do { - if (dart_iter.isMember(topologyElement)) - return true; - dart_iter.alpha0().alpha1(); - } while (dart_iter != dart); + // - DART_TYPE::isMember(TOPOLOGY_ELEMENT_TYPE) + + DART_TYPE dart_iter = aDart; + do + { + if( dart_iter.isMember( aTopologyElement ) ) + return true; + dart_iter.Alpha0().Alpha1(); + } + while( dart_iter != aDart ); + return false; - } +} - - //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - bool TriangulationHelper::locateFaceWithNode(const NodeType& node, DartType& dart_iter) { +//------------------------------------------------------------------------------------------------ +// Private/Hidden function (might change later) +template +bool TRIANGULATION_HELPER::locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter ) +{ // Locate a face in the topology structure with the given node as a member // Assumes: - // - TraitsType::orient2d(DartType, DartType, NodeType) - // - DartType::isMember(NodeType) + // - TRAITS_TYPE::Orient2D(DART_TYPE, DART_TYPE, NODE_TYPE) + // - DART_TYPE::isMember(NODE_TYPE) // - Note that if false is returned, the node might still be in the // topology structure. Application programmer // should check all if by hypothesis the node is in the topology structure; - // see doc. on locateTriangle. - - bool status = locateFaceSimplest(node, dart_iter); - if (status == false) - return status; - - // True was returned from locateFaceSimplest, but if the located triangle is + // see doc. on LocateTriangle. + + bool status = LocateFaceSimplest( aNode, aDartIter ); + + if( status == false ) + return status; + + // True was returned from LocateFaceSimplest, but if the located triangle is // degenerate and the node is on the extension of the edges, // the node might still be inside. Check if node is a member and return false // if not. (Still the node might be in the topology structure, see doc. above - // and in locateTriangle(const PointType& point, DartType& dart_iter) - - return isMemberOfFace(node, dart_iter); - } + // and in locateTriangle(const POINT_TYPE& point, DART_TYPE& dart_iter) + return isMemberOfFace( aNode, aDartIter ); +} - //------------------------------------------------------------------------------------------------ - /** Locates the face containing a given point. - * It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that - * there are no holes, the boundary is convex and there are no degenerate faces. - * - * \param point - * A point to be located - * - * \param dart - * An arbitrary CCW dart in the triangulation\n - * Output: A CCW dart in the located face - * - * \retval bool - * \c true if a face is found; \c false if not. - * - * \require - * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) - * - * \note - * - If \c false is returned, \e point may still be inside a face if the tessellation is not - * \e regular as explained above. - * - * \see - * locateTriangle - */ - template - bool TriangulationHelper::locateFaceSimplest(const PointType& point, DartType& dart) { +/** Locates the face containing a given point. + * It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that + * there are no holes, the boundary is convex and there are no degenerate faces. + * + * \param aPoint + * A point to be located + * + * \param aDart + * An arbitrary CCW dart in the triangulation\n + * Output: A CCW dart in the located face + * + * \retval bool + * \c true if a face is found; \c false if not. + * + * \require + * - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE&) + * + * \note + * - If \c false is returned, \e point may still be inside a face if the tessellation is not + * \e regular as explained above. + * + * \see + * LocateTriangle + */ +template +bool TRIANGULATION_HELPER::LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart ) +{ // Not degenerate triangles if point is on the extension of the edges // But inTriangle may be called in case of true (may update to inFace2) // Convex boundary @@ -623,867 +620,867 @@ private: // convex faces (works for general convex faces) // Not specialized for triangles, but ok? // - // TraitsType::orint2d(PointType) is the half open half-plane defined + // TRAITS_TYPE::orint2d(POINT_TYPE) is the half open half-plane defined // by the dart: // n1 = dart.node() - // n2 = dart.alpha0().node + // n2 = dart.Alpha0().node // Only the following gives true: // ((n2->x()-n1->x())*(point.y()-n1->y()) >= (point.x()-n1->x())*(n2->y()-n1->y())) - - DartType dart_start; - dart_start = dart; - DartType dart_prev; - - DartType d0; - for (;;) { - d0 = dart; - d0.alpha0(); - if (TraitsType::orient2d(dart, d0, point) >= 0) { - dart.alpha0().alpha1(); - if (dart == dart_start) - return true; // left to all edges in face - } - else { - dart_prev = dart; - dart.alpha2(); - if (dart == dart_prev) - return false; // iteration to outside boundary - - dart_start = dart; - dart_start.alpha0(); - - dart.alpha1(); // avoid twice on same edge and ccw in next - } + + DART_TYPE dart_start; + dart_start = aDart; + DART_TYPE dart_prev; + + DART_TYPE d0; + for( ;; ) + { + d0 = aDart; + d0.Alpha0(); + + if( TRAITS_TYPE::Orient2D( aDart, d0, aPoint ) >= 0 ) + { + aDart.Alpha0().Alpha1(); + if( aDart == dart_start ) + return true; // left to all edges in face + } + else + { + dart_prev = aDart; + aDart.Alpha2(); + + if( aDart == dart_prev ) + return false; // iteration to outside boundary + + dart_start = aDart; + dart_start.Alpha0(); + + aDart.Alpha1(); // avoid twice on same edge and ccw in next + } } - } +} - //------------------------------------------------------------------------------------------------ - /** Locates the triangle containing a given point. - * It is assumed that the triangulation is \e regular in the sense that there - * are no holes and the boundary is convex. - * This function deals with degeneracy to some extent, but round-off errors may still - * lead to a wrong result if triangles are degenerate. - * - * \param point - * A point to be located - * - * \param dart - * An arbitrary CCW dart in the triangulation\n - * Output: A CCW dart in the located triangle - * - * \retval bool - * \c true if a triangle is found; \c false if not.\n - * If \e point is outside the triangulation, in which case \c false is returned, - * then the edge associated with \e dart will be at the boundary of the triangulation. - * - * \using - * - locateFaceSimplest - * - inTriangle - */ - template - bool TriangulationHelper::locateTriangle(const PointType& point, DartType& dart) { +/** Locates the triangle containing a given point. + * It is assumed that the triangulation is \e regular in the sense that there + * are no holes and the boundary is convex. + * This function deals with degeneracy to some extent, but round-off errors may still + * lead to a wrong result if triangles are degenerate. + * + * \param point + * A point to be located + * + * \param dart + * An arbitrary CCW dart in the triangulation\n + * Output: A CCW dart in the located triangle + * + * \retval bool + * \c true if a triangle is found; \c false if not.\n + * If \e point is outside the m_triangulation, in which case \c false is returned, + * then the edge associated with \e dart will be at the boundary of the m_triangulation. + * + * \using + * - LocateFaceSimplest + * - InTriangle + */ +template +bool TRIANGULATION_HELPER::LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart ) +{ // The purpose is to have a fast and stable procedure that // i) avoids concluding that a point is inside a triangle if it is not inside // ii) avoids infinite loops - + // Thus, if false is returned, the point might still be inside a triangle in // the triangulation. But this will probably only occur in the following cases: // i) There are holes in the triangulation which causes the procedure to stop. - // ii) The boundary of the triangulation is not convex. + // ii) The boundary of the m_triangulation is not convex. // ii) There might be degenerate triangles interior to the triangulation, or on the // the boundary, which in some cases might cause the procedure to stop there due // to the logic of the algorithm. - + // It is the application programmer's responsibility to check further if false is // returned. For example, if by hypothesis the point is inside a triangle // in the triangulation and and false is returned, then all triangles in the // triangulation should be checked by the application. This can be done using // the function: - // bool inTriangle(const PointType& point, const DartType& dart). - - + // bool inTriangle(const POINT_TYPE& point, const DART_TYPE& dart). + // Assumes: - // - crossProduct2d, scalarProduct2d etc., see functions called - - bool status = locateFaceSimplest(point, dart); - if (status == false) - return status; + // - CrossProduct2D, ScalarProduct2D etc., see functions called + + bool status = LocateFaceSimplest( aPoint, aDart ); + if( status == false ) + return status; + // There may be degeneracy, i.e., the point might be outside the triangle // on the extension of the edges of a degenerate triangle. - + // The next call returns true if inside a non-degenerate or a degenerate triangle, // but false if the point coincides with the "supernode" in the case where all // edges are degenerate. - return inTriangle(point, dart); - } + return InTriangle( aPoint, aDart ); +} - - //------------------------------------------------------------------------------------------------ - /** Checks if \e point is inside the triangle associated with \e dart. - * A fast and simple function that does not deal with degeneracy. - * - * \param dart - * A CCW dart in the triangle - * - * \require - * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) - * - * \see - * inTriangle for a more robust function - */ - template - bool TriangulationHelper::inTriangleSimplest(const PointType& point, const DartType& dart) { - +//------------------------------------------------------------------------------------------------ +/** Checks if \e point is inside the triangle associated with \e dart. + * A fast and simple function that does not deal with degeneracy. + * + * \param aDart + * A CCW dart in the triangle + * + * \require + * - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE&) + * + * \see + * InTriangle for a more robust function + */ +template +bool TRIANGULATION_HELPER::InTriangleSimplest( const POINT_TYPE& aPoint, const DART_TYPE& aDart ) +{ // Fast and simple: Do not deal with degenerate faces, i.e., if there is // degeneracy, true will be returned if the point is on the extension of the // edges of a degenerate triangle + + DART_TYPE d_iter = aDart; + DART_TYPE d0 = d_iter; + d0.Alpha0(); - DartType d_iter = dart; - DartType d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; - - d_iter.alpha0().alpha1(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + + d_iter.Alpha0().Alpha1(); d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; + d0.Alpha0(); - d_iter.alpha0().alpha1(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + + d_iter.Alpha0().Alpha1(); d0 = d_iter; - d0.alpha0(); - if (!TraitsType::orient2d(d_iter, d0, point) >= 0) - return false; + d0.Alpha0(); + if( !TRAITS_TYPE::Orient2D( d_iter, d0, aPoint ) >= 0 ) + return false; + return true; - } +} +/** Checks if \e point is inside the triangle associated with \e dart. + * This function deals with degeneracy to some extent, but round-off errors may still + * lead to wrong result if the triangle is degenerate. + * + * \param aDart + * A CCW dart in the triangle + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, POINT_TYPE&) + * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, POINT_TYPE&) + * + * \see + * InTriangleSimplest + */ +template +bool TRIANGULATION_HELPER::InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart ) +{ - //------------------------------------------------------------------------------------------------ - /** Checks if \e point is inside the triangle associated with \e dart. - * This function deals with degeneracy to some extent, but round-off errors may still - * lead to wrong result if the triangle is degenerate. - * - * \param dart - * A CCW dart in the triangle - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, PointType&) - * - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, PointType&) - * - * \see - * inTriangleSimplest - */ - template - bool TriangulationHelper::inTriangle(const PointType& point, const DartType& dart) { - // SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT // ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH // notInE1 && notInE1.neghbour ? - - + // Returns true if inside (but not necessarily strictly inside) // Works for degenerate triangles, but not when all edges are degenerate, - // and the point coincides with all nodes; + // and the aPoint coincides with all nodes; // then false is always returned. - - typedef typename TraitsType::real_type real_type; - - DartType dart_iter = dart; - - real_type cr1 = TraitsType::crossProduct2d(dart_iter, point); - if (cr1 < 0) - return false; - - dart_iter.alpha0().alpha1(); - real_type cr2 = TraitsType::crossProduct2d(dart_iter, point); - - if (cr2 < 0) - return false; - - dart_iter.alpha0().alpha1(); - real_type cr3 = TraitsType::crossProduct2d(dart_iter, point); - if (cr3 < 0) - return false; - + + typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE; + + DART_TYPE dart_iter = aDart; + + REAL_TYPE cr1 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + if( cr1 < 0 ) + return false; + + dart_iter.Alpha0().Alpha1(); + REAL_TYPE cr2 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + + if( cr2 < 0 ) + return false; + + dart_iter.Alpha0().Alpha1(); + REAL_TYPE cr3 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint ); + if( cr3 < 0 ) + return false; + // All cross products are >= 0 // Check for degeneracy - - if (cr1 != 0 || cr2 != 0 || cr3 != 0) - return true; // inside non-degenerate face - + if( cr1 != 0 || cr2 != 0 || cr3 != 0 ) + return true; // inside non-degenerate face + // All cross-products are zero, i.e. degenerate triangle, check if inside - // Strategy: d.scalarProduct2d >= 0 && alpha0(d).d.scalarProduct2d >= 0 for one of - // the edges. But if all edges are degenerate and the point is on (all) the nodes, + // Strategy: d.ScalarProduct2D >= 0 && alpha0(d).d.ScalarProduct2D >= 0 for one of + // the edges. But if all edges are degenerate and the aPoint is on (all) the nodes, // then "false is returned". - - DartType dart_tmp = dart_iter; - real_type sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - real_type sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(), point); - - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + + DART_TYPE dart_tmp = dart_iter; + REAL_TYPE sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + REAL_TYPE sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); + + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } + + dart_tmp = dart_iter.Alpha0().Alpha1(); + sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); - dart_tmp = dart_iter.alpha0().alpha1(); - sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } + + dart_tmp = dart_iter.Alpha1(); + sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint ); + sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint ); - dart_tmp = dart_iter.alpha1(); - sc1 = TraitsType::scalarProduct2d(dart_tmp,point); - sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); - if (sc1 >= 0 && sc2 >= 0) { - // test for degenerate edge - if (sc1 != 0 || sc2 != 0) - return true; // interior to this edge or on a node (but see comment above) + if( sc1 >= 0 && sc2 >= 0 ) + { + // test for degenerate edge + if( sc1 != 0 || sc2 != 0 ) + return true; // interior to this edge or on a node (but see comment above) } - + // Not on any of the edges of the degenerate triangle. - // The only possibility for the point to be "inside" is that all edges are degenerate + // The only possibility for the aPoint to be "inside" is that all edges are degenerate // and the point coincide with all nodes. So false is returned in this case. - + return false; - } +} //------------------------------------------------------------------------------------------------ - // Private/Hidden function (might change later) - template - void TriangulationHelper::getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3) { - - DartType dart_iter = dart; - +// Private/Hidden function (might change later) +template +void TRIANGULATION_HELPER::getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1, + DART_TYPE& aT2, DART_TYPE& aT3 ) +{ + + DART_TYPE dart_iter = aDart; + // add first - if (dart_iter.alpha2() != dart) { - t1 = dart_iter; - dart_iter = dart; + if( dart_iter.Alpha2() != aDart ) + { + aT1 = dart_iter; + dart_iter = aDart; } - + // add second - dart_iter.alpha0(); - dart_iter.alpha1(); - DartType dart_prev = dart_iter; - if ((dart_iter.alpha2()) != dart_prev) { - t2 = dart_iter; - dart_iter = dart_prev; + dart_iter.Alpha0(); + dart_iter.Alpha1(); + DART_TYPE dart_prev = dart_iter; + + if( ( dart_iter.Alpha2() ) != dart_prev ) + { + aT2 = dart_iter; + dart_iter = dart_prev; } - + // add third - dart_iter.alpha0(); - dart_iter.alpha1(); + dart_iter.Alpha0(); + dart_iter.Alpha1(); dart_prev = dart_iter; - if ((dart_iter.alpha2()) != dart_prev) - t3 = dart_iter; - } + if( ( dart_iter.Alpha2() ) != dart_prev ) + aT3 = dart_iter; +} - //------------------------------------------------------------------------------------------------ - /** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary - * edges, given a dart with an associating edge at the boundary of a topology structure. - * The first dart in the sequence will be the given one, and the others will have the same - * orientation (CCW or CW) as the first. - * Assumes that the given dart is at the boundary. - * - * \param dart - * A dart at the boundary (CCW or CW) - * - * \param boundary - * A sequence of darts, where the associated edges are the boundary edges - * - * \require - * - DartListType::push_back (DartType&) - */ - template - void TriangulationHelper::getBoundary(const DartType& dart, DartListType& boundary) { +//------------------------------------------------------------------------------------------------ +/** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary + * edges, given a dart with an associating edge at the boundary of a topology structure. + * The first dart in the sequence will be the given one, and the others will have the same + * orientation (CCW or CW) as the first. + * Assumes that the given dart is at the boundary. + * + * \param aDart + * A dart at the boundary (CCW or CW) + * + * \param aBoundary + * A sequence of darts, where the associated edges are the boundary edges + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + */ +template +void TRIANGULATION_HELPER::GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary ) +{ // assumes the given dart is at the boundary (by edge) - - DartType dart_iter(dart); - boundary.push_back(dart_iter); // Given dart as first element - dart_iter.alpha0(); - positionAtNextBoundaryEdge(dart_iter); - - while (dart_iter != dart) { - boundary.push_back(dart_iter); - dart_iter.alpha0(); - positionAtNextBoundaryEdge(dart_iter); + + DART_TYPE dart_iter( aDart ); + aBoundary.push_back( dart_iter ); // Given dart as first element + dart_iter.Alpha0(); + PositionAtNextBoundaryEdge( dart_iter ); + + while( dart_iter != aDart ) + { + aBoundary.push_back( dart_iter ); + dart_iter.Alpha0(); + PositionAtNextBoundaryEdge( dart_iter ); } - } +} - - //------------------------------------------------------------------------------------------------ - /* - // Asumes a fixed point (a boundary edge) is given - // - template - class boundary_1_Iterator { // i.e. "circulator" - - DartType current_; - public: - boundaryEdgeIterator(const DartType& dart) {current_ = dart;} - DartType& operator * () const {return current_;} - void operator ++ () {current_.alpha0(); positionAtNextBoundaryEdge(current_);} - }; - */ - - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart is at - * the boundary of the triangulation. - * - * \par Implements: - * \code - * DartType dart_iter = dart; - * if (dart_iter.alpha2() == dart) - * return true; - * else - * return false; - * \endcode - */ - template - bool TriangulationHelper::isBoundaryEdge(const DartType& dart) { +/** Checks if the edge associated with \e dart is at + * the boundary of the m_triangulation. + * + * \par Implements: + * \code + * DART_TYPE dart_iter = dart; + * if (dart_iter.Alpha2() == dart) + * return true; + * else + * return false; + * \endcode + */ +template +bool TRIANGULATION_HELPER::IsBoundaryEdge( const DART_TYPE& aDart ) +{ + DART_TYPE dart_iter = aDart; - DartType dart_iter = dart; - if (dart_iter.alpha2() == dart) - return true; - else - return false; - } - - - //------------------------------------------------------------------------------------------------ - /** Checks if the face associated with \e dart is at - * the boundary of the triangulation. - */ - template - bool TriangulationHelper::isBoundaryFace(const DartType& dart) { - - // Strategy: boundary if alpha2(d)=d - - DartType dart_iter(dart); - DartType dart_prev; - - do { - dart_prev = dart_iter; - - if (dart_iter.alpha2() == dart_prev) + if( dart_iter.Alpha2() == aDart ) return true; - else - dart_iter = dart_prev; // back again - - dart_iter.alpha0(); - dart_iter.alpha1(); - - } while (dart_iter != dart); - - return false; - } + else + return false; +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the node associated with \e dart is at - * the boundary of the triangulation. - */ - template - bool TriangulationHelper::isBoundaryNode(const DartType& dart) { - +/** Checks if the face associated with \e dart is at + * the boundary of the m_triangulation. + */ +template +bool TRIANGULATION_HELPER::IsBoundaryFace( const DART_TYPE& aDart ) +{ // Strategy: boundary if alpha2(d)=d - - DartType dart_iter(dart); - DartType dart_prev; - + + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; + + do + { + dart_prev = dart_iter; + + if( dart_iter.Alpha2() == dart_prev ) + return true; + else + dart_iter = dart_prev; // back again + + dart_iter.Alpha0(); + dart_iter.Alpha1(); + + } while( dart_iter != aDart ); + + return false; +} + +/** Checks if the node associated with \e dart is at + * the boundary of the m_triangulation. + */ +template +bool TRIANGULATION_HELPER::IsBoundaryNode( const DART_TYPE& aDart ) +{ + // Strategy: boundary if alpha2(d)=d + + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; + // If input dart is reached again, then internal node // If alpha2(d)=d, then boundary - - do { - dart_iter.alpha1(); - dart_prev = dart_iter; - dart_iter.alpha2(); - - if (dart_iter == dart_prev) - return true; - - } while (dart_iter != dart); - + + do + { + dart_iter.Alpha1(); + dart_prev = dart_iter; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + return true; + + } while( dart_iter != aDart ); + return false; - } +} +/** Returns the degree of the node associated with \e dart. + * + * \par Definition: + * The \e degree (or valency) of a node \e V in a m_triangulation, + * is defined as the number of edges incident with \e V, i.e., + * the number of edges joining \e V with another node in the triangulation. + */ +template +int TRIANGULATION_HELPER::GetDegreeOfNode( const DART_TYPE& aDart ) +{ + DART_TYPE dart_iter( aDart ); + DART_TYPE dart_prev; - //------------------------------------------------------------------------------------------------ - /** Returns the degree of the node associated with \e dart. - * - * \par Definition: - * The \e degree (or valency) of a node \e V in a triangulation, - * is defined as the number of edges incident with \e V, i.e., - * the number of edges joining \e V with another node in the triangulation. - */ - template - int TriangulationHelper::getDegreeOfNode(const DartType& dart) { - - DartType dart_iter(dart); - DartType dart_prev; - // If input dart is reached again, then interior node // If alpha2(d)=d, then boundary - + int degree = 0; bool boundaryVisited = false; - do { - dart_iter.alpha1(); - degree++; - dart_prev = dart_iter; - - dart_iter.alpha2(); - - if (dart_iter == dart_prev) { - if (!boundaryVisited) { - boundaryVisited = true; - // boundary is reached first time, count in the reversed direction - degree++; // count the start since it is not done above - dart_iter = dart; - dart_iter.alpha2(); + do + { + dart_iter.Alpha1(); + degree++; + dart_prev = dart_iter; + + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + { + if( !boundaryVisited ) + { + boundaryVisited = true; + // boundary is reached first time, count in the reversed direction + degree++; // count the start since it is not done above + dart_iter = aDart; + dart_iter.Alpha2(); + } else + return degree; } - else - return degree; - } - - } while (dart_iter != dart); - + + } while( dart_iter != aDart ); + return degree; - } +} +// Modification of GetDegreeOfNode: +// Strategy, reverse the list and start in the other direction if the boundary +// is reached. NB. copying of darts but ok., or we could have collected pointers, +// but the memory management. - //------------------------------------------------------------------------------------------------ - // Modification of getDegreeOfNode: - // Strategy, reverse the list and start in the other direction if the boundary - // is reached. NB. copying of darts but ok., or we could have collected pointers, - // but the memory management. - - // NOTE: not symmetry if we choose to collect opposite edges - // now we collect darts with radiating edges - - // Remember that we must also copy the node, but ok with push_back - // The size of the list will be the degree of the node - - // No CW/CCW since topology only - - - // Each dart consists of an incident edge and an adjacent node. - // But note that this is only how we interpret the dart in this implementation. - // Given this list, how can we find the opposite edges: - // We can perform alpha1 on each, but for boundary nodes we will get one edge twice. - // But this is will always be the last dart! - // The darts in the list are in sequence and starts with the alpha0(dart) - // alpha0, alpha1 and alpha2 +// NOTE: not symmetry if we choose to collect opposite edges +// now we collect darts with radiating edges - // Private/Hidden function - template - void TriangulationHelper::getNeighborNodes(const DartType& dart, - std::list& node_list, bool& boundary) { - - DartType dart_iter(dart); - - dart_iter.alpha0(); // position the dart at an opposite node - - DartType dart_prev = dart_iter; - +// Remember that we must also copy the node, but ok with push_back +// The size of the list will be the degree of the node + +// No CW/CCW since topology only + +// Each dart consists of an incident edge and an adjacent node. +// But note that this is only how we interpret the dart in this implementation. +// Given this list, how can we find the opposite edges: +// We can perform alpha1 on each, but for boundary nodes we will get one edge twice. +// But this is will always be the last dart! +// The darts in the list are in sequence and starts with the alpha0(dart) +// alpha0, alpha1 and alpha2 + +// Private/Hidden function +template +void TRIANGULATION_HELPER::getNeighborNodes( const DART_TYPE& aDart, + std::list& aNodeList, bool& aBoundary ) +{ + DART_TYPE dart_iter( aDart ); + dart_iter.Alpha0(); // position the dart at an opposite node + + DART_TYPE dart_prev = dart_iter; bool start_at_boundary = false; - dart_iter.alpha2(); - if (dart_iter == dart_prev) - start_at_boundary = true; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + start_at_boundary = true; else - dart_iter = dart_prev; // back again - - DartType dart_start = dart_iter; - - do { - node_list.push_back(dart_iter); - dart_iter.alpha1(); - dart_iter.alpha0(); - dart_iter.alpha1(); - dart_prev = dart_iter; - dart_iter.alpha2(); - if (dart_iter == dart_prev) { - // boundary reached - boundary = true; - if (start_at_boundary == true) { - // add the dart which now is positioned at the opposite boundary - node_list.push_back(dart_iter); - return; - } - else { - // call the function again such that we start at the boundary - // first clear the list and reposition to the initial node - dart_iter.alpha0(); - node_list.clear(); - getNeighborNodes(dart_iter, node_list, boundary); - return; // after one recursive step - } - } - } while (dart_iter != dart_start); - - boundary = false; - } + dart_iter = dart_prev; // back again + DART_TYPE dart_start = dart_iter; - //------------------------------------------------------------------------------------------------ - /** Gets the 0-orbit around an interior node. - * - * \param dart - * A dart (CCW or CW) positioned at an \e interior node. - * - * \retval orbit - * Sequence of darts with one orbit for each arc. All the darts have the same - * orientation (CCW or CW) as \e dart, and \e dart is the first element - * in the sequence. - * - * \require - * - DartListType::push_back (DartType&) - * - * \see - * get_0_orbit_boundary - */ - template - void TriangulationHelper::get_0_orbit_interior(const DartType& dart, DartListType& orbit) { - - DartType d_iter = dart; - orbit.push_back(d_iter); - d_iter.alpha1().alpha2(); - - while (d_iter != dart) { - orbit.push_back(d_iter); - d_iter.alpha1().alpha2(); + do + { + aNodeList.push_back( dart_iter ); + dart_iter.Alpha1(); + dart_iter.Alpha0(); + dart_iter.Alpha1(); + dart_prev = dart_iter; + dart_iter.Alpha2(); + + if( dart_iter == dart_prev ) + { + // boundary reached + aBoundary = true; + + if( start_at_boundary == true ) + { + // add the dart which now is positioned at the opposite boundary + aNodeList.push_back( dart_iter ); + return; + } + else + { + // call the function again such that we start at the boundary + // first clear the list and reposition to the initial node + dart_iter.Alpha0(); + aNodeList.clear(); + getNeighborNodes( dart_iter, aNodeList, aBoundary ); + + return; // after one recursive step + } + } } - } + while( dart_iter != dart_start ); + aBoundary = false; +} - //------------------------------------------------------------------------------------------------ - /** Gets the 0-orbit around a node at the boundary - * - * \param dart - * A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge. - * - * \retval orbit - * Sequence of darts with one orbit for each arc. All the darts, \e exept \e the \e last one, - * have the same orientation (CCW or CW) as \e dart, and \e dart is the first element - * in the sequence. - * - * \require - * - DartListType::push_back (DartType&) - * - * \note - * - The last dart in the sequence have opposite orientation compared to the others! - * - * \see - * get_0_orbit_interior - */ - template - void TriangulationHelper::get_0_orbit_boundary(const DartType& dart, DartListType& orbit) { +/** Gets the 0-orbit around an interior node. + * + * \param aDart + * A dart (CCW or CW) positioned at an \e interior node. + * + * \retval aOrbit + * Sequence of darts with one orbit for each arc. All the darts have the same + * orientation (CCW or CW) as \e dart, and \e dart is the first element + * in the sequence. + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + * + * \see + * Get0OrbitBoundary + */ +template +void TRIANGULATION_HELPER::Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ) +{ + DART_TYPE d_iter = aDart; + aOrbit.push_back( d_iter ); + d_iter.Alpha1().Alpha2(); + + while( d_iter != aDart ) + { + aOrbit.push_back( d_iter ); + d_iter.Alpha1().Alpha2(); + } +} + +/** Gets the 0-orbit around a node at the boundary + * + * \param aDart + * A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge. + * + * \retval orbit + * Sequence of darts with one orbit for each arc. All the darts, \e exept \e the \e last one, + * have the same orientation (CCW or CW) as \e dart, and \e dart is the first element + * in the sequence. + * + * \require + * - DART_LIST_TYPE::push_back (DART_TYPE&) + * + * \note + * - The last dart in the sequence have opposite orientation compared to the others! + * + * \see + * Get0OrbitInterior + */ +template +void TRIANGULATION_HELPER::Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit ) +{ + DART_TYPE dart_prev; + DART_TYPE d_iter = aDart; - DartType dart_prev; - DartType d_iter = dart; - do { - orbit.push_back(d_iter); - d_iter.alpha1(); - dart_prev = d_iter; - d_iter.alpha2(); - } while (d_iter != dart_prev); - - orbit.push_back(d_iter); // the last one with opposite orientation - } + do + { + aOrbit.push_back( d_iter ); + d_iter.Alpha1(); + dart_prev = d_iter; + d_iter.Alpha2(); + } + while( d_iter != dart_prev ); + aOrbit.push_back( d_iter ); // the last one with opposite orientation +} - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 0-orbit, i.e., - * if they share a node. - * \e d1 and/or \e d2 can be CCW or CW. - * - * (This function also examines if the the node associated with - * \e d1 is at the boundary, which slows down the function (slightly). - * If it is known that the node associated with \e d1 is an interior - * node and a faster version is needed, the user should implement his/her - * own version.) - */ - template - bool TriangulationHelper::same_0_orbit(const DartType& d1, const DartType& d2) { - +/** Checks if the two darts belong to the same 0-orbit, i.e., + * if they share a node. + * \e d1 and/or \e d2 can be CCW or CW. + * + * (This function also examines if the the node associated with + * \e d1 is at the boundary, which slows down the function (slightly). + * If it is known that the node associated with \e d1 is an interior + * node and a faster version is needed, the user should implement his/her + * own version.) + */ +template +bool TRIANGULATION_HELPER::Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ // Two copies of the same dart - DartType d_iter = d2; - DartType d_end = d2; - - if (isBoundaryNode(d_iter)) { - // position at both boundary edges - positionAtNextBoundaryEdge(d_iter); - d_end.alpha1(); - positionAtNextBoundaryEdge(d_end); + DART_TYPE d_iter = aD2; + DART_TYPE d_end = aD2; + + if( isBoundaryNode( d_iter ) ) + { + // position at both boundary edges + PositionAtNextBoundaryEdge( d_iter ); + d_end.Alpha1(); + PositionAtNextBoundaryEdge( d_end ); } - - for (;;) { - if (d_iter == d1) - return true; - d_iter.alpha1(); - if (d_iter == d1) - return true; - d_iter.alpha2(); - if (d_iter == d_end) - break; + + for( ;; ) + { + if( d_iter == aD1 ) + return true; + + d_iter.Alpha1(); + + if( d_iter == aD1 ) + return true; + + d_iter.Alpha2(); + + if( d_iter == d_end ) + break; } - + return false; - } +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 1-orbit, i.e., - * if they share an edge. - * \e d1 and/or \e d2 can be CCW or CW. - */ - template - bool TriangulationHelper::same_1_orbit(const DartType& d1, const DartType& d2) { +/** Checks if the two darts belong to the same 1-orbit, i.e., + * if they share an edge. + * \e d1 and/or \e d2 can be CCW or CW. + */ +template +bool TRIANGULATION_HELPER::Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ + DART_TYPE d_iter = aD2; - DartType d_iter = d2; // (Also works at the boundary) - if (d_iter == d1 || d_iter.alpha0() == d1 || d_iter.alpha2() == d1 || d_iter.alpha0() == d1) - return true; - return false; - } + return ( d_iter == aD1 || d_iter.Alpha0() == aD1 || + d_iter.Alpha2() == aD1 || d_iter.Alpha0() == aD1 ); +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the two darts belong to the same 2-orbit, i.e., - * if they lie in the same triangle. - * \e d1 and/or \e d2 can be CCW or CW - */ - template - bool TriangulationHelper::same_2_orbit(const DartType& d1, const DartType& d2) { +//------------------------------------------------------------------------------------------------ +/** Checks if the two darts belong to the same 2-orbit, i.e., + * if they lie in the same triangle. + * \e d1 and/or \e d2 can be CCW or CW + */ +template +bool TRIANGULATION_HELPER::Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 ) +{ + DART_TYPE d_iter = aD2; - DartType d_iter = d2; - if (d_iter == d1 || d_iter.alpha0() == d1 || - d_iter.alpha1() == d1 || d_iter.alpha0() == d1 || - d_iter.alpha1() == d1 || d_iter.alpha0() == d1) - return true; - return false; - } - + return ( d_iter == aD1 || d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 || + d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 || d_iter.Alpha0() == aD1 ); +} - //------------------------------------------------------------------------------------------------ - // Private/Hidden function - template - bool TriangulationHelper::degenerateTriangle(const DartType& dart) { - +// Private/Hidden function +template +bool TRIANGULATION_HELPER::degenerateTriangle( const DART_TYPE& aDart ) +{ // Check if triangle is degenerate // Assumes CCW dart - - DartType d1 = dart; - DartType d2 = d1; - d2.alpha1(); - if (TraitsType::crossProduct2d(d1,d2) == 0) - return true; - - return false; - } - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart is swappable, i.e., if the edge - * is a diagonal in a \e strictly convex (or convex) quadrilateral. - * - * \param allowDegeneracy - * If set to true, the function will also return true if the numerical calculations - * indicate that the quadrilateral is convex only, and not necessarily strictly - * convex. - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (Dart&, Dart&) - */ - template - bool TriangulationHelper::swappableEdge(const DartType& dart, bool allowDegeneracy) { + DART_TYPE d1 = aDart; + DART_TYPE d2 = d1; + d2.Alpha1(); + return ( TRAITS_TYPE::CrossProduct2D( d1, d2 ) == 0 ); +} + +/** Checks if the edge associated with \e dart is swappable, i.e., if the edge + * is a diagonal in a \e strictly convex (or convex) quadrilateral. + * + * \param aAllowDegeneracy + * If set to true, the function will also return true if the numerical calculations + * indicate that the quadrilateral is convex only, and not necessarily strictly + * convex. + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (Dart&, Dart&) + */ +template +bool TRIANGULATION_HELPER::SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy ) +{ // How "safe" is it? - - if (isBoundaryEdge(dart)) - return false; - + + if( IsBoundaryEdge( aDart ) ) + return false; + // "angles" are at the diagonal - DartType d1 = dart; - d1.alpha2().alpha1(); - DartType d2 = dart; - d2.alpha1(); - if (allowDegeneracy) { - if (TraitsType::crossProduct2d(d1,d2) < 0.0) - return false; + DART_TYPE d1 = aDart; + d1.Alpha2().Alpha1(); + DART_TYPE d2 = aDart; + d2.Alpha1(); + + if( aAllowDegeneracy ) + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 ) + return false; } - else { - if (TraitsType::crossProduct2d(d1,d2) <= 0.0) - return false; + else + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 ) + return false; } - + // Opposite side (still angle at the diagonal) - d1 = dart; - d1.alpha0(); + d1 = aDart; + d1.Alpha0(); d2 = d1; - d1.alpha1(); - d2.alpha2().alpha1(); - - if (allowDegeneracy) { - if (TraitsType::crossProduct2d(d1,d2) < 0.0) - return false; + d1.Alpha1(); + d2.Alpha2().Alpha1(); + + if( aAllowDegeneracy ) + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 ) + return false; } - else { - if (TraitsType::crossProduct2d(d1,d2) <= 0.0) - return false; + else + { + if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 ) + return false; } + return true; - } +} +/** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation. + * Position \e dart at a boundary edge in the same 0-orbit.\n + * If the given \e dart is CCW, \e dart is positioned at the left boundary edge + * and will be CW.\n + * If the given \e dart is CW, \e dart is positioned at the right boundary edge + * and will be CCW. + * + * \note + * - The given \e dart must have a source node at the boundary, otherwise an + * infinit loop occurs. + */ +template +void TRIANGULATION_HELPER::PositionAtNextBoundaryEdge( DART_TYPE& aDart ) +{ + DART_TYPE dart_prev; - //------------------------------------------------------------------------------------------------ - /** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation. - * Position \e dart at a boundary edge in the same 0-orbit.\n - * If the given \e dart is CCW, \e dart is positioned at the left boundary edge - * and will be CW.\n - * If the given \e dart is CW, \e dart is positioned at the right boundary edge - * and will be CCW. - * - * \note - * - The given \e dart must have a source node at the boundary, otherwise an - * infinit loop occurs. - */ - template - void TriangulationHelper::positionAtNextBoundaryEdge(DartType& dart) { - - DartType dart_prev; - // If alpha2(d)=d, then boundary - - //old convention: dart.alpha0(); - do { - dart.alpha1(); - dart_prev = dart; - dart.alpha2(); - } while (dart != dart_prev); - } - - //------------------------------------------------------------------------------------------------ - /** Checks if the boundary of a triangulation is convex. - * - * \param dart - * A CCW dart at the boundary of the triangulation - * - * \require - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (const Dart&, const Dart&) - */ - template - bool TriangulationHelper::convexBoundary(const DartType& dart) { - - std::list blist; - getBoundary(dart, blist); - - int no; - no = (int)blist.size(); - typename std::list::const_iterator bit = blist.begin(); - DartType d1 = *bit; - ++bit; - DartType d2; - bool convex = true; - for (; bit != blist.end(); ++bit) { - d2 = *bit; - double crossProd = TraitsType::crossProduct2d(d1, d2); - if (crossProd < 0.0) { - //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; - convex = false; - return convex; - } - d1 = d2; + //old convention: dart.Alpha0(); + do + { + aDart.Alpha1(); + dart_prev = aDart; + aDart.Alpha2(); } - + while( aDart != dart_prev ); +} + +/** Checks if the boundary of a triangulation is convex. + * + * \param dart + * A CCW dart at the boundary of the m_triangulation + * + * \require + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (const Dart&, const Dart&) + */ +template +bool TRIANGULATION_HELPER::ConvexBoundary( const DART_TYPE& aDart ) +{ + std::list blist; + getBoundary( aDart, blist ); + + int no; + no = (int) blist.size(); + typename std::list::const_iterator bit = blist.begin(); + DART_TYPE d1 = *bit; + ++bit; + DART_TYPE d2; + bool convex = true; + + for( ; bit != blist.end(); ++bit ) + { + d2 = *bit; + double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 ); + + if( crossProd < 0.0 ) + { + //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; + convex = false; + return convex; + } + + d1 = d2; + } + // Check the last angle d2 = *blist.begin(); - double crossProd = TraitsType::crossProduct2d(d1, d2); - if (crossProd < 0.0) { - //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; - convex = false; + double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 ); + + if( crossProd < 0.0 ) + { + //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; + convex = false; } - + //if (convex) // cout << "\n---> Boundary is convex\n" << endl; //cout << endl; return convex; - } +} - //@} // End of Topological and Geometric Queries Group +//@} // End of Topological and Geometric Queries Group +/** @name Utilities for Delaunay Triangulation */ +//@{ +//------------------------------------------------------------------------------------------------ +/** Optimizes the edges in the given sequence according to the + * \e Delaunay criterion, i.e., such that the edge will fullfill the + * \e circumcircle criterion (or equivalently the \e MaxMin + * angle criterion) with respect to the quadrilaterals where + * they are diagonals. + * + * \param aElist + * The sequence of edges + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \using + * - swapTestDelaunay + */ +template +void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist ) +{ + OptimizeDelaunay( aElist, aElist.end() ); +} - //------------------------------------------------------------------------------------------------ - // ------------------------ Utilities for Delaunay Triangulation Group -------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Utilities for Delaunay Triangulation */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Optimizes the edges in the given sequence according to the - * \e Delaunay criterion, i.e., such that the edge will fullfill the - * \e circumcircle criterion (or equivalently the \e MaxMin - * angle criterion) with respect to the quadrilaterals where - * they are diagonals. - * - * \param elist - * The sequence of edges - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \using - * - swapTestDelaunay - */ - template - void TriangulationHelper::optimizeDelaunay(DartListType& elist) { - optimizeDelaunay(elist, elist.end()); - } - - - //------------------------------------------------------------------------------------------------ - template - void TriangulationHelper::optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end) { - +//------------------------------------------------------------------------------------------------ +template +void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist, + const typename DART_LIST_TYPE::iterator aEnd ) +{ // CCW darts // Optimize here means Delaunay, but could be any criterion by // requiring a "should swap" in the traits class, or give // a function object? // Assumes that elist has only one dart for each arc. // Darts outside the quadrilateral are preserved - + // For some data structures it is possible to preserve // all darts when swapping. Thus a preserve_darts_when swapping // ccould be given to indicate this and we would gain performance by avoiding // find in list. - + // Requires that swap retuns a dart in the "same position when rotated CCW" // (A vector instead of a list may be better.) - + // First check that elist is not empty - if (elist.empty()) + if( aElist.empty() ) return; // Avoid cycling by more extensive circumcircle test bool cycling_check = true; bool optimal = false; - typename DartListType::iterator it; + typename DART_LIST_TYPE::iterator it; - typename DartListType::iterator end_opt = end; + typename DART_LIST_TYPE::iterator end_opt = aEnd; // Hmm... The following code is trying to derefence an iterator that may // be invalid. This may lead to debug error on Windows, so we comment out @@ -1491,231 +1488,240 @@ private: // problems... // // last_opt is passed the end of the "active list" - //typename DartListType::iterator end_opt; + //typename DART_LIST_TYPE::iterator end_opt; //if (*end != NULL) // end_opt = end; //else // end_opt = elist.end(); - while(!optimal) { - optimal = true; - for (it = elist.begin(); it != end_opt; ++it) { - if (swapTestDelaunay(*it, cycling_check)) { + while( !optimal ) + { + optimal = true; + for( it = aElist.begin(); it != end_opt; ++it ) + { + if( SwapTestDelaunay( *it, cycling_check ) ) + { + // Preserve darts. Potential darts in the list are: + // - The current dart + // - the four CCW darts on the boundary of the quadrilateral + // (the current arc has only one dart) - // Preserve darts. Potential darts in the list are: - // - The current dart - // - the four CCW darts on the boundary of the quadrilateral - // (the current arc has only one dart) - - swapEdgeInList(it, elist); - - optimal = false; - } // end if should swap - } // end for + SwapEdgeInList( it, aElist ); + + optimal = false; + } // end if should swap + } // end for } // end pass - } +} - - //------------------------------------------------------------------------------------------------ - /** Checks if the edge associated with \e dart should be swapped according - * to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or - * equivalently the \e MaxMin angle criterion). - * - * \param cycling_check - * Must be set to \c true when used in connection with optimization algorithms, - * e.g., optimizeDelaunay. This will avoid cycling and infinite loops in nearly - * neutral cases. - * - * \require - * - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, DartType&) - * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (DartType&, DartType&) - */ - template +/** Checks if the edge associated with \e dart should be swapped according + * to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or + * equivalently the \e MaxMin angle criterion). + * + * \param aCyclingCheck + * Must be set to \c true when used in connection with optimization algorithms, + * e.g., OptimizeDelaunay. This will avoid cycling and infinite loops in nearly + * neutral cases. + * + * \require + * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, DART_TYPE&) + * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, DART_TYPE&) + */ +template #if ((_MSC_VER > 0) && (_MSC_VER < 1300))//#ifdef _MSC_VER - bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check = false) const { +bool TRIANGULATION_HELPER::SwapTestDelaunay(const DART_TYPE& aDart, bool aCyclingCheck = false) const +{ #else - bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check) const { +bool TRIANGULATION_HELPER::SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck ) const +{ #endif - // The general strategy is taken from Cline & Renka. They claim that // their algorithm insure numerical stability, but experiments show // that this is not correct for neutral, or almost neutral cases. // I have extended this strategy (without using tolerances) to avoid // cycling and infinit loops when used in connection with LOP algorithms; // see the comments below. - - typedef typename TraitsType::real_type real_type; - - if (isBoundaryEdge(dart)) - return false; - - DartType v11 = dart; - v11.alpha1().alpha0(); - DartType v12 = v11; - v12.alpha1(); - - DartType v22 = dart; - v22.alpha2().alpha1().alpha0(); - DartType v21 = v22; - v21.alpha1(); - - real_type cos1 = TraitsType::scalarProduct2d(v11,v12); - real_type cos2 = TraitsType::scalarProduct2d(v21,v22); - + + typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE; + + if( IsBoundaryEdge( aDart ) ) + return false; + + DART_TYPE v11 = aDart; + v11.Alpha1().Alpha0(); + DART_TYPE v12 = v11; + v12.Alpha1(); + + DART_TYPE v22 = aDart; + v22.Alpha2().Alpha1().Alpha0(); + DART_TYPE v21 = v22; + v21.Alpha1(); + + REAL_TYPE cos1 = TRAITS_TYPE::ScalarProduct2D( v11, v12 ); + REAL_TYPE cos2 = TRAITS_TYPE::ScalarProduct2D( v21, v22 ); + // "Angles" are opposite to the diagonal. // The diagonals should be swapped iff (t1+t2) .gt. 180 // degrees. The following two tests insure numerical // stability according to Cline & Renka. But experiments show // that cycling may still happen; see the aditional test below. - if (cos1 >= 0 && cos2 >= 0) // both angles are grater or equual 90 - return false; - if (cos1 < 0 && cos2 < 0) // both angles are less than 90 - return true; - - real_type sin1 = TraitsType::crossProduct2d(v11,v12); - real_type sin2 = TraitsType::crossProduct2d(v21,v22); - real_type sin12 = sin1*cos2 + cos1*sin2; - if (sin12 >= 0) // equality represents a neutral case - return false; - - if (cycling_check) { - // situation so far is sin12 < 0. Test if this also - // happens for the swapped edge. - - // The numerical calculations so far indicate that the edge is - // not Delaunay and should not be swapped. But experiments show that - // in neutral cases, or almost neutral cases, it may happen that - // the swapped edge may again be found to be not Delaunay and thus - // be swapped if we return true here. This may lead to cycling and - // an infinte loop when used, e.g., in connection with optimizeDelaunay. - // - // In an attempt to avoid this we test if the swapped edge will - // also be found to be not Delaunay by repeating the last test above - // for the swapped edge. - // We now rely on the general requirement for TraitsType::swapEdge which - // should deliver CCW dart back in "the same position"; see the general - // description. This will insure numerical stability as the next calculation - // is the same as if this function was called again with the swapped edge. - // Cycling is thus impossible provided that the initial tests above does - // not result in ambiguity (and they should probably not do so). - - v11.alpha0(); - v12.alpha0(); - v21.alpha0(); - v22.alpha0(); - // as if the edge was swapped/rotated CCW - cos1 = TraitsType::scalarProduct2d(v22,v11); - cos2 = TraitsType::scalarProduct2d(v12,v21); - sin1 = TraitsType::crossProduct2d(v22,v11); - sin2 = TraitsType::crossProduct2d(v12,v21); - sin12 = sin1*cos2 + cos1*sin2; - if (sin12 < 0) { - // A neutral case, but the tests above lead to swapping + if( cos1 >= 0 && cos2 >= 0 ) // both angles are grater or equual 90 return false; - } + + if( cos1 < 0 && cos2 < 0 ) // both angles are less than 90 + return true; + + REAL_TYPE sin1 = TRAITS_TYPE::CrossProduct2D( v11, v12 ); + REAL_TYPE sin2 = TRAITS_TYPE::CrossProduct2D( v21, v22 ); + REAL_TYPE sin12 = sin1 * cos2 + cos1 * sin2; + + if( sin12 >= 0 ) // equality represents a neutral case + return false; + + if( aCyclingCheck ) + { + // situation so far is sin12 < 0. Test if this also + // happens for the swapped edge. + + // The numerical calculations so far indicate that the edge is + // not Delaunay and should not be swapped. But experiments show that + // in neutral cases, or almost neutral cases, it may happen that + // the swapped edge may again be found to be not Delaunay and thus + // be swapped if we return true here. This may lead to cycling and + // an infinte loop when used, e.g., in connection with OptimizeDelaunay. + // + // In an attempt to avoid this we test if the swapped edge will + // also be found to be not Delaunay by repeating the last test above + // for the swapped edge. + // We now rely on the general requirement for TRAITS_TYPE::swapEdge which + // should deliver CCW dart back in "the same position"; see the general + // description. This will insure numerical stability as the next calculation + // is the same as if this function was called again with the swapped edge. + // Cycling is thus impossible provided that the initial tests above does + // not result in ambiguity (and they should probably not do so). + + v11.Alpha0(); + v12.Alpha0(); + v21.Alpha0(); + v22.Alpha0(); + // as if the edge was swapped/rotated CCW + cos1 = TRAITS_TYPE::ScalarProduct2D( v22, v11 ); + cos2 = TRAITS_TYPE::ScalarProduct2D( v12, v21 ); + sin1 = TRAITS_TYPE::CrossProduct2D( v22, v11 ); + sin2 = TRAITS_TYPE::CrossProduct2D( v12, v21 ); + sin12 = sin1 * cos2 + cos1 * sin2; + + if( sin12 < 0 ) + { + // A neutral case, but the tests above lead to swapping + return false; + } } - + return true; - } +} +//----------------------------------------------------------------------- +// +// x +//" / \ " +// / | \ Darts: +//oe2 / | \ oe2 = oppEdge2 +// x....|....x +// \ d| d/ d = diagonal (input and output) +// \ | / +// oe1 \ / oe1 = oppEdge1 +// x +// +//----------------------------------------------------------------------- +/** Recursively swaps edges in the triangulation according to the \e Delaunay criterion. + * + * \param aDiagonal + * A CCW dart representing the edge where the recursion starts from. + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE&)\n + * \b Note: Must be implemented such that the darts outside the quadrilateral + * are not affected by the swap. + * + * \using + * - Calls itself recursively + */ +template +void TRIANGULATION_HELPER::RecSwapDelaunay( DART_TYPE& aDiagonal ) +{ + if( !SwapTestDelaunay( aDiagonal ) ) + // ??? swapTestDelaunay also checks if boundary, so this can be optimized + return; - //----------------------------------------------------------------------- - // - // x - //" / \ " - // / | \ Darts: - //oe2 / | \ oe2 = oppEdge2 - // x....|....x - // \ d| d/ d = diagonal (input and output) - // \ | / - // oe1 \ / oe1 = oppEdge1 - // x - // - //----------------------------------------------------------------------- - /** Recursively swaps edges in the triangulation according to the \e Delaunay criterion. - * - * \param diagonal - * A CCW dart representing the edge where the recursion starts from. - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&)\n - * \b Note: Must be implemented such that the darts outside the quadrilateral - * are not affected by the swap. - * - * \using - * - Calls itself recursively - */ - template - void TriangulationHelper::recSwapDelaunay(DartType& diagonal) { - - if (!swapTestDelaunay(diagonal)) - // ??? swapTestDelaunay also checks if boundary, so this can be optimized - return; - // Get the other "edges" of the current triangle; see illustration above. - DartType oppEdge1 = diagonal; - oppEdge1.alpha1(); + DART_TYPE oppEdge1 = aDiagonal; + oppEdge1.Alpha1(); bool b1; - if (isBoundaryEdge(oppEdge1)) - b1 = true; - else { - b1 = false; - oppEdge1.alpha2(); + + if( IsBoundaryEdge( oppEdge1 ) ) + b1 = true; + else + { + b1 = false; + oppEdge1.Alpha2(); } - - - DartType oppEdge2 = diagonal; - oppEdge2.alpha0().alpha1().alpha0(); + + DART_TYPE oppEdge2 = aDiagonal; + oppEdge2.Alpha0().Alpha1().Alpha0(); bool b2; - if (isBoundaryEdge(oppEdge2)) - b2 = true; - else { - b2 = false; - oppEdge2.alpha2(); + + if( IsBoundaryEdge( oppEdge2 ) ) + b2 = true; + else + { + b2 = false; + oppEdge2.Alpha2(); } - + // Swap the given diagonal - triangulation.swapEdge(diagonal); - - if (!b1) - recSwapDelaunay(oppEdge1); - if (!b2) - recSwapDelaunay(oppEdge2); - } + m_triangulation.swapEdge( aDiagonal ); + if( !b1 ) + RecSwapDelaunay( oppEdge1 ); + + if( !b2 ) + RecSwapDelaunay( oppEdge2 ); +} + +/** Swaps edges away from the (interior) node associated with + * \e dart such that that exactly three edges remain incident + * with the node. + * This function is used as a first step in RemoveInteriorNode + * + * \retval dart + * A CCW dart incident with the node + * + * \par Assumes: + * - The node associated with \e dart is interior to the + * triangulation. + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \note + * - A degenerate triangle may be left at the node. + * - The function is not unique as it depends on which dart + * at the node that is given as input. + * + * \see + * SwapEdgesAwayFromBoundaryNode + */ +template +void TRIANGULATION_HELPER::SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart, + LIST_TYPE& aSwappedEdges ) +{ - //------------------------------------------------------------------------------------------------ - /** Swaps edges away from the (interior) node associated with - * \e dart such that that exactly three edges remain incident - * with the node. - * This function is used as a first step in removeInteriorNode - * - * \retval dart - * A CCW dart incident with the node - * - * \par Assumes: - * - The node associated with \e dart is interior to the - * triangulation. - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \note - * - A degenerate triangle may be left at the node. - * - The function is not unique as it depends on which dart - * at the node that is given as input. - * - * \see - * swapEdgesAwayFromBoundaryNode - */ - template - void TriangulationHelper::swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges) { - // Same iteration as in fixEdgesAtCorner, but not boundary - DartType dnext = dart; - + DART_TYPE dnext = aDart; + // Allow degeneracy, otherwise we might end up with degree=4. // For example, the reverse operation of inserting a point on an // existing edge gives a situation where all edges are non-swappable. @@ -1724,53 +1730,56 @@ private: // ??? An alternative here is to wait with degeneracy till we get an // infinite loop with degree > 3. bool allowDegeneracy = true; - - int degree = getDegreeOfNode(dart); - DartType d_iter; - while (degree > 3) { - d_iter = dnext; - dnext.alpha1().alpha2(); - - if (swappableEdge(d_iter, allowDegeneracy)) { - triangulation.swapEdge(d_iter); // swap the edge away - // Collect swapped edges in the list - // "Hide" the dart on the other side of the edge to avoid it being changed for - // other swaps - DartType swapped_edge = d_iter; // it was delivered back - swapped_edge.alpha2().alpha0(); // CCW (if not at boundary) - swapped_edges.push_back(swapped_edge); - - degree--; - } + + int degree = getDegreeOfNode( aDart ); + DART_TYPE d_iter; + + while( degree > 3 ) + { + d_iter = dnext; + dnext.Alpha1().Alpha2(); + + if( SwappableEdge( d_iter, allowDegeneracy ) ) + { + m_triangulation.swapEdge( d_iter ); // swap the edge away + // Collect swapped edges in the list + // "Hide" the dart on the other side of the edge to avoid it being changed for + // other swaps + DART_TYPE swapped_edge = d_iter; // it was delivered back + swapped_edge.Alpha2().Alpha0(); // CCW (if not at boundary) + aSwappedEdges.push_back( swapped_edge ); + + degree--; + } } + // Output, incident to the node - dart = dnext; - } + aDart = dnext; +} - - //------------------------------------------------------------------------------------------------ - /** Swaps edges away from the (boundary) node associated with - * \e dart in such a way that when removing the edges that remain incident - * with the node, the boundary of the triangulation will be convex. - * This function is used as a first step in removeBoundaryNode - * - * \retval dart - * A CCW dart incident with the node - * - * \require - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType& \e dart)\n - * \b Note: Must be implemented such that \e dart is delivered back in a position as - * seen if it was glued to the edge when swapping (rotating) the edge CCW - * - * \par Assumes: - * - The node associated with \e dart is at the boundary of the triangulation. - * - * \see - * swapEdgesAwayFromInteriorNode - */ - template - void TriangulationHelper::swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges) { - +/** Swaps edges away from the (boundary) node associated with + * \e dart in such a way that when removing the edges that remain incident + * with the node, the boundary of the triangulation will be convex. + * This function is used as a first step in RemoveBoundaryNode + * + * \retval dart + * A CCW dart incident with the node + * + * \require + * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n + * \b Note: Must be implemented such that \e dart is delivered back in a position as + * seen if it was glued to the edge when swapping (rotating) the edge CCW + * + * \par Assumes: + * - The node associated with \e dart is at the boundary of the m_triangulation. + * + * \see + * SwapEdgesAwayFromInteriorNode + */ +template +void TRIANGULATION_HELPER::SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart, + LIST_TYPE& aSwappedEdges ) +{ // All darts that are swappable. // To treat collinear nodes at an existing boundary, we must allow degeneracy // when swapping to the boundary. @@ -1780,98 +1789,108 @@ private: // Assume for the swap in the traits class: // - A dart on the swapped edge is delivered back in a position as // seen if it was glued to the edge when swapping (rotating) the edge CCW - + //int degree = getDegreeOfNode(dart); - -passes: - - // Swap swappable edges that radiate from the node away - DartType d_iter = dart; // ???? can simply use dart - d_iter.alpha1().alpha2(); // first not at boundary - DartType d_next = d_iter; - bool bend = false; - bool swapped_next_to_boundary = false; - bool swapped_in_pass = false; - - bool allowDegeneracy; // = true; - DartType tmp1, tmp2; - - while (!bend) { - - d_next.alpha1().alpha2(); - if (isBoundaryEdge(d_next)) - bend = true; // then it is CW since alpha2 - - // To allow removing among collinear nodes at the boundary, - // degenerate triangles must be allowed - // (they will be removed when used in connection with removeBoundaryNode) - tmp1 = d_iter; tmp1.alpha1(); - tmp2 = d_iter; tmp2.alpha2().alpha1(); // don't bother with boundary (checked later) - - if (isBoundaryEdge(tmp1) && isBoundaryEdge(tmp2)) - allowDegeneracy = true; - else - allowDegeneracy = false; - - if (swappableEdge(d_iter, allowDegeneracy)) { - triangulation.swapEdge(d_iter); - - // Collect swapped edges in the list - // "Hide" the dart on the other side of the edge to avoid it being changed for - // other swapps - DartType swapped_edge = d_iter; // it was delivered back - swapped_edge.alpha2().alpha0(); // CCW - swapped_edges.push_back(swapped_edge); - - //degree--; // if degree is 2, or bend=true, we are done - swapped_in_pass = true; - if (bend) - swapped_next_to_boundary = true; + + passes: + // Swap swappable edges that radiate from the node away + DART_TYPE d_iter = aDart; // ???? can simply use dart + d_iter.Alpha1().Alpha2(); // first not at boundary + DART_TYPE d_next = d_iter; + bool bend = false; + bool swapped_next_to_boundary = false; + bool swapped_in_pass = false; + + bool allowDegeneracy; // = true; + DART_TYPE tmp1, tmp2; + + while( !bend ) + { + d_next.Alpha1().Alpha2(); + + if( IsBoundaryEdge( d_next ) ) + bend = true; // then it is CW since alpha2 + + // To allow removing among collinear nodes at the boundary, + // degenerate triangles must be allowed + // (they will be removed when used in connection with RemoveBoundaryNode) + tmp1 = d_iter; + tmp1.Alpha1(); + tmp2 = d_iter; + tmp2.Alpha2().Alpha1(); // don't bother with boundary (checked later) + + if( IsBoundaryEdge( tmp1 ) && IsBoundaryEdge( tmp2 ) ) + allowDegeneracy = true; + else + allowDegeneracy = false; + + if( SwappableEdge( d_iter, allowDegeneracy ) ) + { + m_triangulation.swapEdge( d_iter ); + + // Collect swapped edges in the list + // "Hide" the dart on the other side of the edge to avoid it being changed for + // other swapps + DART_TYPE swapped_edge = d_iter; // it was delivered back + swapped_edge.Alpha2().Alpha0(); // CCW + aSwappedEdges.push_back( swapped_edge ); + + //degree--; // if degree is 2, or bend=true, we are done + swapped_in_pass = true; + if( bend ) + swapped_next_to_boundary = true; + } + + if( !bend ) + d_iter = d_next; } - if (!bend) - d_iter = d_next; - } - - // Deliver a dart as output in the same position as the incoming dart - if (swapped_next_to_boundary) { - // Assume that "swapping is CCW and dart is preserved in the same position - d_iter.alpha1().alpha0().alpha1(); // CW and see below - } - else { - d_iter.alpha1(); // CW and see below - } - positionAtNextBoundaryEdge(d_iter); // CCW - - dart = d_iter; // for next pass or output - - // If a dart was swapped in this iteration we must run it more - if (swapped_in_pass) - goto passes; - } + // Deliver a dart as output in the same position as the incoming dart + if( swapped_next_to_boundary ) + { + // Assume that "swapping is CCW and dart is preserved in the same position + d_iter.Alpha1().Alpha0().Alpha1(); // CW and see below + } + else + { + d_iter.Alpha1(); // CW and see below + } + PositionAtNextBoundaryEdge( d_iter ); // CCW - //------------------------------------------------------------------------------------------------ - /** Swap the the edge associated with iterator \e it and update affected darts - * in \e elist accordingly. - * The darts affected by the swap are those in the same quadrilateral. - * Thus, if one want to preserve one or more of these darts on should - * keep them in \e elist. - */ - template - void TriangulationHelper::swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist) { + aDart = d_iter; // for next pass or output + + // If a dart was swapped in this iteration we must run it more + if( swapped_in_pass ) + goto passes; +} + +/** Swap the the edge associated with iterator \e it and update affected darts + * in \e elist accordingly. + * The darts affected by the swap are those in the same quadrilateral. + * Thus, if one want to preserve one or more of these darts on should + * keep them in \e elist. + */ +template +void TRIANGULATION_HELPER::SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt, + DART_LIST_TYPE& aElist ) +{ + + typename DART_LIST_TYPE::iterator it1, it2, it3, it4; + DART_TYPE dart( *aIt ); + + //typename TRAITS_TYPE::DART_TYPE d1 = dart; d1.Alpha2().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d2 = d1; d2.Alpha0().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d3 = dart; d3.Alpha0().Alpha1(); + //typename TRAITS_TYPE::DART_TYPE d4 = d3; d4.Alpha0().Alpha1(); + DART_TYPE d1 = dart; + d1.Alpha2().Alpha1(); + DART_TYPE d2 = d1; + d2.Alpha0().Alpha1(); + DART_TYPE d3 = dart; + d3.Alpha0().Alpha1(); + DART_TYPE d4 = d3; + d4.Alpha0().Alpha1(); - typename DartListType::iterator it1, it2, it3, it4; - DartType dart(*it); - - //typename TraitsType::DartType d1 = dart; d1.alpha2().alpha1(); - //typename TraitsType::DartType d2 = d1; d2.alpha0().alpha1(); - //typename TraitsType::DartType d3 = dart; d3.alpha0().alpha1(); - //typename TraitsType::DartType d4 = d3; d4.alpha0().alpha1(); - DartType d1 = dart; d1.alpha2().alpha1(); - DartType d2 = d1; d2.alpha0().alpha1(); - DartType d3 = dart; d3.alpha0().alpha1(); - DartType d4 = d3; d4.alpha0().alpha1(); - // Find pinters to the darts that may change. // ??? Note, this is not very efficient since we must use find, which is O(N), // four times. @@ -1881,37 +1900,49 @@ passes: // - sould we use another container type or, // - erase them and reinsert? // - or use two lists? - it1 = find(elist.begin(), elist.end(), d1); - it2 = find(elist.begin(), elist.end(), d2); - it3 = find(elist.begin(), elist.end(), d3); - it4 = find(elist.begin(), elist.end(), d4); - - triangulation.swapEdge(dart); + it1 = find( aElist.begin(), aElist.end(), d1 ); + it2 = find( aElist.begin(), aElist.end(), d2 ); + it3 = find( aElist.begin(), aElist.end(), d3 ); + it4 = find( aElist.begin(), aElist.end(), d4 ); + + m_triangulation.swapEdge( dart ); // Update the current dart which may have changed - *it = dart; - + *aIt = dart; + // Update darts that may have changed again (if they were present) // Note that dart is delivered back after swapping - if (it1 != elist.end()) { - d1 = dart; d1.alpha1().alpha0(); - *it1 = d1; + if( it1 != aElist.end() ) + { + d1 = dart; + d1.Alpha1().Alpha0(); + *it1 = d1; } - if (it2 != elist.end()) { - d2 = dart; d2.alpha2().alpha1(); - *it2 = d2; + + if( it2 != aElist.end() ) + { + d2 = dart; + d2.Alpha2().Alpha1(); + *it2 = d2; } - if (it3 != elist.end()) { - d3 = dart; d3.alpha2().alpha1().alpha0().alpha1(); - *it3 = d3; + + if( it3 != aElist.end() ) + { + d3 = dart; + d3.Alpha2().Alpha1().Alpha0().Alpha1(); + *it3 = d3; } - if (it4 != elist.end()) { - d4 = dart; d4.alpha0().alpha1(); - *it4 = d4; + + if( it4 != aElist.end() ) + { + d4 = dart; + d4.Alpha0().Alpha1(); + *it4 = d4; } - } - - //@} // End of Utilities for Delaunay Triangulation Group - -}; // End of ttl namespace scope (but other files may also contain functions for ttl) +} + +//@} // End of Utilities for Delaunay Triangulation Group + +} +// End of ttl namespace scope (but other files may also contain functions for ttl) #endif // _TTL_H_ diff --git a/include/ttl/ttl_util.h b/include/ttl/ttl_util.h index cfdf509531..398f6f316e 100644 --- a/include/ttl/ttl_util.h +++ b/include/ttl/ttl_util.h @@ -3,11 +3,11 @@ * Applied Mathematics, Norway. * * Contact information: E-mail: tor.dokken@sintef.no - * SINTEF ICT, Department of Applied Mathematics, + * SINTEF ICT, DeaPArtment of Applied Mathematics, * P.O. Box 124 Blindern, * 0314 Oslo, Norway. * - * This file is part of TTL. + * This file is aPArt of TTL. * * TTL is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -16,7 +16,7 @@ * * TTL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A aPARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public @@ -40,28 +40,22 @@ #ifndef _TTL_UTIL_H_ #define _TTL_UTIL_H_ - #include #include - #ifdef _MSC_VER # if _MSC_VER < 1300 # include # endif #endif - -//using namespace std; - - /** \brief Utilities * -* This name space contains utility functions for TTL.\n +* This name saPAce contains utility functions for TTL.\n * * Point and vector algebra such as scalar product and cross product * between vectors are implemented here. -* These functions are required by functions in the \ref ttl namespace, +* These functions are required by functions in the \ref ttl namesaPAce, * where they are assumed to be present in the \ref hed::TTLtraits "TTLtraits" class. * Thus, the user can call these functions from the traits class. * For efficiency reasons, the user may consider implementing these @@ -77,67 +71,59 @@ * ttl and \ref api * * \author -* Øyvind Hjelle, oyvindhj@ifi.uio.no +* �yvind Hjelle, oyvindhj@ifi.uio.no */ +namespace ttl_util +{ +/** @name Computational geometry */ +//@{ +/** Scalar product between two 2D vectors. + * + * \aPAr Returns: + * \code + * aDX1*aDX2 + aDY1*aDY2 + * \endcode + */ +template +REAL_TYPE ScalarProduct2D( REAL_TYPE aDX1, REAL_TYPE aDY1, REAL_TYPE aDX2, REAL_TYPE aDY2 ) +{ + return aDX1 * aDX2 + aDY1 * aDY2; +} -namespace ttl_util { +/** Cross product between two 2D vectors. (The z-component of the actual cross product.) + * + * \aPAr Returns: + * \code + * aDX1*aDY2 - aDY1*aDX2 + * \endcode + */ +template +REAL_TYPE CrossProduct2D( REAL_TYPE aDX1, REAL_TYPE aDY1, REAL_TYPE aDX2, REAL_TYPE aDY2 ) +{ + return aDX1 * aDY2 - aDY1 * aDX2; +} +/** Returns a positive value if the 2D nodes/points \e aPA, \e aPB, and + * \e aPC occur in counterclockwise order; a negative value if they occur + * in clockwise order; and zero if they are collinear. + * + * \note + * - This is a finite arithmetic fast version. It can be made more robust using + * exact arithmetic schemes by Jonathan Richard Shewchuk. See + * http://www-2.cs.cmu.edu/~quake/robust.html + */ +template +REAL_TYPE Orient2DFast( REAL_TYPE aPA[2], REAL_TYPE aPB[2], REAL_TYPE aPC[2] ) +{ + REAL_TYPE acx = aPA[0] - aPC[0]; + REAL_TYPE bcx = aPB[0] - aPC[0]; + REAL_TYPE acy = aPA[1] - aPC[1]; + REAL_TYPE bcy = aPB[1] - aPC[1]; - //------------------------------------------------------------------------------------------------ - // ------------------------------ Computational Geometry Group ---------------------------------- - //------------------------------------------------------------------------------------------------ - - /** @name Computational geometry */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Scalar product between two 2D vectors. - * - * \par Returns: - * \code - * dx1*dx2 + dy1*dy2 - * \endcode - */ - template - real_type scalarProduct2d(real_type dx1, real_type dy1, real_type dx2, real_type dy2) { - return dx1*dx2 + dy1*dy2; - } - - - //------------------------------------------------------------------------------------------------ - /** Cross product between two 2D vectors. (The z-component of the actual cross product.) - * - * \par Returns: - * \code - * dx1*dy2 - dy1*dx2 - * \endcode - */ - template - real_type crossProduct2d(real_type dx1, real_type dy1, real_type dx2, real_type dy2) { - return dx1*dy2 - dy1*dx2; - } - - - //------------------------------------------------------------------------------------------------ - /** Returns a positive value if the 2D nodes/points \e pa, \e pb, and - * \e pc occur in counterclockwise order; a negative value if they occur - * in clockwise order; and zero if they are collinear. - * - * \note - * - This is a finite arithmetic fast version. It can be made more robust using - * exact arithmetic schemes by Jonathan Richard Shewchuk. See - * http://www-2.cs.cmu.edu/~quake/robust.html - */ - template - real_type orient2dfast(real_type pa[2], real_type pb[2], real_type pc[2]) { - real_type acx = pa[0] - pc[0]; - real_type bcx = pb[0] - pc[0]; - real_type acy = pa[1] - pc[1]; - real_type bcy = pb[1] - pc[1]; return acx * bcy - acy * bcx; - } +} -}; // End of ttl_util namespace scope +} // namespace ttl_util #endif // _TTL_UTIL_H_ diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index b2bc4d5899..f74a412479 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -68,7 +68,7 @@ bool sortDistance( const RN_NODE_PTR& aOrigin, const RN_NODE_PTR& aNode1, bool sortWeight( const RN_EDGE_PTR& aEdge1, const RN_EDGE_PTR& aEdge2 ) { - return aEdge1->getWeight() < aEdge2->getWeight(); + return aEdge1->GetWeight() < aEdge2->GetWeight(); } @@ -92,7 +92,7 @@ bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ) bool isEdgeConnectingNode( const RN_EDGE_PTR& aEdge, const RN_NODE_PTR& aNode ) { - return aEdge->getSourceNode() == aNode || aEdge->getTargetNode() == aNode; + return aEdge->GetSourceNode() == aNode || aEdge->GetTargetNode() == aNode; } @@ -125,8 +125,8 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, { RN_EDGE_PTR& dt = *aEdges.begin(); - int srcTag = tags[dt->getSourceNode()]; - int trgTag = tags[dt->getTargetNode()]; + int srcTag = tags[dt->GetSourceNode()]; + int trgTag = tags[dt->GetTargetNode()]; // Check if by adding this edge we are going to join two different forests if( srcTag != trgTag ) @@ -139,7 +139,7 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, // Move nodes that were marked with old tag to the list marked with the new tag cycles[srcTag].splice( cycles[srcTag].end(), cycles[trgTag] ); - if( dt->getWeight() == 0 ) // Skip already existing connections (weight == 0) + if( dt->GetWeight() == 0 ) // Skip already existing connections (weight == 0) { mstExpectedSize--; } @@ -148,9 +148,9 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, // Do a copy of edge, but make it RN_EDGE_MST. In contrary to RN_EDGE, // RN_EDGE_MST saves both source and target node and does not require any other // edges to exist for getting source/target nodes - RN_EDGE_MST_PTR newEdge = boost::make_shared( dt->getSourceNode(), - dt->getTargetNode(), - dt->getWeight() ); + RN_EDGE_MST_PTR newEdge = boost::make_shared( dt->GetSourceNode(), + dt->GetTargetNode(), + dt->GetWeight() ); mst->push_back( newEdge ); ++mstSize; } @@ -169,8 +169,8 @@ std::vector* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges, void RN_NET::validateEdge( RN_EDGE_PTR& aEdge ) { - RN_NODE_PTR source = aEdge->getSourceNode(); - RN_NODE_PTR target = aEdge->getTargetNode(); + RN_NODE_PTR source = aEdge->GetSourceNode(); + RN_NODE_PTR target = aEdge->GetTargetNode(); bool valid = true; // If any of nodes belonging to the edge has the flag set, @@ -280,13 +280,13 @@ void RN_NET::compute() std::partial_sort_copy( boardNodes.begin(), boardNodes.end(), nodes.begin(), nodes.end() ); TRIANGULATOR triangulator; - triangulator.createDelaunay( nodes.begin(), nodes.end() ); - boost::scoped_ptr triangEdges( triangulator.getEdges() ); + triangulator.CreateDelaunay( nodes.begin(), nodes.end() ); + boost::scoped_ptr triangEdges( triangulator.GetEdges() ); // Compute weight/distance for edges resulting from triangulation RN_LINKS::RN_EDGE_LIST::iterator eit, eitEnd; for( eit = (*triangEdges).begin(), eitEnd = (*triangEdges).end(); eit != eitEnd; ++eit ) - (*eit)->setWeight( getDistance( (*eit)->getSourceNode(), (*eit)->getTargetNode() ) ); + (*eit)->SetWeight( getDistance( (*eit)->GetSourceNode(), (*eit)->GetTargetNode() ) ); // Add the currently existing connections list to the results of triangulation std::copy( boardEdges.begin(), boardEdges.end(), std::front_inserter( *triangEdges ) ); @@ -508,8 +508,8 @@ void RN_NET::RemoveItem( const TRACK* aTrack ) RN_EDGE_PTR& edge = m_tracks.at( aTrack ); // Save nodes, so they can be cleared later - RN_NODE_PTR aBegin = edge->getSourceNode(); - RN_NODE_PTR aEnd = edge->getTargetNode(); + RN_NODE_PTR aBegin = edge->GetSourceNode(); + RN_NODE_PTR aEnd = edge->GetTargetNode(); m_links.RemoveConnection( edge ); // Remove nodes associated with the edge. It is done in a safe way, there is a check @@ -696,8 +696,8 @@ std::list RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) con const TRACK* track = static_cast( aItem ); RN_EDGE_PTR edge = m_tracks.at( track ); - nodes.push_back( edge->getSourceNode() ); - nodes.push_back( edge->getTargetNode() ); + nodes.push_back( edge->GetSourceNode() ); + nodes.push_back( edge->GetTargetNode() ); } break; diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 712909f2fa..afc9c0935f 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -50,13 +50,13 @@ class ZONE_CONTAINER; class CPolyPt; // Preserve KiCad coding style policy -typedef hed::Node RN_NODE; -typedef hed::NodePtr RN_NODE_PTR; -typedef hed::Edge RN_EDGE; -typedef hed::EdgePtr RN_EDGE_PTR; -typedef hed::EdgeMST RN_EDGE_MST; -typedef boost::shared_ptr RN_EDGE_MST_PTR; -typedef hed::Triangulation TRIANGULATOR; +typedef hed::NODE RN_NODE; +typedef hed::NODE_PTR RN_NODE_PTR; +typedef hed::EDGE RN_EDGE; +typedef hed::EDGE_PTR RN_EDGE_PTR; +typedef hed::EDGE_MST RN_EDGE_MST; +typedef hed::TRIANGULATION TRIANGULATOR; +typedef boost::shared_ptr RN_EDGE_MST_PTR; bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 5de2527111..ffe88c3c7f 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -97,8 +97,8 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const BOOST_FOREACH( const RN_EDGE_PTR& edge, *edges ) { - const RN_NODE_PTR& sourceNode = edge->getSourceNode(); - const RN_NODE_PTR& targetNode = edge->getTargetNode(); + const RN_NODE_PTR& sourceNode = edge->GetSourceNode(); + const RN_NODE_PTR& targetNode = edge->GetTargetNode(); VECTOR2D source( sourceNode->GetX(), sourceNode->GetY() ); VECTOR2D target( targetNode->GetX(), targetNode->GetY() );