MinimalCycleBasis.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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/MinHeap.h>
  9. #include <array>
  10. #include <map>
  11. #include <memory>
  12. #include <set>
  13. #include <stack>
  14. // Extract the minimal cycle basis for a planar graph. The input vertices and
  15. // edges must form a graph for which edges intersect only at vertices; that is,
  16. // no two edges must intersect at an interior point of one of the edges. The
  17. // algorithm is described in
  18. // https://www.geometrictools.com/Documentation/MinimalCycleBasis.pdf
  19. // The graph might have filaments, which are polylines in the graph that are
  20. // not shared by a cycle. These are also extracted by the implementation.
  21. // Because the inputs to the constructor are vertices and edges of the graph,
  22. // isolated vertices are ignored.
  23. //
  24. // The computations that determine which adjacent vertex to visit next during
  25. // a filament or cycle traversal do not require division, so the exact
  26. // arithmetic type BSNumber<UIntegerAP32> suffices for ComputeType when you
  27. // want to ensure a correct output. (Floating-point rounding errors
  28. // potentially can lead to an incorrect output.)
  29. namespace WwiseGTE
  30. {
  31. template <typename Real>
  32. class MinimalCycleBasis
  33. {
  34. public:
  35. struct Tree
  36. {
  37. std::vector<int> cycle;
  38. std::vector<std::shared_ptr<Tree>> children;
  39. };
  40. // The input positions and edges must form a planar graph for which
  41. // edges intersect only at vertices; that is, no two edges must
  42. // intersect at an interior point of one of the edges.
  43. MinimalCycleBasis(
  44. std::vector<std::array<Real, 2>> const& positions,
  45. std::vector<std::array<int, 2>> const& edges,
  46. std::vector<std::shared_ptr<Tree>>& forest)
  47. {
  48. forest.clear();
  49. if (positions.size() == 0 || edges.size() == 0)
  50. {
  51. // The graph is empty, so there are no filaments or cycles.
  52. return;
  53. }
  54. // Determine the unique positions referenced by the edges.
  55. std::map<int, std::shared_ptr<Vertex>> unique;
  56. for (auto const& edge : edges)
  57. {
  58. for (int i = 0; i < 2; ++i)
  59. {
  60. int name = edge[i];
  61. if (unique.find(name) == unique.end())
  62. {
  63. auto vertex = std::make_shared<Vertex>(name, &positions[name]);
  64. unique.insert(std::make_pair(name, vertex));
  65. }
  66. }
  67. }
  68. // Assign responsibility for ownership of the Vertex objects.
  69. std::vector<Vertex*> vertices;
  70. mVertexStorage.reserve(unique.size());
  71. vertices.reserve(unique.size());
  72. for (auto const& element : unique)
  73. {
  74. mVertexStorage.push_back(element.second);
  75. vertices.push_back(element.second.get());
  76. }
  77. // Determine the adjacencies from the edge information.
  78. for (auto const& edge : edges)
  79. {
  80. auto iter0 = unique.find(edge[0]);
  81. auto iter1 = unique.find(edge[1]);
  82. iter0->second->adjacent.insert(iter1->second.get());
  83. iter1->second->adjacent.insert(iter0->second.get());
  84. }
  85. // Get the connected components of the graph. The 'visited' flags
  86. // are 0 (unvisited), 1 (discovered), 2 (finished). The Vertex
  87. // constructor sets all 'visited' flags to 0.
  88. std::vector<std::vector<Vertex*>> components;
  89. for (auto vInitial : mVertexStorage)
  90. {
  91. if (vInitial->visited == 0)
  92. {
  93. components.push_back(std::vector<Vertex*>());
  94. DepthFirstSearch(vInitial.get(), components.back());
  95. }
  96. }
  97. // The depth-first search is used later for collecting vertices
  98. // for subgraphs that are detached from the main graph, so the
  99. // 'visited' flags must be reset to zero after component finding.
  100. for (auto vertex : mVertexStorage)
  101. {
  102. vertex->visited = 0;
  103. }
  104. // Get the primitives for the components.
  105. for (auto& component : components)
  106. {
  107. forest.push_back(ExtractBasis(component));
  108. }
  109. }
  110. // No copy or assignment allowed.
  111. MinimalCycleBasis(MinimalCycleBasis const&) = delete;
  112. MinimalCycleBasis& operator=(MinimalCycleBasis const&) = delete;
  113. private:
  114. struct Vertex
  115. {
  116. Vertex(int inName, std::array<Real, 2> const* inPosition)
  117. :
  118. name(inName),
  119. position(inPosition),
  120. visited(0)
  121. {
  122. }
  123. bool operator< (Vertex const& vertex) const
  124. {
  125. return name < vertex.name;
  126. }
  127. // The index into the 'positions' input provided to the call to
  128. // operator(). The index is used when reporting cycles to the
  129. // caller of the constructor for MinimalCycleBasis.
  130. int name;
  131. // Multiple vertices can share a position during processing of
  132. // graph components.
  133. std::array<Real, 2> const* position;
  134. // The mVertexStorage member owns the Vertex objects and maintains
  135. // the reference counts on those objects. The adjacent pointers
  136. // are considered to be weak pointers; neither object ownership
  137. // nor reference counting is required by 'adjacent'.
  138. std::set<Vertex*> adjacent;
  139. // Support for depth-first traversal of a graph.
  140. int visited;
  141. };
  142. // The constructor uses GetComponents(...) and DepthFirstSearch(...)
  143. // to get the connected components of the graph implied by the input
  144. // 'edges'. Recursive processing uses only DepthFirstSearch(...) to
  145. // collect vertices of the subgraphs of the original graph.
  146. static void DepthFirstSearch(Vertex* vInitial, std::vector<Vertex*>& component)
  147. {
  148. std::stack<Vertex*> vStack;
  149. vStack.push(vInitial);
  150. while (vStack.size() > 0)
  151. {
  152. Vertex* vertex = vStack.top();
  153. vertex->visited = 1;
  154. size_t i = 0;
  155. for (auto adjacent : vertex->adjacent)
  156. {
  157. if (adjacent && adjacent->visited == 0)
  158. {
  159. vStack.push(adjacent);
  160. break;
  161. }
  162. ++i;
  163. }
  164. if (i == vertex->adjacent.size())
  165. {
  166. vertex->visited = 2;
  167. component.push_back(vertex);
  168. vStack.pop();
  169. }
  170. }
  171. }
  172. // Support for traversing a simply connected component of the graph.
  173. std::shared_ptr<Tree> ExtractBasis(std::vector<Vertex*>& component)
  174. {
  175. // The root will not have its 'cycle' member set. The children
  176. // are the cycle trees extracted from the component.
  177. auto tree = std::make_shared<Tree>();
  178. while (component.size() > 0)
  179. {
  180. RemoveFilaments(component);
  181. if (component.size() > 0)
  182. {
  183. tree->children.push_back(ExtractCycleFromComponent(component));
  184. }
  185. }
  186. if (tree->cycle.size() == 0 && tree->children.size() == 1)
  187. {
  188. // Replace the parent by the child to avoid having two empty
  189. // cycles in parent/child.
  190. auto child = tree->children.back();
  191. tree->cycle = std::move(child->cycle);
  192. tree->children = std::move(child->children);
  193. }
  194. return tree;
  195. }
  196. void RemoveFilaments(std::vector<Vertex*>& component)
  197. {
  198. // Locate all filament endpoints, which are vertices, each having
  199. // exactly one adjacent vertex.
  200. std::vector<Vertex*> endpoints;
  201. for (auto vertex : component)
  202. {
  203. if (vertex->adjacent.size() == 1)
  204. {
  205. endpoints.push_back(vertex);
  206. }
  207. }
  208. if (endpoints.size() > 0)
  209. {
  210. // Remove the filaments from the component. If a filament has
  211. // two endpoints, each having one adjacent vertex, the
  212. // adjacency set of the final visited vertex become empty.
  213. // We must test for that condition before starting a new
  214. // filament removal.
  215. for (auto vertex : endpoints)
  216. {
  217. if (vertex->adjacent.size() == 1)
  218. {
  219. // Traverse the filament and remove the vertices.
  220. while (vertex->adjacent.size() == 1)
  221. {
  222. // Break the connection between the two vertices.
  223. Vertex* adjacent = *vertex->adjacent.begin();
  224. adjacent->adjacent.erase(vertex);
  225. vertex->adjacent.erase(adjacent);
  226. // Traverse to the adjacent vertex.
  227. vertex = adjacent;
  228. }
  229. }
  230. }
  231. // At this time the component is either empty (it was a union
  232. // of polylines) or it has no filaments and at least one
  233. // cycle. Remove the isolated vertices generated by filament
  234. // extraction.
  235. std::vector<Vertex*> remaining;
  236. remaining.reserve(component.size());
  237. for (auto vertex : component)
  238. {
  239. if (vertex->adjacent.size() > 0)
  240. {
  241. remaining.push_back(vertex);
  242. }
  243. }
  244. component = std::move(remaining);
  245. }
  246. }
  247. std::shared_ptr<Tree> ExtractCycleFromComponent(std::vector<Vertex*>& component)
  248. {
  249. // Search for the left-most vertex of the component. If two or
  250. // more vertices attain minimum x-value, select the one that has
  251. // minimum y-value.
  252. Vertex* minVertex = component[0];
  253. for (auto vertex : component)
  254. {
  255. if (*vertex->position < *minVertex->position)
  256. {
  257. minVertex = vertex;
  258. }
  259. }
  260. // Traverse the closed walk, duplicating the starting vertex as
  261. // the last vertex.
  262. std::vector<Vertex*> closedWalk;
  263. Vertex* vCurr = minVertex;
  264. Vertex* vStart = vCurr;
  265. closedWalk.push_back(vStart);
  266. Vertex* vAdj = GetClockwiseMost(nullptr, vStart);
  267. while (vAdj != vStart)
  268. {
  269. closedWalk.push_back(vAdj);
  270. Vertex* vNext = GetCounterclockwiseMost(vCurr, vAdj);
  271. vCurr = vAdj;
  272. vAdj = vNext;
  273. }
  274. closedWalk.push_back(vStart);
  275. // Recursively process the closed walk to extract cycles.
  276. auto tree = ExtractCycleFromClosedWalk(closedWalk);
  277. // The isolated vertices generated by cycle removal are also
  278. // removed from the component.
  279. std::vector<Vertex*> remaining;
  280. remaining.reserve(component.size());
  281. for (auto vertex : component)
  282. {
  283. if (vertex->adjacent.size() > 0)
  284. {
  285. remaining.push_back(vertex);
  286. }
  287. }
  288. component = std::move(remaining);
  289. return tree;
  290. }
  291. std::shared_ptr<Tree> ExtractCycleFromClosedWalk(std::vector<Vertex*>& closedWalk)
  292. {
  293. auto tree = std::make_shared<Tree>();
  294. std::map<Vertex*, int> duplicates;
  295. std::set<int> detachments;
  296. int numClosedWalk = static_cast<int>(closedWalk.size());
  297. for (int i = 1; i < numClosedWalk - 1; ++i)
  298. {
  299. auto diter = duplicates.find(closedWalk[i]);
  300. if (diter == duplicates.end())
  301. {
  302. // We have not yet visited this vertex.
  303. duplicates.insert(std::make_pair(closedWalk[i], i));
  304. continue;
  305. }
  306. // The vertex has been visited previously. Collapse the
  307. // closed walk by removing the subwalk sharing this vertex.
  308. // Note that the vertex is pointed to by
  309. // closedWalk[diter->second] and closedWalk[i].
  310. int iMin = diter->second, iMax = i;
  311. detachments.insert(iMin);
  312. for (int j = iMin + 1; j < iMax; ++j)
  313. {
  314. Vertex* vertex = closedWalk[j];
  315. duplicates.erase(vertex);
  316. detachments.erase(j);
  317. }
  318. closedWalk.erase(closedWalk.begin() + iMin + 1, closedWalk.begin() + iMax + 1);
  319. numClosedWalk = static_cast<int>(closedWalk.size());
  320. i = iMin;
  321. }
  322. if (numClosedWalk > 3)
  323. {
  324. // We do not know whether closedWalk[0] is a detachment point.
  325. // To determine this, we must test for any edges strictly
  326. // contained by the wedge formed by the edges
  327. // <closedWalk[0],closedWalk[N-1]> and
  328. // <closedWalk[0],closedWalk[1]>. However, we must execute
  329. // this test even for the known detachment points. The
  330. // ensuing logic is designed to handle this and reduce the
  331. // amount of code, so we insert closedWalk[0] into the
  332. // detachment set and will ignore it later if it actually
  333. // is not.
  334. detachments.insert(0);
  335. // Detach subgraphs from the vertices of the cycle.
  336. for (auto i : detachments)
  337. {
  338. Vertex* original = closedWalk[i];
  339. Vertex* maxVertex = closedWalk[i + 1];
  340. Vertex* minVertex = (i > 0 ? closedWalk[i - 1] : closedWalk[numClosedWalk - 2]);
  341. std::array<Real, 2> dMin, dMax;
  342. for (int j = 0; j < 2; ++j)
  343. {
  344. dMin[j] = (*minVertex->position)[j] - (*original->position)[j];
  345. dMax[j] = (*maxVertex->position)[j] - (*original->position)[j];
  346. }
  347. // For debugging.
  348. bool isConvex = (dMax[0] * dMin[1] >= dMax[1] * dMin[0]);
  349. (void)isConvex;
  350. std::set<Vertex*> inWedge;
  351. std::set<Vertex*> adjacent = original->adjacent;
  352. for (auto vertex : adjacent)
  353. {
  354. if (vertex->name == minVertex->name || vertex->name == maxVertex->name)
  355. {
  356. continue;
  357. }
  358. std::array<Real, 2> dVer;
  359. for (int j = 0; j < 2; ++j)
  360. {
  361. dVer[j] = (*vertex->position)[j] - (*original->position)[j];
  362. }
  363. bool containsVertex;
  364. if (isConvex)
  365. {
  366. containsVertex =
  367. dVer[0] * dMin[1] > dVer[1] * dMin[0] &&
  368. dVer[0] * dMax[1] < dVer[1] * dMax[0];
  369. }
  370. else
  371. {
  372. containsVertex =
  373. (dVer[0] * dMin[1] > dVer[1] * dMin[0]) ||
  374. (dVer[0] * dMax[1] < dVer[1] * dMax[0]);
  375. }
  376. if (containsVertex)
  377. {
  378. inWedge.insert(vertex);
  379. }
  380. }
  381. if (inWedge.size() > 0)
  382. {
  383. // The clone will manage the adjacents for 'original'
  384. // that lie inside the wedge defined by the first and
  385. // last edges of the subgraph rooted at 'original'.
  386. // The sorting is in the clockwise direction.
  387. auto clone = std::make_shared<Vertex>(original->name, original->position);
  388. mVertexStorage.push_back(clone);
  389. // Detach the edges inside the wedge.
  390. for (auto vertex : inWedge)
  391. {
  392. original->adjacent.erase(vertex);
  393. vertex->adjacent.erase(original);
  394. clone->adjacent.insert(vertex);
  395. vertex->adjacent.insert(clone.get());
  396. }
  397. // Get the subgraph (it is a single connected
  398. // component).
  399. std::vector<Vertex*> component;
  400. DepthFirstSearch(clone.get(), component);
  401. // Extract the cycles of the subgraph.
  402. tree->children.push_back(ExtractBasis(component));
  403. }
  404. // else the candidate was closedWalk[0] and it has no
  405. // subgraph to detach.
  406. }
  407. tree->cycle = std::move(ExtractCycle(closedWalk));
  408. }
  409. else
  410. {
  411. // Detach the subgraph from vertex closedWalk[0]; the subgraph
  412. // is attached via a filament.
  413. Vertex* original = closedWalk[0];
  414. Vertex* adjacent = closedWalk[1];
  415. auto clone = std::make_shared<Vertex>(original->name, original->position);
  416. mVertexStorage.push_back(clone);
  417. original->adjacent.erase(adjacent);
  418. adjacent->adjacent.erase(original);
  419. clone->adjacent.insert(adjacent);
  420. adjacent->adjacent.insert(clone.get());
  421. // Get the subgraph (it is a single connected component).
  422. std::vector<Vertex*> component;
  423. DepthFirstSearch(clone.get(), component);
  424. // Extract the cycles of the subgraph.
  425. tree->children.push_back(ExtractBasis(component));
  426. if (tree->cycle.size() == 0 && tree->children.size() == 1)
  427. {
  428. // Replace the parent by the child to avoid having two
  429. // empty cycles in parent/child.
  430. auto child = tree->children.back();
  431. tree->cycle = std::move(child->cycle);
  432. tree->children = std::move(child->children);
  433. }
  434. }
  435. return tree;
  436. }
  437. std::vector<int> ExtractCycle(std::vector<Vertex*>& closedWalk)
  438. {
  439. // TODO: This logic was designed not to remove filaments after
  440. // the cycle deletion is complete. Modify this to allow filament
  441. // removal.
  442. // The closed walk is a cycle.
  443. int const numVertices = static_cast<int>(closedWalk.size());
  444. std::vector<int> cycle(numVertices);
  445. for (int i = 0; i < numVertices; ++i)
  446. {
  447. cycle[i] = closedWalk[i]->name;
  448. }
  449. // The clockwise-most edge is always removable.
  450. Vertex* v0 = closedWalk[0];
  451. Vertex* v1 = closedWalk[1];
  452. Vertex* vBranch = (v0->adjacent.size() > 2 ? v0 : nullptr);
  453. v0->adjacent.erase(v1);
  454. v1->adjacent.erase(v0);
  455. // Remove edges while traversing counterclockwise.
  456. while (v1 != vBranch && v1->adjacent.size() == 1)
  457. {
  458. Vertex* adj = *v1->adjacent.begin();
  459. v1->adjacent.erase(adj);
  460. adj->adjacent.erase(v1);
  461. v1 = adj;
  462. }
  463. if (v1 != v0)
  464. {
  465. // If v1 had exactly 3 adjacent vertices, removal of the CCW
  466. // edge that shared v1 leads to v1 having 2 adjacent vertices.
  467. // When the CW removal occurs and we reach v1, the edge
  468. // deletion will lead to v1 having 1 adjacent vertex, making
  469. // it a filament endpoint. We must ensure we do not delete v1
  470. // in this case, allowing the recursive algorithm to handle
  471. // the filament later.
  472. vBranch = v1;
  473. // Remove edges while traversing clockwise.
  474. while (v0 != vBranch && v0->adjacent.size() == 1)
  475. {
  476. v1 = *v0->adjacent.begin();
  477. v0->adjacent.erase(v1);
  478. v1->adjacent.erase(v0);
  479. v0 = v1;
  480. }
  481. }
  482. // else the cycle is its own connected component.
  483. return cycle;
  484. }
  485. Vertex* GetClockwiseMost(Vertex* vPrev, Vertex* vCurr) const
  486. {
  487. Vertex* vNext = nullptr;
  488. bool vCurrConvex = false;
  489. std::array<Real, 2> dCurr, dNext;
  490. if (vPrev)
  491. {
  492. dCurr[0] = (*vCurr->position)[0] - (*vPrev->position)[0];
  493. dCurr[1] = (*vCurr->position)[1] - (*vPrev->position)[1];
  494. }
  495. else
  496. {
  497. dCurr[0] = static_cast<Real>(0);
  498. dCurr[1] = static_cast<Real>(-1);
  499. }
  500. for (auto vAdj : vCurr->adjacent)
  501. {
  502. // vAdj is a vertex adjacent to vCurr. No backtracking is
  503. // allowed.
  504. if (vAdj == vPrev)
  505. {
  506. continue;
  507. }
  508. // Compute the potential direction to move in.
  509. std::array<Real, 2> dAdj;
  510. dAdj[0] = (*vAdj->position)[0] - (*vCurr->position)[0];
  511. dAdj[1] = (*vAdj->position)[1] - (*vCurr->position)[1];
  512. // Select the first candidate.
  513. if (!vNext)
  514. {
  515. vNext = vAdj;
  516. dNext = dAdj;
  517. vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
  518. continue;
  519. }
  520. // Update if the next candidate is clockwise of the current
  521. // clockwise-most vertex.
  522. if (vCurrConvex)
  523. {
  524. if (dCurr[0] * dAdj[1] < dCurr[1] * dAdj[0]
  525. || dNext[0] * dAdj[1] < dNext[1] * dAdj[0])
  526. {
  527. vNext = vAdj;
  528. dNext = dAdj;
  529. vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
  530. }
  531. }
  532. else
  533. {
  534. if (dCurr[0] * dAdj[1] < dCurr[1] * dAdj[0]
  535. && dNext[0] * dAdj[1] < dNext[1] * dAdj[0])
  536. {
  537. vNext = vAdj;
  538. dNext = dAdj;
  539. vCurrConvex = (dNext[0] * dCurr[1] < dNext[1] * dCurr[0]);
  540. }
  541. }
  542. }
  543. return vNext;
  544. }
  545. Vertex* GetCounterclockwiseMost(Vertex* vPrev, Vertex* vCurr) const
  546. {
  547. Vertex* vNext = nullptr;
  548. bool vCurrConvex = false;
  549. std::array<Real, 2> dCurr, dNext;
  550. if (vPrev)
  551. {
  552. dCurr[0] = (*vCurr->position)[0] - (*vPrev->position)[0];
  553. dCurr[1] = (*vCurr->position)[1] - (*vPrev->position)[1];
  554. }
  555. else
  556. {
  557. dCurr[0] = static_cast<Real>(0);
  558. dCurr[1] = static_cast<Real>(-1);
  559. }
  560. for (auto vAdj : vCurr->adjacent)
  561. {
  562. // vAdj is a vertex adjacent to vCurr. No backtracking is
  563. // allowed.
  564. if (vAdj == vPrev)
  565. {
  566. continue;
  567. }
  568. // Compute the potential direction to move in.
  569. std::array<Real, 2> dAdj;
  570. dAdj[0] = (*vAdj->position)[0] - (*vCurr->position)[0];
  571. dAdj[1] = (*vAdj->position)[1] - (*vCurr->position)[1];
  572. // Select the first candidate.
  573. if (!vNext)
  574. {
  575. vNext = vAdj;
  576. dNext = dAdj;
  577. vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
  578. continue;
  579. }
  580. // Select the next candidate if it is counterclockwise of the
  581. // current counterclockwise-most vertex.
  582. if (vCurrConvex)
  583. {
  584. if (dCurr[0] * dAdj[1] > dCurr[1] * dAdj[0]
  585. && dNext[0] * dAdj[1] > dNext[1] * dAdj[0])
  586. {
  587. vNext = vAdj;
  588. dNext = dAdj;
  589. vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
  590. }
  591. }
  592. else
  593. {
  594. if (dCurr[0] * dAdj[1] > dCurr[1] * dAdj[0]
  595. || dNext[0] * dAdj[1] > dNext[1] * dAdj[0])
  596. {
  597. vNext = vAdj;
  598. dNext = dAdj;
  599. vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
  600. }
  601. }
  602. }
  603. return vNext;
  604. }
  605. // Storage for referenced vertices of the original graph and for new
  606. // vertices added during graph traversal.
  607. std::vector<std::shared_ptr<Vertex>> mVertexStorage;
  608. };
  609. }