Main interface to TTL. More...
Functions | |
Delaunay Triangulation | |
template<class TraitsType , class DartType , class PointType > | |
bool | insertNode (DartType &dart, PointType &point) |
Inserts a new node in an existing Delaunay triangulation and swaps edges to obtain a new Delaunay triangulation. | |
template<class TraitsType , class DartType > | |
void | removeRectangularBoundary (DartType &dart) |
Removes the rectangular boundary of a triangulation as a final step of an incremental Delaunay triangulation. | |
template<class TraitsType , class DartType > | |
void | removeNode (DartType &dart) |
Removes the node associated with dart and updates the triangulation to be Delaunay. | |
template<class TraitsType , class DartType > | |
void | removeBoundaryNode (DartType &dart) |
Removes the boundary node associated with dart and updates the triangulation to be Delaunay. | |
template<class TraitsType , class DartType > | |
void | removeInteriorNode (DartType &dart) |
Removes the interior node associated with dart and updates the triangulation to be Delaunay. | |
template<class TraitsType , class ForwardIterator , class DartType > | |
void | insertNodes (ForwardIterator first, ForwardIterator last, DartType &dart) |
Topological and Geometric Queries | |
template<class TraitsType , class PointType , class DartType > | |
bool | locateFaceSimplest (const PointType &point, DartType &dart) |
Locates the face containing a given point. | |
template<class TraitsType , class PointType , class DartType > | |
bool | locateTriangle (const PointType &point, DartType &dart) |
Locates the triangle containing a given point. | |
template<class TraitsType , class PointType , class DartType > | |
bool | inTriangleSimplest (const PointType &point, const DartType &dart) |
Checks if point is inside the triangle associated with dart. | |
template<class TraitsType , class PointType , class DartType > | |
bool | inTriangle (const PointType &point, const DartType &dart) |
Checks if point is inside the triangle associated with dart. | |
template<class DartType , class DartListType > | |
void | 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. | |
template<class DartType > | |
bool | isBoundaryEdge (const DartType &dart) |
Checks if the edge associated with dart is at the boundary of the triangulation. | |
template<class DartType > | |
bool | isBoundaryFace (const DartType &dart) |
Checks if the face associated with dart is at the boundary of the triangulation. | |
template<class DartType > | |
bool | isBoundaryNode (const DartType &dart) |
Checks if the node associated with dart is at the boundary of the triangulation. | |
template<class DartType > | |
int | getDegreeOfNode (const DartType &dart) |
Returns the degree of the node associated with dart. | |
template<class DartType , class DartListType > | |
void | get_0_orbit_interior (const DartType &dart, DartListType &orbit) |
Gets the 0-orbit around an interior node. | |
template<class DartType , class DartListType > | |
void | get_0_orbit_boundary (const DartType &dart, DartListType &orbit) |
Gets the 0-orbit around a node at the boundary. | |
template<class DartType > | |
bool | 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. | |
template<class DartType > | |
bool | 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. | |
template<class DartType > | |
bool | 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. | |
template<class TraitsType , class DartType > | |
bool | swappableEdge (const DartType &dart, bool allowDegeneracy) |
Checks if the edge associated with dart is swappable, i.e., if the edge is a diagonal in a strictly convex (or convex) quadrilateral. | |
template<class DartType > | |
void | positionAtNextBoundaryEdge (DartType &dart) |
Given a dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation. | |
template<class TraitsType , class DartType > | |
bool | convexBoundary (const DartType &dart) |
Checks if the boundary of a triangulation is convex. | |
template<class TopologyElementType , class DartType > | |
bool | isMemberOfFace (const TopologyElementType &topologyElement, const DartType &dart) |
template<class TraitsType , class NodeType , class DartType > | |
bool | locateFaceWithNode (const NodeType &node, DartType &dart_iter) |
template<class DartType > | |
void | getAdjacentTriangles (const DartType &dart, DartType &t1, DartType &t2, DartType &t3) |
template<class DartType > | |
void | getNeighborNodes (const DartType &dart, list< DartType > &node_list, bool &boundary) |
template<class TraitsType , class DartType > | |
bool | degenerateTriangle (const DartType &dart) |
Utilities for Delaunay Triangulation | |
template<class TraitsType , class DartType , class DartListType > | |
void | optimizeDelaunay (DartListType &elist) |
Optimizes the edges in the given sequence according to the Delaunay criterion, i.e., such that the edge will fullfill the circumcircle criterion (or equivalently the MaxMin angle criterion) with respect to the quadrilaterals where they are diagonals. | |
template<class TraitsType , class DartType , class DartListType > | |
void | optimizeDelaunay (DartListType &elist, const typename DartListType::iterator end) |
template<class TraitsType , class DartType > | |
bool | swapTestDelaunay (const DartType &dart, bool cycling_check) |
Checks if the edge associated with dart should be swapped according to the Delaunay criterion, i.e., the circumcircle criterion (or equivalently the MaxMin angle criterion). | |
template<class TraitsType , class DartType > | |
void | recSwapDelaunay (DartType &diagonal) |
Recursively swaps edges in the triangulation according to the Delaunay criterion. | |
template<class TraitsType , class DartType , class ListType > | |
void | swapEdgesAwayFromInteriorNode (DartType &dart, ListType &swapped_edges) |
Swaps edges away from the (interior) node associated with dart such that that exactly three edges remain incident with the node. | |
template<class TraitsType , class DartType , class ListType > | |
void | swapEdgesAwayFromBoundaryNode (DartType &dart, ListType &swapped_edges) |
Swaps edges away from the (boundary) node associated with dart in such a way that when removing the edges that remain incident with the node, the boundary of the triangulation will be convex. | |
template<class TraitsType , class DartType , class DartListType > | |
void | swapEdgeInList (const typename DartListType::iterator &it, DartListType &elist) |
Swap the the edge associated with iterator it and update affected darts in elist accordingly. | |
Constrained (Delaunay) Triangulation | |
template<class TraitsType , class DartType > | |
DartType | insertConstraint (DartType &dstart, DartType &dend, bool optimize_delaunay) |
Inserts a constrained edge between two existing nodes in a triangulation. |
Main interface to TTL.
This namespace contains the basic generic algorithms for the TTL, the Triangulation Template Library.
Examples of functionality are:
bool ttl::convexBoundary | ( | const DartType & | dart | ) | [inline] |
Checks if the boundary of a triangulation is convex.
dart | A CCW dart at the boundary of the triangulation |
Definition at line 1355 of file ttl.h.
References ttl_util::crossProduct2d(), and getBoundary().
01355 { 01356 01357 list<DartType> blist; 01358 ttl::getBoundary(dart, blist); 01359 01360 int no; 01361 no = blist.size(); 01362 typename list<DartType>::const_iterator bit = blist.begin(); 01363 DartType d1 = *bit; 01364 ++bit; 01365 DartType d2; 01366 bool convex = true; 01367 for (; bit != blist.end(); ++bit) { 01368 d2 = *bit; 01369 double crossProd = TraitsType::crossProduct2d(d1, d2); 01370 if (crossProd < 0.0) { 01371 //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; 01372 convex = false; 01373 return convex; 01374 } 01375 d1 = d2; 01376 } 01377 01378 // Check the last angle 01379 d2 = *blist.begin(); 01380 double crossProd = TraitsType::crossProduct2d(d1, d2); 01381 if (crossProd < 0.0) { 01382 //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl; 01383 convex = false; 01384 } 01385 01386 //if (convex) 01387 // cout << "\n---> Boundary is convex\n" << endl; 01388 //cout << endl; 01389 return convex; 01390 }
bool ttl::degenerateTriangle | ( | const DartType & | dart | ) | [inline] |
Definition at line 1249 of file ttl.h.
References ttl_util::crossProduct2d().
01249 { 01250 01251 // Check if triangle is degenerate 01252 // Assumes CCW dart 01253 01254 DartType d1 = dart; 01255 DartType d2 = d1; 01256 d2.alpha1(); 01257 if (TraitsType::crossProduct2d(d1,d2) == 0) 01258 return true; 01259 01260 return false; 01261 }
void ttl::get_0_orbit_boundary | ( | const DartType & | dart, | |
DartListType & | orbit | |||
) | [inline] |
Gets the 0-orbit around a node at the boundary.
dart | A dart (CCW or CW) positioned at a boundary node and at a boundary edge. |
orbit | Sequence of darts with one orbit for each arc. All the darts, exept the last one, have the same orientation (CCW or CW) as dart, and dart is the first element in the sequence. |
Definition at line 1158 of file ttl.h.
01158 { 01159 01160 DartType dart_prev; 01161 DartType d_iter = dart; 01162 do { 01163 orbit.push_back(d_iter); 01164 d_iter.alpha1(); 01165 dart_prev = d_iter; 01166 d_iter.alpha2(); 01167 } while (d_iter != dart_prev); 01168 01169 orbit.push_back(d_iter); // the last one with opposite orientation 01170 }
void ttl::get_0_orbit_interior | ( | const DartType & | dart, | |
DartListType & | orbit | |||
) | [inline] |
Gets the 0-orbit around an interior node.
dart | A dart (CCW or CW) positioned at an interior node. |
orbit | Sequence of darts with one orbit for each arc. All the darts have the same orientation (CCW or CW) as dart, and dart is the first element in the sequence. |
void ttl::getAdjacentTriangles | ( | const DartType & | dart, | |
DartType & | t1, | |||
DartType & | t2, | |||
DartType & | t3 | |||
) | [inline] |
Definition at line 831 of file ttl.h.
00831 { 00832 00833 DartType dart_iter = dart; 00834 00835 // add first 00836 if (dart_iter.alpha2() != dart) { 00837 t1 = dart_iter; 00838 dart_iter = dart; 00839 } 00840 00841 // add second 00842 dart_iter.alpha0(); 00843 dart_iter.alpha1(); 00844 DartType dart_prev = dart_iter; 00845 if ((dart_iter.alpha2()) != dart_prev) { 00846 t2 = dart_iter; 00847 dart_iter = dart_prev; 00848 } 00849 00850 // add third 00851 dart_iter.alpha0(); 00852 dart_iter.alpha1(); 00853 dart_prev = dart_iter; 00854 if ((dart_iter.alpha2()) != dart_prev) 00855 t3 = dart_iter; 00856 }
void ttl::getBoundary | ( | const DartType & | dart, | |
DartListType & | boundary | |||
) | [inline] |
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.
dart | A dart at the boundary (CCW or CW) | |
boundary | A sequence of darts, where the associated edges are the boundary edges |
Definition at line 876 of file ttl.h.
References positionAtNextBoundaryEdge().
Referenced by convexBoundary().
00876 { 00877 // assumes the given dart is at the boundary (by edge) 00878 00879 DartType dart_iter(dart); 00880 boundary.push_back(dart_iter); // Given dart as first element 00881 dart_iter.alpha0(); 00882 positionAtNextBoundaryEdge(dart_iter); 00883 00884 while (dart_iter != dart) { 00885 boundary.push_back(dart_iter); 00886 dart_iter.alpha0(); 00887 positionAtNextBoundaryEdge(dart_iter); 00888 } 00889 }
int ttl::getDegreeOfNode | ( | const DartType & | dart | ) | [inline] |
Returns the degree of the node associated with dart.
Definition at line 999 of file ttl.h.
Referenced by swapEdgesAwayFromInteriorNode().
00999 { 01000 01001 DartType dart_iter(dart); 01002 DartType dart_prev; 01003 01004 // If input dart is reached again, then interior node 01005 // If alpha2(d)=d, then boundary 01006 01007 int degree = 0; 01008 bool boundaryVisited = false; 01009 do { 01010 dart_iter.alpha1(); 01011 degree++; 01012 dart_prev = dart_iter; 01013 01014 dart_iter.alpha2(); 01015 01016 if (dart_iter == dart_prev) { 01017 if (!boundaryVisited) { 01018 boundaryVisited = true; 01019 // boundary is reached first time, count in the reversed direction 01020 degree++; // count the start since it is not done above 01021 dart_iter = dart; 01022 dart_iter.alpha2(); 01023 } 01024 else 01025 return degree; 01026 } 01027 01028 } while (dart_iter != dart); 01029 01030 return degree; 01031 }
void ttl::getNeighborNodes | ( | const DartType & | dart, | |
list< DartType > & | node_list, | |||
bool & | boundary | |||
) | [inline] |
Definition at line 1059 of file ttl.h.
01059 { 01060 01061 DartType dart_iter(dart); 01062 01063 dart_iter.alpha0(); // position the dart at an opposite node 01064 01065 DartType dart_prev = dart_iter; 01066 01067 bool start_at_boundary = false; 01068 dart_iter.alpha2(); 01069 if (dart_iter == dart_prev) 01070 start_at_boundary = true; 01071 else 01072 dart_iter = dart_prev; // back again 01073 01074 DartType dart_start = dart_iter; 01075 01076 do { 01077 node_list.push_back(dart_iter); 01078 dart_iter.alpha1(); 01079 dart_iter.alpha0(); 01080 dart_iter.alpha1(); 01081 dart_prev = dart_iter; 01082 dart_iter.alpha2(); 01083 if (dart_iter == dart_prev) { 01084 // boundary reached 01085 boundary = true; 01086 if (start_at_boundary == true) { 01087 // add the dart which now is positioned at the opposite boundary 01088 node_list.push_back(dart_iter); 01089 return; 01090 } 01091 else { 01092 // call the function again such that we start at the boundary 01093 // first clear the list and reposition to the initial node 01094 dart_iter.alpha0(); 01095 node_list.clear(); 01096 getNeighborNodes(dart_iter, node_list, boundary); 01097 return; // after one recursive step 01098 } 01099 } 01100 } while (dart_iter != dart_start); 01101 01102 boundary = false; 01103 }
DartType ttl::insertConstraint | ( | DartType & | dstart, | |
DartType & | dend, | |||
bool | optimize_delaunay | |||
) | [inline] |
Inserts a constrained edge between two existing nodes in a triangulation.
If the constraint falls on one or more existing nodes and this is detected by the predicate TraitsType::orient2d
, which should return zero in this case, the constraint is split. Otherwise a degenerate triangle will be made along the constraint.
dstart | A CCW dart with the start node of the constraint as the source node | |
dend | A CCW dart with the end node of the constraint as the source node | |
optimize_delaunay | If set to true , the resulting triangulation will be a constrained Delaunay triangulation. If set to false , the resulting triangulation will not necessarily be of constrained Delaunay type. |
DartType | A dart representing the constrained edge. |
true
Definition at line 543 of file ttl_constr.h.
References same_0_orbit().
00543 { 00544 00545 // Assumes: 00546 // - It is the users responsibility to avoid crossing constraints 00547 // - The constraint cannot cross the boundary, i.e., the boundary must be 00548 // convex in the area of crossing edges. 00549 // - dtart and dend are preserved (same node associated.) 00550 00551 00552 // Find edges crossing the constraint and put them in elist. 00553 // If findCrossingEdges reaches a Node lying on the constraint, this function 00554 // calls itself recursively. 00555 00556 // RECURSION 00557 list<DartType> elist; 00558 DartType next_start = ttl_constr::findCrossingEdges<TraitsType>(dstart, dend, elist); 00559 00560 // If there are no crossing edges (elist is empty), we assume that the constraint 00561 // is an existing edge. 00562 // In this case, findCrossingEdges returns the constraint. 00563 // Put the constraint in the list to fit with the procedures below 00564 // (elist can also be empty in the case of invalid input data (the constraint is in 00565 // a non-convex area) but this is the users responsibility.) 00566 00567 //by Thomas Sevaldrud if (elist.size() == 0) 00568 //by Thomas Sevaldrud elist.push_back(next_start); 00569 00570 // findCrossingEdges stops if it finds a node lying on the constraint. 00571 // A dart with this node as start node is returned 00572 // We call insertConstraint recursivly until the received dart is dend 00573 if (!ttl::same_0_orbit(next_start, dend)) { 00574 00575 #ifdef DEBUG_TTL_CONSTR_PLOT 00576 cout << "RECURSION due to collinearity along constraint" << endl; 00577 #endif 00578 00579 insertConstraint<TraitsType,DartType>(next_start, dend, optimize_delaunay); 00580 } 00581 00582 // Swap edges such that the constraint edge is present in the transformed triangulation. 00583 if (elist.size() > 0) // by Thomas Sevaldrud 00584 ttl_constr::transformToConstraint<TraitsType>(dstart, next_start, elist); 00585 00586 #ifdef DEBUG_TTL_CONSTR_PLOT 00587 cout << "size of elist = " << elist.size() << endl; 00588 if (elist.size() > 0) { 00589 DartType the_constraint = elist.back(); 00590 ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl; 00591 the_constraint.alpha0(); 00592 ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl << endl; 00593 } 00594 #endif 00595 00596 // Optimize to constrained Delaunay triangulation if required. 00597 typename list<DartType>::iterator end_opt = elist.end(); 00598 if (optimize_delaunay) { 00599 00600 // Indicate that the constrained edge, which is the last element in the list, 00601 // should not be swapped 00602 --end_opt; 00603 ttl::optimizeDelaunay<TraitsType, DartType>(elist, end_opt); 00604 } 00605 00606 if(elist.size() == 0) // by Thomas Sevaldrud 00607 return next_start; // by Thomas Sevaldrud 00608 00609 // Return the constraint, which is still the last element in the list 00610 end_opt = elist.end(); 00611 --end_opt; 00612 return *end_opt; 00613 }
bool ttl::insertNode | ( | DartType & | dart, | |
PointType & | point | |||
) | [inline] |
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 insertNode
has been called repeatedly with all the points, ttl::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 x and y.
dart | An arbitrary CCW dart in the tringulation. Output: A CCW dart incident to the new node. | |
point | A point (node) to be inserted in the triangulation. |
bool | true if point was inserted; false if not.If point is outside the triangulation, or the input dart is not valid, false is returned. |
Definition at line 268 of file ttl.h.
References isBoundaryEdge().
00268 { 00269 00270 bool found = ttl::locateTriangle<TraitsType>(point, dart); 00271 if (!found) { 00272 #ifdef DEBUG_TTL 00273 cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; 00274 #endif 00275 return false; 00276 } 00277 00278 // ??? can we hide the dart? this is not possible if one triangle only 00279 TraitsType::splitTriangle(dart, point); 00280 00281 DartType d1 = dart; 00282 d1.alpha2().alpha1().alpha2().alpha0().alpha1(); 00283 00284 DartType d2 = dart; 00285 d2.alpha1().alpha0().alpha1(); 00286 00287 // Preserve a dart as output incident to the node and CCW 00288 DartType d3 = dart; 00289 d3.alpha2(); 00290 dart = d3; // and see below 00291 //DartType dsav = d3; 00292 d3.alpha0().alpha1(); 00293 00294 //if (!TraitsType::fixedEdge(d1) && !ttl::isBoundaryEdge(d1)) { 00295 if (!ttl::isBoundaryEdge(d1)) { 00296 d1.alpha2(); 00297 recSwapDelaunay<TraitsType>(d1); 00298 } 00299 00300 //if (!TraitsType::fixedEdge(d2) && !ttl::isBoundaryEdge(d2)) { 00301 if (!ttl::isBoundaryEdge(d2)) { 00302 d2.alpha2(); 00303 recSwapDelaunay<TraitsType>(d2); 00304 } 00305 00306 // Preserve the incoming dart as output incident to the node and CCW 00307 //d = dsav.alpha2(); 00308 dart.alpha2(); 00309 //if (!TraitsType::fixedEdge(d3) && !ttl::isBoundaryEdge(d3)) { 00310 if (!ttl::isBoundaryEdge(d3)) { 00311 d3.alpha2(); 00312 recSwapDelaunay<TraitsType>(d3); 00313 } 00314 00315 return true; 00316 }
void ttl::insertNodes | ( | ForwardIterator | first, | |
ForwardIterator | last, | |||
DartType & | dart | |||
) | [inline] |
bool ttl::inTriangle | ( | const PointType & | point, | |
const DartType & | dart | |||
) | [inline] |
Checks if point is inside the triangle associated with dart.
This function deals with degeneracy to some extent, but round-off errors may still lead to wrong result if the triangle is degenerate.
dart | A CCW dart in the triangle |
Definition at line 750 of file ttl.h.
References ttl_util::crossProduct2d(), and ttl_util::scalarProduct2d().
00750 { 00751 00752 // SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT 00753 // ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH 00754 // notInE1 && notInE1.neghbour ? 00755 00756 00757 // Returns true if inside (but not necessarily strictly inside) 00758 // Works for degenerate triangles, but not when all edges are degenerate, 00759 // and the point coincides with all nodes; 00760 // then false is always returned. 00761 00762 typedef typename TraitsType::real_type real_type; 00763 00764 DartType dart_iter = dart; 00765 00766 real_type cr1 = TraitsType::crossProduct2d(dart_iter, point); 00767 if (cr1 < 0) 00768 return false; 00769 00770 dart_iter.alpha0().alpha1(); 00771 real_type cr2 = TraitsType::crossProduct2d(dart_iter, point); 00772 00773 if (cr2 < 0) 00774 return false; 00775 00776 dart_iter.alpha0().alpha1(); 00777 real_type cr3 = TraitsType::crossProduct2d(dart_iter, point); 00778 if (cr3 < 0) 00779 return false; 00780 00781 // All cross products are >= 0 00782 // Check for degeneracy 00783 00784 if (cr1 != 0 || cr2 != 0 || cr3 != 0) 00785 return true; // inside non-degenerate face 00786 00787 // All cross-products are zero, i.e. degenerate triangle, check if inside 00788 // Strategy: d.scalarProduct2d >= 0 && alpha0(d).d.scalarProduct2d >= 0 for one of 00789 // the edges. But if all edges are degenerate and the point is on (all) the nodes, 00790 // then "false is returned". 00791 00792 DartType dart_tmp = dart_iter; 00793 real_type sc1 = TraitsType::scalarProduct2d(dart_tmp,point); 00794 real_type sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(), point); 00795 00796 if (sc1 >= 0 && sc2 >= 0) { 00797 // test for degenerate edge 00798 if (sc1 != 0 || sc2 != 0) 00799 return true; // interior to this edge or on a node (but see comment above) 00800 } 00801 00802 dart_tmp = dart_iter.alpha0().alpha1(); 00803 sc1 = TraitsType::scalarProduct2d(dart_tmp,point); 00804 sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); 00805 if (sc1 >= 0 && sc2 >= 0) { 00806 // test for degenerate edge 00807 if (sc1 != 0 || sc2 != 0) 00808 return true; // interior to this edge or on a node (but see comment above) 00809 } 00810 00811 dart_tmp = dart_iter.alpha1(); 00812 sc1 = TraitsType::scalarProduct2d(dart_tmp,point); 00813 sc2 = TraitsType::scalarProduct2d(dart_tmp.alpha0(),point); 00814 if (sc1 >= 0 && sc2 >= 0) { 00815 // test for degenerate edge 00816 if (sc1 != 0 || sc2 != 0) 00817 return true; // interior to this edge or on a node (but see comment above) 00818 } 00819 00820 // Not on any of the edges of the degenerate triangle. 00821 // The only possibility for the point to be "inside" is that all edges are degenerate 00822 // and the point coincide with all nodes. So false is returned in this case. 00823 00824 return false; 00825 }
bool ttl::inTriangleSimplest | ( | const PointType & | point, | |
const DartType & | dart | |||
) | [inline] |
Checks if point is inside the triangle associated with dart.
A fast and simple function that does not deal with degeneracy.
dart | A CCW dart in the triangle |
Definition at line 706 of file ttl.h.
00706 { 00707 00708 // Fast and simple: Do not deal with degenerate faces, i.e., if there is 00709 // degeneracy, true will be returned if the point is on the extension of the 00710 // edges of a degenerate triangle 00711 00712 DartType d_iter = dart; 00713 DartType d0 = d_iter; 00714 d0.alpha0(); 00715 if (!TraitsType::orient2d(d_iter, d0, point) >= 0) 00716 return false; 00717 00718 d_iter.alpha0().alpha1(); 00719 d0 = d_iter; 00720 d0.alpha0(); 00721 if (!TraitsType::orient2d(d_iter, d0, point) >= 0) 00722 return false; 00723 00724 d_iter.alpha0().alpha1(); 00725 d0 = d_iter; 00726 d0.alpha0(); 00727 if (!TraitsType::orient2d(d_iter, d0, point) >= 0) 00728 return false; 00729 00730 return true; 00731 }
bool ttl::isBoundaryEdge | ( | const DartType & | dart | ) | [inline] |
Checks if the edge associated with dart is at the boundary of the triangulation.
DartType dart_iter = dart; if (dart_iter.alpha2() == dart) return true; else return false;
Definition at line 922 of file ttl.h.
Referenced by insertNode(), recSwapDelaunay(), removeBoundaryNode(), swapEdgesAwayFromBoundaryNode(), swappableEdge(), and swapTestDelaunay().
bool ttl::isBoundaryFace | ( | const DartType & | dart | ) | [inline] |
Checks if the face associated with dart is at the boundary of the triangulation.
Definition at line 937 of file ttl.h.
00937 { 00938 00939 // Strategy: boundary if alpha2(d)=d 00940 00941 DartType dart_iter(dart); 00942 DartType dart_prev; 00943 00944 do { 00945 dart_prev = dart_iter; 00946 00947 if (dart_iter.alpha2() == dart_prev) 00948 return true; 00949 else 00950 dart_iter = dart_prev; // back again 00951 00952 dart_iter.alpha0(); 00953 dart_iter.alpha1(); 00954 00955 } while (dart_iter != dart); 00956 00957 return false; 00958 }
bool ttl::isBoundaryNode | ( | const DartType & | dart | ) | [inline] |
Checks if the node associated with dart is at the boundary of the triangulation.
Definition at line 966 of file ttl.h.
Referenced by ttl_constr::getAtSmallestAngle(), removeNode(), and same_0_orbit().
00966 { 00967 00968 // Strategy: boundary if alpha2(d)=d 00969 00970 DartType dart_iter(dart); 00971 DartType dart_prev; 00972 00973 // If input dart is reached again, then internal node 00974 // If alpha2(d)=d, then boundary 00975 00976 do { 00977 dart_iter.alpha1(); 00978 dart_prev = dart_iter; 00979 dart_iter.alpha2(); 00980 00981 if (dart_iter == dart_prev) 00982 return true; 00983 00984 } while (dart_iter != dart); 00985 00986 return false; 00987 }
bool ttl::isMemberOfFace | ( | const TopologyElementType & | topologyElement, | |
const DartType & | dart | |||
) | [inline] |
Definition at line 517 of file ttl.h.
Referenced by locateFaceWithNode().
00517 { 00518 00519 // Check if the given topology element (node, edge or face) is a member of the face 00520 // Assumes: 00521 // - DartType::isMember(TopologyElementType) 00522 00523 DartType dart_iter = dart; 00524 do { 00525 if (dart_iter.isMember(topologyElement)) 00526 return true; 00527 dart_iter.alpha0().alpha1(); 00528 } while (dart_iter != dart); 00529 00530 return false; 00531 }
bool ttl::locateFaceSimplest | ( | const PointType & | point, | |
DartType & | dart | |||
) | [inline] |
Locates the face containing a given point.
It is assumed that the tessellation (e.g. a triangulation) is regular in the sense that there are no holes, the boundary is convex and there are no degenerate faces.
point | A point to be located | |
dart | An arbitrary CCW dart in the triangulation Output: A CCW dart in the located face |
bool | true if a face is found; false if not. |
false
is returned, point may still be inside a face if the tessellation is not regular as explained above.Definition at line 587 of file ttl.h.
00587 { 00588 // Not degenerate triangles if point is on the extension of the edges 00589 // But inTriangle may be called in case of true (may update to inFace2) 00590 // Convex boundary 00591 // no holes 00592 // convex faces (works for general convex faces) 00593 // Not specialized for triangles, but ok? 00594 // 00595 // TraitsType::orint2d(PointType) is the half open half-plane defined 00596 // by the dart: 00597 // n1 = dart.node() 00598 // n2 = dart.alpha0().node 00599 // Only the following gives true: 00600 // ((n2->x()-n1->x())*(point.y()-n1->y()) >= (point.x()-n1->x())*(n2->y()-n1->y())) 00601 00602 DartType dart_start; 00603 dart_start = dart; 00604 DartType dart_prev; 00605 00606 DartType d0; 00607 for (;;) { 00608 d0 = dart; 00609 d0.alpha0(); 00610 if (TraitsType::orient2d(dart, d0, point) >= 0) { 00611 dart.alpha0().alpha1(); 00612 if (dart == dart_start) 00613 return true; // left to all edges in face 00614 } 00615 else { 00616 dart_prev = dart; 00617 dart.alpha2(); 00618 if (dart == dart_prev) 00619 return false; // iteration to outside boundary 00620 00621 dart_start = dart; 00622 dart_start.alpha0(); 00623 00624 dart.alpha1(); // avoid twice on same edge and ccw in next 00625 } 00626 } 00627 }
bool ttl::locateFaceWithNode | ( | const NodeType & | node, | |
DartType & | dart_iter | |||
) | [inline] |
Definition at line 537 of file ttl.h.
References isMemberOfFace().
00537 { 00538 // Locate a face in the topology structure with the given node as a member 00539 // Assumes: 00540 // - TraitsType::orient2d(DartType, DartType, NodeType) 00541 // - DartType::isMember(NodeType) 00542 // - Note that if false is returned, the node might still be in the 00543 // topology structure. Application programmer 00544 // should check all if by hypothesis the node is in the topology structure; 00545 // see doc. on locateTriangle. 00546 00547 bool status = locateFaceSimplest<TraitsType>(node, dart_iter); 00548 if (status == false) 00549 return status; 00550 00551 // True was returned from locateFaceSimplest, but if the located triangle is 00552 // degenerate and the node is on the extension of the edges, 00553 // the node might still be inside. Check if node is a member and return false 00554 // if not. (Still the node might be in the topology structure, see doc. above 00555 // and in locateTriangle(const PointType& point, DartType& dart_iter) 00556 00557 return isMemberOfFace(node, dart_iter); 00558 }
bool ttl::locateTriangle | ( | const PointType & | point, | |
DartType & | dart | |||
) | [inline] |
Locates the triangle containing a given point.
It is assumed that the triangulation is 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.
point | A point to be located | |
dart | An arbitrary CCW dart in the triangulation Output: A CCW dart in the located triangle |
bool | true if a triangle is found; false if not.If point is outside the triangulation, in which case false is returned, then the edge associated with dart will be at the boundary of the triangulation. |
Definition at line 654 of file ttl.h.
00654 { 00655 // The purpose is to have a fast and stable procedure that 00656 // i) avoids concluding that a point is inside a triangle if it is not inside 00657 // ii) avoids infinite loops 00658 00659 // Thus, if false is returned, the point might still be inside a triangle in 00660 // the triangulation. But this will probably only occur in the following cases: 00661 // i) There are holes in the triangulation which causes the procedure to stop. 00662 // ii) The boundary of the triangulation is not convex. 00663 // ii) There might be degenerate triangles interior to the triangulation, or on the 00664 // the boundary, which in some cases might cause the procedure to stop there due 00665 // to the logic of the algorithm. 00666 00667 // It is the application programmer's responsibility to check further if false is 00668 // returned. For example, if by hypothesis the point is inside a triangle 00669 // in the triangulation and and false is returned, then all triangles in the 00670 // triangulation should be checked by the application. This can be done using 00671 // the function: 00672 // bool inTriangle(const PointType& point, const DartType& dart). 00673 00674 00675 // Assumes: 00676 // - crossProduct2d, scalarProduct2d etc., see functions called 00677 00678 bool status = locateFaceSimplest<TraitsType>(point, dart); 00679 if (status == false) 00680 return status; 00681 00682 // There may be degeneracy, i.e., the point might be outside the triangle 00683 // on the extension of the edges of a degenerate triangle. 00684 00685 // The next call returns true if inside a non-degenerate or a degenerate triangle, 00686 // but false if the point coincides with the "supernode" in the case where all 00687 // edges are degenerate. 00688 return inTriangle<TraitsType>(point, dart); 00689 }
void ttl::optimizeDelaunay | ( | DartListType & | elist, | |
const typename DartListType::iterator | end | |||
) | [inline] |
Definition at line 1428 of file ttl.h.
01428 { 01429 01430 // CCW darts 01431 // Optimize here means Delaunay, but could be any criterion by 01432 // requiring a "should swap" in the traits class, or give 01433 // a function object? 01434 // Assumes that elist has only one dart for each arc. 01435 // Darts outside the quadrilateral are preserved 01436 01437 // For some data structures it is possible to preserve 01438 // all darts when swapping. Thus a preserve_darts_when swapping 01439 // ccould be given to indicate this and we would gain performance by avoiding 01440 // find in list. 01441 01442 // Requires that swap retuns a dart in the "same position when rotated CCW" 01443 // (A vector instead of a list may be better.) 01444 01445 // First check that elist is not empty 01446 if (elist.empty()) 01447 return; 01448 01449 // Avoid cycling by more extensive circumcircle test 01450 bool cycling_check = true; 01451 bool optimal = false; 01452 typename DartListType::iterator it; 01453 01454 typename DartListType::iterator end_opt = end; 01455 01456 // Hmm... The following code is trying to derefence an iterator that may 01457 // be invalid. This may lead to debug error on Windows, so we comment out 01458 // this code. Checking elist.empty() above will prevent some 01459 // problems... 01460 // 01461 // last_opt is passed the end of the "active list" 01462 //typename DartListType::iterator end_opt; 01463 //if (*end != NULL) 01464 // end_opt = end; 01465 //else 01466 // end_opt = elist.end(); 01467 01468 while(!optimal) { 01469 optimal = true; 01470 for (it = elist.begin(); it != end_opt; ++it) { 01471 if (ttl::swapTestDelaunay<TraitsType>(*it, cycling_check)) { 01472 01473 // Preserve darts. Potential darts in the list are: 01474 // - The current dart 01475 // - the four CCW darts on the boundary of the quadrilateral 01476 // (the current arc has only one dart) 01477 01478 ttl::swapEdgeInList<TraitsType, DartType>(it, elist); 01479 01480 optimal = false; 01481 } // end if should swap 01482 } // end for 01483 } // end pass 01484 }
void ttl::optimizeDelaunay | ( | DartListType & | elist | ) | [inline] |
Optimizes the edges in the given sequence according to the Delaunay criterion, i.e., such that the edge will fullfill the circumcircle criterion (or equivalently the MaxMin angle criterion) with respect to the quadrilaterals where they are diagonals.
elist | The sequence of edges |
void ttl::positionAtNextBoundaryEdge | ( | DartType & | dart | ) | [inline] |
Given a dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation.
Position dart at a boundary edge in the same 0-orbit.
If the given dart is CCW, dart is positioned at the left boundary edge and will be CW.
If the given dart is CW, dart is positioned at the right boundary edge and will be CCW.
Definition at line 1330 of file ttl.h.
Referenced by ttl_constr::getAtSmallestAngle(), getBoundary(), removeBoundaryNode(), removeRectangularBoundary(), same_0_orbit(), and swapEdgesAwayFromBoundaryNode().
void ttl::recSwapDelaunay | ( | DartType & | diagonal | ) | [inline] |
Recursively swaps edges in the triangulation according to the Delaunay criterion.
diagonal | A CCW dart representing the edge where the recursion starts from. |
Definition at line 1617 of file ttl.h.
References isBoundaryEdge().
01617 { 01618 01619 if (!ttl::swapTestDelaunay<TraitsType>(diagonal)) 01620 // ??? ttl::swapTestDelaunay also checks if boundary, so this can be optimized 01621 return; 01622 01623 // Get the other "edges" of the current triangle; see illustration above. 01624 DartType oppEdge1 = diagonal; 01625 oppEdge1.alpha1(); 01626 bool b1; 01627 if (ttl::isBoundaryEdge(oppEdge1)) 01628 b1 = true; 01629 else { 01630 b1 = false; 01631 oppEdge1.alpha2(); 01632 } 01633 01634 01635 DartType oppEdge2 = diagonal; 01636 oppEdge2.alpha0().alpha1().alpha0(); 01637 bool b2; 01638 if (ttl::isBoundaryEdge(oppEdge2)) 01639 b2 = true; 01640 else { 01641 b2 = false; 01642 oppEdge2.alpha2(); 01643 } 01644 01645 // Swap the given diagonal 01646 TraitsType::swapEdge(diagonal); 01647 01648 if (!b1) 01649 recSwapDelaunay<TraitsType>(oppEdge1); 01650 if (!b2) 01651 recSwapDelaunay<TraitsType>(oppEdge2); 01652 }
void ttl::removeBoundaryNode | ( | DartType & | dart | ) | [inline] |
Removes the boundary node associated with dart and updates the triangulation to be Delaunay.
Definition at line 402 of file ttl.h.
References isBoundaryEdge(), and positionAtNextBoundaryEdge().
00402 { 00403 00404 // ... and update Delaunay 00405 // - CCW dart must be given (for remove) 00406 // - No dart is delivered back now (but this is possible if 00407 // we assume that there is not only one triangle left in the triangulation. 00408 00409 // Position at boundary edge and CCW 00410 if (!ttl::isBoundaryEdge(dart)) { 00411 dart.alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) 00412 ttl::positionAtNextBoundaryEdge(dart); 00413 } 00414 00415 list<DartType> swapped_edges; 00416 ttl::swapEdgesAwayFromBoundaryNode<TraitsType>(dart, swapped_edges); 00417 00418 // Remove boundary triangles and remove the new boundary from the list 00419 // of swapped edges, see below. 00420 DartType d_iter = dart; 00421 DartType dnext = dart; 00422 bool bend = false; 00423 while (bend == false) { 00424 dnext.alpha1().alpha2(); 00425 if (ttl::isBoundaryEdge(dnext)) 00426 bend = true; // Stop when boundary 00427 00428 // Generic: Also remove the new boundary from the list of swapped edges 00429 DartType n_bedge = d_iter; 00430 n_bedge.alpha1().alpha0().alpha1().alpha2(); // new boundary edge 00431 00432 // ??? can we avoid find if we do this in swap away? 00433 typename list<DartType>::iterator it; 00434 it = find(swapped_edges.begin(), swapped_edges.end(), n_bedge); 00435 00436 if (it != swapped_edges.end()) 00437 swapped_edges.erase(it); 00438 00439 // Remove the boundary triangle 00440 TraitsType::removeBoundaryTriangle(d_iter); 00441 d_iter = dnext; 00442 } 00443 00444 // Optimize Delaunay 00445 typedef list<DartType> DartListType; 00446 ttl::optimizeDelaunay<TraitsType, DartType, DartListType>(swapped_edges); 00447 }
void ttl::removeInteriorNode | ( | DartType & | dart | ) | [inline] |
Removes the interior node associated with dart and updates the triangulation to be Delaunay.
Definition at line 466 of file ttl.h.
00466 { 00467 00468 // ... and update to Delaunay. 00469 // Must allow degeneracy temporarily, see comments in swap edges away 00470 // Assumes: 00471 // - revese_splitTriangle does not affect darts 00472 // outside the resulting triangle. 00473 00474 // 1) Swaps edges away from the node until degree=3 (generic) 00475 // 2) Removes the remaining 3 triangles and creates a new to fill the hole 00476 // unsplitTriangle which is required 00477 // 3) Runs LOP on the platelet to obtain a Delaunay triangulation 00478 // (No dart is delivered as output) 00479 00480 // Assumes dart is counterclockwise 00481 00482 list<DartType> swapped_edges; 00483 ttl::swapEdgesAwayFromInteriorNode<TraitsType>(dart, swapped_edges); 00484 00485 // The reverse operation of split triangle: 00486 // Make one triangle of the three triangles at the node associated with dart 00487 // TraitsType:: 00488 TraitsType::reverse_splitTriangle(dart); 00489 00490 // ???? Not generic yet if we are very strict: 00491 // When calling unsplit triangle, darts at the three opposite sides may 00492 // change! 00493 // Should we hide them longer away??? This is possible since they cannot 00494 // be boundary edges. 00495 // ----> Or should we just require that they are not changed??? 00496 00497 // Make the swapped-away edges Delaunay. 00498 // Note the theoretical result: if there are no edges in the list, 00499 // the triangulation is Delaunay already 00500 00501 ttl::optimizeDelaunay<TraitsType, DartType>(swapped_edges); 00502 }
void ttl::removeNode | ( | DartType & | dart | ) | [inline] |
Removes the node associated with dart and updates the triangulation to be Delaunay.
Definition at line 381 of file ttl.h.
References isBoundaryNode().
00381 { 00382 00383 if (ttl::isBoundaryNode(dart)) 00384 ttl::removeBoundaryNode<TraitsType>(dart); 00385 else 00386 ttl::removeInteriorNode<TraitsType>(dart); 00387 }
void ttl::removeRectangularBoundary | ( | DartType & | dart | ) | [inline] |
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.
dart | A CCW dart at the boundary of the triangulation Output: A CCW dart at the new boundary |
Definition at line 352 of file ttl.h.
References positionAtNextBoundaryEdge().
00352 { 00353 00354 DartType d_next = dart; 00355 DartType d_iter; 00356 00357 for (int i = 0; i < 4; i++) { 00358 d_iter = d_next; 00359 d_next.alpha0(); 00360 ttl::positionAtNextBoundaryEdge(d_next); 00361 ttl::removeBoundaryNode<TraitsType>(d_iter); 00362 } 00363 00364 dart = d_next; // Return a dart at the new boundary 00365 }
bool ttl::same_0_orbit | ( | const DartType & | d1, | |
const DartType & | d2 | |||
) | [inline] |
Checks if the two darts belong to the same 0-orbit, i.e., if they share a node.
d1 and/or d2 can be CCW or CW.
(This function also examines if the the node associated with d1 is at the boundary, which slows down the function (slightly). If it is known that the node associated with d1 is an interior node and a faster version is needed, the user should implement his/her own version.)
Definition at line 1185 of file ttl.h.
References isBoundaryNode(), and positionAtNextBoundaryEdge().
Referenced by insertConstraint(), and ttl_constr::isTheConstraint().
01185 { 01186 01187 // Two copies of the same dart 01188 DartType d_iter = d2; 01189 DartType d_end = d2; 01190 01191 if (ttl::isBoundaryNode(d_iter)) { 01192 // position at both boundary edges 01193 ttl::positionAtNextBoundaryEdge(d_iter); 01194 d_end.alpha1(); 01195 ttl::positionAtNextBoundaryEdge(d_end); 01196 } 01197 01198 for (;;) { 01199 if (d_iter == d1) 01200 return true; 01201 d_iter.alpha1(); 01202 if (d_iter == d1) 01203 return true; 01204 d_iter.alpha2(); 01205 if (d_iter == d_end) 01206 break; 01207 } 01208 01209 return false; 01210 }
bool ttl::same_1_orbit | ( | const DartType & | d1, | |
const DartType & | d2 | |||
) | [inline] |
Checks if the two darts belong to the same 1-orbit, i.e., if they share an edge.
d1 and/or d2 can be CCW or CW.
bool ttl::same_2_orbit | ( | const DartType & | d1, | |
const DartType & | d2 | |||
) | [inline] |
Checks if the two darts belong to the same 2-orbit, i.e., if they lie in the same triangle.
d1 and/or d2 can be CCW or CW
void ttl::swapEdgeInList | ( | const typename DartListType::iterator & | it, | |
DartListType & | elist | |||
) | [inline] |
Swap the the edge associated with iterator it and update affected darts in 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 elist.
Definition at line 1829 of file ttl.h.
01829 { 01830 01831 typename DartListType::iterator it1, it2, it3, it4; 01832 DartType dart(*it); 01833 01834 //typename TraitsType::DartType d1 = dart; d1.alpha2().alpha1(); 01835 //typename TraitsType::DartType d2 = d1; d2.alpha0().alpha1(); 01836 //typename TraitsType::DartType d3 = dart; d3.alpha0().alpha1(); 01837 //typename TraitsType::DartType d4 = d3; d4.alpha0().alpha1(); 01838 DartType d1 = dart; d1.alpha2().alpha1(); 01839 DartType d2 = d1; d2.alpha0().alpha1(); 01840 DartType d3 = dart; d3.alpha0().alpha1(); 01841 DartType d4 = d3; d4.alpha0().alpha1(); 01842 01843 // Find pinters to the darts that may change. 01844 // ??? Note, this is not very efficient since we must use find, which is O(N), 01845 // four times. 01846 // - Solution?: replace elist with a vector of pair (dart,number) 01847 // and avoid find? 01848 // - make a function for swapping generically? 01849 // - sould we use another container type or, 01850 // - erase them and reinsert? 01851 // - or use two lists? 01852 it1 = find(elist.begin(), elist.end(), d1); 01853 it2 = find(elist.begin(), elist.end(), d2); 01854 it3 = find(elist.begin(), elist.end(), d3); 01855 it4 = find(elist.begin(), elist.end(), d4); 01856 01857 TraitsType::swapEdge(dart); 01858 // Update the current dart which may have changed 01859 *it = dart; 01860 01861 // Update darts that may have changed again (if they were present) 01862 // Note that dart is delivered back after swapping 01863 if (it1 != elist.end()) { 01864 d1 = dart; d1.alpha1().alpha0(); 01865 *it1 = d1; 01866 } 01867 if (it2 != elist.end()) { 01868 d2 = dart; d2.alpha2().alpha1(); 01869 *it2 = d2; 01870 } 01871 if (it3 != elist.end()) { 01872 d3 = dart; d3.alpha2().alpha1().alpha0().alpha1(); 01873 *it3 = d3; 01874 } 01875 if (it4 != elist.end()) { 01876 d4 = dart; d4.alpha0().alpha1(); 01877 *it4 = d4; 01878 } 01879 }
void ttl::swapEdgesAwayFromBoundaryNode | ( | DartType & | dart, | |
ListType & | swapped_edges | |||
) | [inline] |
Swaps edges away from the (boundary) node associated with 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 ttl::removeBoundaryNode
dart | A CCW dart incident with the node |
Definition at line 1740 of file ttl.h.
References isBoundaryEdge(), and positionAtNextBoundaryEdge().
01740 { 01741 01742 // All darts that are swappable. 01743 // To treat collinear nodes at an existing boundary, we must allow degeneracy 01744 // when swapping to the boundary. 01745 // dart is CCW and at the boundary. 01746 // The 0-orbit runs CCW 01747 // Deliver the dart back in the "same position". 01748 // Assume for the swap in the traits class: 01749 // - A dart on the swapped edge is delivered back in a position as 01750 // seen if it was glued to the edge when swapping (rotating) the edge CCW 01751 01752 //int degree = ttl::getDegreeOfNode(dart); 01753 01754 passes: 01755 01756 // Swap swappable edges that radiate from the node away 01757 DartType d_iter = dart; // ???? can simply use dart 01758 d_iter.alpha1().alpha2(); // first not at boundary 01759 DartType d_next = d_iter; 01760 bool bend = false; 01761 bool swapped_next_to_boundary = false; 01762 bool swapped_in_pass = false; 01763 01764 bool allowDegeneracy; // = true; 01765 DartType tmp1, tmp2; 01766 01767 while (!bend) { 01768 01769 d_next.alpha1().alpha2(); 01770 if (ttl::isBoundaryEdge(d_next)) 01771 bend = true; // then it is CW since alpha2 01772 01773 // To allow removing among collinear nodes at the boundary, 01774 // degenerate triangles must be allowed 01775 // (they will be removed when used in connection with removeBoundaryNode) 01776 tmp1 = d_iter; tmp1.alpha1(); 01777 tmp2 = d_iter; tmp2.alpha2().alpha1(); // don't bother with boundary (checked later) 01778 01779 if (ttl::isBoundaryEdge(tmp1) && ttl::isBoundaryEdge(tmp2)) 01780 allowDegeneracy = true; 01781 else 01782 allowDegeneracy = false; 01783 01784 if (ttl::swappableEdge<TraitsType>(d_iter, allowDegeneracy)) { 01785 TraitsType::swapEdge(d_iter); 01786 01787 // Collect swapped edges in the list 01788 // "Hide" the dart on the other side of the edge to avoid it being changed for 01789 // other swapps 01790 DartType swapped_edge = d_iter; // it was delivered back 01791 swapped_edge.alpha2().alpha0(); // CCW 01792 swapped_edges.push_back(swapped_edge); 01793 01794 //degree--; // if degree is 2, or bend=true, we are done 01795 swapped_in_pass = true; 01796 if (bend) 01797 swapped_next_to_boundary = true; 01798 } 01799 if (!bend) 01800 d_iter = d_next; 01801 } 01802 01803 // Deliver a dart as output in the same position as the incoming dart 01804 if (swapped_next_to_boundary) { 01805 // Assume that "swapping is CCW and dart is preserved in the same position 01806 d_iter.alpha1().alpha0().alpha1(); // CW and see below 01807 } 01808 else { 01809 d_iter.alpha1(); // CW and see below 01810 } 01811 ttl::positionAtNextBoundaryEdge(d_iter); // CCW 01812 01813 dart = d_iter; // for next pass or output 01814 01815 // If a dart was swapped in this iteration we must run it more 01816 if (swapped_in_pass) 01817 goto passes; 01818 }
void ttl::swapEdgesAwayFromInteriorNode | ( | DartType & | dart, | |
ListType & | swapped_edges | |||
) | [inline] |
Swaps edges away from the (interior) node associated with dart such that that exactly three edges remain incident with the node.
This function is used as a first step in ttl::removeInteriorNode
dart | A CCW dart incident with the node |
Definition at line 1682 of file ttl.h.
References getDegreeOfNode().
01682 { 01683 01684 // Same iteration as in fixEdgesAtCorner, but not boundary 01685 DartType dnext = dart; 01686 01687 // Allow degeneracy, otherwise we might end up with degree=4. 01688 // For example, the reverse operation of inserting a point on an 01689 // existing edge gives a situation where all edges are non-swappable. 01690 // Ideally, degeneracy in this case should be along the actual node, 01691 // but there is no strategy for this now. 01692 // ??? An alternative here is to wait with degeneracy till we get an 01693 // infinite loop with degree > 3. 01694 bool allowDegeneracy = true; 01695 01696 int degree = ttl::getDegreeOfNode(dart); 01697 DartType d_iter; 01698 while (degree > 3) { 01699 d_iter = dnext; 01700 dnext.alpha1().alpha2(); 01701 01702 if (ttl::swappableEdge<TraitsType>(d_iter, allowDegeneracy)) { 01703 TraitsType::swapEdge(d_iter); // swap the edge away 01704 // Collect swapped edges in the list 01705 // "Hide" the dart on the other side of the edge to avoid it being changed for 01706 // other swaps 01707 DartType swapped_edge = d_iter; // it was delivered back 01708 swapped_edge.alpha2().alpha0(); // CCW (if not at boundary) 01709 swapped_edges.push_back(swapped_edge); 01710 01711 degree--; 01712 } 01713 } 01714 // Output, incident to the node 01715 dart = dnext; 01716 }
bool ttl::swappableEdge | ( | const DartType & | dart, | |
bool | allowDegeneracy | |||
) | [inline] |
Checks if the edge associated with dart is swappable, i.e., if the edge is a diagonal in a strictly convex (or convex) quadrilateral.
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. |
Definition at line 1277 of file ttl.h.
References ttl_util::crossProduct2d(), and isBoundaryEdge().
01277 { 01278 01279 // How "safe" is it? 01280 01281 if (isBoundaryEdge(dart)) 01282 return false; 01283 01284 // "angles" are at the diagonal 01285 DartType d1 = dart; 01286 d1.alpha2().alpha1(); 01287 DartType d2 = dart; 01288 d2.alpha1(); 01289 if (allowDegeneracy) { 01290 if (TraitsType::crossProduct2d(d1,d2) < 0.0) 01291 return false; 01292 } 01293 else { 01294 if (TraitsType::crossProduct2d(d1,d2) <= 0.0) 01295 return false; 01296 } 01297 01298 // Opposite side (still angle at the diagonal) 01299 d1 = dart; 01300 d1.alpha0(); 01301 d2 = d1; 01302 d1.alpha1(); 01303 d2.alpha2().alpha1(); 01304 01305 if (allowDegeneracy) { 01306 if (TraitsType::crossProduct2d(d1,d2) < 0.0) 01307 return false; 01308 } 01309 else { 01310 if (TraitsType::crossProduct2d(d1,d2) <= 0.0) 01311 return false; 01312 } 01313 return true; 01314 }
bool ttl::swapTestDelaunay | ( | const DartType & | dart, | |
bool | cycling_check | |||
) | [inline] |
Checks if the edge associated with dart should be swapped according to the Delaunay criterion, i.e., the circumcircle criterion (or equivalently the MaxMin angle criterion).
cycling_check | Must be set to true when used in connection with optimization algorithms, e.g., optimizeDelaunay. This will avoid cycling and infinite loops in nearly neutral cases. |
Definition at line 1505 of file ttl.h.
References ttl_util::crossProduct2d(), isBoundaryEdge(), and ttl_util::scalarProduct2d().
01505 { 01506 #endif 01507 01508 // The general strategy is taken from Cline & Renka. They claim that 01509 // their algorithm insure numerical stability, but experiments show 01510 // that this is not correct for neutral, or almost neutral cases. 01511 // I have extended this strategy (without using tolerances) to avoid 01512 // cycling and infinit loops when used in connection with LOP algorithms; 01513 // see the comments below. 01514 01515 typedef typename TraitsType::real_type real_type; 01516 01517 if (isBoundaryEdge(dart)) 01518 return false; 01519 01520 DartType v11 = dart; 01521 v11.alpha1().alpha0(); 01522 DartType v12 = v11; 01523 v12.alpha1(); 01524 01525 DartType v22 = dart; 01526 v22.alpha2().alpha1().alpha0(); 01527 DartType v21 = v22; 01528 v21.alpha1(); 01529 01530 real_type cos1 = TraitsType::scalarProduct2d(v11,v12); 01531 real_type cos2 = TraitsType::scalarProduct2d(v21,v22); 01532 01533 // "Angles" are opposite to the diagonal. 01534 // The diagonals should be swapped iff (t1+t2) .gt. 180 01535 // degrees. The following two tests insure numerical 01536 // stability according to Cline & Renka. But experiments show 01537 // that cycling may still happen; see the aditional test below. 01538 if (cos1 >= 0 && cos2 >= 0) // both angles are grater or equual 90 01539 return false; 01540 if (cos1 < 0 && cos2 < 0) // both angles are less than 90 01541 return true; 01542 01543 real_type sin1 = TraitsType::crossProduct2d(v11,v12); 01544 real_type sin2 = TraitsType::crossProduct2d(v21,v22); 01545 real_type sin12 = sin1*cos2 + cos1*sin2; 01546 if (sin12 >= 0) // equality represents a neutral case 01547 return false; 01548 01549 if (cycling_check) { 01550 // situation so far is sin12 < 0. Test if this also 01551 // happens for the swapped edge. 01552 01553 // The numerical calculations so far indicate that the edge is 01554 // not Delaunay and should not be swapped. But experiments show that 01555 // in neutral cases, or almost neutral cases, it may happen that 01556 // the swapped edge may again be found to be not Delaunay and thus 01557 // be swapped if we return true here. This may lead to cycling and 01558 // an infinte loop when used, e.g., in connection with optimizeDelaunay. 01559 // 01560 // In an attempt to avoid this we test if the swapped edge will 01561 // also be found to be not Delaunay by repeating the last test above 01562 // for the swapped edge. 01563 // We now rely on the general requirement for TraitsType::swapEdge which 01564 // should deliver CCW dart back in "the same position"; see the general 01565 // description. This will insure numerical stability as the next calculation 01566 // is the same as if this function was called again with the swapped edge. 01567 // Cycling is thus impossible provided that the initial tests above does 01568 // not result in ambiguity (and they should probably not do so). 01569 01570 v11.alpha0(); 01571 v12.alpha0(); 01572 v21.alpha0(); 01573 v22.alpha0(); 01574 // as if the edge was swapped/rotated CCW 01575 cos1 = TraitsType::scalarProduct2d(v22,v11); 01576 cos2 = TraitsType::scalarProduct2d(v12,v21); 01577 sin1 = TraitsType::crossProduct2d(v22,v11); 01578 sin2 = TraitsType::crossProduct2d(v12,v21); 01579 sin12 = sin1*cos2 + cos1*sin2; 01580 if (sin12 < 0) { 01581 // A neutral case, but the tests above lead to swapping 01582 return false; 01583 } 01584 } 01585 01586 return true; 01587 }