ttl_constr.h

Go to the documentation of this file.
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_

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