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) |
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.
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 }
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 }
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 }
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 }
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 }