AdaptiveSkeletonClimbing2.h 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  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 <array>
  10. #include <cstdint>
  11. #include <map>
  12. #include <memory>
  13. #include <ostream>
  14. #include <vector>
  15. // Extract level surfaces using an adaptive approach to reduce the triangle
  16. // count. The implementation is for the algorithm described in the paper
  17. // Multiresolution Isosurface Extraction with Adaptive Skeleton Climbing
  18. // Tim Poston, Tien-Tsin Wong and Pheng-Ann Heng
  19. // Computer Graphics forum, volume 17, issue 3, September 1998
  20. // pages 137-147
  21. // https://onlinelibrary.wiley.com/doi/abs/10.1111/1467-8659.00261
  22. namespace WwiseGTE
  23. {
  24. // The image type T must be one of the integer types: int8_t, int16_t,
  25. // int32_t, uint8_t, uint16_t or uint32_t. Internal integer computations
  26. // are performed using int64_t. The type Real is for extraction to
  27. // floating-point vertices.
  28. template <typename T, typename Real>
  29. class AdaptiveSkeletonClimbing2
  30. {
  31. public:
  32. // Construction and destruction. The input image is assumed to
  33. // contain (2^N+1)-by-(2^N+1) elements where N >= 0. The organization
  34. // is row-major order for (x,y).
  35. AdaptiveSkeletonClimbing2(int N, T const* inputPixels)
  36. :
  37. mTwoPowerN(1 << N),
  38. mSize(mTwoPowerN + 1),
  39. mInputPixels(inputPixels),
  40. mXMerge(mSize),
  41. mYMerge(mSize)
  42. {
  43. static_assert(std::is_integral<T>::value && sizeof(T) <= 4,
  44. "Type T must be int{8,16,32}_t or uint{8,16,32}_t.");
  45. if (N <= 0 || mInputPixels == nullptr)
  46. {
  47. LogError("Invalid input.");
  48. }
  49. for (int i = 0; i < mSize; ++i)
  50. {
  51. mXMerge[i] = std::make_shared<LinearMergeTree>(N);
  52. mYMerge[i] = std::make_shared<LinearMergeTree>(N);
  53. }
  54. mXYMerge = std::make_unique<AreaMergeTree>(N, mXMerge, mYMerge);
  55. }
  56. // TODO: Refactor this class to have base class CurveExtractor.
  57. typedef std::array<Real, 2> Vertex;
  58. typedef std::array<int, 2> Edge;
  59. void Extract(Real level, int depth,
  60. std::vector<Vertex>& vertices, std::vector<Edge>& edges)
  61. {
  62. std::vector<Rectangle> rectangles;
  63. std::vector<Vertex> localVertices;
  64. std::vector<Edge> localEdges;
  65. SetLevel(level, depth);
  66. GetRectangles(rectangles);
  67. for (auto& rectangle : rectangles)
  68. {
  69. if (rectangle.type > 0)
  70. {
  71. GetComponents(level, rectangle, localVertices, localEdges);
  72. }
  73. }
  74. vertices = std::move(localVertices);
  75. edges = std::move(localEdges);
  76. }
  77. void MakeUnique(std::vector<Vertex>& vertices, std::vector<Edge>& edges)
  78. {
  79. size_t numVertices = vertices.size();
  80. size_t numEdges = edges.size();
  81. if (numVertices == 0 || numEdges == 0)
  82. {
  83. return;
  84. }
  85. // Compute the map of unique vertices and assign to them new and
  86. // unique indices.
  87. std::map<Vertex, int> vmap;
  88. int nextVertex = 0;
  89. for (size_t v = 0; v < numVertices; ++v)
  90. {
  91. // Keep only unique vertices.
  92. auto result = vmap.insert(std::make_pair(vertices[v], nextVertex));
  93. if (result.second)
  94. {
  95. ++nextVertex;
  96. }
  97. }
  98. // Compute the map of unique edges and assign to them new and
  99. // unique indices.
  100. std::map<Edge, int> emap;
  101. int nextEdge = 0;
  102. for (size_t e = 0; e < numEdges; ++e)
  103. {
  104. // Replace old vertex indices by new vertex indices.
  105. Edge& edge = edges[e];
  106. for (int i = 0; i < 2; ++i)
  107. {
  108. auto iter = vmap.find(vertices[edge[i]]);
  109. LogAssert(iter != vmap.end(), "Expecting the vertex to be in the vmap.");
  110. edge[i] = iter->second;
  111. }
  112. // Keep only unique edges.
  113. auto result = emap.insert(std::make_pair(edge, nextEdge));
  114. if (result.second)
  115. {
  116. ++nextEdge;
  117. }
  118. }
  119. // Pack the vertices into an array.
  120. vertices.resize(vmap.size());
  121. for (auto const& element : vmap)
  122. {
  123. vertices[element.second] = element.first;
  124. }
  125. // Pack the edges into an array.
  126. edges.resize(emap.size());
  127. for (auto const& element : emap)
  128. {
  129. edges[element.second] = element.first;
  130. }
  131. }
  132. private:
  133. // Helper classes for the skeleton climbing.
  134. struct QuadRectangle
  135. {
  136. QuadRectangle()
  137. :
  138. xOrigin(0),
  139. yOrigin(0),
  140. xStride(0),
  141. yStride(0),
  142. valid(false)
  143. {
  144. }
  145. QuadRectangle(int inXOrigin, int inYOrigin, int inXStride, int inYStride)
  146. {
  147. Initialize(inXOrigin, inYOrigin, inXStride, inYStride);
  148. }
  149. void Initialize(int inXOrigin, int inYOrigin, int inXStride, int inYStride)
  150. {
  151. xOrigin = inXOrigin;
  152. yOrigin = inYOrigin;
  153. xStride = inXStride;
  154. yStride = inYStride;
  155. valid = true;
  156. }
  157. int xOrigin, yOrigin, xStride, yStride;
  158. bool valid;
  159. };
  160. struct QuadNode
  161. {
  162. QuadNode()
  163. {
  164. // The members are uninitialized.
  165. }
  166. QuadNode(int xOrigin, int yOrigin, int xNext, int yNext, int stride)
  167. :
  168. r00(xOrigin, yOrigin, stride, stride),
  169. r10(xNext, yOrigin, stride, stride),
  170. r01(xOrigin, yNext, stride, stride),
  171. r11(xNext, yNext, stride, stride)
  172. {
  173. }
  174. void Initialize(int xOrigin, int yOrigin, int xNext, int yNext, int stride)
  175. {
  176. r00.Initialize(xOrigin, yOrigin, stride, stride);
  177. r10.Initialize(xNext, yOrigin, stride, stride);
  178. r01.Initialize(xOrigin, yNext, stride, stride);
  179. r11.Initialize(xNext, yNext, stride, stride);
  180. }
  181. bool IsMono() const
  182. {
  183. return !r10.valid && !r01.valid && !r11.valid;
  184. }
  185. int GetQuantity() const
  186. {
  187. int quantity = 0;
  188. if (r00.valid)
  189. {
  190. ++quantity;
  191. }
  192. if (r10.valid)
  193. {
  194. ++quantity;
  195. }
  196. if (r01.valid)
  197. {
  198. ++quantity;
  199. }
  200. if (r11.valid)
  201. {
  202. ++quantity;
  203. }
  204. return quantity;
  205. }
  206. QuadRectangle r00, r10, r01, r11;
  207. };
  208. class LinearMergeTree
  209. {
  210. public:
  211. LinearMergeTree(int N)
  212. :
  213. mTwoPowerN(1 << N),
  214. mNodes(2 * mTwoPowerN - 1)
  215. {
  216. }
  217. enum
  218. {
  219. CFG_NONE,
  220. CFG_INCR,
  221. CFG_DECR,
  222. CFG_MULT
  223. };
  224. // Member access.
  225. int GetQuantity() const
  226. {
  227. return 2 * mTwoPowerN - 1;
  228. }
  229. int GetNode(int i) const
  230. {
  231. return mNodes[i];
  232. }
  233. int GetEdge(int i) const
  234. {
  235. // assert: mNodes[i] == CFG_INCR || mNodes[i] == CFG_DECR
  236. // Traverse binary tree looking for incr or decr leaf node.
  237. int const firstLeaf = mTwoPowerN - 1;
  238. while (i < firstLeaf)
  239. {
  240. i = 2 * i + 1;
  241. if (mNodes[i] == CFG_NONE)
  242. {
  243. ++i;
  244. }
  245. }
  246. return i - firstLeaf;
  247. }
  248. void SetLevel(Real level, T const* data, int offset, int stride)
  249. {
  250. // Assert: The 'level' is not an image value. Because T is
  251. // an integer type, choose 'level' to be a Real-valued number
  252. // that does not represent an integer.
  253. // Determine the sign changes between pairs of consecutive
  254. // samples.
  255. int const firstLeaf = mTwoPowerN - 1;
  256. for (int i = 0, leaf = firstLeaf; i < mTwoPowerN; ++i, ++leaf)
  257. {
  258. int base = offset + stride * i;
  259. Real value0 = static_cast<Real>(data[base]);
  260. Real value1 = static_cast<Real>(data[base + stride]);
  261. if (value0 > level)
  262. {
  263. if (value1 > level)
  264. {
  265. mNodes[leaf] = CFG_NONE;
  266. }
  267. else
  268. {
  269. mNodes[leaf] = CFG_DECR;
  270. }
  271. }
  272. else // value0 < level
  273. {
  274. if (value1 > level)
  275. {
  276. mNodes[leaf] = CFG_INCR;
  277. }
  278. else
  279. {
  280. mNodes[leaf] = CFG_NONE;
  281. }
  282. }
  283. }
  284. // Propagate the sign change information up the binary tree.
  285. for (int i = firstLeaf - 1; i >= 0; --i)
  286. {
  287. int twoIp1 = 2 * i + 1;
  288. int child0 = mNodes[twoIp1];
  289. int child1 = mNodes[twoIp1 + 1];
  290. mNodes[i] = (child0 | child1);
  291. }
  292. }
  293. private:
  294. int mTwoPowerN;
  295. std::vector<int> mNodes;
  296. };
  297. struct Rectangle
  298. {
  299. Rectangle(int inXOrigin, int inYOrigin, int inXStride, int inYStride)
  300. :
  301. xOrigin(inXOrigin),
  302. yOrigin(inYOrigin),
  303. xStride(inXStride),
  304. yStride(inYStride),
  305. yOfXMin(-1),
  306. yOfXMax(-1),
  307. xOfYMin(-1),
  308. xOfYMax(-1),
  309. type(0)
  310. {
  311. }
  312. int xOrigin, yOrigin, xStride, yStride;
  313. int yOfXMin, yOfXMax, xOfYMin, xOfYMax;
  314. // A 4-bit flag for how the level set intersects the rectangle
  315. // boundary.
  316. // bit 0 = xmin edge
  317. // bit 1 = xmax edge
  318. // bit 2 = ymin edge
  319. // bit 3 = ymax edge
  320. // A bit is set if the corresponding edge is intersected by the
  321. // level set. This information is known from the CFG flags for
  322. // LinearMergeTree. Intersection occurs whenever the flag is
  323. // CFG_INCR or CFG_DECR.
  324. unsigned int type;
  325. };
  326. class AreaMergeTree
  327. {
  328. public:
  329. AreaMergeTree(int N,
  330. std::vector<std::shared_ptr<LinearMergeTree>> const& xMerge,
  331. std::vector<std::shared_ptr<LinearMergeTree>> const& yMerge)
  332. :
  333. mXMerge(xMerge),
  334. mYMerge(yMerge),
  335. mNodes(((1 << 2 * (N + 1)) - 1) / 3)
  336. {
  337. }
  338. void ConstructMono(int A, int LX, int LY, int xOrigin, int yOrigin,
  339. int stride, int depth)
  340. {
  341. if (stride > 1) // internal nodes
  342. {
  343. int hStride = stride / 2;
  344. int ABase = 4 * A;
  345. int A00 = ++ABase;
  346. int A10 = ++ABase;
  347. int A01 = ++ABase;
  348. int A11 = ++ABase;
  349. int LXBase = 2 * LX;
  350. int LX0 = ++LXBase;
  351. int LX1 = ++LXBase;
  352. int LYBase = 2 * LY;
  353. int LY0 = ++LYBase;
  354. int LY1 = ++LYBase;
  355. int xNext = xOrigin + hStride;
  356. int yNext = yOrigin + hStride;
  357. int depthM1 = depth - 1;
  358. ConstructMono(A00, LX0, LY0, xOrigin, yOrigin, hStride, depthM1);
  359. ConstructMono(A10, LX1, LY0, xNext, yOrigin, hStride, depthM1);
  360. ConstructMono(A01, LX0, LY1, xOrigin, yNext, hStride, depthM1);
  361. ConstructMono(A11, LX1, LY1, xNext, yNext, hStride, depthM1);
  362. if (depth >= 0)
  363. {
  364. // Merging is prevented above the specified depth in
  365. // the tree. This allows a single object to produce
  366. // any resolution isocontour rather than using
  367. // multiple objects to do so.
  368. mNodes[A].Initialize(xOrigin, yOrigin, xNext, yNext, hStride);
  369. return;
  370. }
  371. bool mono00 = mNodes[A00].IsMono();
  372. bool mono10 = mNodes[A10].IsMono();
  373. bool mono01 = mNodes[A01].IsMono();
  374. bool mono11 = mNodes[A11].IsMono();
  375. QuadNode node0(xOrigin, yOrigin, xNext, yNext, hStride);
  376. QuadNode node1 = node0;
  377. // Merge x first, y second.
  378. if (mono00 && mono10)
  379. {
  380. DoXMerge(node0.r00, node0.r10, LX, yOrigin);
  381. }
  382. if (mono01 && mono11)
  383. {
  384. DoXMerge(node0.r01, node0.r11, LX, yNext);
  385. }
  386. if (mono00 && mono01)
  387. {
  388. DoYMerge(node0.r00, node0.r01, xOrigin, LY);
  389. }
  390. if (mono10 && mono11)
  391. {
  392. DoYMerge(node0.r10, node0.r11, xNext, LY);
  393. }
  394. // Merge y first, x second.
  395. if (mono00 && mono01)
  396. {
  397. DoYMerge(node1.r00, node1.r01, xOrigin, LY);
  398. }
  399. if (mono10 && mono11)
  400. {
  401. DoYMerge(node1.r10, node1.r11, xNext, LY);
  402. }
  403. if (mono00 && mono10)
  404. {
  405. DoXMerge(node1.r00, node1.r10, LX, yOrigin);
  406. }
  407. if (mono01 && mono11)
  408. {
  409. DoXMerge(node1.r01, node1.r11, LX, yNext);
  410. }
  411. // Choose the merge that produced the smallest number of
  412. // rectangles.
  413. if (node0.GetQuantity() <= node1.GetQuantity())
  414. {
  415. mNodes[A] = node0;
  416. }
  417. else
  418. {
  419. mNodes[A] = node1;
  420. }
  421. }
  422. else // leaf nodes
  423. {
  424. mNodes[A].r00.Initialize(xOrigin, yOrigin, 1, 1);
  425. }
  426. }
  427. void GetRectangles(int A, int LX, int LY, int xOrigin, int yOrigin,
  428. int stride, std::vector<Rectangle>& rectangles)
  429. {
  430. int hStride = stride / 2;
  431. int ABase = 4 * A;
  432. int A00 = ++ABase;
  433. int A10 = ++ABase;
  434. int A01 = ++ABase;
  435. int A11 = ++ABase;
  436. int LXBase = 2 * LX;
  437. int LX0 = ++LXBase;
  438. int LX1 = ++LXBase;
  439. int LYBase = 2 * LY;
  440. int LY0 = ++LYBase;
  441. int LY1 = ++LYBase;
  442. int xNext = xOrigin + hStride;
  443. int yNext = yOrigin + hStride;
  444. QuadRectangle const& r00 = mNodes[A].r00;
  445. if (r00.valid)
  446. {
  447. if (r00.xStride == stride)
  448. {
  449. if (r00.yStride == stride)
  450. {
  451. rectangles.push_back(GetRectangle(r00, LX, LY));
  452. }
  453. else
  454. {
  455. rectangles.push_back(GetRectangle(r00, LX, LY0));
  456. }
  457. }
  458. else
  459. {
  460. if (r00.yStride == stride)
  461. {
  462. rectangles.push_back(GetRectangle(r00, LX0, LY));
  463. }
  464. else
  465. {
  466. GetRectangles(A00, LX0, LY0, xOrigin, yOrigin, hStride, rectangles);
  467. }
  468. }
  469. }
  470. QuadRectangle const& r10 = mNodes[A].r10;
  471. if (r10.valid)
  472. {
  473. if (r10.yStride == stride)
  474. {
  475. rectangles.push_back(GetRectangle(r10, LX1, LY));
  476. }
  477. else
  478. {
  479. GetRectangles(A10, LX1, LY0, xNext, yOrigin, hStride, rectangles);
  480. }
  481. }
  482. QuadRectangle const& r01 = mNodes[A].r01;
  483. if (r01.valid)
  484. {
  485. if (r01.xStride == stride)
  486. {
  487. rectangles.push_back(GetRectangle(r01, LX, LY1));
  488. }
  489. else
  490. {
  491. GetRectangles(A01, LX0, LY1, xOrigin, yNext, hStride, rectangles);
  492. }
  493. }
  494. QuadRectangle const& r11 = mNodes[A].r11;
  495. if (r11.valid)
  496. {
  497. GetRectangles(A11, LX1, LY1, xNext, yNext, hStride, rectangles);
  498. }
  499. }
  500. private:
  501. void DoXMerge(QuadRectangle& r0, QuadRectangle& r1, int LX, int yOrigin)
  502. {
  503. if (r0.valid && r1.valid && r0.yStride == r1.yStride)
  504. {
  505. // Rectangles are x-mergeable.
  506. int incr = 0, decr = 0;
  507. for (int y = 0; y <= r0.yStride; ++y)
  508. {
  509. switch (mXMerge[yOrigin + y]->GetNode(LX))
  510. {
  511. case LinearMergeTree::CFG_MULT:
  512. return;
  513. case LinearMergeTree::CFG_INCR:
  514. ++incr;
  515. break;
  516. case LinearMergeTree::CFG_DECR:
  517. ++decr;
  518. break;
  519. }
  520. }
  521. if (incr == 0 || decr == 0)
  522. {
  523. // Strongly mono, x-merge the rectangles.
  524. r0.xStride *= 2;
  525. r1.valid = false;
  526. }
  527. }
  528. }
  529. void DoYMerge(QuadRectangle& r0, QuadRectangle& r1, int xOrigin, int LY)
  530. {
  531. if (r0.valid && r1.valid && r0.xStride == r1.xStride)
  532. {
  533. // Rectangles are y-mergeable.
  534. int incr = 0, decr = 0;
  535. for (int x = 0; x <= r0.xStride; ++x)
  536. {
  537. switch (mYMerge[xOrigin + x]->GetNode(LY))
  538. {
  539. case LinearMergeTree::CFG_MULT:
  540. return;
  541. case LinearMergeTree::CFG_INCR:
  542. ++incr;
  543. break;
  544. case LinearMergeTree::CFG_DECR:
  545. ++decr;
  546. break;
  547. }
  548. }
  549. if (incr == 0 || decr == 0)
  550. {
  551. // Strongly mono, y-merge the rectangles.
  552. r0.yStride *= 2;
  553. r1.valid = false;
  554. }
  555. }
  556. }
  557. Rectangle GetRectangle(QuadRectangle const& qrect, int LX, int LY)
  558. {
  559. Rectangle rect(qrect.xOrigin, qrect.yOrigin, qrect.xStride, qrect.yStride);
  560. // xmin edge
  561. auto merge = mYMerge[qrect.xOrigin];
  562. if (merge->GetNode(LY) != LinearMergeTree::CFG_NONE)
  563. {
  564. rect.yOfXMin = merge->GetEdge(LY);
  565. if (rect.yOfXMin != -1)
  566. {
  567. rect.type |= 0x01;
  568. }
  569. }
  570. // xmax edge
  571. merge = mYMerge[qrect.xOrigin + qrect.xStride];
  572. if (merge->GetNode(LY) != LinearMergeTree::CFG_NONE)
  573. {
  574. rect.yOfXMax = merge->GetEdge(LY);
  575. if (rect.yOfXMax != -1)
  576. {
  577. rect.type |= 0x02;
  578. }
  579. }
  580. // ymin edge
  581. merge = mXMerge[qrect.yOrigin];
  582. if (merge->GetNode(LX) != LinearMergeTree::CFG_NONE)
  583. {
  584. rect.xOfYMin = merge->GetEdge(LX);
  585. if (rect.xOfYMin != -1)
  586. {
  587. rect.type |= 0x04;
  588. }
  589. }
  590. // ymax edge
  591. merge = mXMerge[qrect.yOrigin + qrect.yStride];
  592. if (merge->GetNode(LX) != LinearMergeTree::CFG_NONE)
  593. {
  594. rect.xOfYMax = merge->GetEdge(LX);
  595. if (rect.xOfYMax != -1)
  596. {
  597. rect.type |= 0x08;
  598. }
  599. }
  600. return rect;
  601. }
  602. std::vector<std::shared_ptr<LinearMergeTree>> mXMerge;
  603. std::vector<std::shared_ptr<LinearMergeTree>> mYMerge;
  604. std::vector<QuadNode> mNodes;
  605. };
  606. private:
  607. // Support for extraction of level sets.
  608. Real GetInterp(Real level, int base, int index, int increment)
  609. {
  610. Real f0 = static_cast<Real>(mInputPixels[index]);
  611. index += increment;
  612. Real f1 = static_cast<Real>(mInputPixels[index]);
  613. LogAssert((f0 - level) * (f1 - level) < (Real)0, "Unexpected condition.");
  614. return static_cast<Real>(base) + (level - f0) / (f1 - f0);
  615. }
  616. void AddVertex(std::vector<Vertex>& vertices, Real x, Real y)
  617. {
  618. Vertex vertex = { x, y };
  619. vertices.push_back(vertex);
  620. }
  621. void AddEdge(std::vector<Vertex>& vertices,
  622. std::vector<Edge>& edges, Real x0, Real y0, Real x1, Real y1)
  623. {
  624. int v0 = static_cast<int>(vertices.size());
  625. int v1 = v0 + 1;
  626. Edge edge = { v0, v1 };
  627. edges.push_back(edge);
  628. Vertex vertex0 = { x0, y0 };
  629. Vertex vertex1 = { x1, y1 };
  630. vertices.push_back(vertex0);
  631. vertices.push_back(vertex1);
  632. }
  633. void SetLevel(Real level, int depth)
  634. {
  635. int offset, stride;
  636. for (int y = 0; y < mSize; ++y)
  637. {
  638. offset = mSize * y;
  639. stride = 1;
  640. mXMerge[y]->SetLevel(level, mInputPixels, offset, stride);
  641. }
  642. for (int x = 0; x < mSize; ++x)
  643. {
  644. offset = x;
  645. stride = mSize;
  646. mYMerge[x]->SetLevel(level, mInputPixels, offset, stride);
  647. }
  648. mXYMerge->ConstructMono(0, 0, 0, 0, 0, mTwoPowerN, depth);
  649. }
  650. void GetRectangles(std::vector<Rectangle>& rectangles)
  651. {
  652. mXYMerge->GetRectangles(0, 0, 0, 0, 0, mTwoPowerN, rectangles);
  653. }
  654. void GetComponents(Real level, Rectangle const& rectangle,
  655. std::vector<Vertex>& vertices, std::vector<Edge>& edges)
  656. {
  657. int x, y;
  658. Real x0, y0, x1, y1;
  659. switch (rectangle.type)
  660. {
  661. case 3: // two vertices, on xmin and xmax
  662. LogAssert(rectangle.yOfXMin != -1, "Unexpected condition.");
  663. x = rectangle.xOrigin;
  664. y = rectangle.yOfXMin;
  665. x0 = static_cast<Real>(x);
  666. y0 = GetInterp(level, y, x + mSize * y, mSize);
  667. LogAssert(rectangle.yOfXMax != -1, "Unexpected condition.");
  668. x = rectangle.xOrigin + rectangle.xStride;
  669. y = rectangle.yOfXMax;
  670. x1 = static_cast<Real>(x);
  671. y1 = GetInterp(level, y, x + mSize * y, mSize);
  672. AddEdge(vertices, edges, x0, y0, x1, y1);
  673. break;
  674. case 5: // two vertices, on xmin and ymin
  675. LogAssert(rectangle.yOfXMin != -1, "Unexpected condition.");
  676. x = rectangle.xOrigin;
  677. y = rectangle.yOfXMin;
  678. x0 = static_cast<Real>(x);
  679. y0 = GetInterp(level, y, x + mSize * y, mSize);
  680. LogAssert(rectangle.xOfYMin != -1, "Unexpected condition.");
  681. x = rectangle.xOfYMin;
  682. y = rectangle.yOrigin;
  683. x1 = GetInterp(level, x, x + mSize * y, 1);
  684. y1 = static_cast<Real>(y);
  685. AddEdge(vertices, edges, x0, y0, x1, y1);
  686. break;
  687. case 6: // two vertices, on xmax and ymin
  688. LogAssert(rectangle.yOfXMax != -1, "Unexpected condition.");
  689. x = rectangle.xOrigin + rectangle.xStride;
  690. y = rectangle.yOfXMax;
  691. x0 = static_cast<Real>(x);
  692. y0 = GetInterp(level, y, x + mSize * y, mSize);
  693. LogAssert(rectangle.xOfYMin != -1, "Unexpected condition.");
  694. x = rectangle.xOfYMin;
  695. y = rectangle.yOrigin;
  696. x1 = GetInterp(level, x, x + mSize * y, 1);
  697. y1 = static_cast<Real>(y);
  698. AddEdge(vertices, edges, x0, y0, x1, y1);
  699. break;
  700. case 9: // two vertices, on xmin and ymax
  701. LogAssert(rectangle.yOfXMin != -1, "Unexpected condition.");
  702. x = rectangle.xOrigin;
  703. y = rectangle.yOfXMin;
  704. x0 = static_cast<Real>(x);
  705. y0 = GetInterp(level, y, x + mSize * y, mSize);
  706. LogAssert(rectangle.xOfYMax != -1, "Unexpected condition.");
  707. x = rectangle.xOfYMax;
  708. y = rectangle.yOrigin + rectangle.yStride;
  709. x1 = GetInterp(level, x, x + mSize * y, 1);
  710. y1 = static_cast<Real>(y);
  711. AddEdge(vertices, edges, x0, y0, x1, y1);
  712. break;
  713. case 10: // two vertices, on xmax and ymax
  714. LogAssert(rectangle.yOfXMax != -1, "Unexpected condition.");
  715. x = rectangle.xOrigin + rectangle.xStride;
  716. y = rectangle.yOfXMax;
  717. x0 = static_cast<Real>(x);
  718. y0 = GetInterp(level, y, x + mSize * y, mSize);
  719. LogAssert(rectangle.xOfYMax != -1, "Unexpected condition.");
  720. x = rectangle.xOfYMax;
  721. y = rectangle.yOrigin + rectangle.yStride;
  722. x1 = GetInterp(level, x, x + mSize * y, 1);
  723. y1 = static_cast<Real>(y);
  724. AddEdge(vertices, edges, x0, y0, x1, y1);
  725. break;
  726. case 12: // two vertices, on ymin and ymax
  727. LogAssert(rectangle.xOfYMin != -1, "Unexpected condition.");
  728. x = rectangle.xOfYMin;
  729. y = rectangle.yOrigin;
  730. x0 = GetInterp(level, x, x + mSize * y, 1);
  731. y0 = static_cast<Real>(y);
  732. LogAssert(rectangle.xOfYMax != -1, "Unexpected condition.");
  733. x = rectangle.xOfYMax;
  734. y = rectangle.yOrigin + rectangle.yStride;
  735. x1 = GetInterp(level, x, x + mSize * y, 1);
  736. y1 = static_cast<Real>(y);
  737. AddEdge(vertices, edges, x0, y0, x1, y1);
  738. break;
  739. case 15: // four vertices, one per edge, need to disambiguate
  740. {
  741. LogAssert(rectangle.xStride == 1 && rectangle.yStride == 1,
  742. "Unexpected condition.");
  743. LogAssert(rectangle.yOfXMin != -1, "Unexpected condition.");
  744. x = rectangle.xOrigin;
  745. y = rectangle.yOfXMin;
  746. x0 = static_cast<Real>(x);
  747. y0 = GetInterp(level, y, x + mSize * y, mSize);
  748. LogAssert(rectangle.yOfXMax != -1, "Unexpected condition.");
  749. x = rectangle.xOrigin + rectangle.xStride;
  750. y = rectangle.yOfXMax;
  751. x1 = static_cast<Real>(x);
  752. y1 = GetInterp(level, y, x + mSize * y, mSize);
  753. LogAssert(rectangle.xOfYMin != -1, "Unexpected condition.");
  754. x = rectangle.xOfYMin;
  755. y = rectangle.yOrigin;
  756. Real fx2 = GetInterp(level, x, x + mSize * y, 1);
  757. Real fy2 = static_cast<Real>(y);
  758. LogAssert(rectangle.xOfYMax != -1, "Unexpected condition.");
  759. x = rectangle.xOfYMax;
  760. y = rectangle.yOrigin + rectangle.yStride;
  761. Real fx3 = GetInterp(level, x, x + mSize * y, 1);
  762. Real fy3 = static_cast<Real>(y);
  763. int index = rectangle.xOrigin + mSize * rectangle.yOrigin;
  764. int64_t i00 = static_cast<int64_t>(mInputPixels[index]);
  765. ++index;
  766. int64_t i10 = static_cast<int64_t>(mInputPixels[index]);
  767. index += mSize;
  768. int64_t i11 = static_cast<int64_t>(mInputPixels[index]);
  769. --index;
  770. int64_t i01 = static_cast<int64_t>(mInputPixels[index]);
  771. int64_t det = i00 * i11 - i01 * i10;
  772. if (det > 0)
  773. {
  774. // Disjoint hyperbolic segments, pair <P0,P2> and <P1,P3>.
  775. AddEdge(vertices, edges, x0, y0, fx2, fy2);
  776. AddEdge(vertices, edges, x1, y1, fx3, fy3);
  777. }
  778. else if (det < 0)
  779. {
  780. // Disjoint hyperbolic segments, pair <P0,P3> and <P1,P2>.
  781. AddEdge(vertices, edges, x0, y0, fx3, fy3);
  782. AddEdge(vertices, edges, x1, y1, fx2, fy2);
  783. }
  784. else
  785. {
  786. // Plus-sign configuration, add branch point to
  787. // tessellation.
  788. Real fx4 = fx2, fy4 = y0;
  789. AddEdge(vertices, edges, x0, y0, fx4, fy4);
  790. AddEdge(vertices, edges, x1, y1, fx4, fy4);
  791. AddEdge(vertices, edges, fx2, fy2, fx4, fy4);
  792. AddEdge(vertices, edges, fx3, fy3, fx4, fy4);
  793. }
  794. break;
  795. }
  796. default:
  797. LogError("Unexpected condition.");
  798. }
  799. }
  800. // Support for debugging.
  801. void PrintRectangles(std::ostream& output, std::vector<Rectangle> const& rectangles)
  802. {
  803. for (size_t i = 0; i < rectangles.size(); ++i)
  804. {
  805. auto const& rectangle = rectangles[i];
  806. output << "rectangle " << i << std::endl;
  807. output << " x origin = " << rectangle.xOrigin << std::endl;
  808. output << " y origin = " << rectangle.yOrigin << std::endl;
  809. output << " x stride = " << rectangle.xStride << std::endl;
  810. output << " y stride = " << rectangle.yStride << std::endl;
  811. output << " flag = " << rectangle.type << std::endl;
  812. output << " y of xmin = " << rectangle.yOfXMin << std::endl;
  813. output << " y of xmax = " << rectangle.yOfXMax << std::endl;
  814. output << " x of ymin = " << rectangle.xOfYMin << std::endl;
  815. output << " x of ymax = " << rectangle.xOfYMax << std::endl;
  816. output << std::endl;
  817. }
  818. }
  819. // Storage of image data.
  820. int mTwoPowerN, mSize;
  821. T const* mInputPixels;
  822. // Trees for linear merging.
  823. std::vector<std::shared_ptr<LinearMergeTree>> mXMerge, mYMerge;
  824. // Tree for area merging.
  825. std::unique_ptr<AreaMergeTree> mXYMerge;
  826. };
  827. }