ttl_constr Namespace Reference

Constrained Delaunay triangulation. More...

Functions

template<class DartType >
bool isTheConstraint (const DartType &dart, const DartType &dstart, const DartType &dend)
template<class TraitsType , class DartType >
bool crossesConstraint (DartType &dstart, DartType &dend, DartType &d1, DartType &d2)
template<class TraitsType , class DartType >
DartType getAtSmallestAngle (const DartType &dstart, const DartType &dend)
template<class TraitsType , class DartType , class ListType >
DartType findCrossingEdges (const DartType &dstart, const DartType &dend, ListType &elist)
template<class TraitsType , class DartType >
void transformToConstraint (DartType &dstart, DartType &dend, list< DartType > &elist)

Detailed Description

Constrained Delaunay triangulation.

Basic generic algorithms in TTL for inserting a constrained edge between two existing nodes.

See documentation for the namespace ttl for general requirements and assumptions.

Author:
Øyvind Hjelle, oyvindhj@ifi.uio.no

Function Documentation

template<class TraitsType , class DartType >
bool ttl_constr::crossesConstraint ( DartType &  dstart,
DartType &  dend,
DartType &  d1,
DartType &  d2 
) [inline]

Definition at line 113 of file ttl_constr.h.

00113                                                                                          {
00114     
00115     typename TraitsType::real_type orient_1 = TraitsType::orient2d(dstart,d1,dend);
00116     typename TraitsType::real_type orient_2 = TraitsType::orient2d(dstart,d2,dend);
00117     // ??? Should we refine this? e.g. find if (dstart,dend) (d1,d2) represent the same edge
00118     if ((orient_1 <= 0 && orient_2 <= 0) || (orient_1 >= 0 && orient_2 >= 0))
00119       return false;
00120     
00121     return true;
00122   }

template<class TraitsType , class DartType , class ListType >
DartType ttl_constr::findCrossingEdges ( const DartType &  dstart,
const DartType &  dend,
ListType &  elist 
) [inline]

Definition at line 263 of file ttl_constr.h.

00263                                                                                               {
00264     
00265     const DartType my_start = getAtSmallestAngle<TraitsType>(dstart, dend);
00266     DartType my_end   = getAtSmallestAngle<TraitsType>(dend, dstart);
00267     
00268     DartType d_iter = my_start;
00269     if (d_iter.alpha0().alpha2() == my_end)
00270       return d_iter; // The constraint is an existing edge and we are done
00271     
00272     // Facts/status so far:
00273     // - my_start and my_end are now both CCW and the constraint is not a boundary edge.
00274     // - Further, the constraint is not one single existing edge, but it might be a collection
00275     //   of collinear edges in which case we return the current collinear edge
00276     //   and calling this function until all are collected.
00277     
00278     my_end.alpha1(); // CW! // ??? this is probably ok for testing now?
00279     
00280     d_iter = my_start;
00281     d_iter.alpha0().alpha1(); // alpha0 is downwards or along the constraint
00282     
00283     // Facts:
00284     // - d_iter is guaranteed to intersect, but can be in start point.
00285     // - d_iter.alpha0() is not at dend yet
00286     typename TraitsType::real_type orient = TraitsType::orient2d(dstart, d_iter, dend);
00287 
00288     // Use round-off error/tolerance or rely on the orient2d predicate ???
00289     // Make a warning message if orient != exact 0
00290     if (orient == 0)
00291       return d_iter;
00292 
00293 #ifdef DEBUG_TTL_CONSTR
00294     else if (fabs(orient) <= ROUNDOFFZERO) {
00295       cout << "The darts are not exactly colinear, but |d1 x d2| <= " << ROUNDOFFZERO << endl;
00296       return d_iter; // collinear, not done (and not collect in the list)
00297     }
00298 #endif
00299 
00300     // Collect intersecting edges
00301     // --------------------------
00302     elist.push_back(d_iter); // The first with interior intersection point
00303     
00304     // Facts, status so far:
00305     // - The first intersecting edge is now collected
00306     // (- d_iter.alpha0() is still not at dend)
00307     
00308     // d_iter should always be the edge that intersects and be below or on the constraint
00309     // One of the two edges opposite to d_iter must intersect, or we have collinearity
00310     
00311     // Note: Almost collinear cases can be handled on the
00312     // application side with orient2d. We should probably
00313     // return an int and the application will set it to zero
00314     for(;;) {
00315       // assume orient have been calc. and collinearity has been tested,
00316       // above the first time and below later
00317       d_iter.alpha2().alpha1(); // 2a same node
00318       
00319       DartType d0 = d_iter;
00320       d0.alpha0(); // CW
00321       if (d0 == my_end)
00322         return dend; // WE ARE DONE (but can we enter an endless loop???)
00323       
00324       // d_iter or d_iter.alpha0().alpha1() must intersect
00325       orient = TraitsType::orient2d(dstart, d0, dend);
00326       
00327       if (orient == 0) 
00328         return d0.alpha1();
00329 
00330 #ifdef DEBUG_TTL_CONSTR
00331       else if (fabs(orient) <= ROUNDOFFZERO) {
00332         return d0.alpha1(); // CCW, collinear
00333       }
00334 #endif
00335 
00336       else if (orient > 0) { // orient > 0 and still below
00337         // This one must intersect!
00338         d_iter = d0.alpha1();
00339       }
00340       elist.push_back(d_iter);
00341     }
00342   }

template<class TraitsType , class DartType >
DartType ttl_constr::getAtSmallestAngle ( const DartType &  dstart,
const DartType &  dend 
) [inline]

Definition at line 151 of file ttl_constr.h.

References ttl::isBoundaryNode(), and ttl::positionAtNextBoundaryEdge().

00151                                                                               {
00152     
00153     // - Must boundary be convex???
00154     // - Handle the case where the constraint is already present???
00155     // - Handle dstart and/or dend at the boundary
00156     //   (dstart and dend may define a boundary edge)
00157     
00158     DartType d_iter = dstart;
00159     if (ttl::isBoundaryNode(d_iter)) {
00160       d_iter.alpha1(); // CW
00161       ttl::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary)
00162     }
00163     
00164     // assume convex boundary; see comments
00165     
00166     DartType d0 = d_iter;
00167     d0.alpha0();
00168     bool ccw = true; // the rotation later
00169     typename TraitsType::real_type o_iter = TraitsType::orient2d(d_iter, d0, dend);
00170     if (o_iter == 0) { // collinear BUT can be on "back side"
00171       d0.alpha1().alpha0(); // CW
00172       if (TraitsType::orient2d(dstart, dend, d0) > 0)
00173         return d_iter; //(=dstart) collinear
00174       else {
00175         // collinear on "back side"
00176         d_iter.alpha1().alpha2(); // assume convex boundary
00177         ccw = true;
00178       }
00179     }
00180     else if (o_iter < 0) {
00181       // Prepare for rotating CW and with d_iter CW
00182       d_iter.alpha1();
00183       ccw = false;
00184     }
00185     
00186     // Set first angle
00187     d0 = d_iter; d0.alpha0();
00188     o_iter = TraitsType::orient2d(dstart, d0, dend);
00189     
00190     typename TraitsType::real_type o_next;
00191     
00192     // Rotate towards the constraint CCW or CW.
00193     // Here we assume that the boundary is convex.
00194     DartType d_next = d_iter;
00195     for (;;) {
00196       d_next.alpha1(); // CW !!! (if ccw == true)
00197       d0 = d_next; d0.alpha0();
00198       o_next = TraitsType::orient2d(dstart, d0, dend);
00199       
00200       if (ccw && o_next < 0) // and o_iter > 0
00201         return d_iter;
00202       else if (!ccw && o_next > 0)
00203         return d_next; // CCW
00204       else if (o_next == 0) {
00205         if (ccw)
00206           return d_next.alpha2(); // also ok if boundary
00207         else
00208           return d_next;
00209       }
00210       
00211       // prepare next
00212       d_next.alpha2(); // CCW if ccw
00213       d_iter = d_next; // also ok if boundary CCW if ccw == true
00214     }
00215   }

template<class DartType >
bool ttl_constr::isTheConstraint ( const DartType &  dart,
const DartType &  dstart,
const DartType &  dend 
) [inline]

Definition at line 82 of file ttl_constr.h.

References ttl::same_0_orbit().

Referenced by transformToConstraint().

00082                                                                                              {
00083     DartType d0 = dart;
00084     d0.alpha0(); // CW
00085     if ((ttl::same_0_orbit(dstart, dart) && ttl::same_0_orbit(dend, d0)) ||
00086       (ttl::same_0_orbit(dstart, d0)  && ttl::same_0_orbit(dend, dart))) {
00087       return true;
00088     }
00089     return false;
00090   }

template<class TraitsType , class DartType >
void ttl_constr::transformToConstraint ( DartType &  dstart,
DartType &  dend,
list< DartType > &  elist 
) [inline]

Definition at line 383 of file ttl_constr.h.

References isTheConstraint().

00383                                                                                         {
00384     
00385     typename list<DartType>::iterator it, used;
00386     
00387     // We may enter in a situation where dstart and dend are altered because of a swap.
00388     // (The general rule is that darts inside the actual quadrilateral can be changed,
00389     // but not those outside.)
00390     // So, we need some look-ahead strategies for dstart and dend and change these
00391     // after a swap if necessary.
00392     
00393     int dartsInList = elist.size();
00394     if (dartsInList == 0)
00395       return;
00396 
00397     bool erase; // indicates if an edge is swapped away from the constraint such that it can be
00398                 // moved to the back of the list
00399     bool locked = false;
00400     do {
00401       int noswap = 0;
00402       it = elist.begin();
00403 
00404       // counts how many edges that have been swapped per list-cycle
00405       int counter = 1;
00406       while(it != elist.end()) { // ??? change this test with counter > dartsInList
00407         erase = false;
00408         // Check if our virtual end of the list has been crossed. It breaks the
00409         // while and starts all over again in the do-while loop
00410         if (counter > dartsInList)
00411           break;
00412         
00413         if (ttl::swappableEdge<TraitsType, DartType>(*it, true)) {
00414           // Dyn & Goren & Rippa 's notation:
00415           // The node assosiated with dart *it is denoted u_m. u_m has edges crossing the constraint
00416           // named w_1, ... , w_r . The other node to the edge assosiated with dart *it is w_s.
00417           // We want to swap from edge u_m<->w_s to edge w_{s-1}<->w_{s+1}.
00418           DartType op1 = *it;
00419           DartType op2 = op1;
00420           op1.alpha1().alpha0(); //finds dart with node w_{s-1}
00421           op2.alpha2().alpha1().alpha0(); // (CW) finds dart with node w_{s+1}
00422           DartType tmp = *it; tmp.alpha0(); // Dart with assosiated node opposite to node of *it allong edge
00423           // If there is a locked situation we swap, even if the result is crossing the constraint
00424           // If there is a looked situation, but we do an ordinary swap, it should be treated as
00425           // if we were not in a locked situation!!
00426 
00427           // The flag swap_away indicates if the edge is swapped away from the constraint such that
00428           // it does not cross the constraint.
00429           bool swap_away = (crossesConstraint<TraitsType>(dstart, dend, *it, tmp) &&
00430                             !crossesConstraint<TraitsType>(dstart, dend, op1, op2));
00431           if (swap_away || locked) {
00432             // Do a look-ahead to see if dstart and/or dend are in the quadrilateral
00433             // If so, we mark it with a flag to make sure we update them after the swap
00434             // (they may have been changed during the swap according to the general rule!)
00435             bool start = false;
00436             bool end = false;
00437             
00438             DartType d = *it;
00439             if (d.alpha1().alpha0() == dstart)
00440               start = true;
00441             d = *it;
00442             if (d.alpha2().alpha1().alpha0().alpha1() == dend)
00443               end = true;
00444             
00445             // This is the only place swapping is called when inserting a constraint
00446             ttl::swapEdgeInList<TraitsType, DartType>(it,elist);
00447             
00448             // If we, during look-ahead, found that dstart and/or dend were in the quadrilateral,
00449             // we update them.
00450             if (end)
00451               dend = *it;
00452             if (start) {
00453               dstart = *it;
00454               dstart.alpha0().alpha2();
00455             }
00456             
00457             if (swap_away) { // !locked || //it should be sufficient with swap_away ???
00458               noswap++;
00459               erase = true;
00460             }
00461             
00462             if (isTheConstraint(*it, dstart, dend)) {
00463               // Move the constraint to the end of the list
00464               DartType the_constraint = *it;
00465               elist.erase(it);
00466               elist.push_back(the_constraint);
00467               return;
00468             } //endif
00469           } //endif
00470         } //endif "swappable edge"
00471         
00472                 
00473         // Move the edge to the end of the list if it was swapped away from the constraint
00474         if (erase) {
00475           used = it;
00476           elist.push_back(*it);
00477           ++it;
00478           elist.erase(used);
00479           --dartsInList;
00480         } 
00481         else {
00482           ++it;
00483           ++counter;
00484         }
00485         
00486       } //end while
00487       
00488       if (noswap == 0)
00489         locked = true;
00490       
00491     } while (dartsInList != 0);
00492     
00493     
00494 #ifdef DEBUG_TTL_CONSTR
00495     // We will never enter here. (If elist is empty, we return above).
00496     cout << "??????? ERROR 2, should never enter here ????????????????????????? SKIP ???? " << endl;
00497     exit(-1);
00498 #endif
00499 
00500   }


Generated on Wed Nov 17 17:44:28 2010 for TTL by  doxygen 1.6.1