Delaunay2.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  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/Logger.h>
  9. #include <Mathematics/ETManifoldMesh.h>
  10. #include <Mathematics/PrimalQuery2.h>
  11. #include <Mathematics/Line.h>
  12. #include <set>
  13. // Delaunay triangulation of points (intrinsic dimensionality 2).
  14. // VQ = number of vertices
  15. // V = array of vertices
  16. // TQ = number of triangles
  17. // I = Array of 3-tuples of indices into V that represent the triangles
  18. // (3*TQ total elements). Access via GetIndices(*).
  19. // A = Array of 3-tuples of indices into I that represent the adjacent
  20. // triangles (3*TQ total elements). Access via GetAdjacencies(*).
  21. // The i-th triangle has vertices
  22. // vertex[0] = V[I[3*i+0]]
  23. // vertex[1] = V[I[3*i+1]]
  24. // vertex[2] = V[I[3*i+2]]
  25. // and edge index pairs
  26. // edge[0] = <I[3*i+0],I[3*i+1]>
  27. // edge[1] = <I[3*i+1],I[3*i+2]>
  28. // edge[2] = <I[3*i+2],I[3*i+0]>
  29. // The triangles adjacent to these edges have indices
  30. // adjacent[0] = A[3*i+0] is the triangle sharing edge[0]
  31. // adjacent[1] = A[3*i+1] is the triangle sharing edge[1]
  32. // adjacent[2] = A[3*i+2] is the triangle sharing edge[2]
  33. // If there is no adjacent triangle, the A[*] value is set to -1. The
  34. // triangle adjacent to edge[j] has vertices
  35. // adjvertex[0] = V[I[3*adjacent[j]+0]]
  36. // adjvertex[1] = V[I[3*adjacent[j]+1]]
  37. // adjvertex[2] = V[I[3*adjacent[j]+2]]
  38. // The only way to ensure a correct result for the input vertices (assumed to
  39. // be exact) is to choose ComputeType for exact rational arithmetic. You may
  40. // use BSNumber. No divisions are performed in this computation, so you do
  41. // not have to use BSRational.
  42. //
  43. // The worst-case choices of N for Real of type BSNumber or BSRational with
  44. // integer storage UIntegerFP32<N> are listed in the next table. The numerical
  45. // computations are encapsulated in PrimalQuery2<Real>::ToLine and
  46. // PrimalQuery2<Real>::ToCircumcircle, the latter query the dominant one in
  47. // determining N. We recommend using only BSNumber, because no divisions are
  48. // performed in the convex-hull computations.
  49. //
  50. // input type | compute type | N
  51. // -----------+--------------+------
  52. // float | BSNumber | 35
  53. // double | BSNumber | 263
  54. // float | BSRational | 12302
  55. // double | BSRational | 92827
  56. namespace WwiseGTE
  57. {
  58. template <typename InputType, typename ComputeType>
  59. class Delaunay2
  60. {
  61. public:
  62. // The class is a functor to support computing the Delaunay
  63. // triangulation of multiple data sets using the same class object.
  64. virtual ~Delaunay2() = default;
  65. Delaunay2()
  66. :
  67. mEpsilon((InputType)0),
  68. mDimension(0),
  69. mLine(Vector2<InputType>::Zero(), Vector2<InputType>::Zero()),
  70. mNumVertices(0),
  71. mNumUniqueVertices(0),
  72. mNumTriangles(0),
  73. mVertices(nullptr),
  74. mIndex{ { { 0, 1 }, { 1, 2 }, { 2, 0 } } }
  75. {
  76. }
  77. // The input is the array of vertices whose Delaunay triangulation is
  78. // required. The epsilon value is used to determine the intrinsic
  79. // dimensionality of the vertices (d = 0, 1, or 2). When epsilon is
  80. // positive, the determination is fuzzy--vertices approximately the
  81. // same point, approximately on a line, or planar. The return value
  82. // is 'true' if and only if the hull construction is successful.
  83. bool operator()(int numVertices, Vector2<InputType> const* vertices, InputType epsilon)
  84. {
  85. mEpsilon = std::max(epsilon, (InputType)0);
  86. mDimension = 0;
  87. mLine.origin = Vector2<InputType>::Zero();
  88. mLine.direction = Vector2<InputType>::Zero();
  89. mNumVertices = numVertices;
  90. mNumUniqueVertices = 0;
  91. mNumTriangles = 0;
  92. mVertices = vertices;
  93. mGraph.Clear();
  94. mIndices.clear();
  95. mAdjacencies.clear();
  96. mDuplicates.resize(std::max(numVertices, 3));
  97. int i, j;
  98. if (mNumVertices < 3)
  99. {
  100. // Delaunay2 should be called with at least three points.
  101. return false;
  102. }
  103. IntrinsicsVector2<InputType> info(mNumVertices, vertices, mEpsilon);
  104. if (info.dimension == 0)
  105. {
  106. // mDimension is 0; mGraph, mIndices, and mAdjacencies are empty
  107. return false;
  108. }
  109. if (info.dimension == 1)
  110. {
  111. // The set is (nearly) collinear.
  112. mDimension = 1;
  113. mLine = Line2<InputType>(info.origin, info.direction[0]);
  114. return false;
  115. }
  116. mDimension = 2;
  117. // Compute the vertices for the queries.
  118. mComputeVertices.resize(mNumVertices);
  119. mQuery.Set(mNumVertices, &mComputeVertices[0]);
  120. for (i = 0; i < mNumVertices; ++i)
  121. {
  122. for (j = 0; j < 2; ++j)
  123. {
  124. mComputeVertices[i][j] = vertices[i][j];
  125. }
  126. }
  127. // Insert the (nondegenerate) triangle constructed by the call to
  128. // GetInformation. This is necessary for the circumcircle-visibility
  129. // algorithm to work correctly.
  130. if (!info.extremeCCW)
  131. {
  132. std::swap(info.extreme[1], info.extreme[2]);
  133. }
  134. if (!mGraph.Insert(info.extreme[0], info.extreme[1], info.extreme[2]))
  135. {
  136. return false;
  137. }
  138. // Incrementally update the triangulation. The set of processed
  139. // points is maintained to eliminate duplicates, either in the
  140. // original input points or in the points obtained by snap rounding.
  141. std::set<ProcessedVertex> processed;
  142. for (i = 0; i < 3; ++i)
  143. {
  144. j = info.extreme[i];
  145. processed.insert(ProcessedVertex(vertices[j], j));
  146. mDuplicates[j] = j;
  147. }
  148. for (i = 0; i < mNumVertices; ++i)
  149. {
  150. ProcessedVertex v(vertices[i], i);
  151. auto iter = processed.find(v);
  152. if (iter == processed.end())
  153. {
  154. if (!Update(i))
  155. {
  156. // A failure can occur if ComputeType is not an exact
  157. // arithmetic type.
  158. return false;
  159. }
  160. processed.insert(v);
  161. mDuplicates[i] = i;
  162. }
  163. else
  164. {
  165. mDuplicates[i] = iter->location;
  166. }
  167. }
  168. mNumUniqueVertices = static_cast<int>(processed.size());
  169. // Assign integer values to the triangles for use by the caller.
  170. std::map<std::shared_ptr<Triangle>, int> permute;
  171. i = -1;
  172. permute[nullptr] = i++;
  173. for (auto const& element : mGraph.GetTriangles())
  174. {
  175. permute[element.second] = i++;
  176. }
  177. // Put Delaunay triangles into an array (vertices and adjacency info).
  178. mNumTriangles = static_cast<int>(mGraph.GetTriangles().size());
  179. int numindices = 3 * mNumTriangles;
  180. if (numindices > 0)
  181. {
  182. mIndices.resize(numindices);
  183. mAdjacencies.resize(numindices);
  184. i = 0;
  185. for (auto const& element : mGraph.GetTriangles())
  186. {
  187. std::shared_ptr<Triangle> tri = element.second;
  188. for (j = 0; j < 3; ++j, ++i)
  189. {
  190. mIndices[i] = tri->V[j];
  191. mAdjacencies[i] = permute[tri->T[j].lock()];
  192. }
  193. }
  194. }
  195. return true;
  196. }
  197. // Dimensional information. If GetDimension() returns 1, the points
  198. // lie on a line P+t*D (fuzzy comparison when epsilon > 0). You can
  199. // sort these if you need a polyline output by projecting onto the
  200. // line each vertex X = P+t*D, where t = Dot(D,X-P).
  201. inline InputType GetEpsilon() const
  202. {
  203. return mEpsilon;
  204. }
  205. inline int GetDimension() const
  206. {
  207. return mDimension;
  208. }
  209. inline Line2<InputType> const& GetLine() const
  210. {
  211. return mLine;
  212. }
  213. // Member access.
  214. inline int GetNumVertices() const
  215. {
  216. return mNumVertices;
  217. }
  218. inline int GetNumUniqueVertices() const
  219. {
  220. return mNumUniqueVertices;
  221. }
  222. inline int GetNumTriangles() const
  223. {
  224. return mNumTriangles;
  225. }
  226. inline Vector2<InputType> const* GetVertices() const
  227. {
  228. return mVertices;
  229. }
  230. inline PrimalQuery2<ComputeType> const& GetQuery() const
  231. {
  232. return mQuery;
  233. }
  234. inline ETManifoldMesh const& GetGraph() const
  235. {
  236. return mGraph;
  237. }
  238. inline std::vector<int> const& GetIndices() const
  239. {
  240. return mIndices;
  241. }
  242. inline std::vector<int> const& GetAdjacencies() const
  243. {
  244. return mAdjacencies;
  245. }
  246. // If 'vertices' has no duplicates, GetDuplicates()[i] = i for all i.
  247. // If vertices[i] is the first occurrence of a vertex and if
  248. // vertices[j] is found later, then GetDuplicates()[j] = i.
  249. inline std::vector<int> const& GetDuplicates() const
  250. {
  251. return mDuplicates;
  252. }
  253. // Locate those triangle edges that do not share other triangles. The
  254. // returned array has hull.size() = 2*numEdges, each pair representing
  255. // an edge. The edges are not ordered, but the pair of vertices for
  256. // an edge is ordered so that they conform to a counterclockwise
  257. // traversal of the hull. The return value is 'true' if and only if
  258. // the dimension is 2.
  259. bool GetHull(std::vector<int>& hull) const
  260. {
  261. if (mDimension == 2)
  262. {
  263. // Count the number of edges that are not shared by two
  264. // triangles.
  265. int numEdges = 0;
  266. for (auto adj : mAdjacencies)
  267. {
  268. if (adj == -1)
  269. {
  270. ++numEdges;
  271. }
  272. }
  273. if (numEdges > 0)
  274. {
  275. // Enumerate the edges.
  276. hull.resize(2 * numEdges);
  277. int current = 0, i = 0;
  278. for (auto adj : mAdjacencies)
  279. {
  280. if (adj == -1)
  281. {
  282. int tri = i / 3, j = i % 3;
  283. hull[current++] = mIndices[3 * tri + j];
  284. hull[current++] = mIndices[3 * tri + ((j + 1) % 3)];
  285. }
  286. ++i;
  287. }
  288. return true;
  289. }
  290. else
  291. {
  292. LogError("Unexpected. There must be at least one triangle.");
  293. }
  294. }
  295. else
  296. {
  297. LogError("The dimension must be 2.");
  298. }
  299. }
  300. // Get the vertex indices for triangle i. The function returns 'true'
  301. // when the dimension is 2 and i is a valid triangle index, in which
  302. // case the vertices are valid; otherwise, the function returns
  303. // 'false' and the vertices are invalid.
  304. bool GetIndices(int i, std::array<int, 3>& indices) const
  305. {
  306. if (mDimension == 2)
  307. {
  308. int numTriangles = static_cast<int>(mIndices.size() / 3);
  309. if (0 <= i && i < numTriangles)
  310. {
  311. indices[0] = mIndices[3 * i];
  312. indices[1] = mIndices[3 * i + 1];
  313. indices[2] = mIndices[3 * i + 2];
  314. return true;
  315. }
  316. }
  317. else
  318. {
  319. LogError("The dimension must be 2.");
  320. }
  321. return false;
  322. }
  323. // Get the indices for triangles adjacent to triangle i. The function
  324. // returns 'true' when the dimension is 2 and if i is a valid triangle
  325. // index, in which case the adjacencies are valid; otherwise, the
  326. // function returns 'false' and the adjacencies are invalid.
  327. bool GetAdjacencies(int i, std::array<int, 3>& adjacencies) const
  328. {
  329. if (mDimension == 2)
  330. {
  331. int numTriangles = static_cast<int>(mIndices.size() / 3);
  332. if (0 <= i && i < numTriangles)
  333. {
  334. adjacencies[0] = mAdjacencies[3 * i];
  335. adjacencies[1] = mAdjacencies[3 * i + 1];
  336. adjacencies[2] = mAdjacencies[3 * i + 2];
  337. return true;
  338. }
  339. }
  340. else
  341. {
  342. LogError("The dimension must be 2.");
  343. }
  344. return false;
  345. }
  346. // Support for searching the triangulation for a triangle that
  347. // contains a point. If there is a containing triangle, the returned
  348. // value is a triangle index i with 0 <= i < GetNumTriangles(). If
  349. // there is not a containing triangle, -1 is returned. The
  350. // computations are performed using exact rational arithmetic.
  351. //
  352. // The SearchInfo input stores information about the triangle search
  353. // when looking for the triangle (if any) that contains p. The first
  354. // triangle searched is 'initialTriangle'. On return 'path' stores
  355. // those (ordered) triangle indices visited during the search. The
  356. // last visited triangle has index 'finalTriangle and vertex indices
  357. // 'finalV[0,1,2]', stored in counterclockwise order. The last edge
  358. // of the search is <finalV[0],finalV[1]>. For spatially coherent
  359. // inputs p for numerous calls to this function, you will want to
  360. // specify 'finalTriangle' from the previous call as 'initialTriangle'
  361. // for the next call, which should reduce search times.
  362. struct SearchInfo
  363. {
  364. int initialTriangle;
  365. int numPath;
  366. std::vector<int> path;
  367. int finalTriangle;
  368. std::array<int, 3> finalV;
  369. };
  370. int GetContainingTriangle(Vector2<InputType> const& p, SearchInfo& info) const
  371. {
  372. if (mDimension == 2)
  373. {
  374. Vector2<ComputeType> test{ p[0], p[1] };
  375. int numTriangles = static_cast<int>(mIndices.size() / 3);
  376. info.path.resize(numTriangles);
  377. info.numPath = 0;
  378. int triangle;
  379. if (0 <= info.initialTriangle && info.initialTriangle < numTriangles)
  380. {
  381. triangle = info.initialTriangle;
  382. }
  383. else
  384. {
  385. info.initialTriangle = 0;
  386. triangle = 0;
  387. }
  388. // Use triangle edges as binary separating lines.
  389. for (int i = 0; i < numTriangles; ++i)
  390. {
  391. int ibase = 3 * triangle;
  392. int const* v = &mIndices[ibase];
  393. info.path[info.numPath++] = triangle;
  394. info.finalTriangle = triangle;
  395. info.finalV[0] = v[0];
  396. info.finalV[1] = v[1];
  397. info.finalV[2] = v[2];
  398. if (mQuery.ToLine(test, v[0], v[1]) > 0)
  399. {
  400. triangle = mAdjacencies[ibase];
  401. if (triangle == -1)
  402. {
  403. info.finalV[0] = v[0];
  404. info.finalV[1] = v[1];
  405. info.finalV[2] = v[2];
  406. return -1;
  407. }
  408. continue;
  409. }
  410. if (mQuery.ToLine(test, v[1], v[2]) > 0)
  411. {
  412. triangle = mAdjacencies[ibase + 1];
  413. if (triangle == -1)
  414. {
  415. info.finalV[0] = v[1];
  416. info.finalV[1] = v[2];
  417. info.finalV[2] = v[0];
  418. return -1;
  419. }
  420. continue;
  421. }
  422. if (mQuery.ToLine(test, v[2], v[0]) > 0)
  423. {
  424. triangle = mAdjacencies[ibase + 2];
  425. if (triangle == -1)
  426. {
  427. info.finalV[0] = v[2];
  428. info.finalV[1] = v[0];
  429. info.finalV[2] = v[1];
  430. return -1;
  431. }
  432. continue;
  433. }
  434. return triangle;
  435. }
  436. }
  437. else
  438. {
  439. LogError("The dimension must be 2.");
  440. }
  441. return -1;
  442. }
  443. protected:
  444. // Support for incremental Delaunay triangulation.
  445. typedef ETManifoldMesh::Triangle Triangle;
  446. bool GetContainingTriangle(int i, std::shared_ptr<Triangle>& tri) const
  447. {
  448. int numTriangles = static_cast<int>(mGraph.GetTriangles().size());
  449. for (int t = 0; t < numTriangles; ++t)
  450. {
  451. int j;
  452. for (j = 0; j < 3; ++j)
  453. {
  454. int v0 = tri->V[mIndex[j][0]];
  455. int v1 = tri->V[mIndex[j][1]];
  456. if (mQuery.ToLine(i, v0, v1) > 0)
  457. {
  458. // Point i sees edge <v0,v1> from outside the triangle.
  459. auto adjTri = tri->T[j].lock();
  460. if (adjTri)
  461. {
  462. // Traverse to the triangle sharing the face.
  463. tri = adjTri;
  464. break;
  465. }
  466. else
  467. {
  468. // We reached a hull edge, so the point is outside
  469. // the hull. TODO: Once a hull data structure is
  470. // in place, return tri->T[j] as the candidate for
  471. // starting a search for visible hull edges.
  472. return false;
  473. }
  474. }
  475. }
  476. if (j == 3)
  477. {
  478. // The point is inside all four edges, so the point is inside
  479. // a triangle.
  480. return true;
  481. }
  482. }
  483. LogError("Unexpected termination of loop.");
  484. }
  485. bool GetAndRemoveInsertionPolygon(int i, std::set<std::shared_ptr<Triangle>>& candidates,
  486. std::set<EdgeKey<true>>& boundary)
  487. {
  488. // Locate the triangles that make up the insertion polygon.
  489. ETManifoldMesh polygon;
  490. while (candidates.size() > 0)
  491. {
  492. std::shared_ptr<Triangle> tri = *candidates.begin();
  493. candidates.erase(candidates.begin());
  494. for (int j = 0; j < 3; ++j)
  495. {
  496. auto adj = tri->T[j].lock();
  497. if (adj && candidates.find(adj) == candidates.end())
  498. {
  499. int a0 = adj->V[0];
  500. int a1 = adj->V[1];
  501. int a2 = adj->V[2];
  502. if (mQuery.ToCircumcircle(i, a0, a1, a2) <= 0)
  503. {
  504. // Point i is in the circumcircle.
  505. candidates.insert(adj);
  506. }
  507. }
  508. }
  509. if (!polygon.Insert(tri->V[0], tri->V[1], tri->V[2]))
  510. {
  511. return false;
  512. }
  513. if (!mGraph.Remove(tri->V[0], tri->V[1], tri->V[2]))
  514. {
  515. return false;
  516. }
  517. }
  518. // Get the boundary edges of the insertion polygon.
  519. for (auto const& element : polygon.GetTriangles())
  520. {
  521. std::shared_ptr<Triangle> tri = element.second;
  522. for (int j = 0; j < 3; ++j)
  523. {
  524. if (!tri->T[j].lock())
  525. {
  526. boundary.insert(EdgeKey<true>(tri->V[mIndex[j][0]], tri->V[mIndex[j][1]]));
  527. }
  528. }
  529. }
  530. return true;
  531. }
  532. bool Update(int i)
  533. {
  534. // The return value of mGraph.Insert(...) is nullptr if there was
  535. // a failure to insert. The Update function will return 'false'
  536. // when the insertion fails.
  537. auto const& tmap = mGraph.GetTriangles();
  538. std::shared_ptr<Triangle> tri = tmap.begin()->second;
  539. if (GetContainingTriangle(i, tri))
  540. {
  541. // The point is inside the convex hull. The insertion polygon
  542. // contains only triangles in the current triangulation; the
  543. // hull does not change.
  544. // Use a depth-first search for those triangles whose
  545. // circumcircles contain point i.
  546. std::set<std::shared_ptr<Triangle>> candidates;
  547. candidates.insert(tri);
  548. // Get the boundary of the insertion polygon C that contains
  549. // the triangles whose circumcircles contain point i. Polygon
  550. // C contains the point i.
  551. std::set<EdgeKey<true>> boundary;
  552. if (!GetAndRemoveInsertionPolygon(i, candidates, boundary))
  553. {
  554. return false;
  555. }
  556. // The insertion polygon consists of the triangles formed by
  557. // point i and the faces of C.
  558. for (auto const& key : boundary)
  559. {
  560. int v0 = key.V[0];
  561. int v1 = key.V[1];
  562. if (mQuery.ToLine(i, v0, v1) < 0)
  563. {
  564. if (!mGraph.Insert(i, v0, v1))
  565. {
  566. return false;
  567. }
  568. }
  569. // else: Point i is on an edge of 'tri', so the
  570. // subdivision has degenerate triangles. Ignore these.
  571. }
  572. }
  573. else
  574. {
  575. // The point is outside the convex hull. The insertion
  576. // polygon is formed by point i and any triangles in the
  577. // current triangulation whose circumcircles contain point i.
  578. // Locate the convex hull of the triangles. TODO: Maintain a
  579. // hull data structure that is updated incrementally.
  580. std::set<EdgeKey<true>> hull;
  581. for (auto const& element : tmap)
  582. {
  583. std::shared_ptr<Triangle> t = element.second;
  584. for (int j = 0; j < 3; ++j)
  585. {
  586. if (!t->T[j].lock())
  587. {
  588. hull.insert(EdgeKey<true>(t->V[mIndex[j][0]], t->V[mIndex[j][1]]));
  589. }
  590. }
  591. }
  592. // TODO: Until the hull change, for now just iterate over all
  593. // the hull edges and use the ones visible to point i to
  594. // locate the insertion polygon.
  595. auto const& emap = mGraph.GetEdges();
  596. std::set<std::shared_ptr<Triangle>> candidates;
  597. std::set<EdgeKey<true>> visible;
  598. for (auto const& key : hull)
  599. {
  600. int v0 = key.V[0];
  601. int v1 = key.V[1];
  602. if (mQuery.ToLine(i, v0, v1) > 0)
  603. {
  604. auto iter = emap.find(EdgeKey<false>(v0, v1));
  605. if (iter != emap.end() && iter->second->T[1].lock() == nullptr)
  606. {
  607. auto adj = iter->second->T[0].lock();
  608. if (adj && candidates.find(adj) == candidates.end())
  609. {
  610. int a0 = adj->V[0];
  611. int a1 = adj->V[1];
  612. int a2 = adj->V[2];
  613. if (mQuery.ToCircumcircle(i, a0, a1, a2) <= 0)
  614. {
  615. // Point i is in the circumcircle.
  616. candidates.insert(adj);
  617. }
  618. else
  619. {
  620. // Point i is not in the circumcircle but
  621. // the hull edge is visible.
  622. visible.insert(key);
  623. }
  624. }
  625. }
  626. else
  627. {
  628. // TODO: Add a preprocessor symbol to this file
  629. // to allow throwing an exception. Currently, the
  630. // code exits gracefully when floating-point
  631. // rounding causes problems.
  632. //
  633. // LogError("Unexpected condition (ComputeType not exact?)");
  634. return false;
  635. }
  636. }
  637. }
  638. // Get the boundary of the insertion subpolygon C that
  639. // contains the triangles whose circumcircles contain point i.
  640. std::set<EdgeKey<true>> boundary;
  641. if (!GetAndRemoveInsertionPolygon(i, candidates, boundary))
  642. {
  643. return false;
  644. }
  645. // The insertion polygon P consists of the triangles formed by
  646. // point i and the back edges of C *and* the visible edges of
  647. // mGraph-C.
  648. for (auto const& key : boundary)
  649. {
  650. int v0 = key.V[0];
  651. int v1 = key.V[1];
  652. if (mQuery.ToLine(i, v0, v1) < 0)
  653. {
  654. // This is a back edge of the boundary.
  655. if (!mGraph.Insert(i, v0, v1))
  656. {
  657. return false;
  658. }
  659. }
  660. }
  661. for (auto const& key : visible)
  662. {
  663. if (!mGraph.Insert(i, key.V[1], key.V[0]))
  664. {
  665. return false;
  666. }
  667. }
  668. }
  669. return true;
  670. }
  671. // The epsilon value is used for fuzzy determination of intrinsic
  672. // dimensionality. If the dimension is 0 or 1, the constructor
  673. // returns early. The caller is responsible for retrieving the
  674. // dimension and taking an alternate path should the dimension be
  675. // smaller than 2. If the dimension is 0, the caller may as well
  676. // treat all vertices[] as a single point, say, vertices[0]. If the
  677. // dimension is 1, the caller can query for the approximating line and
  678. // project vertices[] onto it for further processing.
  679. InputType mEpsilon;
  680. int mDimension;
  681. Line2<InputType> mLine;
  682. // The array of vertices used for geometric queries. If you want to
  683. // be certain of a correct result, choose ComputeType to be BSNumber.
  684. std::vector<Vector2<ComputeType>> mComputeVertices;
  685. PrimalQuery2<ComputeType> mQuery;
  686. // The graph information.
  687. int mNumVertices;
  688. int mNumUniqueVertices;
  689. int mNumTriangles;
  690. Vector2<InputType> const* mVertices;
  691. ETManifoldMesh mGraph;
  692. std::vector<int> mIndices;
  693. std::vector<int> mAdjacencies;
  694. // If a vertex occurs multiple times in the 'vertices' input to the
  695. // constructor, the first processed occurrence of that vertex has an
  696. // index stored in this array. If there are no duplicates, then
  697. // mDuplicates[i] = i for all i.
  698. struct ProcessedVertex
  699. {
  700. ProcessedVertex() = default;
  701. ProcessedVertex(Vector2<InputType> const& inVertex, int inLocation)
  702. :
  703. vertex(inVertex),
  704. location(inLocation)
  705. {
  706. }
  707. bool operator<(ProcessedVertex const& v) const
  708. {
  709. return vertex < v.vertex;
  710. }
  711. Vector2<InputType> vertex;
  712. int location;
  713. };
  714. std::vector<int> mDuplicates;
  715. // Indexing for the vertices of the triangle adjacent to a vertex.
  716. // The edge adjacent to vertex j is <mIndex[j][0], mIndex[j][1]> and
  717. // is listed so that the triangle interior is to your left as you walk
  718. // around the edges. TODO: Use the "opposite edge" to be consistent
  719. // with that of TetrahedronKey. The "opposite" idea extends easily to
  720. // higher dimensions.
  721. std::array<std::array<int, 2>, 3> mIndex;
  722. };
  723. }