You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1901 lines
61 KiB

  1. /*
  2. * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT,
  3. * Applied Mathematics, Norway.
  4. *
  5. * Contact information: E-mail: tor.dokken@sintef.no
  6. * SINTEF ICT, Department of Applied Mathematics,
  7. * P.O. Box 124 Blindern,
  8. * 0314 Oslo, Norway.
  9. *
  10. * This file is part of TTL.
  11. *
  12. * TTL is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Affero General Public License as
  14. * published by the Free Software Foundation, either version 3 of the
  15. * License, or (at your option) any later version.
  16. *
  17. * TTL is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public
  23. * License along with TTL. If not, see
  24. * <http://www.gnu.org/licenses/>.
  25. *
  26. * In accordance with Section 7(b) of the GNU Affero General Public
  27. * License, a covered work must retain the producer line in every data
  28. * file that is created or manipulated using TTL.
  29. *
  30. * Other Usage
  31. * You can be released from the requirements of the license by purchasing
  32. * a commercial license. Buying such a license is mandatory as soon as you
  33. * develop commercial activities involving the TTL library without
  34. * disclosing the source code of your own applications.
  35. *
  36. * This file may be used in accordance with the terms contained in a
  37. * written agreement between you and SINTEF ICT.
  38. */
  39. #ifndef _TTL_H_
  40. #define _TTL_H_
  41. #include <list>
  42. #include <iterator>
  43. // Debugging
  44. #ifdef DEBUG_TTL
  45. static void errorAndExit( char* aMessage )
  46. {
  47. cout << "\n!!! ERROR: " << aMessage << " !!!\n" << endl;
  48. exit(-1);
  49. }
  50. #endif
  51. // Next on TOPOLOGY:
  52. // - get triangle strips
  53. // - weighted graph, algorithms using a weight (real) for each edge,
  54. // e.g. an "abstract length". Use for minimum spanning tree
  55. // or some arithmetics on weights?
  56. // - Circulators as defined in CGAL with more STL compliant code
  57. // - analyze in detail locateFace: e.g. detect 0-orbit in case of infinite loop
  58. // around a node etc.
  59. /**
  60. * \brief Main interface to TTL
  61. *
  62. * This namespace contains the basic generic algorithms for the TTL,
  63. * the Triangulation Template Library.\n
  64. *
  65. * Examples of functionality are:
  66. * - Incremental Delaunay triangulation
  67. * - Constrained triangulation
  68. * - Insert/remove nodes and constrained edges
  69. * - Traversal operations
  70. * - Misc. queries for extracting information for visualisation systems etc.
  71. *
  72. * \par General requirements and assumptions:
  73. * - \e DART_TYPE and \e TRAITS_TYPE should be implemented in accordance with the description
  74. * in \ref api.
  75. * - A \b "Requires:" section in the documentation of a function template
  76. * shows which functionality is required in \e TRAITS_TYPE to
  77. * support that specific function.\n
  78. * Functionalty required in \e DART_TYPE is the same (almost) for all
  79. * function templates; see \ref api and the example referred to.
  80. * - When a reference to a \e dart object is passed to a function in TTL,
  81. * it is assumed that it is oriented \e counterclockwise (CCW) in a triangle
  82. * unless it is explicitly mentioned that it can also be \e clockwise (CW).
  83. * The same applies for a dart that is passed from a function in TTL to
  84. * the users TRAITS_TYPE class (or struct).
  85. * - When an edge (represented with a dart) is swapped, it is assumed that darts
  86. * outside the quadrilateral where the edge is a diagonal are not affected by
  87. * the swap. Thus, \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge"
  88. * must be implemented in accordance with this rule.
  89. *
  90. * \par Glossary:
  91. * - General terms are explained in \ref api.
  92. * - \e CCW - counterclockwise
  93. * - \e CW - clockwise
  94. * - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around
  95. * a node, around an edge and in a triangle respectively;
  96. * see get_0_orbit_interior and get_0_orbit_boundary
  97. * - \e arc - In a triangulation an arc is equivalent with an edge
  98. *
  99. * \see
  100. * \ref ttl_util and \ref api
  101. *
  102. * \author
  103. * yvind Hjelle, oyvindhj@ifi.uio.no
  104. */
  105. namespace ttl
  106. {
  107. class TRIANGULATION_HELPER
  108. {
  109. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  110. public:
  111. TRIANGULATION_HELPER( hed::TRIANGULATION& aTriang ) :
  112. m_triangulation( aTriang )
  113. {
  114. }
  115. // Delaunay Triangulation
  116. template <class TRAITS_TYPE, class DART_TYPE, class POINT_TYPE>
  117. bool InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint );
  118. template <class TRAITS_TYPE, class DART_TYPE>
  119. void RemoveRectangularBoundary( DART_TYPE& aDart );
  120. template <class TRAITS_TYPE, class DART_TYPE>
  121. void RemoveNode( DART_TYPE& aDart );
  122. template <class TRAITS_TYPE, class DART_TYPE>
  123. void RemoveBoundaryNode( DART_TYPE& aDart );
  124. template <class TRAITS_TYPE, class DART_TYPE>
  125. void RemoveInteriorNode( DART_TYPE& aDart );
  126. // Topological and Geometric Queries
  127. // ---------------------------------
  128. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  129. static bool LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart );
  130. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  131. static bool LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart );
  132. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  133. static bool InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart );
  134. template <class DART_TYPE, class DART_LIST_TYPE>
  135. static void GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary );
  136. template <class DART_TYPE>
  137. static bool IsBoundaryEdge( const DART_TYPE& aDart );
  138. template <class DART_TYPE>
  139. static bool IsBoundaryFace( const DART_TYPE& aDart );
  140. template <class DART_TYPE>
  141. static bool IsBoundaryNode( const DART_TYPE& aDart );
  142. template <class DART_TYPE>
  143. static int GetDegreeOfNode( const DART_TYPE& aDart );
  144. template <class DART_TYPE, class DART_LIST_TYPE>
  145. static void Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit );
  146. template <class DART_TYPE, class DART_LIST_TYPE>
  147. static void Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit );
  148. template <class DART_TYPE>
  149. static bool Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 );
  150. template <class DART_TYPE>
  151. static bool Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 );
  152. template <class DART_TYPE>
  153. static bool Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 );
  154. template <class TRAITS_TYPE, class DART_TYPE>
  155. static bool SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy = false );
  156. template <class DART_TYPE>
  157. static void PositionAtNextBoundaryEdge( DART_TYPE& aDart );
  158. template <class TRAITS_TYPE, class DART_TYPE>
  159. static bool ConvexBoundary( const DART_TYPE& aDart );
  160. // Utilities for Delaunay Triangulation
  161. // ------------------------------------
  162. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  163. void OptimizeDelaunay( DART_LIST_TYPE& aElist );
  164. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  165. void OptimizeDelaunay( DART_LIST_TYPE& aElist, const typename DART_LIST_TYPE::iterator aEnd );
  166. template <class TRAITS_TYPE, class DART_TYPE>
  167. bool SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck = false ) const;
  168. template <class TRAITS_TYPE, class DART_TYPE>
  169. void RecSwapDelaunay( DART_TYPE& aDiagonal );
  170. template <class TRAITS_TYPE, class DART_TYPE, class LIST_TYPE>
  171. void SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges );
  172. template <class TRAITS_TYPE, class DART_TYPE, class LIST_TYPE>
  173. void SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart, LIST_TYPE& aSwappedEdges );
  174. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  175. void SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt, DART_LIST_TYPE& aElist );
  176. // Constrained Triangulation
  177. // -------------------------
  178. template <class TRAITS_TYPE, class DART_TYPE>
  179. static DART_TYPE InsertConstraint( DART_TYPE& aDStart, DART_TYPE& aDEnd, bool aOptimizeDelaunay );
  180. private:
  181. hed::TRIANGULATION& m_triangulation;
  182. template <class TRAITS_TYPE, class FORWARD_ITERATOR, class DART_TYPE>
  183. void insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast, DART_TYPE& aDart );
  184. template <class TOPOLOGY_ELEMENT_TYPE, class DART_TYPE>
  185. static bool isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement, const DART_TYPE& aDart );
  186. template <class TRAITS_TYPE, class NODE_TYPE, class DART_TYPE>
  187. static bool locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter );
  188. template <class DART_TYPE>
  189. static void getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1, DART_TYPE& aT2,
  190. DART_TYPE& aT3 );
  191. template <class DART_TYPE>
  192. static void getNeighborNodes( const DART_TYPE& aDart, std::list<DART_TYPE>& aNodeList,
  193. bool& aBoundary );
  194. template <class TRAITS_TYPE, class DART_TYPE>
  195. static bool degenerateTriangle( const DART_TYPE& aDart );
  196. };
  197. #endif // DOXYGEN_SHOULD_SKIP_THIS
  198. /** @name Delaunay Triangulation */
  199. //@{
  200. /**
  201. * Inserts a new node in an existing Delaunay triangulation and
  202. * swaps edges to obtain a new Delaunay triangulation.
  203. * This is the basic function for incremental Delaunay triangulation.
  204. * When starting from a set of points, an initial Delaunay triangulation
  205. * can be created as two triangles forming a rectangle that contains
  206. * all the points.
  207. * After \c insertNode has been called repeatedly with all the points,
  208. * removeRectangularBoundary can be called to remove triangles
  209. * at the boundary of the triangulation so that the boundary
  210. * form the convex hull of the points.
  211. *
  212. * Note that this incremetal scheme will run much faster if the points
  213. * have been sorted lexicographically on \e x and \e y.
  214. *
  215. * \param aDart
  216. * An arbitrary CCW dart in the tringulation.\n
  217. * Output: A CCW dart incident to the new node.
  218. *
  219. * \param aPoint
  220. * A point (node) to be inserted in the triangulation.
  221. *
  222. * \retval bool
  223. * \c true if \e point was inserted; \c false if not.\n
  224. * If \e point is outside the triangulation, or the input dart is not valid,
  225. * \c false is returned.
  226. *
  227. * \require
  228. * - \ref hed::TTLtraits::splitTriangle "TRAITS_TYPE::splitTriangle" (DART_TYPE&, const POINT_TYPE&)
  229. *
  230. * \using
  231. * - locateTriangle
  232. * - RecSwapDelaunay
  233. *
  234. * \note
  235. * - For efficiency reasons \e dart should be close to the insertion \e point.
  236. *
  237. * \see
  238. * removeRectangularBoundary
  239. */
  240. template <class TRAITS_TYPE, class DART_TYPE, class POINT_TYPE>
  241. bool TRIANGULATION_HELPER::InsertNode( DART_TYPE& aDart, POINT_TYPE& aPoint )
  242. {
  243. bool found = LocateTriangle<TRAITS_TYPE>( aPoint, aDart );
  244. if( !found )
  245. {
  246. #ifdef DEBUG_TTL
  247. cout << "ERROR: Triangulation::insertNode: NO triangle found. /n";
  248. #endif
  249. return false;
  250. }
  251. // ??? can we hide the dart? this is not possible if one triangle only
  252. m_triangulation.splitTriangle( aDart, aPoint );
  253. DART_TYPE d1 = aDart;
  254. d1.Alpha2().Alpha1().Alpha2().Alpha0().Alpha1();
  255. DART_TYPE d2 = aDart;
  256. d2.Alpha1().Alpha0().Alpha1();
  257. // Preserve a dart as output incident to the node and CCW
  258. DART_TYPE d3 = aDart;
  259. d3.Alpha2();
  260. aDart = d3; // and see below
  261. //DART_TYPE dsav = d3;
  262. d3.Alpha0().Alpha1();
  263. //if (!TRAITS_TYPE::fixedEdge(d1) && !IsBoundaryEdge(d1)) {
  264. if( !IsBoundaryEdge( d1 ) )
  265. {
  266. d1.Alpha2();
  267. RecSwapDelaunay<TRAITS_TYPE>( d1 );
  268. }
  269. //if (!TRAITS_TYPE::fixedEdge(d2) && !IsBoundaryEdge(d2)) {
  270. if( !IsBoundaryEdge( d2 ) )
  271. {
  272. d2.Alpha2();
  273. RecSwapDelaunay<TRAITS_TYPE>( d2 );
  274. }
  275. // Preserve the incoming dart as output incident to the node and CCW
  276. //d = dsav.Alpha2();
  277. aDart.Alpha2();
  278. //if (!TRAITS_TYPE::fixedEdge(d3) && !IsBoundaryEdge(d3)) {
  279. if( !IsBoundaryEdge( d3 ) )
  280. {
  281. d3.Alpha2();
  282. RecSwapDelaunay<TRAITS_TYPE>( d3 );
  283. }
  284. return true;
  285. }
  286. //------------------------------------------------------------------------------------------------
  287. // Private/Hidden function (might change later)
  288. template <class TRAITS_TYPE, class FORWARD_ITERATOR, class DART_TYPE>
  289. void TRIANGULATION_HELPER::insertNodes( FORWARD_ITERATOR aFirst, FORWARD_ITERATOR aLast,
  290. DART_TYPE& aDart )
  291. {
  292. // Assumes that the dereferenced point objects are pointers.
  293. // References to the point objects are then passed to TTL.
  294. FORWARD_ITERATOR it;
  295. for( it = aFirst; it != aLast; ++it )
  296. {
  297. InsertNode<TRAITS_TYPE>( aDart, **it );
  298. }
  299. }
  300. /** Removes the rectangular boundary of a triangulation as a final step of an
  301. * incremental Delaunay triangulation.
  302. * The four nodes at the corners will be removed and the resulting triangulation
  303. * will have a convex boundary and be Delaunay.
  304. *
  305. * \param dart
  306. * A CCW dart at the boundary of the triangulation\n
  307. * Output: A CCW dart at the new boundary
  308. *
  309. * \using
  310. * - RemoveBoundaryNode
  311. *
  312. * \note
  313. * - This function requires that the boundary of the m_triangulation is
  314. * a rectangle with four nodes (one in each corner).
  315. */
  316. template <class TRAITS_TYPE, class DART_TYPE>
  317. void TRIANGULATION_HELPER::RemoveRectangularBoundary( DART_TYPE& aDart )
  318. {
  319. DART_TYPE d_next = aDart;
  320. DART_TYPE d_iter;
  321. for( int i = 0; i < 4; i++ )
  322. {
  323. d_iter = d_next;
  324. d_next.Alpha0();
  325. PositionAtNextBoundaryEdge( d_next );
  326. RemoveBoundaryNode<TRAITS_TYPE>( d_iter );
  327. }
  328. aDart = d_next; // Return a dart at the new boundary
  329. }
  330. /** Removes the node associated with \e dart and
  331. * updates the triangulation to be Delaunay.
  332. *
  333. * \using
  334. * - RemoveBoundaryNode if \e dart represents a node at the boundary
  335. * - RemoveInteriorNode if \e dart represents an interior node
  336. *
  337. * \note
  338. * - The node cannot belong to a fixed (constrained) edge that is not
  339. * swappable. (An endless loop is likely to occur in this case).
  340. */
  341. template <class TRAITS_TYPE, class DART_TYPE>
  342. void TRIANGULATION_HELPER::RemoveNode( DART_TYPE& aDart )
  343. {
  344. if( isBoundaryNode( aDart ) )
  345. RemoveBoundaryNode<TRAITS_TYPE>( aDart );
  346. else
  347. RemoveInteriorNode<TRAITS_TYPE>( aDart );
  348. }
  349. /** Removes the boundary node associated with \e dart and
  350. * updates the triangulation to be Delaunay.
  351. *
  352. * \using
  353. * - SwapEdgesAwayFromBoundaryNode
  354. * - OptimizeDelaunay
  355. *
  356. * \require
  357. * - \ref hed::TTLtraits::removeBoundaryTriangle "TRAITS_TYPE::removeBoundaryTriangle" (Dart&)
  358. */
  359. template <class TRAITS_TYPE, class DART_TYPE>
  360. void TRIANGULATION_HELPER::RemoveBoundaryNode( DART_TYPE& aDart )
  361. {
  362. // ... and update Delaunay
  363. // - CCW dart must be given (for remove)
  364. // - No dart is delivered back now (but this is possible if
  365. // we assume that there is not only one triangle left in the m_triangulation.
  366. // Position at boundary edge and CCW
  367. if( !IsBoundaryEdge( aDart ) )
  368. {
  369. aDart.Alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW)
  370. PositionAtNextBoundaryEdge( aDart );
  371. }
  372. std::list<DART_TYPE> swapped_edges;
  373. SwapEdgesAwayFromBoundaryNode<TRAITS_TYPE>( aDart, swapped_edges );
  374. // Remove boundary triangles and remove the new boundary from the list
  375. // of swapped edges, see below.
  376. DART_TYPE d_iter = aDart;
  377. DART_TYPE dnext = aDart;
  378. bool bend = false;
  379. while( bend == false )
  380. {
  381. dnext.Alpha1().Alpha2();
  382. if( IsBoundaryEdge( dnext ) )
  383. bend = true; // Stop when boundary
  384. // Generic: Also remove the new boundary from the list of swapped edges
  385. DART_TYPE n_bedge = d_iter;
  386. n_bedge.Alpha1().Alpha0().Alpha1().Alpha2(); // new boundary edge
  387. // ??? can we avoid find if we do this in swap away?
  388. typename std::list<DART_TYPE>::iterator it;
  389. it = find( swapped_edges.begin(), swapped_edges.end(), n_bedge );
  390. if( it != swapped_edges.end() )
  391. swapped_edges.erase( it );
  392. // Remove the boundary triangle
  393. m_triangulation.removeBoundaryTriangle( d_iter );
  394. d_iter = dnext;
  395. }
  396. // Optimize Delaunay
  397. typedef std::list<DART_TYPE> DART_LIST_TYPE;
  398. OptimizeDelaunay<TRAITS_TYPE, DART_TYPE, DART_LIST_TYPE>( swapped_edges );
  399. }
  400. /** Removes the interior node associated with \e dart and
  401. * updates the triangulation to be Delaunay.
  402. *
  403. * \using
  404. * - SwapEdgesAwayFromInteriorNode
  405. * - OptimizeDelaunay
  406. *
  407. * \require
  408. * - \ref hed::TTLtraits::reverse_splitTriangle "TRAITS_TYPE::reverse_splitTriangle" (Dart&)
  409. *
  410. * \note
  411. * - The node cannot belong to a fixed (constrained) edge that is not
  412. * swappable. (An endless loop is likely to occur in this case).
  413. */
  414. template <class TRAITS_TYPE, class DART_TYPE>
  415. void TRIANGULATION_HELPER::RemoveInteriorNode( DART_TYPE& aDart )
  416. {
  417. // ... and update to Delaunay.
  418. // Must allow degeneracy temporarily, see comments in swap edges away
  419. // Assumes:
  420. // - revese_splitTriangle does not affect darts
  421. // outside the resulting triangle.
  422. // 1) Swaps edges away from the node until degree=3 (generic)
  423. // 2) Removes the remaining 3 triangles and creates a new to fill the hole
  424. // unsplitTriangle which is required
  425. // 3) Runs LOP on the platelet to obtain a Delaunay m_triangulation
  426. // (No dart is delivered as output)
  427. // Assumes dart is counterclockwise
  428. std::list<DART_TYPE> swapped_edges;
  429. SwapEdgesAwayFromInteriorNode<TRAITS_TYPE>( aDart, swapped_edges );
  430. // The reverse operation of split triangle:
  431. // Make one triangle of the three triangles at the node associated with dart
  432. // TRAITS_TYPE::
  433. m_triangulation.reverseSplitTriangle( aDart );
  434. // ???? Not generic yet if we are very strict:
  435. // When calling unsplit triangle, darts at the three opposite sides may
  436. // change!
  437. // Should we hide them longer away??? This is possible since they cannot
  438. // be boundary edges.
  439. // ----> Or should we just require that they are not changed???
  440. // Make the swapped-away edges Delaunay.
  441. // Note the theoretical result: if there are no edges in the list,
  442. // the triangulation is Delaunay already
  443. OptimizeDelaunay<TRAITS_TYPE, DART_TYPE>( swapped_edges );
  444. }
  445. //@} // End of Delaunay Triangulation Group
  446. /** @name Topological and Geometric Queries */
  447. //@{
  448. //------------------------------------------------------------------------------------------------
  449. // Private/Hidden function (might change later)
  450. template <class TOPOLOGY_ELEMENT_TYPE, class DART_TYPE>
  451. bool TRIANGULATION_HELPER::isMemberOfFace( const TOPOLOGY_ELEMENT_TYPE& aTopologyElement,
  452. const DART_TYPE& aDart )
  453. {
  454. // Check if the given topology element (node, edge or face) is a member of the face
  455. // Assumes:
  456. // - DART_TYPE::isMember(TOPOLOGY_ELEMENT_TYPE)
  457. DART_TYPE dart_iter = aDart;
  458. do
  459. {
  460. if( dart_iter.isMember( aTopologyElement ) )
  461. return true;
  462. dart_iter.Alpha0().Alpha1();
  463. }
  464. while( dart_iter != aDart );
  465. return false;
  466. }
  467. //------------------------------------------------------------------------------------------------
  468. // Private/Hidden function (might change later)
  469. template <class TRAITS_TYPE, class NODE_TYPE, class DART_TYPE>
  470. bool TRIANGULATION_HELPER::locateFaceWithNode( const NODE_TYPE& aNode, DART_TYPE& aDartIter )
  471. {
  472. // Locate a face in the topology structure with the given node as a member
  473. // Assumes:
  474. // - TRAITS_TYPE::Orient2D(DART_TYPE, DART_TYPE, NODE_TYPE)
  475. // - DART_TYPE::isMember(NODE_TYPE)
  476. // - Note that if false is returned, the node might still be in the
  477. // topology structure. Application programmer
  478. // should check all if by hypothesis the node is in the topology structure;
  479. // see doc. on LocateTriangle.
  480. bool status = LocateFaceSimplest<TRAITS_TYPE>( aNode, aDartIter );
  481. if( status == false )
  482. return status;
  483. // True was returned from LocateFaceSimplest, but if the located triangle is
  484. // degenerate and the node is on the extension of the edges,
  485. // the node might still be inside. Check if node is a member and return false
  486. // if not. (Still the node might be in the topology structure, see doc. above
  487. // and in locateTriangle(const POINT_TYPE& point, DART_TYPE& dart_iter)
  488. return isMemberOfFace( aNode, aDartIter );
  489. }
  490. /** Locates the face containing a given point.
  491. * It is assumed that the tessellation (e.g. a triangulation) is \e regular in the sense that
  492. * there are no holes, the boundary is convex and there are no degenerate faces.
  493. *
  494. * \param aPoint
  495. * A point to be located
  496. *
  497. * \param aDart
  498. * An arbitrary CCW dart in the triangulation\n
  499. * Output: A CCW dart in the located face
  500. *
  501. * \retval bool
  502. * \c true if a face is found; \c false if not.
  503. *
  504. * \require
  505. * - \ref hed::TTLtraits::Orient2D "TRAITS_TYPE::Orient2D" (DART_TYPE&, DART_TYPE&, POINT_TYPE&)
  506. *
  507. * \note
  508. * - If \c false is returned, \e point may still be inside a face if the tessellation is not
  509. * \e regular as explained above.
  510. *
  511. * \see
  512. * LocateTriangle
  513. */
  514. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  515. bool TRIANGULATION_HELPER::LocateFaceSimplest( const POINT_TYPE& aPoint, DART_TYPE& aDart )
  516. {
  517. // Not degenerate triangles if point is on the extension of the edges
  518. // But inTriangle may be called in case of true (may update to inFace2)
  519. // Convex boundary
  520. // no holes
  521. // convex faces (works for general convex faces)
  522. // Not specialized for triangles, but ok?
  523. //
  524. // TRAITS_TYPE::orint2d(POINT_TYPE) is the half open half-plane defined
  525. // by the dart:
  526. // n1 = dart.node()
  527. // n2 = dart.Alpha0().node
  528. // Only the following gives true:
  529. // ((n2->x()-n1->x())*(point.y()-n1->y()) >= (point.x()-n1->x())*(n2->y()-n1->y()))
  530. DART_TYPE dart_start;
  531. dart_start = aDart;
  532. DART_TYPE dart_prev;
  533. DART_TYPE d0;
  534. for( ;; )
  535. {
  536. d0 = aDart;
  537. d0.Alpha0();
  538. if( TRAITS_TYPE::Orient2D( aDart, d0, aPoint ) >= 0 )
  539. {
  540. aDart.Alpha0().Alpha1();
  541. if( aDart == dart_start )
  542. return true; // left to all edges in face
  543. }
  544. else
  545. {
  546. dart_prev = aDart;
  547. aDart.Alpha2();
  548. if( aDart == dart_prev )
  549. return false; // iteration to outside boundary
  550. dart_start = aDart;
  551. dart_start.Alpha0();
  552. aDart.Alpha1(); // avoid twice on same edge and ccw in next
  553. }
  554. }
  555. }
  556. /** Locates the triangle containing a given point.
  557. * It is assumed that the triangulation is \e regular in the sense that there
  558. * are no holes and the boundary is convex.
  559. * This function deals with degeneracy to some extent, but round-off errors may still
  560. * lead to a wrong result if triangles are degenerate.
  561. *
  562. * \param point
  563. * A point to be located
  564. *
  565. * \param dart
  566. * An arbitrary CCW dart in the triangulation\n
  567. * Output: A CCW dart in the located triangle
  568. *
  569. * \retval bool
  570. * \c true if a triangle is found; \c false if not.\n
  571. * If \e point is outside the m_triangulation, in which case \c false is returned,
  572. * then the edge associated with \e dart will be at the boundary of the m_triangulation.
  573. *
  574. * \using
  575. * - LocateFaceSimplest
  576. * - InTriangle
  577. */
  578. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  579. bool TRIANGULATION_HELPER::LocateTriangle( const POINT_TYPE& aPoint, DART_TYPE& aDart )
  580. {
  581. // The purpose is to have a fast and stable procedure that
  582. // i) avoids concluding that a point is inside a triangle if it is not inside
  583. // ii) avoids infinite loops
  584. // Thus, if false is returned, the point might still be inside a triangle in
  585. // the triangulation. But this will probably only occur in the following cases:
  586. // i) There are holes in the triangulation which causes the procedure to stop.
  587. // ii) The boundary of the m_triangulation is not convex.
  588. // ii) There might be degenerate triangles interior to the triangulation, or on the
  589. // the boundary, which in some cases might cause the procedure to stop there due
  590. // to the logic of the algorithm.
  591. // It is the application programmer's responsibility to check further if false is
  592. // returned. For example, if by hypothesis the point is inside a triangle
  593. // in the triangulation and and false is returned, then all triangles in the
  594. // triangulation should be checked by the application. This can be done using
  595. // the function:
  596. // bool inTriangle(const POINT_TYPE& point, const DART_TYPE& dart).
  597. // Assumes:
  598. // - CrossProduct2D, ScalarProduct2D etc., see functions called
  599. bool status = LocateFaceSimplest<TRAITS_TYPE>( aPoint, aDart );
  600. if( status == false )
  601. return status;
  602. // There may be degeneracy, i.e., the point might be outside the triangle
  603. // on the extension of the edges of a degenerate triangle.
  604. // The next call returns true if inside a non-degenerate or a degenerate triangle,
  605. // but false if the point coincides with the "supernode" in the case where all
  606. // edges are degenerate.
  607. return InTriangle<TRAITS_TYPE>( aPoint, aDart );
  608. }
  609. /** Checks if \e point is inside the triangle associated with \e dart.
  610. * This function deals with degeneracy to some extent, but round-off errors may still
  611. * lead to wrong result if the triangle is degenerate.
  612. *
  613. * \param aDart
  614. * A CCW dart in the triangle
  615. *
  616. * \require
  617. * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, POINT_TYPE&)
  618. * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, POINT_TYPE&)
  619. *
  620. * \see
  621. * InTriangleSimplest
  622. */
  623. template <class TRAITS_TYPE, class POINT_TYPE, class DART_TYPE>
  624. bool TRIANGULATION_HELPER::InTriangle( const POINT_TYPE& aPoint, const DART_TYPE& aDart )
  625. {
  626. // SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT
  627. // ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH
  628. // notInE1 && notInE1.neghbour ?
  629. // Returns true if inside (but not necessarily strictly inside)
  630. // Works for degenerate triangles, but not when all edges are degenerate,
  631. // and the aPoint coincides with all nodes;
  632. // then false is always returned.
  633. typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE;
  634. DART_TYPE dart_iter = aDart;
  635. REAL_TYPE cr1 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint );
  636. if( cr1 < 0 )
  637. return false;
  638. dart_iter.Alpha0().Alpha1();
  639. REAL_TYPE cr2 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint );
  640. if( cr2 < 0 )
  641. return false;
  642. dart_iter.Alpha0().Alpha1();
  643. REAL_TYPE cr3 = TRAITS_TYPE::CrossProduct2D( dart_iter, aPoint );
  644. if( cr3 < 0 )
  645. return false;
  646. // All cross products are >= 0
  647. // Check for degeneracy
  648. if( cr1 != 0 || cr2 != 0 || cr3 != 0 )
  649. return true; // inside non-degenerate face
  650. // All cross-products are zero, i.e. degenerate triangle, check if inside
  651. // Strategy: d.ScalarProduct2D >= 0 && alpha0(d).d.ScalarProduct2D >= 0 for one of
  652. // the edges. But if all edges are degenerate and the aPoint is on (all) the nodes,
  653. // then "false is returned".
  654. DART_TYPE dart_tmp = dart_iter;
  655. REAL_TYPE sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint );
  656. REAL_TYPE sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint );
  657. if( sc1 >= 0 && sc2 >= 0 )
  658. {
  659. // test for degenerate edge
  660. if( sc1 != 0 || sc2 != 0 )
  661. return true; // interior to this edge or on a node (but see comment above)
  662. }
  663. dart_tmp = dart_iter.Alpha0().Alpha1();
  664. sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint );
  665. sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint );
  666. if( sc1 >= 0 && sc2 >= 0 )
  667. {
  668. // test for degenerate edge
  669. if( sc1 != 0 || sc2 != 0 )
  670. return true; // interior to this edge or on a node (but see comment above)
  671. }
  672. dart_tmp = dart_iter.Alpha1();
  673. sc1 = TRAITS_TYPE::ScalarProduct2D( dart_tmp, aPoint );
  674. sc2 = TRAITS_TYPE::ScalarProduct2D( dart_tmp.Alpha0(), aPoint );
  675. if( sc1 >= 0 && sc2 >= 0 )
  676. {
  677. // test for degenerate edge
  678. if( sc1 != 0 || sc2 != 0 )
  679. return true; // interior to this edge or on a node (but see comment above)
  680. }
  681. // Not on any of the edges of the degenerate triangle.
  682. // The only possibility for the aPoint to be "inside" is that all edges are degenerate
  683. // and the point coincide with all nodes. So false is returned in this case.
  684. return false;
  685. }
  686. //------------------------------------------------------------------------------------------------
  687. // Private/Hidden function (might change later)
  688. template <class DART_TYPE>
  689. void TRIANGULATION_HELPER::getAdjacentTriangles( const DART_TYPE& aDart, DART_TYPE& aT1,
  690. DART_TYPE& aT2, DART_TYPE& aT3 )
  691. {
  692. DART_TYPE dart_iter = aDart;
  693. // add first
  694. if( dart_iter.Alpha2() != aDart )
  695. {
  696. aT1 = dart_iter;
  697. dart_iter = aDart;
  698. }
  699. // add second
  700. dart_iter.Alpha0();
  701. dart_iter.Alpha1();
  702. DART_TYPE dart_prev = dart_iter;
  703. if( ( dart_iter.Alpha2() ) != dart_prev )
  704. {
  705. aT2 = dart_iter;
  706. dart_iter = dart_prev;
  707. }
  708. // add third
  709. dart_iter.Alpha0();
  710. dart_iter.Alpha1();
  711. dart_prev = dart_iter;
  712. if( ( dart_iter.Alpha2() ) != dart_prev )
  713. aT3 = dart_iter;
  714. }
  715. //------------------------------------------------------------------------------------------------
  716. /** Gets the boundary as sequence of darts, where the edges associated with the darts are boundary
  717. * edges, given a dart with an associating edge at the boundary of a topology structure.
  718. * The first dart in the sequence will be the given one, and the others will have the same
  719. * orientation (CCW or CW) as the first.
  720. * Assumes that the given dart is at the boundary.
  721. *
  722. * \param aDart
  723. * A dart at the boundary (CCW or CW)
  724. *
  725. * \param aBoundary
  726. * A sequence of darts, where the associated edges are the boundary edges
  727. *
  728. * \require
  729. * - DART_LIST_TYPE::push_back (DART_TYPE&)
  730. */
  731. template <class DART_TYPE, class DART_LIST_TYPE>
  732. void TRIANGULATION_HELPER::GetBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aBoundary )
  733. {
  734. // assumes the given dart is at the boundary (by edge)
  735. DART_TYPE dart_iter( aDart );
  736. aBoundary.push_back( dart_iter ); // Given dart as first element
  737. dart_iter.Alpha0();
  738. PositionAtNextBoundaryEdge( dart_iter );
  739. while( dart_iter != aDart )
  740. {
  741. aBoundary.push_back( dart_iter );
  742. dart_iter.Alpha0();
  743. PositionAtNextBoundaryEdge( dart_iter );
  744. }
  745. }
  746. /** Checks if the edge associated with \e dart is at
  747. * the boundary of the m_triangulation.
  748. *
  749. * \par Implements:
  750. * \code
  751. * DART_TYPE dart_iter = dart;
  752. * if (dart_iter.Alpha2() == dart)
  753. * return true;
  754. * else
  755. * return false;
  756. * \endcode
  757. */
  758. template <class DART_TYPE>
  759. bool TRIANGULATION_HELPER::IsBoundaryEdge( const DART_TYPE& aDart )
  760. {
  761. DART_TYPE dart_iter = aDart;
  762. if( dart_iter.Alpha2() == aDart )
  763. return true;
  764. else
  765. return false;
  766. }
  767. /** Checks if the face associated with \e dart is at
  768. * the boundary of the m_triangulation.
  769. */
  770. template <class DART_TYPE>
  771. bool TRIANGULATION_HELPER::IsBoundaryFace( const DART_TYPE& aDart )
  772. {
  773. // Strategy: boundary if alpha2(d)=d
  774. DART_TYPE dart_iter( aDart );
  775. DART_TYPE dart_prev;
  776. do
  777. {
  778. dart_prev = dart_iter;
  779. if( dart_iter.Alpha2() == dart_prev )
  780. return true;
  781. else
  782. dart_iter = dart_prev; // back again
  783. dart_iter.Alpha0();
  784. dart_iter.Alpha1();
  785. } while( dart_iter != aDart );
  786. return false;
  787. }
  788. /** Checks if the node associated with \e dart is at
  789. * the boundary of the m_triangulation.
  790. */
  791. template <class DART_TYPE>
  792. bool TRIANGULATION_HELPER::IsBoundaryNode( const DART_TYPE& aDart )
  793. {
  794. // Strategy: boundary if alpha2(d)=d
  795. DART_TYPE dart_iter( aDart );
  796. DART_TYPE dart_prev;
  797. // If input dart is reached again, then internal node
  798. // If alpha2(d)=d, then boundary
  799. do
  800. {
  801. dart_iter.Alpha1();
  802. dart_prev = dart_iter;
  803. dart_iter.Alpha2();
  804. if( dart_iter == dart_prev )
  805. return true;
  806. } while( dart_iter != aDart );
  807. return false;
  808. }
  809. /** Returns the degree of the node associated with \e dart.
  810. *
  811. * \par Definition:
  812. * The \e degree (or valency) of a node \e V in a m_triangulation,
  813. * is defined as the number of edges incident with \e V, i.e.,
  814. * the number of edges joining \e V with another node in the triangulation.
  815. */
  816. template <class DART_TYPE>
  817. int TRIANGULATION_HELPER::GetDegreeOfNode( const DART_TYPE& aDart )
  818. {
  819. DART_TYPE dart_iter( aDart );
  820. DART_TYPE dart_prev;
  821. // If input dart is reached again, then interior node
  822. // If alpha2(d)=d, then boundary
  823. int degree = 0;
  824. bool boundaryVisited = false;
  825. do
  826. {
  827. dart_iter.Alpha1();
  828. degree++;
  829. dart_prev = dart_iter;
  830. dart_iter.Alpha2();
  831. if( dart_iter == dart_prev )
  832. {
  833. if( !boundaryVisited )
  834. {
  835. boundaryVisited = true;
  836. // boundary is reached first time, count in the reversed direction
  837. degree++; // count the start since it is not done above
  838. dart_iter = aDart;
  839. dart_iter.Alpha2();
  840. } else
  841. return degree;
  842. }
  843. } while( dart_iter != aDart );
  844. return degree;
  845. }
  846. // Modification of GetDegreeOfNode:
  847. // Strategy, reverse the list and start in the other direction if the boundary
  848. // is reached. NB. copying of darts but ok., or we could have collected pointers,
  849. // but the memory management.
  850. // NOTE: not symmetry if we choose to collect opposite edges
  851. // now we collect darts with radiating edges
  852. // Remember that we must also copy the node, but ok with push_back
  853. // The size of the list will be the degree of the node
  854. // No CW/CCW since topology only
  855. // Each dart consists of an incident edge and an adjacent node.
  856. // But note that this is only how we interpret the dart in this implementation.
  857. // Given this list, how can we find the opposite edges:
  858. // We can perform alpha1 on each, but for boundary nodes we will get one edge twice.
  859. // But this is will always be the last dart!
  860. // The darts in the list are in sequence and starts with the alpha0(dart)
  861. // alpha0, alpha1 and alpha2
  862. // Private/Hidden function
  863. template <class DART_TYPE>
  864. void TRIANGULATION_HELPER::getNeighborNodes( const DART_TYPE& aDart,
  865. std::list<DART_TYPE>& aNodeList, bool& aBoundary )
  866. {
  867. DART_TYPE dart_iter( aDart );
  868. dart_iter.Alpha0(); // position the dart at an opposite node
  869. DART_TYPE dart_prev = dart_iter;
  870. bool start_at_boundary = false;
  871. dart_iter.Alpha2();
  872. if( dart_iter == dart_prev )
  873. start_at_boundary = true;
  874. else
  875. dart_iter = dart_prev; // back again
  876. DART_TYPE dart_start = dart_iter;
  877. do
  878. {
  879. aNodeList.push_back( dart_iter );
  880. dart_iter.Alpha1();
  881. dart_iter.Alpha0();
  882. dart_iter.Alpha1();
  883. dart_prev = dart_iter;
  884. dart_iter.Alpha2();
  885. if( dart_iter == dart_prev )
  886. {
  887. // boundary reached
  888. aBoundary = true;
  889. if( start_at_boundary == true )
  890. {
  891. // add the dart which now is positioned at the opposite boundary
  892. aNodeList.push_back( dart_iter );
  893. return;
  894. }
  895. else
  896. {
  897. // call the function again such that we start at the boundary
  898. // first clear the list and reposition to the initial node
  899. dart_iter.Alpha0();
  900. aNodeList.clear();
  901. getNeighborNodes( dart_iter, aNodeList, aBoundary );
  902. return; // after one recursive step
  903. }
  904. }
  905. }
  906. while( dart_iter != dart_start );
  907. aBoundary = false;
  908. }
  909. /** Gets the 0-orbit around an interior node.
  910. *
  911. * \param aDart
  912. * A dart (CCW or CW) positioned at an \e interior node.
  913. *
  914. * \retval aOrbit
  915. * Sequence of darts with one orbit for each arc. All the darts have the same
  916. * orientation (CCW or CW) as \e dart, and \e dart is the first element
  917. * in the sequence.
  918. *
  919. * \require
  920. * - DART_LIST_TYPE::push_back (DART_TYPE&)
  921. *
  922. * \see
  923. * Get0OrbitBoundary
  924. */
  925. template <class DART_TYPE, class DART_LIST_TYPE>
  926. void TRIANGULATION_HELPER::Get0OrbitInterior( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit )
  927. {
  928. DART_TYPE d_iter = aDart;
  929. aOrbit.push_back( d_iter );
  930. d_iter.Alpha1().Alpha2();
  931. while( d_iter != aDart )
  932. {
  933. aOrbit.push_back( d_iter );
  934. d_iter.Alpha1().Alpha2();
  935. }
  936. }
  937. /** Gets the 0-orbit around a node at the boundary
  938. *
  939. * \param aDart
  940. * A dart (CCW or CW) positioned at a \e boundary \e node and at a \e boundary \e edge.
  941. *
  942. * \retval orbit
  943. * Sequence of darts with one orbit for each arc. All the darts, \e exept \e the \e last one,
  944. * have the same orientation (CCW or CW) as \e dart, and \e dart is the first element
  945. * in the sequence.
  946. *
  947. * \require
  948. * - DART_LIST_TYPE::push_back (DART_TYPE&)
  949. *
  950. * \note
  951. * - The last dart in the sequence have opposite orientation compared to the others!
  952. *
  953. * \see
  954. * Get0OrbitInterior
  955. */
  956. template <class DART_TYPE, class DART_LIST_TYPE>
  957. void TRIANGULATION_HELPER::Get0OrbitBoundary( const DART_TYPE& aDart, DART_LIST_TYPE& aOrbit )
  958. {
  959. DART_TYPE dart_prev;
  960. DART_TYPE d_iter = aDart;
  961. do
  962. {
  963. aOrbit.push_back( d_iter );
  964. d_iter.Alpha1();
  965. dart_prev = d_iter;
  966. d_iter.Alpha2();
  967. }
  968. while( d_iter != dart_prev );
  969. aOrbit.push_back( d_iter ); // the last one with opposite orientation
  970. }
  971. /** Checks if the two darts belong to the same 0-orbit, i.e.,
  972. * if they share a node.
  973. * \e d1 and/or \e d2 can be CCW or CW.
  974. *
  975. * (This function also examines if the the node associated with
  976. * \e d1 is at the boundary, which slows down the function (slightly).
  977. * If it is known that the node associated with \e d1 is an interior
  978. * node and a faster version is needed, the user should implement his/her
  979. * own version.)
  980. */
  981. template <class DART_TYPE>
  982. bool TRIANGULATION_HELPER::Same0Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 )
  983. {
  984. // Two copies of the same dart
  985. DART_TYPE d_iter = aD2;
  986. DART_TYPE d_end = aD2;
  987. if( isBoundaryNode( d_iter ) )
  988. {
  989. // position at both boundary edges
  990. PositionAtNextBoundaryEdge( d_iter );
  991. d_end.Alpha1();
  992. PositionAtNextBoundaryEdge( d_end );
  993. }
  994. for( ;; )
  995. {
  996. if( d_iter == aD1 )
  997. return true;
  998. d_iter.Alpha1();
  999. if( d_iter == aD1 )
  1000. return true;
  1001. d_iter.Alpha2();
  1002. if( d_iter == d_end )
  1003. break;
  1004. }
  1005. return false;
  1006. }
  1007. /** Checks if the two darts belong to the same 1-orbit, i.e.,
  1008. * if they share an edge.
  1009. * \e d1 and/or \e d2 can be CCW or CW.
  1010. */
  1011. template <class DART_TYPE>
  1012. bool TRIANGULATION_HELPER::Same1Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 )
  1013. {
  1014. DART_TYPE d_iter = aD2;
  1015. // (Also works at the boundary)
  1016. return ( d_iter == aD1 || d_iter.Alpha0() == aD1 ||
  1017. d_iter.Alpha2() == aD1 || d_iter.Alpha0() == aD1 );
  1018. }
  1019. //------------------------------------------------------------------------------------------------
  1020. /** Checks if the two darts belong to the same 2-orbit, i.e.,
  1021. * if they lie in the same triangle.
  1022. * \e d1 and/or \e d2 can be CCW or CW
  1023. */
  1024. template <class DART_TYPE>
  1025. bool TRIANGULATION_HELPER::Same2Orbit( const DART_TYPE& aD1, const DART_TYPE& aD2 )
  1026. {
  1027. DART_TYPE d_iter = aD2;
  1028. return ( d_iter == aD1 || d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 ||
  1029. d_iter.Alpha0() == aD1 || d_iter.Alpha1() == aD1 || d_iter.Alpha0() == aD1 );
  1030. }
  1031. // Private/Hidden function
  1032. template <class TRAITS_TYPE, class DART_TYPE>
  1033. bool TRIANGULATION_HELPER::degenerateTriangle( const DART_TYPE& aDart )
  1034. {
  1035. // Check if triangle is degenerate
  1036. // Assumes CCW dart
  1037. DART_TYPE d1 = aDart;
  1038. DART_TYPE d2 = d1;
  1039. d2.Alpha1();
  1040. return ( TRAITS_TYPE::CrossProduct2D( d1, d2 ) == 0 );
  1041. }
  1042. /** Checks if the edge associated with \e dart is swappable, i.e., if the edge
  1043. * is a diagonal in a \e strictly convex (or convex) quadrilateral.
  1044. *
  1045. * \param aAllowDegeneracy
  1046. * If set to true, the function will also return true if the numerical calculations
  1047. * indicate that the quadrilateral is convex only, and not necessarily strictly
  1048. * convex.
  1049. *
  1050. * \require
  1051. * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (Dart&, Dart&)
  1052. */
  1053. template <class TRAITS_TYPE, class DART_TYPE>
  1054. bool TRIANGULATION_HELPER::SwappableEdge( const DART_TYPE& aDart, bool aAllowDegeneracy )
  1055. {
  1056. // How "safe" is it?
  1057. if( IsBoundaryEdge( aDart ) )
  1058. return false;
  1059. // "angles" are at the diagonal
  1060. DART_TYPE d1 = aDart;
  1061. d1.Alpha2().Alpha1();
  1062. DART_TYPE d2 = aDart;
  1063. d2.Alpha1();
  1064. if( aAllowDegeneracy )
  1065. {
  1066. if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 )
  1067. return false;
  1068. }
  1069. else
  1070. {
  1071. if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 )
  1072. return false;
  1073. }
  1074. // Opposite side (still angle at the diagonal)
  1075. d1 = aDart;
  1076. d1.Alpha0();
  1077. d2 = d1;
  1078. d1.Alpha1();
  1079. d2.Alpha2().Alpha1();
  1080. if( aAllowDegeneracy )
  1081. {
  1082. if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) < 0.0 )
  1083. return false;
  1084. }
  1085. else
  1086. {
  1087. if( TRAITS_TYPE::CrossProduct2D( d1, d2 ) <= 0.0 )
  1088. return false;
  1089. }
  1090. return true;
  1091. }
  1092. /** Given a \e dart, CCW or CW, positioned in a 0-orbit at the boundary of a tessellation.
  1093. * Position \e dart at a boundary edge in the same 0-orbit.\n
  1094. * If the given \e dart is CCW, \e dart is positioned at the left boundary edge
  1095. * and will be CW.\n
  1096. * If the given \e dart is CW, \e dart is positioned at the right boundary edge
  1097. * and will be CCW.
  1098. *
  1099. * \note
  1100. * - The given \e dart must have a source node at the boundary, otherwise an
  1101. * infinit loop occurs.
  1102. */
  1103. template <class DART_TYPE>
  1104. void TRIANGULATION_HELPER::PositionAtNextBoundaryEdge( DART_TYPE& aDart )
  1105. {
  1106. DART_TYPE dart_prev;
  1107. // If alpha2(d)=d, then boundary
  1108. //old convention: dart.Alpha0();
  1109. do
  1110. {
  1111. aDart.Alpha1();
  1112. dart_prev = aDart;
  1113. aDart.Alpha2();
  1114. }
  1115. while( aDart != dart_prev );
  1116. }
  1117. /** Checks if the boundary of a triangulation is convex.
  1118. *
  1119. * \param dart
  1120. * A CCW dart at the boundary of the m_triangulation
  1121. *
  1122. * \require
  1123. * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (const Dart&, const Dart&)
  1124. */
  1125. template <class TRAITS_TYPE, class DART_TYPE>
  1126. bool TRIANGULATION_HELPER::ConvexBoundary( const DART_TYPE& aDart )
  1127. {
  1128. std::list<DART_TYPE> blist;
  1129. getBoundary( aDart, blist );
  1130. int no;
  1131. no = (int) blist.size();
  1132. typename std::list<DART_TYPE>::const_iterator bit = blist.begin();
  1133. DART_TYPE d1 = *bit;
  1134. ++bit;
  1135. DART_TYPE d2;
  1136. bool convex = true;
  1137. for( ; bit != blist.end(); ++bit )
  1138. {
  1139. d2 = *bit;
  1140. double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 );
  1141. if( crossProd < 0.0 )
  1142. {
  1143. //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl;
  1144. convex = false;
  1145. return convex;
  1146. }
  1147. d1 = d2;
  1148. }
  1149. // Check the last angle
  1150. d2 = *blist.begin();
  1151. double crossProd = TRAITS_TYPE::CrossProduct2D( d1, d2 );
  1152. if( crossProd < 0.0 )
  1153. {
  1154. //cout << "!!! Boundary is NOT convex: crossProd = " << crossProd << endl;
  1155. convex = false;
  1156. }
  1157. //if (convex)
  1158. // cout << "\n---> Boundary is convex\n" << endl;
  1159. //cout << endl;
  1160. return convex;
  1161. }
  1162. //@} // End of Topological and Geometric Queries Group
  1163. /** @name Utilities for Delaunay Triangulation */
  1164. //@{
  1165. //------------------------------------------------------------------------------------------------
  1166. /** Optimizes the edges in the given sequence according to the
  1167. * \e Delaunay criterion, i.e., such that the edge will fullfill the
  1168. * \e circumcircle criterion (or equivalently the \e MaxMin
  1169. * angle criterion) with respect to the quadrilaterals where
  1170. * they are diagonals.
  1171. *
  1172. * \param aElist
  1173. * The sequence of edges
  1174. *
  1175. * \require
  1176. * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n
  1177. * \b Note: Must be implemented such that \e dart is delivered back in a position as
  1178. * seen if it was glued to the edge when swapping (rotating) the edge CCW
  1179. *
  1180. * \using
  1181. * - swapTestDelaunay
  1182. */
  1183. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  1184. void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist )
  1185. {
  1186. OptimizeDelaunay<TRAITS_TYPE, DART_TYPE, DART_LIST_TYPE>( aElist, aElist.end() );
  1187. }
  1188. //------------------------------------------------------------------------------------------------
  1189. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  1190. void TRIANGULATION_HELPER::OptimizeDelaunay( DART_LIST_TYPE& aElist,
  1191. const typename DART_LIST_TYPE::iterator aEnd )
  1192. {
  1193. // CCW darts
  1194. // Optimize here means Delaunay, but could be any criterion by
  1195. // requiring a "should swap" in the traits class, or give
  1196. // a function object?
  1197. // Assumes that elist has only one dart for each arc.
  1198. // Darts outside the quadrilateral are preserved
  1199. // For some data structures it is possible to preserve
  1200. // all darts when swapping. Thus a preserve_darts_when swapping
  1201. // ccould be given to indicate this and we would gain performance by avoiding
  1202. // find in list.
  1203. // Requires that swap retuns a dart in the "same position when rotated CCW"
  1204. // (A vector instead of a list may be better.)
  1205. // First check that elist is not empty
  1206. if( aElist.empty() )
  1207. return;
  1208. // Avoid cycling by more extensive circumcircle test
  1209. bool cycling_check = true;
  1210. bool optimal = false;
  1211. typename DART_LIST_TYPE::iterator it;
  1212. typename DART_LIST_TYPE::iterator end_opt = aEnd;
  1213. // Hmm... The following code is trying to derefence an iterator that may
  1214. // be invalid. This may lead to debug error on Windows, so we comment out
  1215. // this code. Checking elist.empty() above will prevent some
  1216. // problems...
  1217. //
  1218. // last_opt is passed the end of the "active list"
  1219. //typename DART_LIST_TYPE::iterator end_opt;
  1220. //if (*end != NULL)
  1221. // end_opt = end;
  1222. //else
  1223. // end_opt = elist.end();
  1224. while( !optimal )
  1225. {
  1226. optimal = true;
  1227. for( it = aElist.begin(); it != end_opt; ++it )
  1228. {
  1229. if( SwapTestDelaunay<TRAITS_TYPE>( *it, cycling_check ) )
  1230. {
  1231. // Preserve darts. Potential darts in the list are:
  1232. // - The current dart
  1233. // - the four CCW darts on the boundary of the quadrilateral
  1234. // (the current arc has only one dart)
  1235. SwapEdgeInList<TRAITS_TYPE, DART_TYPE>( it, aElist );
  1236. optimal = false;
  1237. } // end if should swap
  1238. } // end for
  1239. } // end pass
  1240. }
  1241. /** Checks if the edge associated with \e dart should be swapped according
  1242. * to the \e Delaunay criterion, i.e., the \e circumcircle criterion (or
  1243. * equivalently the \e MaxMin angle criterion).
  1244. *
  1245. * \param aCyclingCheck
  1246. * Must be set to \c true when used in connection with optimization algorithms,
  1247. * e.g., OptimizeDelaunay. This will avoid cycling and infinite loops in nearly
  1248. * neutral cases.
  1249. *
  1250. * \require
  1251. * - \ref hed::TTLtraits::ScalarProduct2D "TRAITS_TYPE::ScalarProduct2D" (DART_TYPE&, DART_TYPE&)
  1252. * - \ref hed::TTLtraits::CrossProduct2D "TRAITS_TYPE::CrossProduct2D" (DART_TYPE&, DART_TYPE&)
  1253. */
  1254. template <class TRAITS_TYPE, class DART_TYPE>
  1255. #if ((_MSC_VER > 0) && (_MSC_VER < 1300))//#ifdef _MSC_VER
  1256. bool TRIANGULATION_HELPER::SwapTestDelaunay(const DART_TYPE& aDart, bool aCyclingCheck = false) const
  1257. {
  1258. #else
  1259. bool TRIANGULATION_HELPER::SwapTestDelaunay( const DART_TYPE& aDart, bool aCyclingCheck ) const
  1260. {
  1261. #endif
  1262. // The general strategy is taken from Cline & Renka. They claim that
  1263. // their algorithm insure numerical stability, but experiments show
  1264. // that this is not correct for neutral, or almost neutral cases.
  1265. // I have extended this strategy (without using tolerances) to avoid
  1266. // cycling and infinit loops when used in connection with LOP algorithms;
  1267. // see the comments below.
  1268. typedef typename TRAITS_TYPE::REAL_TYPE REAL_TYPE;
  1269. if( IsBoundaryEdge( aDart ) )
  1270. return false;
  1271. DART_TYPE v11 = aDart;
  1272. v11.Alpha1().Alpha0();
  1273. DART_TYPE v12 = v11;
  1274. v12.Alpha1();
  1275. DART_TYPE v22 = aDart;
  1276. v22.Alpha2().Alpha1().Alpha0();
  1277. DART_TYPE v21 = v22;
  1278. v21.Alpha1();
  1279. REAL_TYPE cos1 = TRAITS_TYPE::ScalarProduct2D( v11, v12 );
  1280. REAL_TYPE cos2 = TRAITS_TYPE::ScalarProduct2D( v21, v22 );
  1281. // "Angles" are opposite to the diagonal.
  1282. // The diagonals should be swapped iff (t1+t2) .gt. 180
  1283. // degrees. The following two tests insure numerical
  1284. // stability according to Cline & Renka. But experiments show
  1285. // that cycling may still happen; see the aditional test below.
  1286. if( cos1 >= 0 && cos2 >= 0 ) // both angles are grater or equual 90
  1287. return false;
  1288. if( cos1 < 0 && cos2 < 0 ) // both angles are less than 90
  1289. return true;
  1290. REAL_TYPE sin1 = TRAITS_TYPE::CrossProduct2D( v11, v12 );
  1291. REAL_TYPE sin2 = TRAITS_TYPE::CrossProduct2D( v21, v22 );
  1292. REAL_TYPE sin12 = sin1 * cos2 + cos1 * sin2;
  1293. if( sin12 >= 0 ) // equality represents a neutral case
  1294. return false;
  1295. if( aCyclingCheck )
  1296. {
  1297. // situation so far is sin12 < 0. Test if this also
  1298. // happens for the swapped edge.
  1299. // The numerical calculations so far indicate that the edge is
  1300. // not Delaunay and should not be swapped. But experiments show that
  1301. // in neutral cases, or almost neutral cases, it may happen that
  1302. // the swapped edge may again be found to be not Delaunay and thus
  1303. // be swapped if we return true here. This may lead to cycling and
  1304. // an infinte loop when used, e.g., in connection with OptimizeDelaunay.
  1305. //
  1306. // In an attempt to avoid this we test if the swapped edge will
  1307. // also be found to be not Delaunay by repeating the last test above
  1308. // for the swapped edge.
  1309. // We now rely on the general requirement for TRAITS_TYPE::swapEdge which
  1310. // should deliver CCW dart back in "the same position"; see the general
  1311. // description. This will insure numerical stability as the next calculation
  1312. // is the same as if this function was called again with the swapped edge.
  1313. // Cycling is thus impossible provided that the initial tests above does
  1314. // not result in ambiguity (and they should probably not do so).
  1315. v11.Alpha0();
  1316. v12.Alpha0();
  1317. v21.Alpha0();
  1318. v22.Alpha0();
  1319. // as if the edge was swapped/rotated CCW
  1320. cos1 = TRAITS_TYPE::ScalarProduct2D( v22, v11 );
  1321. cos2 = TRAITS_TYPE::ScalarProduct2D( v12, v21 );
  1322. sin1 = TRAITS_TYPE::CrossProduct2D( v22, v11 );
  1323. sin2 = TRAITS_TYPE::CrossProduct2D( v12, v21 );
  1324. sin12 = sin1 * cos2 + cos1 * sin2;
  1325. if( sin12 < 0 )
  1326. {
  1327. // A neutral case, but the tests above lead to swapping
  1328. return false;
  1329. }
  1330. }
  1331. return true;
  1332. }
  1333. //-----------------------------------------------------------------------
  1334. //
  1335. // x
  1336. //" / \ "
  1337. // / | \ Darts:
  1338. //oe2 / | \ oe2 = oppEdge2
  1339. // x....|....x
  1340. // \ d| d/ d = diagonal (input and output)
  1341. // \ | /
  1342. // oe1 \ / oe1 = oppEdge1
  1343. // x
  1344. //
  1345. //-----------------------------------------------------------------------
  1346. /** Recursively swaps edges in the triangulation according to the \e Delaunay criterion.
  1347. *
  1348. * \param aDiagonal
  1349. * A CCW dart representing the edge where the recursion starts from.
  1350. *
  1351. * \require
  1352. * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE&)\n
  1353. * \b Note: Must be implemented such that the darts outside the quadrilateral
  1354. * are not affected by the swap.
  1355. *
  1356. * \using
  1357. * - Calls itself recursively
  1358. */
  1359. template <class TRAITS_TYPE, class DART_TYPE>
  1360. void TRIANGULATION_HELPER::RecSwapDelaunay( DART_TYPE& aDiagonal )
  1361. {
  1362. if( !SwapTestDelaunay<TRAITS_TYPE>( aDiagonal ) )
  1363. // ??? swapTestDelaunay also checks if boundary, so this can be optimized
  1364. return;
  1365. // Get the other "edges" of the current triangle; see illustration above.
  1366. DART_TYPE oppEdge1 = aDiagonal;
  1367. oppEdge1.Alpha1();
  1368. bool b1;
  1369. if( IsBoundaryEdge( oppEdge1 ) )
  1370. b1 = true;
  1371. else
  1372. {
  1373. b1 = false;
  1374. oppEdge1.Alpha2();
  1375. }
  1376. DART_TYPE oppEdge2 = aDiagonal;
  1377. oppEdge2.Alpha0().Alpha1().Alpha0();
  1378. bool b2;
  1379. if( IsBoundaryEdge( oppEdge2 ) )
  1380. b2 = true;
  1381. else
  1382. {
  1383. b2 = false;
  1384. oppEdge2.Alpha2();
  1385. }
  1386. // Swap the given diagonal
  1387. m_triangulation.swapEdge( aDiagonal );
  1388. if( !b1 )
  1389. RecSwapDelaunay<TRAITS_TYPE>( oppEdge1 );
  1390. if( !b2 )
  1391. RecSwapDelaunay<TRAITS_TYPE>( oppEdge2 );
  1392. }
  1393. /** Swaps edges away from the (interior) node associated with
  1394. * \e dart such that that exactly three edges remain incident
  1395. * with the node.
  1396. * This function is used as a first step in RemoveInteriorNode
  1397. *
  1398. * \retval dart
  1399. * A CCW dart incident with the node
  1400. *
  1401. * \par Assumes:
  1402. * - The node associated with \e dart is interior to the
  1403. * triangulation.
  1404. *
  1405. * \require
  1406. * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n
  1407. * \b Note: Must be implemented such that \e dart is delivered back in a position as
  1408. * seen if it was glued to the edge when swapping (rotating) the edge CCW
  1409. *
  1410. * \note
  1411. * - A degenerate triangle may be left at the node.
  1412. * - The function is not unique as it depends on which dart
  1413. * at the node that is given as input.
  1414. *
  1415. * \see
  1416. * SwapEdgesAwayFromBoundaryNode
  1417. */
  1418. template <class TRAITS_TYPE, class DART_TYPE, class LIST_TYPE>
  1419. void TRIANGULATION_HELPER::SwapEdgesAwayFromInteriorNode( DART_TYPE& aDart,
  1420. LIST_TYPE& aSwappedEdges )
  1421. {
  1422. // Same iteration as in fixEdgesAtCorner, but not boundary
  1423. DART_TYPE dnext = aDart;
  1424. // Allow degeneracy, otherwise we might end up with degree=4.
  1425. // For example, the reverse operation of inserting a point on an
  1426. // existing edge gives a situation where all edges are non-swappable.
  1427. // Ideally, degeneracy in this case should be along the actual node,
  1428. // but there is no strategy for this now.
  1429. // ??? An alternative here is to wait with degeneracy till we get an
  1430. // infinite loop with degree > 3.
  1431. bool allowDegeneracy = true;
  1432. int degree = getDegreeOfNode( aDart );
  1433. DART_TYPE d_iter;
  1434. while( degree > 3 )
  1435. {
  1436. d_iter = dnext;
  1437. dnext.Alpha1().Alpha2();
  1438. if( SwappableEdge<TRAITS_TYPE>( d_iter, allowDegeneracy ) )
  1439. {
  1440. m_triangulation.swapEdge( d_iter ); // swap the edge away
  1441. // Collect swapped edges in the list
  1442. // "Hide" the dart on the other side of the edge to avoid it being changed for
  1443. // other swaps
  1444. DART_TYPE swapped_edge = d_iter; // it was delivered back
  1445. swapped_edge.Alpha2().Alpha0(); // CCW (if not at boundary)
  1446. aSwappedEdges.push_back( swapped_edge );
  1447. degree--;
  1448. }
  1449. }
  1450. // Output, incident to the node
  1451. aDart = dnext;
  1452. }
  1453. /** Swaps edges away from the (boundary) node associated with
  1454. * \e dart in such a way that when removing the edges that remain incident
  1455. * with the node, the boundary of the triangulation will be convex.
  1456. * This function is used as a first step in RemoveBoundaryNode
  1457. *
  1458. * \retval dart
  1459. * A CCW dart incident with the node
  1460. *
  1461. * \require
  1462. * - \ref hed::TTLtraits::swapEdge "TRAITS_TYPE::swapEdge" (DART_TYPE& \e dart)\n
  1463. * \b Note: Must be implemented such that \e dart is delivered back in a position as
  1464. * seen if it was glued to the edge when swapping (rotating) the edge CCW
  1465. *
  1466. * \par Assumes:
  1467. * - The node associated with \e dart is at the boundary of the m_triangulation.
  1468. *
  1469. * \see
  1470. * SwapEdgesAwayFromInteriorNode
  1471. */
  1472. template <class TRAITS_TYPE, class DART_TYPE, class LIST_TYPE>
  1473. void TRIANGULATION_HELPER::SwapEdgesAwayFromBoundaryNode( DART_TYPE& aDart,
  1474. LIST_TYPE& aSwappedEdges )
  1475. {
  1476. // All darts that are swappable.
  1477. // To treat collinear nodes at an existing boundary, we must allow degeneracy
  1478. // when swapping to the boundary.
  1479. // dart is CCW and at the boundary.
  1480. // The 0-orbit runs CCW
  1481. // Deliver the dart back in the "same position".
  1482. // Assume for the swap in the traits class:
  1483. // - A dart on the swapped edge is delivered back in a position as
  1484. // seen if it was glued to the edge when swapping (rotating) the edge CCW
  1485. //int degree = getDegreeOfNode(dart);
  1486. passes:
  1487. // Swap swappable edges that radiate from the node away
  1488. DART_TYPE d_iter = aDart; // ???? can simply use dart
  1489. d_iter.Alpha1().Alpha2(); // first not at boundary
  1490. DART_TYPE d_next = d_iter;
  1491. bool bend = false;
  1492. bool swapped_next_to_boundary = false;
  1493. bool swapped_in_pass = false;
  1494. bool allowDegeneracy; // = true;
  1495. DART_TYPE tmp1, tmp2;
  1496. while( !bend )
  1497. {
  1498. d_next.Alpha1().Alpha2();
  1499. if( IsBoundaryEdge( d_next ) )
  1500. bend = true; // then it is CW since alpha2
  1501. // To allow removing among collinear nodes at the boundary,
  1502. // degenerate triangles must be allowed
  1503. // (they will be removed when used in connection with RemoveBoundaryNode)
  1504. tmp1 = d_iter;
  1505. tmp1.Alpha1();
  1506. tmp2 = d_iter;
  1507. tmp2.Alpha2().Alpha1(); // don't bother with boundary (checked later)
  1508. if( IsBoundaryEdge( tmp1 ) && IsBoundaryEdge( tmp2 ) )
  1509. allowDegeneracy = true;
  1510. else
  1511. allowDegeneracy = false;
  1512. if( SwappableEdge<TRAITS_TYPE>( d_iter, allowDegeneracy ) )
  1513. {
  1514. m_triangulation.swapEdge( d_iter );
  1515. // Collect swapped edges in the list
  1516. // "Hide" the dart on the other side of the edge to avoid it being changed for
  1517. // other swapps
  1518. DART_TYPE swapped_edge = d_iter; // it was delivered back
  1519. swapped_edge.Alpha2().Alpha0(); // CCW
  1520. aSwappedEdges.push_back( swapped_edge );
  1521. //degree--; // if degree is 2, or bend=true, we are done
  1522. swapped_in_pass = true;
  1523. if( bend )
  1524. swapped_next_to_boundary = true;
  1525. }
  1526. if( !bend )
  1527. d_iter = d_next;
  1528. }
  1529. // Deliver a dart as output in the same position as the incoming dart
  1530. if( swapped_next_to_boundary )
  1531. {
  1532. // Assume that "swapping is CCW and dart is preserved in the same position
  1533. d_iter.Alpha1().Alpha0().Alpha1(); // CW and see below
  1534. }
  1535. else
  1536. {
  1537. d_iter.Alpha1(); // CW and see below
  1538. }
  1539. PositionAtNextBoundaryEdge( d_iter ); // CCW
  1540. aDart = d_iter; // for next pass or output
  1541. // If a dart was swapped in this iteration we must run it more
  1542. if( swapped_in_pass )
  1543. goto passes;
  1544. }
  1545. /** Swap the the edge associated with iterator \e it and update affected darts
  1546. * in \e elist accordingly.
  1547. * The darts affected by the swap are those in the same quadrilateral.
  1548. * Thus, if one want to preserve one or more of these darts on should
  1549. * keep them in \e elist.
  1550. */
  1551. template <class TRAITS_TYPE, class DART_TYPE, class DART_LIST_TYPE>
  1552. void TRIANGULATION_HELPER::SwapEdgeInList( const typename DART_LIST_TYPE::iterator& aIt,
  1553. DART_LIST_TYPE& aElist )
  1554. {
  1555. typename DART_LIST_TYPE::iterator it1, it2, it3, it4;
  1556. DART_TYPE dart( *aIt );
  1557. //typename TRAITS_TYPE::DART_TYPE d1 = dart; d1.Alpha2().Alpha1();
  1558. //typename TRAITS_TYPE::DART_TYPE d2 = d1; d2.Alpha0().Alpha1();
  1559. //typename TRAITS_TYPE::DART_TYPE d3 = dart; d3.Alpha0().Alpha1();
  1560. //typename TRAITS_TYPE::DART_TYPE d4 = d3; d4.Alpha0().Alpha1();
  1561. DART_TYPE d1 = dart;
  1562. d1.Alpha2().Alpha1();
  1563. DART_TYPE d2 = d1;
  1564. d2.Alpha0().Alpha1();
  1565. DART_TYPE d3 = dart;
  1566. d3.Alpha0().Alpha1();
  1567. DART_TYPE d4 = d3;
  1568. d4.Alpha0().Alpha1();
  1569. // Find pinters to the darts that may change.
  1570. // ??? Note, this is not very efficient since we must use find, which is O(N),
  1571. // four times.
  1572. // - Solution?: replace elist with a vector of pair (dart,number)
  1573. // and avoid find?
  1574. // - make a function for swapping generically?
  1575. // - sould we use another container type or,
  1576. // - erase them and reinsert?
  1577. // - or use two lists?
  1578. it1 = find( aElist.begin(), aElist.end(), d1 );
  1579. it2 = find( aElist.begin(), aElist.end(), d2 );
  1580. it3 = find( aElist.begin(), aElist.end(), d3 );
  1581. it4 = find( aElist.begin(), aElist.end(), d4 );
  1582. m_triangulation.swapEdge( dart );
  1583. // Update the current dart which may have changed
  1584. *aIt = dart;
  1585. // Update darts that may have changed again (if they were present)
  1586. // Note that dart is delivered back after swapping
  1587. if( it1 != aElist.end() )
  1588. {
  1589. d1 = dart;
  1590. d1.Alpha1().Alpha0();
  1591. *it1 = d1;
  1592. }
  1593. if( it2 != aElist.end() )
  1594. {
  1595. d2 = dart;
  1596. d2.Alpha2().Alpha1();
  1597. *it2 = d2;
  1598. }
  1599. if( it3 != aElist.end() )
  1600. {
  1601. d3 = dart;
  1602. d3.Alpha2().Alpha1().Alpha0().Alpha1();
  1603. *it3 = d3;
  1604. }
  1605. if( it4 != aElist.end() )
  1606. {
  1607. d4 = dart;
  1608. d4.Alpha0().Alpha1();
  1609. *it4 = d4;
  1610. }
  1611. }
  1612. //@} // End of Utilities for Delaunay Triangulation Group
  1613. }
  1614. // End of ttl namespace scope (but other files may also contain functions for ttl)
  1615. #endif // _TTL_H_