Fixes build error with the choosy CLANG (Thanks to Maciej Suminski)
This commit is contained in:
parent
d00fae588a
commit
e76c330aaf
|
@ -357,7 +357,7 @@ private:
|
|||
|
||||
ForwardIterator it;
|
||||
for (it = first; it != last; ++it) {
|
||||
bool status = insertNode<TraitsType>(dart, **it);
|
||||
insertNode<TraitsType>(dart, **it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1914,13 +1914,4 @@ passes:
|
|||
|
||||
}; // End of ttl namespace scope (but other files may also contain functions for ttl)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// ----------------------------- Constrained Triangulation Group --------------------------------
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
// Still namespace ttl
|
||||
|
||||
#include <ttl/ttl_constr.h>
|
||||
|
||||
#endif // _TTL_H_
|
||||
|
|
|
@ -1,635 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT,
|
||||
* Applied Mathematics, Norway.
|
||||
*
|
||||
* Contact information: E-mail: tor.dokken@sintef.no
|
||||
* SINTEF ICT, Department of Applied Mathematics,
|
||||
* P.O. Box 124 Blindern,
|
||||
* 0314 Oslo, Norway.
|
||||
*
|
||||
* This file is part of TTL.
|
||||
*
|
||||
* TTL is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* TTL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with TTL. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public
|
||||
* License, a covered work must retain the producer line in every data
|
||||
* file that is created or manipulated using TTL.
|
||||
*
|
||||
* Other Usage
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial activities involving the TTL library without
|
||||
* disclosing the source code of your own applications.
|
||||
*
|
||||
* This file may be used in accordance with the terms contained in a
|
||||
* written agreement between you and SINTEF ICT.
|
||||
*/
|
||||
|
||||
#ifndef _TTL_CONSTR_H_
|
||||
#define _TTL_CONSTR_H_
|
||||
|
||||
|
||||
#include <list>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
// Debugging
|
||||
#ifdef DEBUG_TTL_CONSTR_PLOT
|
||||
#include <fstream>
|
||||
static ofstream ofile_constr("qweCons.dat");
|
||||
#endif
|
||||
|
||||
/** \brief Constrained Delaunay triangulation
|
||||
*
|
||||
* Basic generic algorithms in TTL for inserting a constrained edge between two existing nodes.\n
|
||||
*
|
||||
* See documentation for the namespace ttl for general requirements and assumptions.
|
||||
*
|
||||
* \author
|
||||
* <EFBFBD>yvind Hjelle, oyvindhj@ifi.uio.no
|
||||
*/
|
||||
|
||||
namespace ttl_constr {
|
||||
|
||||
// ??? A constant used to evluate a numerical expression against a user spesified
|
||||
// roundoff-zero number
|
||||
#ifdef DEBUG_TTL_CONSTR
|
||||
static const double ROUNDOFFZERO = 0.0; // 0.1e-15;
|
||||
#endif
|
||||
|
||||
|
||||
class ConstrainedTriangulation
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/* Checks if \e dart has start and end points in \e dstart and \e dend.
|
||||
*
|
||||
* \param dart
|
||||
* The dart that should be controlled to see if it's the constraint
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart with the startnode of the constraint as the startnode
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart with the endnode of the constraint as the startnode
|
||||
*
|
||||
* \retval bool
|
||||
* A bool confirming that it's the constraint or not
|
||||
*
|
||||
* \using
|
||||
* same_0_orbit
|
||||
*/
|
||||
template <class DartType>
|
||||
static bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) {
|
||||
DartType d0 = dart;
|
||||
d0.alpha0(); // CW
|
||||
if ((ttl::TriangulationHelper::same_0_orbit(dstart, dart) && ttl::TriangulationHelper::same_0_orbit(dend, d0)) ||
|
||||
(ttl::TriangulationHelper::same_0_orbit(dstart, d0) && ttl::TriangulationHelper::same_0_orbit(dend, dart))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/* Checks if \e d1 and \e d2 are on the same side of the line between \e dstart and \e dend.
|
||||
* (The start nodes of \e d1 and \e d2 represent an edge).
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart with the start node of the constraint as the source node of the dart.
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart with the end node of the constraint as the source node of the dart.
|
||||
*
|
||||
* \param d1
|
||||
* A CCW dart with the first node as the start node of the dart.
|
||||
*
|
||||
* \param d2
|
||||
* A CCW dart with the other node as the start node of the dart.
|
||||
*
|
||||
* \using
|
||||
* TraitsType::orient2d
|
||||
*/
|
||||
template <class TraitsType, class DartType>
|
||||
static bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) {
|
||||
|
||||
typename TraitsType::real_type orient_1 = TraitsType::orient2d(dstart,d1,dend);
|
||||
typename TraitsType::real_type orient_2 = TraitsType::orient2d(dstart,d2,dend);
|
||||
// ??? Should we refine this? e.g. find if (dstart,dend) (d1,d2) represent the same edge
|
||||
if ((orient_1 <= 0 && orient_2 <= 0) || (orient_1 >= 0 && orient_2 >= 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/* Return the dart \e d making the smallest non-negative angle,
|
||||
* as calculated with: orient2d(dstart, d.alpha0(), dend),
|
||||
* at the 0-orbit of dstart.
|
||||
* If (dstart,dend) is a CCW boundary edge \e d will be CW, otherwise CCW (since CCW in)
|
||||
* at the 0-orbit of dstart.
|
||||
*
|
||||
* \par Assumes:
|
||||
* - CCW dstart and dend, but returned dart can be CW at the boundary.
|
||||
* - Boundary is convex?
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart dstart
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart dend
|
||||
*
|
||||
* \retval DartType
|
||||
* The dart \e d making the smallest positive (or == 0) angle
|
||||
*
|
||||
* \using
|
||||
* isBoundaryNode
|
||||
* positionAtNextBoundaryEdge
|
||||
* TraitsType::orient2d
|
||||
*/
|
||||
template <class TraitsType, class DartType>
|
||||
static DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) {
|
||||
|
||||
// - Must boundary be convex???
|
||||
// - Handle the case where the constraint is already present???
|
||||
// - Handle dstart and/or dend at the boundary
|
||||
// (dstart and dend may define a boundary edge)
|
||||
|
||||
DartType d_iter = dstart;
|
||||
if (ttl::TriangulationHelper::isBoundaryNode(d_iter)) {
|
||||
d_iter.alpha1(); // CW
|
||||
ttl::TriangulationHelper::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary)
|
||||
}
|
||||
|
||||
// assume convex boundary; see comments
|
||||
|
||||
DartType d0 = d_iter;
|
||||
d0.alpha0();
|
||||
bool ccw = true; // the rotation later
|
||||
typename TraitsType::real_type o_iter = TraitsType::orient2d(d_iter, d0, dend);
|
||||
if (o_iter == 0) { // collinear BUT can be on "back side"
|
||||
d0.alpha1().alpha0(); // CW
|
||||
if (TraitsType::orient2d(dstart, dend, d0) > 0)
|
||||
return d_iter; //(=dstart) collinear
|
||||
else {
|
||||
// collinear on "back side"
|
||||
d_iter.alpha1().alpha2(); // assume convex boundary
|
||||
ccw = true;
|
||||
}
|
||||
}
|
||||
else if (o_iter < 0) {
|
||||
// Prepare for rotating CW and with d_iter CW
|
||||
d_iter.alpha1();
|
||||
ccw = false;
|
||||
}
|
||||
|
||||
// Set first angle
|
||||
d0 = d_iter; d0.alpha0();
|
||||
o_iter = TraitsType::orient2d(dstart, d0, dend);
|
||||
|
||||
typename TraitsType::real_type o_next;
|
||||
|
||||
// Rotate towards the constraint CCW or CW.
|
||||
// Here we assume that the boundary is convex.
|
||||
DartType d_next = d_iter;
|
||||
for (;;) {
|
||||
d_next.alpha1(); // CW !!! (if ccw == true)
|
||||
d0 = d_next; d0.alpha0();
|
||||
o_next = TraitsType::orient2d(dstart, d0, dend);
|
||||
|
||||
if (ccw && o_next < 0) // and o_iter > 0
|
||||
return d_iter;
|
||||
else if (!ccw && o_next > 0)
|
||||
return d_next; // CCW
|
||||
else if (o_next == 0) {
|
||||
if (ccw)
|
||||
return d_next.alpha2(); // also ok if boundary
|
||||
else
|
||||
return d_next;
|
||||
}
|
||||
|
||||
// prepare next
|
||||
d_next.alpha2(); // CCW if ccw
|
||||
d_iter = d_next; // also ok if boundary CCW if ccw == true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/* This function finds all the edges in the triangulation crossing
|
||||
* the spesified constraint and puts them in a list.
|
||||
* In the case of collinearity, an attempt is made to detect this.
|
||||
* The first collinear node between dstart and dend is then returned.
|
||||
*
|
||||
* Strategy:
|
||||
* - Iterate such that \e d_iter is always strictly "below" the constraint
|
||||
* as seen with \e dstart to the left and \e dend to the right.
|
||||
* - Add CCW darts, whose edges intersect the constrait, to a list.
|
||||
* These edges are found by the orient2d predicate:
|
||||
* If two nodes of an edge are on opposite sides of the constraint,
|
||||
* the edge between them intersect.
|
||||
* - Must handle collinnear cases, i.e., if a node falls on the constraint,
|
||||
* and possibly restarting collection of edges. Detecting collinearity
|
||||
* heavily relies on the orient2d predicate which is provided by the
|
||||
* traits class.
|
||||
*
|
||||
* Action:
|
||||
* 1) Find cone/opening angle containing \e dstart and \e dend
|
||||
* 2) Find first edge from the first 0-orbit that intersects
|
||||
* 3) Check which of the two opposite that intersects
|
||||
*
|
||||
* 1)
|
||||
* Rotate CCW and find the (only) case where \e d_iter and \e d_next satisfy:
|
||||
* - orient2d(d_iter, d_iter.alpha0(), dend) > 0
|
||||
* - orient2d(d_next, d_next.alpha0(), dend) < 0
|
||||
*
|
||||
* - check if we are done, i.e., if (d_next.alpha0() == my_dend)
|
||||
* - Note also the situation if, e.g., the constraint is a boundary edge in which case
|
||||
* \e my_dend wil be CW
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart with the startnode of the constraint as the startnode
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart with the endnode of the constraint as the startnode
|
||||
*
|
||||
* \param elist
|
||||
* A list where all the edges crossing the spesified constraint will be put
|
||||
*
|
||||
* \retval dartType
|
||||
* Returns the next "collinear" starting node such that dend is returned when done.
|
||||
*/
|
||||
template <class TraitsType, class DartType, class ListType>
|
||||
static DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) {
|
||||
|
||||
const DartType my_start = getAtSmallestAngle<TraitsType>(dstart, dend);
|
||||
DartType my_end = getAtSmallestAngle<TraitsType>(dend, dstart);
|
||||
|
||||
DartType d_iter = my_start;
|
||||
if (d_iter.alpha0().alpha2() == my_end)
|
||||
return d_iter; // The constraint is an existing edge and we are done
|
||||
|
||||
// Facts/status so far:
|
||||
// - my_start and my_end are now both CCW and the constraint is not a boundary edge.
|
||||
// - Further, the constraint is not one single existing edge, but it might be a collection
|
||||
// of collinear edges in which case we return the current collinear edge
|
||||
// and calling this function until all are collected.
|
||||
|
||||
my_end.alpha1(); // CW! // ??? this is probably ok for testing now?
|
||||
|
||||
d_iter = my_start;
|
||||
d_iter.alpha0().alpha1(); // alpha0 is downwards or along the constraint
|
||||
|
||||
// Facts:
|
||||
// - d_iter is guaranteed to intersect, but can be in start point.
|
||||
// - d_iter.alpha0() is not at dend yet
|
||||
typename TraitsType::real_type orient = TraitsType::orient2d(dstart, d_iter, dend);
|
||||
|
||||
// Use round-off error/tolerance or rely on the orient2d predicate ???
|
||||
// Make a warning message if orient != exact 0
|
||||
if (orient == 0)
|
||||
return d_iter;
|
||||
|
||||
#ifdef DEBUG_TTL_CONSTR
|
||||
else if (fabs(orient) <= ROUNDOFFZERO) {
|
||||
cout << "The darts are not exactly colinear, but |d1 x d2| <= " << ROUNDOFFZERO << endl;
|
||||
return d_iter; // collinear, not done (and not collect in the list)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Collect intersecting edges
|
||||
// --------------------------
|
||||
elist.push_back(d_iter); // The first with interior intersection point
|
||||
|
||||
// Facts, status so far:
|
||||
// - The first intersecting edge is now collected
|
||||
// (- d_iter.alpha0() is still not at dend)
|
||||
|
||||
// d_iter should always be the edge that intersects and be below or on the constraint
|
||||
// One of the two edges opposite to d_iter must intersect, or we have collinearity
|
||||
|
||||
// Note: Almost collinear cases can be handled on the
|
||||
// application side with orient2d. We should probably
|
||||
// return an int and the application will set it to zero
|
||||
for(;;) {
|
||||
// assume orient have been calc. and collinearity has been tested,
|
||||
// above the first time and below later
|
||||
d_iter.alpha2().alpha1(); // 2a same node
|
||||
|
||||
DartType d0 = d_iter;
|
||||
d0.alpha0(); // CW
|
||||
if (d0 == my_end)
|
||||
return dend; // WE ARE DONE (but can we enter an endless loop???)
|
||||
|
||||
// d_iter or d_iter.alpha0().alpha1() must intersect
|
||||
orient = TraitsType::orient2d(dstart, d0, dend);
|
||||
|
||||
if (orient == 0)
|
||||
return d0.alpha1();
|
||||
|
||||
#ifdef DEBUG_TTL_CONSTR
|
||||
else if (fabs(orient) <= ROUNDOFFZERO) {
|
||||
return d0.alpha1(); // CCW, collinear
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (orient > 0) { // orient > 0 and still below
|
||||
// This one must intersect!
|
||||
d_iter = d0.alpha1();
|
||||
}
|
||||
elist.push_back(d_iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/* This function recives a constrained edge and a list of all the edges crossing a constraint.
|
||||
* It then swaps the crossing edges away from the constraint. This is done according to a
|
||||
* scheme suggested by Dyn, Goren & Rippa (slightly modified).
|
||||
* The resulting triangulation is a constrained one, but not necessarily constrained Delaunay.
|
||||
* In other to run optimization later to obtain a constrained Delaunay triangulation,
|
||||
* the swapped edges are maintained in a list.
|
||||
*
|
||||
* Strategy :
|
||||
* - Situation A: Run through the list and swap crossing edges away from the constraint.
|
||||
* All the swapped edges are moved to the end of the list, and are "invisible" to this procedure.
|
||||
* - Situation B: We may come in a situation where none of the crossing edges can be swapped away
|
||||
* from the constraint.
|
||||
* Then we follow the strategy of Dyn, Goren & Rippa and allow edges to be swapped,
|
||||
* even if they are not swapped away from the constraint.
|
||||
* These edges are NOT moved to the end of the list. They are later swapped to none-crossing
|
||||
* edges when the locked situation is solved.
|
||||
* - We keep on swapping edges in Situation B until we have iterated trough the list.
|
||||
* We then resume Situation A.
|
||||
* - This is done until the list is virtualy empty. The resulting \c elist has the constraint
|
||||
* as the last element.
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart dstart
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart dend
|
||||
*
|
||||
* \param elist
|
||||
* A list containing all the edges crossing the spesified constraint
|
||||
*
|
||||
* \using
|
||||
* swappableEdge
|
||||
* swapEdgeInList
|
||||
* crossesConstraint
|
||||
* isTheConstraint
|
||||
*/
|
||||
template <class TraitsType, class DartType>
|
||||
void transformToConstraint(ttl::TriangulationHelper helper, DartType& dstart, DartType& dend,
|
||||
std::list<DartType>& elist) const {
|
||||
|
||||
typename std::list<DartType>::iterator it, used;
|
||||
|
||||
// We may enter in a situation where dstart and dend are altered because of a swap.
|
||||
// (The general rule is that darts inside the actual quadrilateral can be changed,
|
||||
// but not those outside.)
|
||||
// So, we need some look-ahead strategies for dstart and dend and change these
|
||||
// after a swap if necessary.
|
||||
|
||||
int dartsInList = (int)elist.size();
|
||||
if (dartsInList == 0)
|
||||
return;
|
||||
|
||||
bool erase; // indicates if an edge is swapped away from the constraint such that it can be
|
||||
// moved to the back of the list
|
||||
bool locked = false;
|
||||
do {
|
||||
int noswap = 0;
|
||||
it = elist.begin();
|
||||
|
||||
// counts how many edges that have been swapped per list-cycle
|
||||
int counter = 1;
|
||||
while(it != elist.end()) { // ??? change this test with counter > dartsInList
|
||||
erase = false;
|
||||
// Check if our virtual end of the list has been crossed. It breaks the
|
||||
// while and starts all over again in the do-while loop
|
||||
if (counter > dartsInList)
|
||||
break;
|
||||
|
||||
if (ttl::TriangulationHelper::swappableEdge<TraitsType, DartType>(*it, true)) {
|
||||
// Dyn & Goren & Rippa 's notation:
|
||||
// The node assosiated with dart *it is denoted u_m. u_m has edges crossing the constraint
|
||||
// named w_1, ... , w_r . The other node to the edge assosiated with dart *it is w_s.
|
||||
// We want to swap from edge u_m<->w_s to edge w_{s-1}<->w_{s+1}.
|
||||
DartType op1 = *it;
|
||||
DartType op2 = op1;
|
||||
op1.alpha1().alpha0(); //finds dart with node w_{s-1}
|
||||
op2.alpha2().alpha1().alpha0(); // (CW) finds dart with node w_{s+1}
|
||||
DartType tmp = *it; tmp.alpha0(); // Dart with assosiated node opposite to node of *it allong edge
|
||||
// If there is a locked situation we swap, even if the result is crossing the constraint
|
||||
// If there is a looked situation, but we do an ordinary swap, it should be treated as
|
||||
// if we were not in a locked situation!!
|
||||
|
||||
// The flag swap_away indicates if the edge is swapped away from the constraint such that
|
||||
// it does not cross the constraint.
|
||||
bool swap_away = (crossesConstraint<TraitsType>(dstart, dend, *it, tmp) &&
|
||||
!crossesConstraint<TraitsType>(dstart, dend, op1, op2));
|
||||
if (swap_away || locked) {
|
||||
// Do a look-ahead to see if dstart and/or dend are in the quadrilateral
|
||||
// If so, we mark it with a flag to make sure we update them after the swap
|
||||
// (they may have been changed during the swap according to the general rule!)
|
||||
bool start = false;
|
||||
bool end = false;
|
||||
|
||||
DartType d = *it;
|
||||
if (d.alpha1().alpha0() == dstart)
|
||||
start = true;
|
||||
d = *it;
|
||||
if (d.alpha2().alpha1().alpha0().alpha1() == dend)
|
||||
end = true;
|
||||
|
||||
// This is the only place swapping is called when inserting a constraint
|
||||
helper.swapEdgeInList<TraitsType, DartType>(it,elist);
|
||||
|
||||
// If we, during look-ahead, found that dstart and/or dend were in the quadrilateral,
|
||||
// we update them.
|
||||
if (end)
|
||||
dend = *it;
|
||||
if (start) {
|
||||
dstart = *it;
|
||||
dstart.alpha0().alpha2();
|
||||
}
|
||||
|
||||
if (swap_away) { // !locked || //it should be sufficient with swap_away ???
|
||||
noswap++;
|
||||
erase = true;
|
||||
}
|
||||
|
||||
if (isTheConstraint(*it, dstart, dend)) {
|
||||
// Move the constraint to the end of the list
|
||||
DartType the_constraint = *it;
|
||||
elist.erase(it);
|
||||
elist.push_back(the_constraint);
|
||||
return;
|
||||
} //endif
|
||||
} //endif
|
||||
} //endif "swappable edge"
|
||||
|
||||
|
||||
// Move the edge to the end of the list if it was swapped away from the constraint
|
||||
if (erase) {
|
||||
used = it;
|
||||
elist.push_back(*it);
|
||||
++it;
|
||||
elist.erase(used);
|
||||
--dartsInList;
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
++counter;
|
||||
}
|
||||
|
||||
} //end while
|
||||
|
||||
if (noswap == 0)
|
||||
locked = true;
|
||||
|
||||
} while (dartsInList != 0);
|
||||
|
||||
|
||||
#ifdef DEBUG_TTL_CONSTR
|
||||
// We will never enter here. (If elist is empty, we return above).
|
||||
cout << "??????? ERROR 2, should never enter here ????????????????????????? SKIP ???? " << endl;
|
||||
exit(-1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}; // End of ConstrainedTriangulation class
|
||||
|
||||
}; // End of ttl_constr namespace scope
|
||||
|
||||
|
||||
namespace ttl { // (extension)
|
||||
|
||||
/** @name Constrained (Delaunay) Triangulation */
|
||||
//@{
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
/** 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 \c TraitsType::orient2d, which should return zero in this case, the
|
||||
* constraint is split. Otherwise a degenerate triangle will be made along
|
||||
* the constraint.
|
||||
*
|
||||
* \param dstart
|
||||
* A CCW dart with the start node of the constraint as the source node
|
||||
*
|
||||
* \param dend
|
||||
* A CCW dart with the end node of the constraint as the source node
|
||||
*
|
||||
* \param optimize_delaunay
|
||||
* If set to \c true, the resulting triangulation will be
|
||||
* a \e constrained \e Delaunay \e triangulation. If set to \c false, the resulting
|
||||
* triangulation will not necessarily be of constrained Delaunay type.
|
||||
*
|
||||
* \retval DartType
|
||||
* A dart representing the constrained edge.
|
||||
*
|
||||
* \require
|
||||
* - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&)
|
||||
* - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&)
|
||||
*
|
||||
* \using
|
||||
* - optimizeDelaunay if \e optimize_delaunay is set to \c true
|
||||
*
|
||||
* \par Assumes:
|
||||
* - The constrained edge must be inside the existing triangulation (and it cannot
|
||||
* cross the boundary of the triangulation).
|
||||
*/
|
||||
template <class TraitsType, class DartType>
|
||||
DartType TriangulationHelper::insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) {
|
||||
|
||||
// Assumes:
|
||||
// - It is the users responsibility to avoid crossing constraints
|
||||
// - The constraint cannot cross the boundary, i.e., the boundary must be
|
||||
// convex in the area of crossing edges.
|
||||
// - dtart and dend are preserved (same node associated.)
|
||||
|
||||
|
||||
// Find edges crossing the constraint and put them in elist.
|
||||
// If findCrossingEdges reaches a Node lying on the constraint, this function
|
||||
// calls itself recursively.
|
||||
|
||||
// RECURSION
|
||||
std::list<DartType> elist;
|
||||
DartType next_start = ttl_constr::ConstrainedTriangulation::findCrossingEdges<TraitsType>(dstart, dend, elist);
|
||||
|
||||
// If there are no crossing edges (elist is empty), we assume that the constraint
|
||||
// is an existing edge.
|
||||
// In this case, findCrossingEdges returns the constraint.
|
||||
// Put the constraint in the list to fit with the procedures below
|
||||
// (elist can also be empty in the case of invalid input data (the constraint is in
|
||||
// a non-convex area) but this is the users responsibility.)
|
||||
|
||||
//by Thomas Sevaldrud if (elist.size() == 0)
|
||||
//by Thomas Sevaldrud elist.push_back(next_start);
|
||||
|
||||
// findCrossingEdges stops if it finds a node lying on the constraint.
|
||||
// A dart with this node as start node is returned
|
||||
// We call insertConstraint recursivly until the received dart is dend
|
||||
if (!same_0_orbit(next_start, dend)) {
|
||||
|
||||
#ifdef DEBUG_TTL_CONSTR_PLOT
|
||||
cout << "RECURSION due to collinearity along constraint" << endl;
|
||||
#endif
|
||||
|
||||
insertConstraint<TraitsType,DartType>(next_start, dend, optimize_delaunay);
|
||||
}
|
||||
|
||||
// Swap edges such that the constraint edge is present in the transformed triangulation.
|
||||
if (elist.size() > 0) // by Thomas Sevaldrud
|
||||
ttl_constr::ConstrainedTriangulation::transformToConstraint<TraitsType>(dstart, next_start, elist);
|
||||
|
||||
#ifdef DEBUG_TTL_CONSTR_PLOT
|
||||
cout << "size of elist = " << elist.size() << endl;
|
||||
if (elist.size() > 0) {
|
||||
DartType the_constraint = elist.back();
|
||||
ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl;
|
||||
the_constraint.alpha0();
|
||||
ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Optimize to constrained Delaunay triangulation if required.
|
||||
typename std::list<DartType>::iterator end_opt = elist.end();
|
||||
if (optimize_delaunay) {
|
||||
|
||||
// Indicate that the constrained edge, which is the last element in the list,
|
||||
// should not be swapped
|
||||
--end_opt;
|
||||
optimizeDelaunay<TraitsType, DartType>(elist, end_opt);
|
||||
}
|
||||
|
||||
if(elist.size() == 0) // by Thomas Sevaldrud
|
||||
return next_start; // by Thomas Sevaldrud
|
||||
|
||||
// Return the constraint, which is still the last element in the list
|
||||
end_opt = elist.end();
|
||||
--end_opt;
|
||||
return *end_opt;
|
||||
}
|
||||
|
||||
//@} // End of Constrained Triangulation Group
|
||||
|
||||
}; // End of ttl namespace scope (extension)
|
||||
|
||||
#endif // _TTL_CONSTR_H_
|
Loading…
Reference in New Issue