ConstrainedDelaunay2.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Delaunay2.h>
  9. #include <list>
  10. // Various parts of the code have LogAssert or LogError tests. For a correct
  11. // algorithm using exact arithmetic, we do not expect to trigger these.
  12. // However, with floating-point arithmetic, it is possible that the
  13. // triangulation becomes malformed. The calls to the member function
  14. // Insert(...) should be made in a try-catch block. If an exception is
  15. // thrown, you are most likely using a floating-point type for ComputeType
  16. // and floating-point rounding errors have caused problems in the edge
  17. // insertions.
  18. namespace WwiseGTE
  19. {
  20. template <typename InputType, typename ComputeType>
  21. class ConstrainedDelaunay2 : public Delaunay2<InputType, ComputeType>
  22. {
  23. public:
  24. // The class is a functor to support computing the constrained
  25. // Delaunay triangulation of multiple data sets using the same class
  26. // object.
  27. virtual ~ConstrainedDelaunay2() = default;
  28. ConstrainedDelaunay2()
  29. :
  30. Delaunay2<InputType, ComputeType>()
  31. {
  32. }
  33. // This operator computes the Delaunay triangulation only. Read the
  34. // Delaunay2 constructor comments about 'vertices' and 'epsilon'. The
  35. // 'edges' array has indices into the 'vertices' array. No two edges
  36. // should intersect except at endpoints.
  37. bool operator()(int numVertices, Vector2<InputType> const* vertices, InputType epsilon)
  38. {
  39. return Delaunay2<InputType, ComputeType>::operator()(numVertices, vertices, epsilon);
  40. }
  41. // Insert required edges into the triangulation. For correctness of
  42. // the algorithm, if two edges passed to this function intersect, they
  43. // must do so only at vertices passed to operator(). If you have two
  44. // edges that intersect at a point not in the vertices, compute that
  45. // point of intersection and subdivide the edges at that intersection
  46. // (to form more edges), and add the point to the vertices before
  47. // calling operator(). This function has an output array that
  48. // contains the input edge when the only vertices on the edge are its
  49. // endpoints. If the input edge passes through more vertices, the
  50. // edge is subdivided in this function. The output edge is that
  51. // subdivision with first vertex edge[0] and last vertex edge[1], and
  52. // the other vertices are correctly ordered along the edge.
  53. bool Insert(std::array<int, 2> const& edge, std::vector<int>& outEdge)
  54. {
  55. int v0 = edge[0], v1 = edge[1];
  56. if (0 <= v0 && v0 < this->mNumVertices
  57. && 0 <= v1 && v1 < this->mNumVertices)
  58. {
  59. int v0Triangle = GetLinkTriangle(v0);
  60. if (v0Triangle >= 0)
  61. {
  62. // Once an edge is inserted, the base-class mGraph no
  63. // longer represents the triangulation. Clear it in case
  64. // the user tries to access it.
  65. this->mGraph.Clear();
  66. outEdge.clear();
  67. return Insert(edge, v0Triangle, outEdge);
  68. }
  69. }
  70. return false;
  71. }
  72. private:
  73. // The top-level entry point for inserting an edge in the
  74. // triangulation.
  75. bool Insert(std::array<int, 2> const& edge, int v0Triangle, std::vector<int>& outEdge)
  76. {
  77. // Create the neighborhood of triangles that share the vertex v0.
  78. // On entry we already know one such triangle (v0Triangle).
  79. int v0 = edge[0], v1 = edge[1];
  80. std::list<std::pair<int, int>> link;
  81. bool isOpen = true;
  82. bool success = BuildLink(v0, v0Triangle, link, isOpen);
  83. LogAssert(success, CDTFailure());
  84. // Determine which triangle contains the edge. Process the edge
  85. // according to whether it is strictly between two triangle edges
  86. // or is coincident with a triangle edge.
  87. auto item = link.begin();
  88. std::array<int, 3> indices;
  89. success = this->GetIndices(item->first, indices);
  90. LogAssert(success, CDTFailure());
  91. int vNext = indices[(item->second + 1) % 3];
  92. int qr0 = this->mQuery.ToLine(v1, v0, vNext);
  93. while (item != link.end())
  94. {
  95. if (qr0 == 0)
  96. {
  97. // We have to be careful about parallel edges that point
  98. // in the opposite direction of <v0,v1>.
  99. Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
  100. Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
  101. Vector2<ComputeType> const& ctvnext = this->mComputeVertices[vNext];
  102. if (Dot(ctv1 - ctv0, ctvnext - ctv0) > (ComputeType)0)
  103. {
  104. // <v0,v1> is coincident to triangle edge0.
  105. return ProcessCoincident(item->first, v0, v1, vNext, outEdge);
  106. }
  107. // Make sure we enter the next "if" statement to continue
  108. // traversing the link.
  109. qr0 = 1;
  110. }
  111. if (qr0 > 0)
  112. {
  113. // <v0,v1> is not in triangle. Visit the next triangle.
  114. if (++item == link.end())
  115. {
  116. return false;
  117. }
  118. success = this->GetIndices(item->first, indices);
  119. LogAssert(success, CDTFailure());
  120. vNext = indices[(item->second + 1) % 3];
  121. qr0 = this->mQuery.ToLine(v1, v0, vNext);
  122. continue;
  123. }
  124. int vPrev = indices[(item->second + 2) % 3];
  125. int qr1 = this->mQuery.ToLine(v1, v0, vPrev);
  126. while (item != link.end())
  127. {
  128. if (qr1 == 0)
  129. {
  130. // We have to be careful about parallel edges that
  131. // point in the opposite direction of <v0,v1>.
  132. Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
  133. Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
  134. Vector2<ComputeType> const& ctvprev =
  135. this->mComputeVertices[vPrev];
  136. if (Dot(ctv1 - ctv0, ctvprev - ctv0) > (ComputeType)0)
  137. {
  138. // <v0,v1> is coincident to triangle edge1.
  139. return ProcessCoincident(item->first, v0, v1, vPrev, outEdge);
  140. }
  141. // Make sure we enter the next "if" statement to
  142. // continue traversing the link.
  143. qr1 = -1;
  144. }
  145. if (qr1 < 0)
  146. {
  147. // <v0,v1> is not in triangle. Visit the next
  148. // triangle.
  149. if (++item == link.end())
  150. {
  151. return false;
  152. }
  153. this->GetIndices(item->first, indices);
  154. vNext = vPrev;
  155. vPrev = indices[(item->second + 2) % 3];
  156. qr1 = this->mQuery.ToLine(v1, v0, vPrev);
  157. continue;
  158. }
  159. // <v0,v1> is interior to triangle <v0,vNext,vPrev>.
  160. return ProcessInterior(item->first, v0, v1, vNext, vPrev, outEdge);
  161. }
  162. break;
  163. }
  164. // The edge must be contained in some link triangle.
  165. LogError(CDTFailure());
  166. }
  167. // Process the coincident edge.
  168. bool ProcessCoincident(int tri, int v0, int v1, int vOther, std::vector<int>& outEdge)
  169. {
  170. outEdge.push_back(v0);
  171. if (v1 != vOther)
  172. {
  173. // Decompose the edge and process the right-most subedge.
  174. return Insert({ vOther, v1 }, tri, outEdge);
  175. }
  176. else
  177. {
  178. // <v0,v1> is already in the triangulation.
  179. outEdge.push_back(v1);
  180. return true;
  181. }
  182. }
  183. // Process the triangle strip originating at the first endpoint of the
  184. // edge.
  185. bool ProcessInterior(int tri, int v0, int v1, int vNext, int vPrev, std::vector<int>& outEdge)
  186. {
  187. // The triangles of the strip are stored in 'polygon'. The
  188. // retriangulation leads to the same number of triangles, so we
  189. // can reuse the mIndices[] and mAdjacencies[] locations implied
  190. // by the 'polygons' indices.
  191. std::vector<int> polygon;
  192. // The sBoundary[i] (s in {l,r}) array element is <v0,adj>; see
  193. // the header comments for GetAdjBoundary about what these mean.
  194. // The boundary vertex is 'v0', the adjacent triangle 'adj' is
  195. // outside the strip and shares the edge <sBoundary[i-1][0],
  196. // sBoundary[i][0]> with a triangle in 'polygon'. This
  197. // information allows us to connect the adjacent triangles outside
  198. // the strip to new triangles inserted by the retriangulation.
  199. // The value sBoundary[0][1,2] values are set to -1 but they are
  200. // not used in the construction.
  201. std::vector<std::array<int, 2>> lBoundary, rBoundary;
  202. std::array<int, 2> binfo;
  203. polygon.push_back(tri);
  204. lBoundary.push_back({ v0, -1 });
  205. binfo = GetAdjBoundary(tri, vPrev, vPrev);
  206. LogAssert(binfo[0] != 2, CDTFailure());
  207. lBoundary.push_back(binfo);
  208. rBoundary.push_back({ v0, -1 });
  209. binfo = GetAdjBoundary(tri, vNext, v0);
  210. LogAssert(binfo[0] != 2, CDTFailure());
  211. rBoundary.push_back(binfo);
  212. // Visit the triangles in the strip. Guard against an infinite
  213. // loop.
  214. for (int i = 0; i < this->mNumTriangles; ++i)
  215. {
  216. // Find the vertex of the adjacent triangle that is opposite
  217. // the edge <vNext,vPrev> shared with the current triangle.
  218. auto iinfo = GetAdjInterior(tri, vNext, vPrev);
  219. int adj = iinfo[0], vOpposite = iinfo[1];
  220. LogAssert(vOpposite >= 0, CDTFailure());
  221. // Visit the adjacent triangle and insert it into the polygon.
  222. tri = adj;
  223. polygon.push_back(tri);
  224. int qr = this->mQuery.ToLine(vOpposite, v0, v1);
  225. if (qr == 0)
  226. {
  227. // We have encountered a vertex that terminates the
  228. // triangle strip. Retriangulate the polygon. If the
  229. // edge continues through vOpposite, decompose the edge
  230. // and insert the right-most subedge.
  231. binfo = GetAdjBoundary(tri, vOpposite, vOpposite);
  232. LogAssert(binfo[0] != 2, CDTFailure());
  233. lBoundary.push_back(binfo);
  234. binfo = GetAdjBoundary(tri, vOpposite, vNext);
  235. LogAssert(binfo[0] != 2, CDTFailure());
  236. rBoundary.push_back(binfo);
  237. Retriangulate(polygon, lBoundary, rBoundary);
  238. if (vOpposite != v1)
  239. {
  240. outEdge.push_back(v0);
  241. return Insert({ vOpposite, v1 }, tri, outEdge);
  242. }
  243. else
  244. {
  245. return true;
  246. }
  247. }
  248. if (qr < 0)
  249. {
  250. binfo = GetAdjBoundary(tri, vOpposite, vOpposite);
  251. LogAssert(binfo[0] != 2, CDTFailure());
  252. lBoundary.push_back(binfo);
  253. vPrev = vOpposite;
  254. }
  255. else // qr > 0
  256. {
  257. binfo = GetAdjBoundary(tri, vOpposite, vNext);
  258. LogAssert(binfo[0] != 2, CDTFailure());
  259. rBoundary.push_back(binfo);
  260. vNext = vOpposite;
  261. }
  262. }
  263. // The triangle strip should have been located in the loop.
  264. LogError(CDTFailure());
  265. }
  266. // Remove the triangles in the triangle strip and retriangulate the
  267. // left and right polygons using the empty circumcircle condition.
  268. bool Retriangulate(std::vector<int>& polygon,
  269. std::vector<std::array<int, 2>> const& lBoundary,
  270. std::vector<std::array<int, 2>> const& rBoundary)
  271. {
  272. int t0 = RetriangulateLRecurse(lBoundary, 0,
  273. static_cast<int>(lBoundary.size()) - 1, -1, polygon);
  274. int t1 = RetriangulateRRecurse(rBoundary, 0,
  275. static_cast<int>(rBoundary.size()) - 1, -1, polygon);
  276. int v0 = lBoundary.front()[0];
  277. int v1 = lBoundary.back()[0];
  278. bool success = Connect(t0, t1, v0, v1);
  279. LogAssert(success, CDTFailure());
  280. return true;
  281. }
  282. int RetriangulateLRecurse(
  283. std::vector<std::array<int, 2>> const& lBoundary,
  284. int i0, int i1, int a0, std::vector<int>& polygon)
  285. {
  286. // Create triangles when recursing down, connect adjacent
  287. // triangles when returning.
  288. int v0 = lBoundary[i0][0];
  289. int v1 = lBoundary[i1][0];
  290. bool success;
  291. if (i1 - i0 == 1)
  292. {
  293. success = Connect(a0, lBoundary[i1][1], v1, v0);
  294. LogAssert(success, CDTFailure());
  295. return -1; // No triangle created.
  296. }
  297. else
  298. {
  299. // Select i2 in [i0+1,i1-1] for minimum distance to edge
  300. // <i0,i1>.
  301. int i2 = SelectSplit(lBoundary, i0, i1);
  302. int v2 = lBoundary[i2][0];
  303. // Reuse a triangle and fill in its new vertices.
  304. int tri = polygon.back();
  305. polygon.pop_back();
  306. this->mIndices[3 * tri + 0] = v0;
  307. this->mIndices[3 * tri + 1] = v1;
  308. this->mIndices[3 * tri + 2] = v2;
  309. // Recurse downward and create triangles.
  310. int ret0 = RetriangulateLRecurse(lBoundary, i0, i2, tri, polygon);
  311. LogAssert(ret0 >= -1, CDTFailure());
  312. int ret1 = RetriangulateLRecurse(lBoundary, i2, i1, tri, polygon);
  313. LogAssert(ret1 >= -1, CDTFailure());
  314. // Return and connect triangles.
  315. success = Connect(a0, tri, v1, v0);
  316. LogAssert(success, CDTFailure())
  317. return tri;
  318. }
  319. }
  320. int RetriangulateRRecurse(
  321. std::vector<std::array<int, 2>> const& rBoundary,
  322. int i0, int i1, int a0, std::vector<int>& polygon)
  323. {
  324. // Create triangles when recursing down, connect adjacent
  325. // triangles when returning.
  326. int v0 = rBoundary[i0][0];
  327. int v1 = rBoundary[i1][0];
  328. if (i1 - i0 == 1)
  329. {
  330. bool success = Connect(a0, rBoundary[i1][1], v0, v1);
  331. LogAssert(success, CDTFailure());
  332. return -1; // No triangle created.
  333. }
  334. else
  335. {
  336. // Select i2 in [i0+1,i1-1] for minimum distance to edge
  337. // <i0,i1>.
  338. int i2 = SelectSplit(rBoundary, i0, i1);
  339. int v2 = rBoundary[i2][0];
  340. // Reuse a triangle and fill in its new vertices.
  341. int tri = polygon.back();
  342. polygon.pop_back();
  343. this->mIndices[3 * tri + 0] = v1;
  344. this->mIndices[3 * tri + 1] = v0;
  345. this->mIndices[3 * tri + 2] = v2;
  346. // Recurse downward and create triangles.
  347. int ret0 = RetriangulateRRecurse(rBoundary, i0, i2, tri, polygon);
  348. LogAssert(ret0 >= -1, CDTFailure());
  349. int ret1 = RetriangulateRRecurse(rBoundary, i2, i1, tri, polygon);
  350. LogAssert(ret1 >= -1, CDTFailure());
  351. // Return and connect triangles.
  352. bool success = Connect(a0, tri, v0, v1);
  353. LogAssert(success, CDTFailure());
  354. return tri;
  355. }
  356. }
  357. int SelectSplit(std::vector<std::array<int, 2>> const& boundary, int i0, int i1) const
  358. {
  359. int i2;
  360. if (i1 - i0 == 2)
  361. {
  362. // This is the only candidate.
  363. i2 = i0 + 1;
  364. }
  365. else // i1 - i0 > 2
  366. {
  367. // Select the index i2 in [i0+1,i1-1] for which the distance
  368. // from the vertex v2 at i2 to the edge <v0,v1> is minimized.
  369. // To allow exact arithmetic, use a pseudosquared distance
  370. // that avoids divisions and square roots.
  371. i2 = i0 + 1;
  372. int v0 = boundary[i0][0];
  373. int v1 = boundary[i1][0];
  374. int v2 = boundary[i2][0];
  375. ComputeType minpsd = ComputePSD(v0, v1, v2);
  376. for (int i = i2 + 1; i < i1; ++i)
  377. {
  378. v2 = boundary[i][0];
  379. ComputeType psd = ComputePSD(v0, v1, v2);
  380. if (psd < minpsd)
  381. {
  382. minpsd = psd;
  383. i2 = i;
  384. }
  385. }
  386. }
  387. return i2;
  388. }
  389. // Compute a pseudosquared distance from the vertex at v2 to the edge
  390. // <v0,v1>.
  391. ComputeType ComputePSD(int v0, int v1, int v2) const
  392. {
  393. ComputeType psd;
  394. Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
  395. Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
  396. Vector2<ComputeType> const& ctv2 = this->mComputeVertices[v2];
  397. Vector2<ComputeType> V1mV0 = ctv1 - ctv0;
  398. Vector2<ComputeType> V2mV0 = ctv2 - ctv0;
  399. ComputeType sqrlen10 = Dot(V1mV0, V1mV0);
  400. ComputeType dot = Dot(V1mV0, V2mV0);
  401. ComputeType zero(0);
  402. if (dot <= zero)
  403. {
  404. ComputeType sqrlen20 = Dot(V2mV0, V2mV0);
  405. psd = sqrlen10 * sqrlen20;
  406. }
  407. else
  408. {
  409. Vector2<ComputeType> V2mV1 = ctv2 - ctv1;
  410. dot = Dot(V1mV0, V2mV1);
  411. if (dot >= zero)
  412. {
  413. ComputeType sqrlen21 = Dot(V2mV1, V2mV1);
  414. psd = sqrlen10 * sqrlen21;
  415. }
  416. else
  417. {
  418. dot = DotPerp(V2mV0, V1mV0);
  419. psd = sqrlen10 * dot * dot;
  420. }
  421. }
  422. return psd;
  423. }
  424. // Search the triangulation for a triangle that contains the specified
  425. // vertex.
  426. int GetLinkTriangle(int v) const
  427. {
  428. // Remap in case an edge vertex was specified that is a duplicate.
  429. v = this->mDuplicates[v];
  430. int tri = 0;
  431. for (int i = 0; i < this->mNumTriangles; ++i)
  432. {
  433. // Test whether v is a vertex of the triangle.
  434. std::array<int, 3> indices;
  435. bool success = this->GetIndices(tri, indices);
  436. LogAssert(success, CDTFailure());
  437. for (int j = 0; j < 3; ++j)
  438. {
  439. if (v == indices[j])
  440. {
  441. return tri;
  442. }
  443. }
  444. // v must be outside the triangle.
  445. for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)
  446. {
  447. if (this->mQuery.ToLine(v, indices[j0], indices[j1]) > 0)
  448. {
  449. // Vertex v sees the edge from outside, so traverse to
  450. // the triangle sharing the edge.
  451. std::array<int, 3> adjacencies;
  452. success = this->GetAdjacencies(tri, adjacencies);
  453. LogAssert(success, CDTFailure());
  454. int adj = adjacencies[j0];
  455. LogAssert(adj >= 0, CDTFailure());
  456. tri = adj;
  457. break;
  458. }
  459. }
  460. }
  461. // The vertex must be in the triangulation.
  462. LogError(CDTFailure());
  463. }
  464. // Determine the index in {0,1,2} for the triangle 'tri' that contains
  465. // the vertex 'v'.
  466. int GetIndexOfVertex(int tri, int v) const
  467. {
  468. std::array<int, 3> indices;
  469. bool success = this->GetIndices(tri, indices);
  470. LogAssert(success, CDTFailure());
  471. int indexOfV;
  472. for (indexOfV = 0; indexOfV < 3; ++indexOfV)
  473. {
  474. if (v == indices[indexOfV])
  475. {
  476. return indexOfV;
  477. }
  478. }
  479. LogError(CDTFailure());
  480. }
  481. // Given a triangle 'tri' with CCW-edge <v0,v1>, return <adj,v2> where
  482. // 'adj' is the index of the triangle adjacent to 'tri' that shares
  483. // the edge and 'v2' is the vertex of the adjacent triangle opposite
  484. // the edge. This function supports traversing a triangle strip that
  485. // contains a constraint edge, so it is called only when an adjacent
  486. // triangle actually exists.
  487. std::array<int, 2> GetAdjInterior(int tri, int v0, int v1) const
  488. {
  489. int vIndex = GetIndexOfVertex(tri, v0);
  490. LogAssert(vIndex >= 0, CDTFailure());
  491. int adj = this->mAdjacencies[3 * tri + vIndex];
  492. if (adj >= 0)
  493. {
  494. for (int v2Index = 0; v2Index < 3; ++v2Index)
  495. {
  496. int v2 = this->mIndices[3 * adj + v2Index];
  497. if (v2 != v0 && v2 != v1)
  498. {
  499. return{ adj, v2 };
  500. }
  501. }
  502. }
  503. else
  504. {
  505. return{ -1, -1 };
  506. }
  507. LogError(CDTFailure());
  508. }
  509. // Given a triangle 'tri' of the triangle strip, the boundary edge
  510. // must contain the vertex with index 'needBndVertex'. The input
  511. // 'needAdjVIndex' specifies where to look for the index of the
  512. // triangle outside the strip but adjacent to the boundary edge. The
  513. // return value is <needBndVertex, adj> and is used to connect 'tri'
  514. // and 'adj' across a triangle strip boundary.
  515. std::array<int, 2> GetAdjBoundary(int tri, int needBndVertex, int needAdjVIndex) const
  516. {
  517. int vIndex = GetIndexOfVertex(tri, needAdjVIndex);
  518. LogAssert(vIndex >= 0, CDTFailure());
  519. int adj = this->mAdjacencies[3 * tri + vIndex];
  520. return{ needBndVertex, adj };
  521. }
  522. // Set the indices and adjacencies arrays so that 'tri' and 'adj'
  523. // share the common edge; 'tri' has CCW-edge <v0,v1> and 'adj' has
  524. // CCW-edge <v1,v0>.
  525. bool Connect(int tri, int adj, int v0, int v1)
  526. {
  527. if (tri >= 0)
  528. {
  529. int v0Index = GetIndexOfVertex(tri, v0);
  530. LogAssert(v0Index >= 0, CDTFailure());
  531. if (adj >= 0)
  532. {
  533. int v1Index = GetIndexOfVertex(adj, v1);
  534. LogAssert(v1Index >= 0, CDTFailure());
  535. this->mAdjacencies[3 * adj + v1Index] = tri;
  536. }
  537. this->mAdjacencies[3 * tri + v0Index] = adj;
  538. }
  539. // else: tri = -1, which occurs in the top-level call to
  540. // retriangulate
  541. return true;
  542. }
  543. // Create an ordered list of triangles forming the link of a vertex.
  544. // The pair of the list is <triangle,GetIndexOfV(triangle)>. This
  545. // allows us to cache the index of v relative to each triangle in the
  546. // link. The vertex v might be a boundary vertex, in which case the
  547. // neighborhood is open; otherwise, v is an interior vertex and the
  548. // neighborhood is closed. The 'isOpen' parameter specifies the case.
  549. bool BuildLink(int v, int vTriangle, std::list<std::pair<int, int>>& link, bool& isOpen) const
  550. {
  551. // The list starts with a known triangle in the link of v.
  552. int vStartIndex = GetIndexOfVertex(vTriangle, v);
  553. LogAssert(vStartIndex >= 0, CDTFailure());
  554. link.push_front(std::make_pair(vTriangle, vStartIndex));
  555. // Traverse adjacent triangles to the "left" of v. Guard against
  556. // an infinite loop.
  557. int tri = vTriangle, vIndex = vStartIndex;
  558. std::array<int, 3> adjacencies;
  559. for (int i = 0; i < this->mNumTriangles; ++i)
  560. {
  561. bool success = this->GetAdjacencies(tri, adjacencies);
  562. LogAssert(success, CDTFailure());
  563. int adjPrev = adjacencies[(vIndex + 2) % 3];
  564. if (adjPrev >= 0)
  565. {
  566. if (adjPrev != vTriangle)
  567. {
  568. tri = adjPrev;
  569. vIndex = GetIndexOfVertex(tri, v);
  570. LogAssert(vIndex >= 0, CDTFailure());
  571. link.push_back(std::make_pair(tri, vIndex));
  572. }
  573. else
  574. {
  575. // We have reached the starting triangle, so v is an
  576. // interior vertex.
  577. isOpen = false;
  578. return true;
  579. }
  580. }
  581. else
  582. {
  583. // We have reached a triangle with boundary edge, so v is
  584. // a boundary vertex. We mush find more triangles by
  585. // searching to the "right" of v. Guard against an
  586. // infinite loop.
  587. isOpen = true;
  588. tri = vTriangle;
  589. vIndex = vStartIndex;
  590. for (int j = 0; j < this->mNumTriangles; ++j)
  591. {
  592. this->GetAdjacencies(tri, adjacencies);
  593. int adjNext = adjacencies[vIndex];
  594. if (adjNext >= 0)
  595. {
  596. tri = adjNext;
  597. vIndex = GetIndexOfVertex(tri, v);
  598. LogAssert(vIndex >= 0, CDTFailure());
  599. link.push_front(std::make_pair(tri, vIndex));
  600. }
  601. else
  602. {
  603. // We have reached the other boundary edge that
  604. // shares v.
  605. return true;
  606. }
  607. }
  608. break;
  609. }
  610. }
  611. LogError(CDTFailure());
  612. }
  613. static std::string const& CDTFailure()
  614. {
  615. static std::string message = "Unexpected condition. Caused by floating-point rounding error?";
  616. return message;
  617. }
  618. };
  619. }