Image3.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  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/Image.h>
  10. #include <array>
  11. #include <string>
  12. //#define GTE_THROW_ON_IMAGE3_ERRORS
  13. namespace WwiseGTE
  14. {
  15. template <typename PixelType>
  16. class Image3 : public Image<PixelType>
  17. {
  18. public:
  19. // Construction and destruction. The last constructor must have
  20. // positive dimensions; otherwise, the image is empty.
  21. virtual ~Image3()
  22. {
  23. }
  24. Image3()
  25. {
  26. }
  27. Image3(int dimension0, int dimension1, int dimension2)
  28. :
  29. Image<PixelType>(std::vector<int>{ dimension0, dimension1, dimension2 })
  30. {
  31. }
  32. // Support for copy semantics.
  33. Image3(Image3 const& image)
  34. :
  35. Image<PixelType>(image)
  36. {
  37. }
  38. Image3& operator= (Image3 const& image)
  39. {
  40. Image<PixelType>::operator=(image);
  41. return *this;
  42. }
  43. // Support for move semantics.
  44. Image3(Image3&& image)
  45. {
  46. *this = std::move(image);
  47. }
  48. Image3& operator= (Image3&& image)
  49. {
  50. Image<PixelType>::operator=(image);
  51. return *this;
  52. }
  53. // Support for changing the image dimensions. All pixel data is lost
  54. // by this operation.
  55. void Reconstruct(int dimension0, int dimension1, int dimension2)
  56. {
  57. Image<PixelType>::Reconstruct(std::vector<int>{ dimension0, dimension1, dimension2 });
  58. }
  59. // Conversion between 1-dimensional indices and 3-dimensional
  60. // coordinates.
  61. inline size_t GetIndex(int x, int y, int z) const
  62. {
  63. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  64. if (0 <= x && x < this->mDimensions[0]
  65. && 0 <= y && y < this->mDimensions[1]
  66. && 0 <= z && z < this->mDimensions[2])
  67. {
  68. return static_cast<size_t>(x) +
  69. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  70. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  71. }
  72. else
  73. {
  74. LogError(
  75. "Invalid coordinates (" + std::to_string(x) + "," +
  76. std::to_string(y) + "," + std::to_string(z) + ").");
  77. }
  78. #else
  79. return static_cast<size_t>(x) +
  80. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  81. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  82. #endif
  83. }
  84. inline size_t GetIndex(std::array<int, 3> const& coord) const
  85. {
  86. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  87. if (0 <= coord[0] && coord[0] < this->mDimensions[0]
  88. && 0 <= coord[1] && coord[1] < this->mDimensions[1]
  89. && 0 <= coord[2] && coord[2] < this->mDimensions[2])
  90. {
  91. return static_cast<size_t>(coord[0]) +
  92. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  93. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(coord[2]));
  94. }
  95. else
  96. {
  97. LogError(
  98. "Invalid coordinates (" + std::to_string(coord[0]) + "," +
  99. std::to_string(coord[1]) + "," + std::to_string(coord[2]) + ").");
  100. }
  101. #else
  102. return static_cast<size_t>(coord[0]) +
  103. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  104. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(coord[2]));
  105. #endif
  106. }
  107. inline void GetCoordinates(size_t index, int& x, int& y, int& z) const
  108. {
  109. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  110. if (index < this->mPixels.size())
  111. {
  112. x = static_cast<int>(index % this->mDimensions[0]);
  113. index /= this->mDimensions[0];
  114. y = static_cast<int>(index % this->mDimensions[1]);
  115. z = static_cast<int>(index / this->mDimensions[1]);
  116. }
  117. else
  118. {
  119. LogError(
  120. "Invalid index " + std::to_string(index) + ".");
  121. }
  122. #else
  123. x = static_cast<int>(index % this->mDimensions[0]);
  124. index /= this->mDimensions[0];
  125. y = static_cast<int>(index % this->mDimensions[1]);
  126. z = static_cast<int>(index / this->mDimensions[1]);
  127. #endif
  128. }
  129. inline std::array<int, 3> GetCoordinates(size_t index) const
  130. {
  131. std::array<int, 3> coord;
  132. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  133. if (index < this->mPixels.size())
  134. {
  135. coord[0] = static_cast<int>(index % this->mDimensions[0]);
  136. index /= this->mDimensions[0];
  137. coord[1] = static_cast<int>(index % this->mDimensions[1]);
  138. coord[2] = static_cast<int>(index / this->mDimensions[1]);
  139. return coord;
  140. }
  141. else
  142. {
  143. LogError(
  144. "Invalid index " + std::to_string(index) + ".");
  145. }
  146. #else
  147. coord[0] = static_cast<int>(index % this->mDimensions[0]);
  148. index /= this->mDimensions[0];
  149. coord[1] = static_cast<int>(index % this->mDimensions[1]);
  150. coord[2] = static_cast<int>(index / this->mDimensions[1]);
  151. return coord;
  152. #endif
  153. }
  154. // Access the data as a 3-dimensional array. The operator() functions
  155. // test for valid (x,y,z) when iterator checking is enabled and throw
  156. // on invalid (x,y,z). The Get() functions test for valid (x,y,z) and
  157. // clamp when invalid; these functions cannot fail.
  158. inline PixelType& operator() (int x, int y, int z)
  159. {
  160. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  161. if (0 <= x && x < this->mDimensions[0]
  162. && 0 <= y && y < this->mDimensions[1]
  163. && 0 <= z && z < this->mDimensions[2])
  164. {
  165. size_t i = static_cast<size_t>(x) +
  166. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  167. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  168. return this->mPixels[i];
  169. }
  170. else
  171. {
  172. LogError(
  173. "Invalid coordinates (" + std::to_string(x) + "," +
  174. std::to_string(y) + "," + std::to_string(z) + ").");
  175. }
  176. #else
  177. size_t i = static_cast<size_t>(x) +
  178. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  179. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  180. return this->mPixels[i];
  181. #endif
  182. }
  183. inline PixelType const& operator() (int x, int y, int z) const
  184. {
  185. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  186. if (0 <= x && x < this->mDimensions[0]
  187. && 0 <= y && y < this->mDimensions[1]
  188. && 0 <= z && z < this->mDimensions[2])
  189. {
  190. size_t i = static_cast<size_t>(x) +
  191. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  192. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  193. return this->mPixels[i];
  194. }
  195. else
  196. {
  197. LogError(
  198. "Invalid coordinates (" + std::to_string(x) + "," +
  199. std::to_string(y) + "," + std::to_string(z) + ").");
  200. }
  201. #else
  202. size_t i = static_cast<size_t>(x) +
  203. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  204. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  205. return this->mPixels[i];
  206. #endif
  207. }
  208. inline PixelType& operator() (std::array<int, 3> const& coord)
  209. {
  210. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  211. if (0 <= coord[0] && coord[0] < this->mDimensions[0]
  212. && 0 <= coord[1] && coord[1] < this->mDimensions[1]
  213. && 0 <= coord[2] && coord[2] < this->mDimensions[2])
  214. {
  215. size_t i = static_cast<size_t>(coord[0]) +
  216. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  217. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(coord[2]));
  218. return this->mPixels[i];
  219. }
  220. else
  221. {
  222. LogError(
  223. "Invalid coordinates (" + std::to_string(coord[0]) + "," +
  224. std::to_string(coord[1]) + "," + std::to_string(coord[2]) + ").");
  225. }
  226. #else
  227. size_t i = static_cast<size_t>(coord[0]) +
  228. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  229. static_cast<size_t>(this->mDimensions[1] * coord[2]));
  230. return this->mPixels[i];
  231. #endif
  232. }
  233. inline PixelType const& operator() (std::array<int, 3> const& coord) const
  234. {
  235. #if defined(GTE_THROW_ON_IMAGE3_ERRORS)
  236. if (0 <= coord[0] && coord[0] < this->mDimensions[0]
  237. && 0 <= coord[1] && coord[1] < this->mDimensions[1]
  238. && 0 <= coord[2] && coord[2] < this->mDimensions[2])
  239. {
  240. size_t i = static_cast<size_t>(coord[0]) +
  241. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  242. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(coord[2]));
  243. return this->mPixels[i];
  244. }
  245. else
  246. {
  247. LogError(
  248. "Invalid coordinates (" + std::to_string(coord[0]) + "," +
  249. std::to_string(coord[1]) + "," + std::to_string(coord[2]) + ").");
  250. }
  251. #else
  252. size_t i = static_cast<size_t>(coord[0]) +
  253. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  254. static_cast<size_t>(this->mDimensions[1] * coord[2]));
  255. return this->mPixels[i];
  256. #endif
  257. }
  258. inline PixelType& Get(int x, int y, int z)
  259. {
  260. // Clamp to valid (x,y,z).
  261. if (x < 0)
  262. {
  263. x = 0;
  264. }
  265. else if (x >= this->mDimensions[0])
  266. {
  267. x = this->mDimensions[0] - 1;
  268. }
  269. if (y < 0)
  270. {
  271. y = 0;
  272. }
  273. else if (y >= this->mDimensions[1])
  274. {
  275. y = this->mDimensions[1] - 1;
  276. }
  277. if (z < 0)
  278. {
  279. z = 0;
  280. }
  281. else if (z >= this->mDimensions[2])
  282. {
  283. z = this->mDimensions[2] - 1;
  284. }
  285. size_t i = static_cast<size_t>(x) +
  286. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  287. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  288. return this->mPixels[i];
  289. }
  290. inline PixelType const& Get(int x, int y, int z) const
  291. {
  292. // Clamp to valid (x,y,z).
  293. if (x < 0)
  294. {
  295. x = 0;
  296. }
  297. else if (x >= this->mDimensions[0])
  298. {
  299. x = this->mDimensions[0] - 1;
  300. }
  301. if (y < 0)
  302. {
  303. y = 0;
  304. }
  305. else if (y >= this->mDimensions[1])
  306. {
  307. y = this->mDimensions[1] - 1;
  308. }
  309. if (z < 0)
  310. {
  311. z = 0;
  312. }
  313. else if (z >= this->mDimensions[2])
  314. {
  315. z = this->mDimensions[2] - 1;
  316. }
  317. size_t i = static_cast<size_t>(x) +
  318. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(y) +
  319. static_cast<size_t>(this->mDimensions[1]) * static_cast<size_t>(z));
  320. return this->mPixels[i];
  321. }
  322. inline PixelType& Get(std::array<int, 3> coord)
  323. {
  324. // Clamp to valid (x,y,z).
  325. for (int d = 0; d < 3; ++d)
  326. {
  327. if (coord[d] < 0)
  328. {
  329. coord[d] = 0;
  330. }
  331. else if (coord[d] >= this->mDimensions[d])
  332. {
  333. coord[d] = this->mDimensions[d] - 1;
  334. }
  335. }
  336. size_t i = static_cast<size_t>(coord[0]) +
  337. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  338. static_cast<size_t>(this->mDimensions[1] * coord[2]));
  339. return this->mPixels[i];
  340. }
  341. inline PixelType const& Get(std::array<int, 3> coord) const
  342. {
  343. // Clamp to valid (x,y,z).
  344. for (int d = 0; d < 3; ++d)
  345. {
  346. if (coord[d] < 0)
  347. {
  348. coord[d] = 0;
  349. }
  350. else if (coord[d] >= this->mDimensions[d])
  351. {
  352. coord[d] = this->mDimensions[d] - 1;
  353. }
  354. }
  355. size_t i = static_cast<size_t>(coord[0]) +
  356. static_cast<size_t>(this->mDimensions[0]) * (static_cast<size_t>(coord[1]) +
  357. static_cast<size_t>(this->mDimensions[1] * coord[2]));
  358. return this->mPixels[i];
  359. }
  360. // In the following discussion, u, v and w are in {-1,1}. Given a
  361. // voxel (x,y,z), the 6-connected neighbors have relative offsets
  362. // (u,0,0), (0,v,0), and (0,0,w). The 18-connected neighbors include
  363. // the 6-connected neighbors and have additional relative offsets
  364. // (u,v,0), (u,0,w), and (0,v,w). The 26-connected neighbors include
  365. // the 18-connected neighbors and have additional relative offsets
  366. // (u,v,w). The corner neighbors have offsets (0,0,0), (1,0,0),
  367. // (0,1,0), (1,1,0), (0,0,1), (1,0,1), (0,1,1), and (1,1,1) in that
  368. // order. The full neighborhood is the set of 3x3x3 pixels centered
  369. // at (x,y).
  370. // The neighborhoods can be accessed as 1-dimensional indices using
  371. // these functions. The first five functions provide 1-dimensional
  372. // indices relative to any voxel location; these depend only on the
  373. // image dimensions. The last five functions provide 1-dimensional
  374. // indices for the actual voxels in the neighborhood; no clamping is
  375. // used when (x,y,z) is on the boundary.
  376. void GetNeighborhood(std::array<int, 6>& nbr) const
  377. {
  378. int dim0 = this->mDimensions[0];
  379. int dim01 = this->mDimensions[0] * this->mDimensions[1];
  380. nbr[0] = -1; // (x-1,y,z)
  381. nbr[1] = +1; // (x+1,y,z)
  382. nbr[2] = -dim0; // (x,y-1,z)
  383. nbr[3] = +dim0; // (x,y+1,z)
  384. nbr[4] = -dim01; // (x,y,z-1)
  385. nbr[5] = +dim01; // (x,y,z+1)
  386. }
  387. void GetNeighborhood(std::array<int, 18>& nbr) const
  388. {
  389. int dim0 = this->mDimensions[0];
  390. int dim01 = this->mDimensions[0] * this->mDimensions[1];
  391. nbr[0] = -1; // (x-1,y,z)
  392. nbr[1] = +1; // (x+1,y,z)
  393. nbr[2] = -dim0; // (x,y-1,z)
  394. nbr[3] = +dim0; // (x,y+1,z)
  395. nbr[4] = -dim01; // (x,y,z-1)
  396. nbr[5] = +dim01; // (x,y,z+1)
  397. nbr[6] = -1 - dim0; // (x-1,y-1,z)
  398. nbr[7] = +1 - dim0; // (x+1,y-1,z)
  399. nbr[8] = -1 + dim0; // (x-1,y+1,z)
  400. nbr[9] = +1 + dim0; // (x+1,y+1,z)
  401. nbr[10] = -1 + dim01; // (x-1,y,z+1)
  402. nbr[11] = +1 + dim01; // (x+1,y,z+1)
  403. nbr[12] = -dim0 + dim01; // (x,y-1,z+1)
  404. nbr[13] = +dim0 + dim01; // (x,y+1,z+1)
  405. nbr[14] = -1 - dim01; // (x-1,y,z-1)
  406. nbr[15] = +1 - dim01; // (x+1,y,z-1)
  407. nbr[16] = -dim0 - dim01; // (x,y-1,z-1)
  408. nbr[17] = +dim0 - dim01; // (x,y+1,z-1)
  409. }
  410. void GetNeighborhood(std::array<int, 26>& nbr) const
  411. {
  412. int dim0 = this->mDimensions[0];
  413. int dim01 = this->mDimensions[0] * this->mDimensions[1];
  414. nbr[0] = -1; // (x-1,y,z)
  415. nbr[1] = +1; // (x+1,y,z)
  416. nbr[2] = -dim0; // (x,y-1,z)
  417. nbr[3] = +dim0; // (x,y+1,z)
  418. nbr[4] = -dim01; // (x,y,z-1)
  419. nbr[5] = +dim01; // (x,y,z+1)
  420. nbr[6] = -1 - dim0; // (x-1,y-1,z)
  421. nbr[7] = +1 - dim0; // (x+1,y-1,z)
  422. nbr[8] = -1 + dim0; // (x-1,y+1,z)
  423. nbr[9] = +1 + dim0; // (x+1,y+1,z)
  424. nbr[10] = -1 + dim01; // (x-1,y,z+1)
  425. nbr[11] = +1 + dim01; // (x+1,y,z+1)
  426. nbr[12] = -dim0 + dim01; // (x,y-1,z+1)
  427. nbr[13] = +dim0 + dim01; // (x,y+1,z+1)
  428. nbr[14] = -1 - dim01; // (x-1,y,z-1)
  429. nbr[15] = +1 - dim01; // (x+1,y,z-1)
  430. nbr[16] = -dim0 - dim01; // (x,y-1,z-1)
  431. nbr[17] = +dim0 - dim01; // (x,y+1,z-1)
  432. nbr[18] = -1 - dim0 - dim01; // (x-1,y-1,z-1)
  433. nbr[19] = +1 - dim0 - dim01; // (x+1,y-1,z-1)
  434. nbr[20] = -1 + dim0 - dim01; // (x-1,y+1,z-1)
  435. nbr[21] = +1 + dim0 - dim01; // (x+1,y+1,z-1)
  436. nbr[22] = -1 - dim0 + dim01; // (x-1,y-1,z+1)
  437. nbr[23] = +1 - dim0 + dim01; // (x+1,y-1,z+1)
  438. nbr[24] = -1 + dim0 + dim01; // (x-1,y+1,z+1)
  439. nbr[25] = +1 + dim0 + dim01; // (x+1,y+1,z+1)
  440. }
  441. void GetCorners(std::array<int, 8>& nbr) const
  442. {
  443. int dim0 = this->mDimensions[0];
  444. int dim01 = this->mDimensions[0] * this->mDimensions[1];
  445. nbr[0] = 0; // (x,y,z)
  446. nbr[1] = 1; // (x+1,y,z)
  447. nbr[2] = dim0; // (x,y+1,z)
  448. nbr[3] = dim0 + 1; // (x+1,y+1,z)
  449. nbr[4] = dim01; // (x,y,z+1)
  450. nbr[5] = dim01 + 1; // (x+1,y,z+1)
  451. nbr[6] = dim01 + dim0; // (x,y+1,z+1)
  452. nbr[7] = dim01 + dim0 + 1; // (x+1,y+1,z+1)
  453. }
  454. void GetFull(std::array<int, 27>& nbr) const
  455. {
  456. int dim0 = this->mDimensions[0];
  457. int dim01 = this->mDimensions[0] * this->mDimensions[1];
  458. nbr[0] = -1 - dim0 - dim01; // (x-1,y-1,z-1)
  459. nbr[1] = -dim0 - dim01; // (x, y-1,z-1)
  460. nbr[2] = +1 - dim0 - dim01; // (x+1,y-1,z-1)
  461. nbr[3] = -1 - dim01; // (x-1,y, z-1)
  462. nbr[4] = -dim01; // (x, y, z-1)
  463. nbr[5] = +1 - dim01; // (x+1,y, z-1)
  464. nbr[6] = -1 + dim0 - dim01; // (x-1,y+1,z-1)
  465. nbr[7] = +dim0 - dim01; // (x, y+1,z-1)
  466. nbr[8] = +1 + dim0 - dim01; // (x+1,y+1,z-1)
  467. nbr[9] = -1 - dim0; // (x-1,y-1,z)
  468. nbr[10] = -dim0; // (x, y-1,z)
  469. nbr[11] = +1 - dim0; // (x+1,y-1,z)
  470. nbr[12] = -1; // (x-1,y, z)
  471. nbr[13] = 0; // (x, y, z)
  472. nbr[14] = +1; // (x+1,y, z)
  473. nbr[15] = -1 + dim0; // (x-1,y+1,z)
  474. nbr[16] = +dim0; // (x, y+1,z)
  475. nbr[17] = +1 + dim0; // (x+1,y+1,z)
  476. nbr[18] = -1 - dim0 + dim01; // (x-1,y-1,z+1)
  477. nbr[19] = -dim0 + dim01; // (x, y-1,z+1)
  478. nbr[20] = +1 - dim0 + dim01; // (x+1,y-1,z+1)
  479. nbr[21] = -1 + dim01; // (x-1,y, z+1)
  480. nbr[22] = +dim01; // (x, y, z+1)
  481. nbr[23] = +1 + dim01; // (x+1,y, z+1)
  482. nbr[24] = -1 + dim0 + dim01; // (x-1,y+1,z+1)
  483. nbr[25] = +dim0 + dim01; // (x, y+1,z+1)
  484. nbr[26] = +1 + dim0 + dim01; // (x+1,y+1,z+1)
  485. }
  486. void GetNeighborhood(int x, int y, int z, std::array<size_t, 6>& nbr) const
  487. {
  488. size_t index = GetIndex(x, y, z);
  489. std::array<int, 6> inbr;
  490. GetNeighborhood(inbr);
  491. for (int i = 0; i < 6; ++i)
  492. {
  493. nbr[i] = index + inbr[i];
  494. }
  495. }
  496. void GetNeighborhood(int x, int y, int z, std::array<size_t, 18>& nbr) const
  497. {
  498. size_t index = GetIndex(x, y, z);
  499. std::array<int, 18> inbr;
  500. GetNeighborhood(inbr);
  501. for (int i = 0; i < 18; ++i)
  502. {
  503. nbr[i] = index + inbr[i];
  504. }
  505. }
  506. void GetNeighborhood(int x, int y, int z, std::array<size_t, 26>& nbr) const
  507. {
  508. size_t index = GetIndex(x, y, z);
  509. std::array<int, 26> inbr;
  510. GetNeighborhood(inbr);
  511. for (int i = 0; i < 26; ++i)
  512. {
  513. nbr[i] = index + inbr[i];
  514. }
  515. }
  516. void GetCorners(int x, int y, int z, std::array<size_t, 8>& nbr) const
  517. {
  518. size_t index = GetIndex(x, y, z);
  519. std::array<int, 8> inbr;
  520. GetCorners(inbr);
  521. for (int i = 0; i < 8; ++i)
  522. {
  523. nbr[i] = index + inbr[i];
  524. }
  525. }
  526. void GetFull(int x, int y, int z, std::array<size_t, 27>& nbr) const
  527. {
  528. size_t index = GetIndex(x, y, z);
  529. std::array<int, 27> inbr;
  530. GetFull(inbr);
  531. for (int i = 0; i < 27; ++i)
  532. {
  533. nbr[i] = index + inbr[i];
  534. }
  535. }
  536. // The neighborhoods can be accessed as 3-tuples using these
  537. // functions. The first five functions provide 3-tuples relative to
  538. // any voxel location; these depend only on the image dimensions. The
  539. // last five functions provide 3-tuples for the actual voxels in the
  540. // neighborhood; no clamping is used when (x,y,z) is on the boundary.
  541. void GetNeighborhood(std::array<std::array<int, 3>, 6>& nbr) const
  542. {
  543. nbr[0] = { { -1, 0, 0 } };
  544. nbr[1] = { { +1, 0, 0 } };
  545. nbr[2] = { { 0, -1, 0 } };
  546. nbr[3] = { { 0, +1, 0 } };
  547. nbr[4] = { { 0, 0, -1 } };
  548. nbr[5] = { { 0, 0, +1 } };
  549. }
  550. void GetNeighborhood(std::array<std::array<int, 3>, 18>& nbr) const
  551. {
  552. nbr[0] = { { -1, 0, 0 } };
  553. nbr[1] = { { +1, 0, 0 } };
  554. nbr[2] = { { 0, -1, 0 } };
  555. nbr[3] = { { 0, +1, 0 } };
  556. nbr[4] = { { 0, 0, -1 } };
  557. nbr[5] = { { 0, 0, +1 } };
  558. nbr[6] = { { -1, -1, 0 } };
  559. nbr[7] = { { +1, -1, 0 } };
  560. nbr[8] = { { -1, +1, 0 } };
  561. nbr[9] = { { +1, +1, 0 } };
  562. nbr[10] = { { -1, 0, +1 } };
  563. nbr[11] = { { +1, 0, +1 } };
  564. nbr[12] = { { 0, -1, +1 } };
  565. nbr[13] = { { 0, +1, +1 } };
  566. nbr[14] = { { -1, 0, -1 } };
  567. nbr[15] = { { +1, 0, -1 } };
  568. nbr[16] = { { 0, -1, -1 } };
  569. nbr[17] = { { 0, +1, -1 } };
  570. }
  571. void GetNeighborhood(std::array<std::array<int, 3>, 26>& nbr) const
  572. {
  573. nbr[0] = { { -1, 0, 0 } };
  574. nbr[1] = { { +1, 0, 0 } };
  575. nbr[2] = { { 0, -1, 0 } };
  576. nbr[3] = { { 0, +1, 0 } };
  577. nbr[4] = { { 0, 0, -1 } };
  578. nbr[5] = { { 0, 0, +1 } };
  579. nbr[6] = { { -1, -1, 0 } };
  580. nbr[7] = { { +1, -1, 0 } };
  581. nbr[8] = { { -1, +1, 0 } };
  582. nbr[9] = { { +1, +1, 0 } };
  583. nbr[10] = { { -1, 0, +1 } };
  584. nbr[11] = { { +1, 0, +1 } };
  585. nbr[12] = { { 0, -1, +1 } };
  586. nbr[13] = { { 0, +1, +1 } };
  587. nbr[14] = { { -1, 0, -1 } };
  588. nbr[15] = { { +1, 0, -1 } };
  589. nbr[16] = { { 0, -1, -1 } };
  590. nbr[17] = { { 0, +1, -1 } };
  591. nbr[18] = { { -1, -1, -1 } };
  592. nbr[19] = { { +1, -1, -1 } };
  593. nbr[20] = { { -1, +1, -1 } };
  594. nbr[21] = { { +1, +1, -1 } };
  595. nbr[22] = { { -1, -1, +1 } };
  596. nbr[23] = { { +1, -1, +1 } };
  597. nbr[24] = { { -1, +1, +1 } };
  598. nbr[25] = { { +1, +1, +1 } };
  599. }
  600. void GetCorners(std::array<std::array<int, 3>, 8>& nbr) const
  601. {
  602. nbr[0] = { { 0, 0, 0 } };
  603. nbr[1] = { { 1, 0, 0 } };
  604. nbr[2] = { { 0, 1, 0 } };
  605. nbr[3] = { { 1, 1, 0 } };
  606. nbr[4] = { { 0, 0, 1 } };
  607. nbr[5] = { { 1, 0, 1 } };
  608. nbr[6] = { { 0, 1, 1 } };
  609. nbr[7] = { { 1, 1, 1 } };
  610. }
  611. void GetFull(std::array<std::array<int, 3>, 27>& nbr) const
  612. {
  613. nbr[0] = { { -1, -1, -1 } };
  614. nbr[1] = { { 0, -1, -1 } };
  615. nbr[2] = { { +1, -1, -1 } };
  616. nbr[3] = { { -1, 0, -1 } };
  617. nbr[4] = { { 0, 0, -1 } };
  618. nbr[5] = { { +1, 0, -1 } };
  619. nbr[6] = { { -1, +1, -1 } };
  620. nbr[7] = { { 0, +1, -1 } };
  621. nbr[8] = { { +1, +1, -1 } };
  622. nbr[9] = { { -1, -1, 0 } };
  623. nbr[10] = { { 0, -1, 0 } };
  624. nbr[11] = { { +1, -1, 0 } };
  625. nbr[12] = { { -1, 0, 0 } };
  626. nbr[13] = { { 0, 0, 0 } };
  627. nbr[14] = { { +1, 0, 0 } };
  628. nbr[15] = { { -1, +1, 0 } };
  629. nbr[16] = { { 0, +1, 0 } };
  630. nbr[17] = { { +1, +1, 0 } };
  631. nbr[18] = { { -1, -1, +1 } };
  632. nbr[19] = { { 0, -1, +1 } };
  633. nbr[20] = { { +1, -1, +1 } };
  634. nbr[21] = { { -1, 0, +1 } };
  635. nbr[22] = { { 0, 0, +1 } };
  636. nbr[23] = { { +1, 0, +1 } };
  637. nbr[24] = { { -1, +1, +1 } };
  638. nbr[25] = { { 0, +1, +1 } };
  639. nbr[26] = { { +1, +1, +1 } };
  640. }
  641. void GetNeighborhood(int x, int y, int z, std::array<std::array<size_t, 3>, 6>& nbr) const
  642. {
  643. std::array<std::array<int, 3>, 6> inbr;
  644. GetNeighborhood(inbr);
  645. for (int i = 0; i < 6; ++i)
  646. {
  647. nbr[i][0] = static_cast<size_t>(x) + inbr[i][0];
  648. nbr[i][1] = static_cast<size_t>(y) + inbr[i][1];
  649. nbr[i][2] = static_cast<size_t>(z) + inbr[i][2];
  650. }
  651. }
  652. void GetNeighborhood(int x, int y, int z, std::array<std::array<size_t, 3>, 18>& nbr) const
  653. {
  654. std::array<std::array<int, 3>, 18> inbr;
  655. GetNeighborhood(inbr);
  656. for (int i = 0; i < 18; ++i)
  657. {
  658. nbr[i][0] = static_cast<size_t>(x) + inbr[i][0];
  659. nbr[i][1] = static_cast<size_t>(y) + inbr[i][1];
  660. nbr[i][2] = static_cast<size_t>(z) + inbr[i][2];
  661. }
  662. }
  663. void GetNeighborhood(int x, int y, int z, std::array<std::array<size_t, 3>, 26>& nbr) const
  664. {
  665. std::array<std::array<int, 3>, 26> inbr;
  666. GetNeighborhood(inbr);
  667. for (int i = 0; i < 26; ++i)
  668. {
  669. nbr[i][0] = static_cast<size_t>(x) + inbr[i][0];
  670. nbr[i][1] = static_cast<size_t>(y) + inbr[i][1];
  671. nbr[i][2] = static_cast<size_t>(z) + inbr[i][2];
  672. }
  673. }
  674. void GetCorners(int x, int y, int z, std::array<std::array<size_t, 3>, 8>& nbr) const
  675. {
  676. std::array<std::array<int, 3>, 8> inbr;
  677. GetCorners(inbr);
  678. for (int i = 0; i < 8; ++i)
  679. {
  680. nbr[i][0] = static_cast<size_t>(x) + inbr[i][0];
  681. nbr[i][1] = static_cast<size_t>(y) + inbr[i][1];
  682. nbr[i][2] = static_cast<size_t>(z) + inbr[i][2];
  683. }
  684. }
  685. void GetFull(int x, int y, int z, std::array<std::array<size_t, 3>, 27>& nbr) const
  686. {
  687. std::array<std::array<int, 3>, 27> inbr;
  688. GetFull(inbr);
  689. for (int i = 0; i < 27; ++i)
  690. {
  691. nbr[i][0] = static_cast<size_t>(x) + inbr[i][0];
  692. nbr[i][1] = static_cast<size_t>(y) + inbr[i][1];
  693. nbr[i][2] = static_cast<size_t>(z) + inbr[i][2];
  694. }
  695. }
  696. };
  697. }