SurfaceExtractorCubes.h 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  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/SurfaceExtractor.h>
  9. // The level set extraction algorithm implemented here is described
  10. // in Section 3.2 of the document
  11. // https://www.geometrictools.com/Documentation/LevelSetExtraction.pdf
  12. namespace WwiseGTE
  13. {
  14. // The image type T must be one of the integer types: int8_t, int16_t,
  15. // int32_t, uint8_t, uint16_t or uint32_t. Internal integer computations
  16. // are performed using int64_t. The type Real is for extraction to
  17. // floating-point vertices.
  18. template <typename T, typename Real>
  19. class SurfaceExtractorCubes : public SurfaceExtractor<T, Real>
  20. {
  21. public:
  22. // Convenience type definitions.
  23. typedef typename SurfaceExtractor<T, Real>::Vertex Vertex;
  24. typedef typename SurfaceExtractor<T, Real>::Triangle Triangle;
  25. // The input is a 3D image with lexicographically ordered voxels
  26. // (x,y,z) stored in a linear array. Voxel (x,y,z) is stored in the
  27. // array at location index = x + xBound * (y + yBound * z). The
  28. // inputs xBound, yBound and zBound must each be 2 or larger so that
  29. // there is at least one image cube to process. The inputVoxels must
  30. // be nonnull and point to contiguous storage that contains at least
  31. // xBound * yBound * zBound elements.
  32. SurfaceExtractorCubes(int xBound, int yBound, int zBound, T const* inputVoxels)
  33. :
  34. SurfaceExtractor<T, Real>(xBound, yBound, zBound, inputVoxels)
  35. {
  36. }
  37. // Extract level surfaces and return rational vertices. Use the
  38. // base-class Extract if you want real-valued vertices.
  39. virtual void Extract(T level, std::vector<Vertex>& vertices,
  40. std::vector<Triangle>& triangles) override
  41. {
  42. // Adjust the image so that the level set is F(x,y,z) = 0. The
  43. // precondition for 'level' is that it is not exactly a voxel
  44. // value. However, T is an integer type, so we cannot pass in
  45. // a 'level' that has a fractional value. To circumvent this,
  46. // the voxel values are doubled so that they are even integers.
  47. // The level value is doubled and 1 added to obtain an odd
  48. // integer, guaranteeing 'level' is not a voxel value.
  49. int64_t levelI64 = 2 * static_cast<int64_t>(level) + 1;
  50. for (size_t i = 0; i < this->mVoxels.size(); ++i)
  51. {
  52. int64_t inputI64 = 2 * static_cast<int64_t>(this->mInputVoxels[i]);
  53. this->mVoxels[i] = inputI64 - levelI64;
  54. }
  55. vertices.clear();
  56. triangles.clear();
  57. for (int z = 0; z < this->mZBound - 1; ++z)
  58. {
  59. for (int y = 0; y < this->mYBound - 1; ++y)
  60. {
  61. for (int x = 0; x < this->mXBound - 1; ++x)
  62. {
  63. // Get vertices on edges of box (if any).
  64. VETable table;
  65. int type = GetVertices(x, y, z, table);
  66. if (type != 0)
  67. {
  68. // Get edges on faces of box.
  69. GetXMinEdges(x, y, z, type, table);
  70. GetXMaxEdges(x, y, z, type, table);
  71. GetYMinEdges(x, y, z, type, table);
  72. GetYMaxEdges(x, y, z, type, table);
  73. GetZMinEdges(x, y, z, type, table);
  74. GetZMaxEdges(x, y, z, type, table);
  75. // Ear-clip the wireframe mesh.
  76. table.RemoveTriangles(vertices, triangles);
  77. }
  78. }
  79. }
  80. }
  81. }
  82. protected:
  83. enum
  84. {
  85. EI_XMIN_YMIN = 0,
  86. EI_XMIN_YMAX = 1,
  87. EI_XMAX_YMIN = 2,
  88. EI_XMAX_YMAX = 3,
  89. EI_XMIN_ZMIN = 4,
  90. EI_XMIN_ZMAX = 5,
  91. EI_XMAX_ZMIN = 6,
  92. EI_XMAX_ZMAX = 7,
  93. EI_YMIN_ZMIN = 8,
  94. EI_YMIN_ZMAX = 9,
  95. EI_YMAX_ZMIN = 10,
  96. EI_YMAX_ZMAX = 11,
  97. FI_XMIN = 12,
  98. FI_XMAX = 13,
  99. FI_YMIN = 14,
  100. FI_YMAX = 15,
  101. FI_ZMIN = 16,
  102. FI_ZMAX = 17,
  103. EB_XMIN_YMIN = 1 << EI_XMIN_YMIN,
  104. EB_XMIN_YMAX = 1 << EI_XMIN_YMAX,
  105. EB_XMAX_YMIN = 1 << EI_XMAX_YMIN,
  106. EB_XMAX_YMAX = 1 << EI_XMAX_YMAX,
  107. EB_XMIN_ZMIN = 1 << EI_XMIN_ZMIN,
  108. EB_XMIN_ZMAX = 1 << EI_XMIN_ZMAX,
  109. EB_XMAX_ZMIN = 1 << EI_XMAX_ZMIN,
  110. EB_XMAX_ZMAX = 1 << EI_XMAX_ZMAX,
  111. EB_YMIN_ZMIN = 1 << EI_YMIN_ZMIN,
  112. EB_YMIN_ZMAX = 1 << EI_YMIN_ZMAX,
  113. EB_YMAX_ZMIN = 1 << EI_YMAX_ZMIN,
  114. EB_YMAX_ZMAX = 1 << EI_YMAX_ZMAX,
  115. FB_XMIN = 1 << FI_XMIN,
  116. FB_XMAX = 1 << FI_XMAX,
  117. FB_YMIN = 1 << FI_YMIN,
  118. FB_YMAX = 1 << FI_YMAX,
  119. FB_ZMIN = 1 << FI_ZMIN,
  120. FB_ZMAX = 1 << FI_ZMAX
  121. };
  122. // Vertex-edge-triangle table to support mesh topology.
  123. class VETable
  124. {
  125. public:
  126. VETable() = default;
  127. inline bool IsValidVertex(int i) const
  128. {
  129. return mVertex[i].valid;
  130. }
  131. inline int64_t GetXN(int i) const
  132. {
  133. return mVertex[i].pos.xNumer;
  134. }
  135. inline int64_t GetXD(int i) const
  136. {
  137. return mVertex[i].pos.xDenom;
  138. }
  139. inline int64_t GetYN(int i) const
  140. {
  141. return mVertex[i].pos.yNumer;
  142. }
  143. inline int64_t GetYD(int i) const
  144. {
  145. return mVertex[i].pos.yDenom;
  146. }
  147. inline int64_t GetZN(int i) const
  148. {
  149. return mVertex[i].pos.zNumer;
  150. }
  151. inline int64_t GetZD(int i) const
  152. {
  153. return mVertex[i].pos.zDenom;
  154. }
  155. void Insert(int i, Vertex const& pos)
  156. {
  157. TVertex& vertex = mVertex[i];
  158. vertex.pos = pos;
  159. vertex.valid = true;
  160. }
  161. void Insert(int i0, int i1)
  162. {
  163. TVertex& vertex0 = mVertex[i0];
  164. TVertex& vertex1 = mVertex[i1];
  165. vertex0.adj[vertex0.numAdjacents++] = i1;
  166. vertex1.adj[vertex1.numAdjacents++] = i0;
  167. }
  168. void RemoveTriangles(std::vector<Vertex>& vertices, std::vector<Triangle>& triangles)
  169. {
  170. // Ear-clip the wireframe to get the triangles.
  171. Triangle triangle;
  172. while (Remove(triangle))
  173. {
  174. int v0 = static_cast<int>(vertices.size());
  175. int v1 = v0 + 1;
  176. int v2 = v1 + 1;
  177. triangles.push_back(Triangle(v0, v1, v2));
  178. vertices.push_back(mVertex[triangle.v[0]].pos);
  179. vertices.push_back(mVertex[triangle.v[1]].pos);
  180. vertices.push_back(mVertex[triangle.v[2]].pos);
  181. }
  182. }
  183. protected:
  184. void RemoveVertex(int i)
  185. {
  186. TVertex& vertex0 = mVertex[i];
  187. // assert: vertex0.numAdjacents == 2
  188. int a0 = vertex0.adj[0];
  189. int a1 = vertex0.adj[1];
  190. TVertex& adjVertex0 = mVertex[a0];
  191. TVertex& adjVertex1 = mVertex[a1];
  192. int j;
  193. for (j = 0; j < adjVertex0.numAdjacents; ++j)
  194. {
  195. if (adjVertex0.adj[j] == i)
  196. {
  197. adjVertex0.adj[j] = a1;
  198. break;
  199. }
  200. }
  201. // assert: j != adjVertex0.numAdjacents
  202. for (j = 0; j < adjVertex1.numAdjacents; j++)
  203. {
  204. if (adjVertex1.adj[j] == i)
  205. {
  206. adjVertex1.adj[j] = a0;
  207. break;
  208. }
  209. }
  210. // assert: j != adjVertex1.numAdjacents
  211. vertex0.valid = false;
  212. if (adjVertex0.numAdjacents == 2)
  213. {
  214. if (adjVertex0.adj[0] == adjVertex0.adj[1])
  215. {
  216. adjVertex0.valid = false;
  217. }
  218. }
  219. if (adjVertex1.numAdjacents == 2)
  220. {
  221. if (adjVertex1.adj[0] == adjVertex1.adj[1])
  222. {
  223. adjVertex1.valid = false;
  224. }
  225. }
  226. }
  227. bool Remove(Triangle& triangle)
  228. {
  229. for (int i = 0; i < 18; ++i)
  230. {
  231. TVertex& vertex = mVertex[i];
  232. if (vertex.valid && vertex.numAdjacents == 2)
  233. {
  234. triangle.v[0] = i;
  235. triangle.v[1] = vertex.adj[0];
  236. triangle.v[2] = vertex.adj[1];
  237. RemoveVertex(i);
  238. return true;
  239. }
  240. }
  241. return false;
  242. }
  243. class TVertex
  244. {
  245. public:
  246. TVertex()
  247. :
  248. numAdjacents(0),
  249. valid(false)
  250. {
  251. }
  252. Vertex pos;
  253. int numAdjacents;
  254. std::array<int, 4> adj;
  255. bool valid;
  256. };
  257. std::array<TVertex, 18> mVertex;
  258. };
  259. virtual std::array<Real, 3> GetGradient(std::array<Real, 3> const& pos) override
  260. {
  261. std::array<Real, 3> const zero{ (Real)0, (Real)0, (Real)0 };
  262. int x = static_cast<int>(pos[0]);
  263. if (x < 0 || x + 1 >= this->mXBound)
  264. {
  265. return zero;
  266. }
  267. int y = static_cast<int>(pos[1]);
  268. if (y < 0 || y + 1 >= this->mYBound)
  269. {
  270. return zero;
  271. }
  272. int z = static_cast<int>(pos[2]);
  273. if (z < 0 || z + 1 >= this->mZBound)
  274. {
  275. return zero;
  276. }
  277. // Get image values at corners of voxel.
  278. int i000 = x + this->mXBound * (y + this->mYBound * z);
  279. int i100 = i000 + 1;
  280. int i010 = i000 + this->mXBound;
  281. int i110 = i010 + 1;
  282. int i001 = i000 + this->mXYBound;
  283. int i101 = i001 + 1;
  284. int i011 = i001 + this->mXBound;
  285. int i111 = i011 + 1;
  286. Real f000 = static_cast<Real>(this->mVoxels[i000]);
  287. Real f100 = static_cast<Real>(this->mVoxels[i100]);
  288. Real f010 = static_cast<Real>(this->mVoxels[i010]);
  289. Real f110 = static_cast<Real>(this->mVoxels[i110]);
  290. Real f001 = static_cast<Real>(this->mVoxels[i001]);
  291. Real f101 = static_cast<Real>(this->mVoxels[i101]);
  292. Real f011 = static_cast<Real>(this->mVoxels[i011]);
  293. Real f111 = static_cast<Real>(this->mVoxels[i111]);
  294. Real dx = pos[0] - static_cast<Real>(x);
  295. Real dy = pos[1] - static_cast<Real>(y);
  296. Real dz = pos[2] - static_cast<Real>(z);
  297. Real oneMX = 1.0f - dx;
  298. Real oneMY = 1.0f - dy;
  299. Real oneMZ = 1.0f - dz;
  300. std::array<Real, 3> grad;
  301. Real tmp0 = oneMY * (f100 - f000) + dy * (f110 - f010);
  302. Real tmp1 = oneMY * (f101 - f001) + dy * (f111 - f011);
  303. grad[0] = oneMZ * tmp0 + dz * tmp1;
  304. tmp0 = oneMX * (f010 - f000) + dx * (f110 - f100);
  305. tmp1 = oneMX * (f011 - f001) + dx * (f111 - f101);
  306. grad[1] = oneMZ * tmp0 + dz * tmp1;
  307. tmp0 = oneMX * (f001 - f000) + dx * (f101 - f100);
  308. tmp1 = oneMX * (f011 - f010) + dx * (f111 - f110);
  309. grad[2] = oneMY * tmp0 + dy * tmp1;
  310. return grad;
  311. }
  312. int GetVertices(int x, int y, int z, VETable& table)
  313. {
  314. int type = 0;
  315. // Get the image values at the corners of the voxel.
  316. int i000 = x + this->mXBound * (y + this->mYBound * z);
  317. int i100 = i000 + 1;
  318. int i010 = i000 + this->mXBound;
  319. int i110 = i010 + 1;
  320. int i001 = i000 + this->mXYBound;
  321. int i101 = i001 + 1;
  322. int i011 = i001 + this->mXBound;
  323. int i111 = i011 + 1;
  324. int64_t f000 = this->mVoxels[i000];
  325. int64_t f100 = this->mVoxels[i100];
  326. int64_t f010 = this->mVoxels[i010];
  327. int64_t f110 = this->mVoxels[i110];
  328. int64_t f001 = this->mVoxels[i001];
  329. int64_t f101 = this->mVoxels[i101];
  330. int64_t f011 = this->mVoxels[i011];
  331. int64_t f111 = this->mVoxels[i111];
  332. int64_t x0 = x, x1 = x + 1, y0 = y, y1 = y + 1, z0 = z, z1 = z + 1;
  333. int64_t d;
  334. // xmin-ymin edge
  335. if (f000 * f001 < 0)
  336. {
  337. type |= EB_XMIN_YMIN;
  338. d = f001 - f000;
  339. table.Insert(EI_XMIN_YMIN, Vertex(x0, 1, y0, 1, z0 * d - f000, d));
  340. }
  341. // xmin-ymax edge
  342. if (f010 * f011 < 0)
  343. {
  344. type |= EB_XMIN_YMAX;
  345. d = f011 - f010;
  346. table.Insert(EI_XMIN_YMAX, Vertex(x0, 1, y1, 1, z0 * d - f010, d));
  347. }
  348. // xmax-ymin edge
  349. if (f100 * f101 < 0)
  350. {
  351. type |= EB_XMAX_YMIN;
  352. d = f101 - f100;
  353. table.Insert(EI_XMAX_YMIN, Vertex(x1, 1, y0, 1, z0 * d - f100, d));
  354. }
  355. // xmax-ymax edge
  356. if (f110 * f111 < 0)
  357. {
  358. type |= EB_XMAX_YMAX;
  359. d = f111 - f110;
  360. table.Insert(EI_XMAX_YMAX, Vertex(x1, 1, y1, 1, z0 * d - f110, d));
  361. }
  362. // xmin-zmin edge
  363. if (f000 * f010 < 0)
  364. {
  365. type |= EB_XMIN_ZMIN;
  366. d = f010 - f000;
  367. table.Insert(EI_XMIN_ZMIN, Vertex(x0, 1, y0 * d - f000, d, z0, 1));
  368. }
  369. // xmin-zmax edge
  370. if (f001 * f011 < 0)
  371. {
  372. type |= EB_XMIN_ZMAX;
  373. d = f011 - f001;
  374. table.Insert(EI_XMIN_ZMAX, Vertex(x0, 1, y0 * d - f001, d, z1, 1));
  375. }
  376. // xmax-zmin edge
  377. if (f100 * f110 < 0)
  378. {
  379. type |= EB_XMAX_ZMIN;
  380. d = f110 - f100;
  381. table.Insert(EI_XMAX_ZMIN, Vertex(x1, 1, y0 * d - f100, d, z0, 1));
  382. }
  383. // xmax-zmax edge
  384. if (f101 * f111 < 0)
  385. {
  386. type |= EB_XMAX_ZMAX;
  387. d = f111 - f101;
  388. table.Insert(EI_XMAX_ZMAX, Vertex(x1, 1, y0 * d - f101, d, z1, 1));
  389. }
  390. // ymin-zmin edge
  391. if (f000 * f100 < 0)
  392. {
  393. type |= EB_YMIN_ZMIN;
  394. d = f100 - f000;
  395. table.Insert(EI_YMIN_ZMIN, Vertex(x0 * d - f000, d, y0, 1, z0, 1));
  396. }
  397. // ymin-zmax edge
  398. if (f001 * f101 < 0)
  399. {
  400. type |= EB_YMIN_ZMAX;
  401. d = f101 - f001;
  402. table.Insert(EI_YMIN_ZMAX, Vertex(x0 * d - f001, d, y0, 1, z1, 1));
  403. }
  404. // ymax-zmin edge
  405. if (f010 * f110 < 0)
  406. {
  407. type |= EB_YMAX_ZMIN;
  408. d = f110 - f010;
  409. table.Insert(EI_YMAX_ZMIN, Vertex(x0 * d - f010, d, y1, 1, z0, 1));
  410. }
  411. // ymax-zmax edge
  412. if (f011 * f111 < 0)
  413. {
  414. type |= EB_YMAX_ZMAX;
  415. d = f111 - f011;
  416. table.Insert(EI_YMAX_ZMAX, Vertex(x0 * d - f011, d, y1, 1, z1, 1));
  417. }
  418. return type;
  419. }
  420. void GetXMinEdges(int x, int y, int z, int type, VETable& table)
  421. {
  422. int faceType = 0;
  423. if (type & EB_XMIN_YMIN)
  424. {
  425. faceType |= 0x01;
  426. }
  427. if (type & EB_XMIN_YMAX)
  428. {
  429. faceType |= 0x02;
  430. }
  431. if (type & EB_XMIN_ZMIN)
  432. {
  433. faceType |= 0x04;
  434. }
  435. if (type & EB_XMIN_ZMAX)
  436. {
  437. faceType |= 0x08;
  438. }
  439. switch (faceType)
  440. {
  441. case 0:
  442. break;
  443. case 3:
  444. table.Insert(EI_XMIN_YMIN, EI_XMIN_YMAX);
  445. break;
  446. case 5:
  447. table.Insert(EI_XMIN_YMIN, EI_XMIN_ZMIN);
  448. break;
  449. case 6:
  450. table.Insert(EI_XMIN_YMAX, EI_XMIN_ZMIN);
  451. break;
  452. case 9:
  453. table.Insert(EI_XMIN_YMIN, EI_XMIN_ZMAX);
  454. break;
  455. case 10:
  456. table.Insert(EI_XMIN_YMAX, EI_XMIN_ZMAX);
  457. break;
  458. case 12:
  459. table.Insert(EI_XMIN_ZMIN, EI_XMIN_ZMAX);
  460. break;
  461. case 15:
  462. {
  463. // Four vertices, one per edge, need to disambiguate.
  464. int i = x + this->mXBound * (y + this->mYBound * z);
  465. // F(x,y,z)
  466. int64_t f00 = this->mVoxels[i];
  467. i += this->mXBound;
  468. // F(x,y+1,z)
  469. int64_t f10 = this->mVoxels[i];
  470. i += this->mXYBound;
  471. // F(x,y+1,z+1)
  472. int64_t f11 = this->mVoxels[i];
  473. i -= this->mXBound;
  474. // F(x,y,z+1)
  475. int64_t f01 = this->mVoxels[i];
  476. int64_t det = f00 * f11 - f01 * f10;
  477. if (det > 0)
  478. {
  479. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  480. table.Insert(EI_XMIN_YMIN, EI_XMIN_ZMIN);
  481. table.Insert(EI_XMIN_YMAX, EI_XMIN_ZMAX);
  482. }
  483. else if (det < 0)
  484. {
  485. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  486. table.Insert(EI_XMIN_YMIN, EI_XMIN_ZMAX);
  487. table.Insert(EI_XMIN_YMAX, EI_XMIN_ZMIN);
  488. }
  489. else
  490. {
  491. // Plus-sign configuration, add branch point to tessellation.
  492. table.Insert(FI_XMIN, Vertex(
  493. table.GetXN(EI_XMIN_ZMIN), table.GetXD(EI_XMIN_ZMIN),
  494. table.GetYN(EI_XMIN_ZMIN), table.GetYD(EI_XMIN_ZMIN),
  495. table.GetZN(EI_XMIN_YMIN), table.GetZD(EI_XMIN_YMIN)));
  496. // Add edges sharing the branch point.
  497. table.Insert(EI_XMIN_YMIN, FI_XMIN);
  498. table.Insert(EI_XMIN_YMAX, FI_XMIN);
  499. table.Insert(EI_XMIN_ZMIN, FI_XMIN);
  500. table.Insert(EI_XMIN_ZMAX, FI_XMIN);
  501. }
  502. break;
  503. }
  504. default:
  505. LogError("Unexpected condition.");
  506. }
  507. }
  508. void GetXMaxEdges(int x, int y, int z, int type, VETable& table)
  509. {
  510. int faceType = 0;
  511. if (type & EB_XMAX_YMIN)
  512. {
  513. faceType |= 0x01;
  514. }
  515. if (type & EB_XMAX_YMAX)
  516. {
  517. faceType |= 0x02;
  518. }
  519. if (type & EB_XMAX_ZMIN)
  520. {
  521. faceType |= 0x04;
  522. }
  523. if (type & EB_XMAX_ZMAX)
  524. {
  525. faceType |= 0x08;
  526. }
  527. switch (faceType)
  528. {
  529. case 0:
  530. break;
  531. case 3:
  532. table.Insert(EI_XMAX_YMIN, EI_XMAX_YMAX);
  533. break;
  534. case 5:
  535. table.Insert(EI_XMAX_YMIN, EI_XMAX_ZMIN);
  536. break;
  537. case 6:
  538. table.Insert(EI_XMAX_YMAX, EI_XMAX_ZMIN);
  539. break;
  540. case 9:
  541. table.Insert(EI_XMAX_YMIN, EI_XMAX_ZMAX);
  542. break;
  543. case 10:
  544. table.Insert(EI_XMAX_YMAX, EI_XMAX_ZMAX);
  545. break;
  546. case 12:
  547. table.Insert(EI_XMAX_ZMIN, EI_XMAX_ZMAX);
  548. break;
  549. case 15:
  550. {
  551. // Four vertices, one per edge, need to disambiguate.
  552. int i = (x + 1) + this->mXBound * (y + this->mYBound * z);
  553. // F(x,y,z)
  554. int64_t f00 = this->mVoxels[i];
  555. i += this->mXBound;
  556. // F(x,y+1,z)
  557. int64_t f10 = this->mVoxels[i];
  558. i += this->mXYBound;
  559. // F(x,y+1,z+1)
  560. int64_t f11 = this->mVoxels[i];
  561. i -= this->mXBound;
  562. // F(x,y,z+1)
  563. int64_t f01 = this->mVoxels[i];
  564. int64_t det = f00 * f11 - f01 * f10;
  565. if (det > 0)
  566. {
  567. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  568. table.Insert(EI_XMAX_YMIN, EI_XMAX_ZMIN);
  569. table.Insert(EI_XMAX_YMAX, EI_XMAX_ZMAX);
  570. }
  571. else if (det < 0)
  572. {
  573. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  574. table.Insert(EI_XMAX_YMIN, EI_XMAX_ZMAX);
  575. table.Insert(EI_XMAX_YMAX, EI_XMAX_ZMIN);
  576. }
  577. else
  578. {
  579. // Plus-sign configuration, add branch point to tessellation.
  580. table.Insert(FI_XMAX, Vertex(
  581. table.GetXN(EI_XMAX_ZMIN), table.GetXD(EI_XMAX_ZMIN),
  582. table.GetYN(EI_XMAX_ZMIN), table.GetYD(EI_XMAX_ZMIN),
  583. table.GetZN(EI_XMAX_YMIN), table.GetZD(EI_XMAX_YMIN)));
  584. // Add edges sharing the branch point.
  585. table.Insert(EI_XMAX_YMIN, FI_XMAX);
  586. table.Insert(EI_XMAX_YMAX, FI_XMAX);
  587. table.Insert(EI_XMAX_ZMIN, FI_XMAX);
  588. table.Insert(EI_XMAX_ZMAX, FI_XMAX);
  589. }
  590. break;
  591. }
  592. default:
  593. LogError("Unexpected condition.");
  594. }
  595. }
  596. void GetYMinEdges(int x, int y, int z, int type, VETable& table)
  597. {
  598. int faceType = 0;
  599. if (type & EB_XMIN_YMIN)
  600. {
  601. faceType |= 0x01;
  602. }
  603. if (type & EB_XMAX_YMIN)
  604. {
  605. faceType |= 0x02;
  606. }
  607. if (type & EB_YMIN_ZMIN)
  608. {
  609. faceType |= 0x04;
  610. }
  611. if (type & EB_YMIN_ZMAX)
  612. {
  613. faceType |= 0x08;
  614. }
  615. switch (faceType)
  616. {
  617. case 0:
  618. break;
  619. case 3:
  620. table.Insert(EI_XMIN_YMIN, EI_XMAX_YMIN);
  621. break;
  622. case 5:
  623. table.Insert(EI_XMIN_YMIN, EI_YMIN_ZMIN);
  624. break;
  625. case 6:
  626. table.Insert(EI_XMAX_YMIN, EI_YMIN_ZMIN);
  627. break;
  628. case 9:
  629. table.Insert(EI_XMIN_YMIN, EI_YMIN_ZMAX);
  630. break;
  631. case 10:
  632. table.Insert(EI_XMAX_YMIN, EI_YMIN_ZMAX);
  633. break;
  634. case 12:
  635. table.Insert(EI_YMIN_ZMIN, EI_YMIN_ZMAX);
  636. break;
  637. case 15:
  638. {
  639. // Four vertices, one per edge, need to disambiguate.
  640. int i = x + this->mXBound * (y + this->mYBound * z);
  641. // F(x,y,z)
  642. int64_t f00 = this->mVoxels[i];
  643. ++i;
  644. // F(x+1,y,z)
  645. int64_t f10 = this->mVoxels[i];
  646. i += this->mXYBound;
  647. // F(x+1,y,z+1)
  648. int64_t f11 = this->mVoxels[i];
  649. --i;
  650. // F(x,y,z+1)
  651. int64_t f01 = this->mVoxels[i];
  652. int64_t det = f00 * f11 - f01 * f10;
  653. if (det > 0)
  654. {
  655. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  656. table.Insert(EI_XMIN_YMIN, EI_YMIN_ZMIN);
  657. table.Insert(EI_XMAX_YMIN, EI_YMIN_ZMAX);
  658. }
  659. else if (det < 0)
  660. {
  661. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  662. table.Insert(EI_XMIN_YMIN, EI_YMIN_ZMAX);
  663. table.Insert(EI_XMAX_YMIN, EI_YMIN_ZMIN);
  664. }
  665. else
  666. {
  667. // Plus-sign configuration, add branch point to tessellation.
  668. table.Insert(FI_YMIN, Vertex(
  669. table.GetXN(EI_YMIN_ZMIN), table.GetXD(EI_YMIN_ZMIN),
  670. table.GetYN(EI_XMIN_YMIN), table.GetYD(EI_XMIN_YMIN),
  671. table.GetZN(EI_XMIN_YMIN), table.GetZD(EI_XMIN_YMIN)));
  672. // Add edges sharing the branch point.
  673. table.Insert(EI_XMIN_YMIN, FI_YMIN);
  674. table.Insert(EI_XMAX_YMIN, FI_YMIN);
  675. table.Insert(EI_YMIN_ZMIN, FI_YMIN);
  676. table.Insert(EI_YMIN_ZMAX, FI_YMIN);
  677. }
  678. break;
  679. }
  680. default:
  681. LogError("Unexpected condition.");
  682. }
  683. }
  684. void GetYMaxEdges(int x, int y, int z, int type, VETable& table)
  685. {
  686. int faceType = 0;
  687. if (type & EB_XMIN_YMAX)
  688. {
  689. faceType |= 0x01;
  690. }
  691. if (type & EB_XMAX_YMAX)
  692. {
  693. faceType |= 0x02;
  694. }
  695. if (type & EB_YMAX_ZMIN)
  696. {
  697. faceType |= 0x04;
  698. }
  699. if (type & EB_YMAX_ZMAX)
  700. {
  701. faceType |= 0x08;
  702. }
  703. switch (faceType)
  704. {
  705. case 0:
  706. break;
  707. case 3:
  708. table.Insert(EI_XMIN_YMAX, EI_XMAX_YMAX);
  709. break;
  710. case 5:
  711. table.Insert(EI_XMIN_YMAX, EI_YMAX_ZMIN);
  712. break;
  713. case 6:
  714. table.Insert(EI_XMAX_YMAX, EI_YMAX_ZMIN);
  715. break;
  716. case 9:
  717. table.Insert(EI_XMIN_YMAX, EI_YMAX_ZMAX);
  718. break;
  719. case 10:
  720. table.Insert(EI_XMAX_YMAX, EI_YMAX_ZMAX);
  721. break;
  722. case 12:
  723. table.Insert(EI_YMAX_ZMIN, EI_YMAX_ZMAX);
  724. break;
  725. case 15:
  726. {
  727. // Four vertices, one per edge, need to disambiguate.
  728. int i = x + this->mXBound * ((y + 1) + this->mYBound * z);
  729. // F(x,y,z)
  730. int64_t f00 = this->mVoxels[i];
  731. ++i;
  732. // F(x+1,y,z)
  733. int64_t f10 = this->mVoxels[i];
  734. i += this->mXYBound;
  735. // F(x+1,y,z+1)
  736. int64_t f11 = this->mVoxels[i];
  737. --i;
  738. // F(x,y,z+1)
  739. int64_t f01 = this->mVoxels[i];
  740. int64_t det = f00 * f11 - f01 * f10;
  741. if (det > 0)
  742. {
  743. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  744. table.Insert(EI_XMIN_YMAX, EI_YMAX_ZMIN);
  745. table.Insert(EI_XMAX_YMAX, EI_YMAX_ZMAX);
  746. }
  747. else if (det < 0)
  748. {
  749. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  750. table.Insert(EI_XMIN_YMAX, EI_YMAX_ZMAX);
  751. table.Insert(EI_XMAX_YMAX, EI_YMAX_ZMIN);
  752. }
  753. else
  754. {
  755. // Plus-sign configuration, add branch point to tessellation.
  756. table.Insert(FI_YMAX, Vertex(
  757. table.GetXN(EI_YMAX_ZMIN), table.GetXD(EI_YMAX_ZMIN),
  758. table.GetYN(EI_XMIN_YMAX), table.GetYD(EI_XMIN_YMAX),
  759. table.GetZN(EI_XMIN_YMAX), table.GetZD(EI_XMIN_YMAX)));
  760. // Add edges sharing the branch point.
  761. table.Insert(EI_XMIN_YMAX, FI_YMAX);
  762. table.Insert(EI_XMAX_YMAX, FI_YMAX);
  763. table.Insert(EI_YMAX_ZMIN, FI_YMAX);
  764. table.Insert(EI_YMAX_ZMAX, FI_YMAX);
  765. }
  766. break;
  767. }
  768. default:
  769. LogError("Unexpected condition.");
  770. }
  771. }
  772. void GetZMinEdges(int x, int y, int z, int type, VETable& table)
  773. {
  774. int faceType = 0;
  775. if (type & EB_XMIN_ZMIN)
  776. {
  777. faceType |= 0x01;
  778. }
  779. if (type & EB_XMAX_ZMIN)
  780. {
  781. faceType |= 0x02;
  782. }
  783. if (type & EB_YMIN_ZMIN)
  784. {
  785. faceType |= 0x04;
  786. }
  787. if (type & EB_YMAX_ZMIN)
  788. {
  789. faceType |= 0x08;
  790. }
  791. switch (faceType)
  792. {
  793. case 0:
  794. break;
  795. case 3:
  796. table.Insert(EI_XMIN_ZMIN, EI_XMAX_ZMIN);
  797. break;
  798. case 5:
  799. table.Insert(EI_XMIN_ZMIN, EI_YMIN_ZMIN);
  800. break;
  801. case 6:
  802. table.Insert(EI_XMAX_ZMIN, EI_YMIN_ZMIN);
  803. break;
  804. case 9:
  805. table.Insert(EI_XMIN_ZMIN, EI_YMAX_ZMIN);
  806. break;
  807. case 10:
  808. table.Insert(EI_XMAX_ZMIN, EI_YMAX_ZMIN);
  809. break;
  810. case 12:
  811. table.Insert(EI_YMIN_ZMIN, EI_YMAX_ZMIN);
  812. break;
  813. case 15:
  814. {
  815. // Four vertices, one per edge, need to disambiguate.
  816. int i = x + this->mXBound * (y + this->mYBound * z);
  817. // F(x,y,z)
  818. int64_t f00 = this->mVoxels[i];
  819. ++i;
  820. // F(x+1,y,z)
  821. int64_t f10 = this->mVoxels[i];
  822. i += this->mXBound;
  823. // F(x+1,y+1,z)
  824. int64_t f11 = this->mVoxels[i];
  825. --i;
  826. // F(x,y+1,z)
  827. int64_t f01 = this->mVoxels[i];
  828. int64_t det = f00 * f11 - f01 * f10;
  829. if (det > 0)
  830. {
  831. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  832. table.Insert(EI_XMIN_ZMIN, EI_YMIN_ZMIN);
  833. table.Insert(EI_XMAX_ZMIN, EI_YMAX_ZMIN);
  834. }
  835. else if (det < 0)
  836. {
  837. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  838. table.Insert(EI_XMIN_ZMIN, EI_YMAX_ZMIN);
  839. table.Insert(EI_XMAX_ZMIN, EI_YMIN_ZMIN);
  840. }
  841. else
  842. {
  843. // Plus-sign configuration, add branch point to tessellation.
  844. table.Insert(FI_ZMIN, Vertex(
  845. table.GetXN(EI_YMIN_ZMIN), table.GetXD(EI_YMIN_ZMIN),
  846. table.GetYN(EI_XMIN_ZMIN), table.GetYD(EI_XMIN_ZMIN),
  847. table.GetZN(EI_XMIN_ZMIN), table.GetZD(EI_XMIN_ZMIN)));
  848. // Add edges sharing the branch point.
  849. table.Insert(EI_XMIN_ZMIN, FI_ZMIN);
  850. table.Insert(EI_XMAX_ZMIN, FI_ZMIN);
  851. table.Insert(EI_YMIN_ZMIN, FI_ZMIN);
  852. table.Insert(EI_YMAX_ZMIN, FI_ZMIN);
  853. }
  854. break;
  855. }
  856. default:
  857. LogError("Unexpected condition.");
  858. }
  859. }
  860. void GetZMaxEdges(int x, int y, int z, int type, VETable& table)
  861. {
  862. int faceType = 0;
  863. if (type & EB_XMIN_ZMAX)
  864. {
  865. faceType |= 0x01;
  866. }
  867. if (type & EB_XMAX_ZMAX)
  868. {
  869. faceType |= 0x02;
  870. }
  871. if (type & EB_YMIN_ZMAX)
  872. {
  873. faceType |= 0x04;
  874. }
  875. if (type & EB_YMAX_ZMAX)
  876. {
  877. faceType |= 0x08;
  878. }
  879. switch (faceType)
  880. {
  881. case 0:
  882. break;
  883. case 3:
  884. table.Insert(EI_XMIN_ZMAX, EI_XMAX_ZMAX);
  885. break;
  886. case 5:
  887. table.Insert(EI_XMIN_ZMAX, EI_YMIN_ZMAX);
  888. break;
  889. case 6:
  890. table.Insert(EI_XMAX_ZMAX, EI_YMIN_ZMAX);
  891. break;
  892. case 9:
  893. table.Insert(EI_XMIN_ZMAX, EI_YMAX_ZMAX);
  894. break;
  895. case 10:
  896. table.Insert(EI_XMAX_ZMAX, EI_YMAX_ZMAX);
  897. break;
  898. case 12:
  899. table.Insert(EI_YMIN_ZMAX, EI_YMAX_ZMAX);
  900. break;
  901. case 15:
  902. {
  903. // Four vertices, one per edge, need to disambiguate.
  904. int i = x + this->mXBound * (y + this->mYBound * (z + 1));
  905. // F(x,y,z)
  906. int64_t f00 = this->mVoxels[i];
  907. ++i;
  908. // F(x+1,y,z)
  909. int64_t f10 = this->mVoxels[i];
  910. i += this->mXBound;
  911. // F(x+1,y+1,z)
  912. int64_t f11 = this->mVoxels[i];
  913. --i;
  914. // F(x,y+1,z)
  915. int64_t f01 = this->mVoxels[i];
  916. int64_t det = f00 * f11 - f01 * f10;
  917. if (det > 0)
  918. {
  919. // Disjoint hyperbolic segments, pair <P0,P2>, <P1,P3>.
  920. table.Insert(EI_XMIN_ZMAX, EI_YMIN_ZMAX);
  921. table.Insert(EI_XMAX_ZMAX, EI_YMAX_ZMAX);
  922. }
  923. else if (det < 0)
  924. {
  925. // Disjoint hyperbolic segments, pair <P0,P3>, <P1,P2>.
  926. table.Insert(EI_XMIN_ZMAX, EI_YMAX_ZMAX);
  927. table.Insert(EI_XMAX_ZMAX, EI_YMIN_ZMAX);
  928. }
  929. else
  930. {
  931. // Plus-sign configuration, add branch point to tessellation.
  932. table.Insert(FI_ZMAX, Vertex(
  933. table.GetXN(EI_YMIN_ZMAX), table.GetXD(EI_YMIN_ZMAX),
  934. table.GetYN(EI_XMIN_ZMAX), table.GetYD(EI_XMIN_ZMAX),
  935. table.GetZN(EI_XMIN_ZMAX), table.GetZD(EI_XMIN_ZMAX)));
  936. // Add edges sharing the branch point.
  937. table.Insert(EI_XMIN_ZMAX, FI_ZMAX);
  938. table.Insert(EI_XMAX_ZMAX, FI_ZMAX);
  939. table.Insert(EI_YMIN_ZMAX, FI_ZMAX);
  940. table.Insert(EI_YMAX_ZMAX, FI_ZMAX);
  941. }
  942. break;
  943. }
  944. default:
  945. LogError("Unexpected condition.");
  946. }
  947. }
  948. };
  949. }