00001 //================================================================================================== 00002 // 00003 // File: ttl_constr.h 00004 // 00005 // Created: July 2001 00006 // 00007 // Author: Øyvind Hjelle <oyvind.hjelle@math.sintef.no>, 00008 // Gunnar Staff <gunnar.staff@math.sintef.no> 00009 // 00010 // Revision: $Id: ttl_constr.h,v 1.5 2006/07/27 14:02:20 oyvindhj Exp $ 00011 // 00012 // Description: 00013 // 00014 //================================================================================================== 00015 // Copyright (C) 2000-2003 SINTEF Applied Mathematics. All rights reserved. 00016 // 00017 // This file may be distributed under the terms of the Q Public License 00018 // as defined by Trolltech AS of Norway and appearing in the file 00019 // LICENSE.QPL included in the packaging of this file. 00020 // 00021 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00022 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00023 // 00024 //================================================================================================== 00025 00026 00027 #ifndef _TTL_CONSTR_H_ 00028 #define _TTL_CONSTR_H_ 00029 00030 00031 #include <list> 00032 #include <cmath> 00033 00034 00035 // Debugging 00036 #ifdef DEBUG_TTL_CONSTR_PLOT 00037 #include <fstream> 00038 static ofstream ofile_constr("qweCons.dat"); 00039 #endif 00040 00041 00042 using namespace std; 00043 00054 namespace ttl_constr { 00055 00056 // ??? A constant used to evluate a numerical expression against a user spesified 00057 // roundoff-zero number 00058 #ifdef DEBUG_TTL_CONSTR 00059 static const double ROUNDOFFZERO = 0.0; // 0.1e-15; 00060 #endif 00061 00062 00063 //------------------------------------------------------------------------------------------------ 00064 /* Checks if \e dart has start and end points in \e dstart and \e dend. 00065 * 00066 * \param dart 00067 * The dart that should be controlled to see if it's the constraint 00068 * 00069 * \param dstart 00070 * A CCW dart with the startnode of the constraint as the startnode 00071 * 00072 * \param dend 00073 * A CCW dart with the endnode of the constraint as the startnode 00074 * 00075 * \retval bool 00076 * A bool confirming that it's the constraint or not 00077 * 00078 * \using 00079 * ttl::same_0_orbit 00080 */ 00081 template <class DartType> 00082 bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) { 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 } 00091 00092 00093 //------------------------------------------------------------------------------------------------ 00094 /* Checks if \e d1 and \e d2 are on the same side of the line between \e dstart and \e dend. 00095 * (The start nodes of \e d1 and \e d2 represent an edge). 00096 * 00097 * \param dstart 00098 * A CCW dart with the start node of the constraint as the source node of the dart. 00099 * 00100 * \param dend 00101 * A CCW dart with the end node of the constraint as the source node of the dart. 00102 * 00103 * \param d1 00104 * A CCW dart with the first node as the start node of the dart. 00105 * 00106 * \param d2 00107 * A CCW dart with the other node as the start node of the dart. 00108 * 00109 * \using 00110 * TraitsType::orient2d 00111 */ 00112 template <class TraitsType, class DartType> 00113 bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) { 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 } 00123 00124 00125 //------------------------------------------------------------------------------------------------ 00126 /* Return the dart \e d making the smallest non-negative angle, 00127 * as calculated with: orient2d(dstart, d.alpha0(), dend), 00128 * at the 0-orbit of dstart. 00129 * If (dstart,dend) is a CCW boundary edge \e d will be CW, otherwise CCW (since CCW in) 00130 * at the 0-orbit of dstart. 00131 * 00132 * \par Assumes: 00133 * - CCW dstart and dend, but returned dart can be CW at the boundary. 00134 * - Boundary is convex? 00135 * 00136 * \param dstart 00137 * A CCW dart dstart 00138 * 00139 * \param dend 00140 * A CCW dart dend 00141 * 00142 * \retval DartType 00143 * The dart \e d making the smallest positive (or == 0) angle 00144 * 00145 * \using 00146 * ttl::isBoundaryNode 00147 * ttl::positionAtNextBoundaryEdge 00148 * TraitsType::orient2d 00149 */ 00150 template <class TraitsType, class DartType> 00151 DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) { 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 } 00216 00217 00218 //------------------------------------------------------------------------------------------------ 00219 /* This function finds all the edges in the triangulation crossing 00220 * the spesified constraint and puts them in a list. 00221 * In the case of collinearity, an attempt is made to detect this. 00222 * The first collinear node between dstart and dend is then returned. 00223 * 00224 * Strategy: 00225 * - Iterate such that \e d_iter is always strictly "below" the constraint 00226 * as seen with \e dstart to the left and \e dend to the right. 00227 * - Add CCW darts, whose edges intersect the constrait, to a list. 00228 * These edges are found by the orient2d predicate: 00229 * If two nodes of an edge are on opposite sides of the constraint, 00230 * the edge between them intersect. 00231 * - Must handle collinnear cases, i.e., if a node falls on the constraint, 00232 * and possibly restarting collection of edges. Detecting collinearity 00233 * heavily relies on the orient2d predicate which is provided by the 00234 * traits class. 00235 * 00236 * Action: 00237 * 1) Find cone/opening angle containing \e dstart and \e dend 00238 * 2) Find first edge from the first 0-orbit that intersects 00239 * 3) Check which of the two opposite that intersects 00240 * 00241 * 1) 00242 * Rotate CCW and find the (only) case where \e d_iter and \e d_next satisfy: 00243 * - orient2d(d_iter, d_iter.alpha0(), dend) > 0 00244 * - orient2d(d_next, d_next.alpha0(), dend) < 0 00245 * 00246 * - check if we are done, i.e., if (d_next.alpha0() == my_dend) 00247 * - Note also the situation if, e.g., the constraint is a boundary edge in which case 00248 * \e my_dend wil be CW 00249 * 00250 * \param dstart 00251 * A CCW dart with the startnode of the constraint as the startnode 00252 * 00253 * \param dend 00254 * A CCW dart with the endnode of the constraint as the startnode 00255 * 00256 * \param elist 00257 * A list where all the edges crossing the spesified constraint will be put 00258 * 00259 * \retval dartType 00260 * Returns the next "collinear" starting node such that dend is returned when done. 00261 */ 00262 template <class TraitsType, class DartType, class ListType> 00263 DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) { 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 } 00343 00344 00345 //------------------------------------------------------------------------------------------------ 00346 /* This function recives a constrained edge and a list of all the edges crossing a constraint. 00347 * It then swaps the crossing edges away from the constraint. This is done according to a 00348 * scheme suggested by Dyn, Goren & Rippa (slightly modified). 00349 * The resulting triangulation is a constrained one, but not necessarily constrained Delaunay. 00350 * In other to run optimization later to obtain a constrained Delaunay triangulation, 00351 * the swapped edges are maintained in a list. 00352 * 00353 * Strategy : 00354 * - Situation A: Run through the list and swap crossing edges away from the constraint. 00355 * All the swapped edges are moved to the end of the list, and are "invisible" to this procedure. 00356 * - Situation B: We may come in a situation where none of the crossing edges can be swapped away 00357 * from the constraint. 00358 * Then we follow the strategy of Dyn, Goren & Rippa and allow edges to be swapped, 00359 * even if they are not swapped away from the constraint. 00360 * These edges are NOT moved to the end of the list. They are later swapped to none-crossing 00361 * edges when the locked situation is solved. 00362 * - We keep on swapping edges in Situation B until we have iterated trough the list. 00363 * We then resume Situation A. 00364 * - This is done until the list is virtualy empty. The resulting \c elist has the constraint 00365 * as the last element. 00366 * 00367 * \param dstart 00368 * A CCW dart dstart 00369 * 00370 * \param dend 00371 * A CCW dart dend 00372 * 00373 * \param elist 00374 * A list containing all the edges crossing the spesified constraint 00375 * 00376 * \using 00377 * ttl::swappableEdge 00378 * ttl::swapEdgeInList 00379 * ttl::crossesConstraint 00380 * ttl::isTheConstraint 00381 */ 00382 template <class TraitsType, class DartType> 00383 void transformToConstraint(DartType& dstart, DartType& dend, list<DartType>& elist) { 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 } 00501 00502 }; // End of ttl_constr namespace scope 00503 00504 00505 namespace ttl { // (extension) 00506 00509 00510 //------------------------------------------------------------------------------------------------ 00542 template <class TraitsType, class DartType> 00543 DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) { 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 } 00614 00616 00617 }; // End of ttl namespace scope (extension) 00618 00619 #endif // _TTL_CONSTR_H_