1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #ifndef OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED
5 #define OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED
6
7 #include <functional>// for std::hash
8 #include <algorithm> // for std::min(), std::max()
9 #include <array> // for std::array
10 #include <iostream>
11 #include <limits>
12 #include <openvdb/Platform.h>
13 #include "Math.h"
14 #include "Vec3.h"
15
16 #include <tbb/blocked_range.h> // for tbb::split
17
18 namespace openvdb {
19 OPENVDB_USE_VERSION_NAMESPACE
20 namespace OPENVDB_VERSION_NAME {
21 namespace math {
22
23 /// @brief Signed (x, y, z) 32-bit integer coordinates
24 class Coord
25 {
26 public:
27 using Int32 = int32_t;
28 using Index32 = uint32_t;
29 using Vec3i = Vec3<Int32>;
30 using Vec3I = Vec3<Index32>;
31
32 using ValueType = Int32;
33 using Limits = std::numeric_limits<ValueType>;
34
Coord()35 Coord(): mVec{{0, 0, 0}} {}
Coord(Int32 xyz)36 explicit Coord(Int32 xyz): mVec{{xyz, xyz, xyz}} {}
Coord(Int32 x,Int32 y,Int32 z)37 Coord(Int32 x, Int32 y, Int32 z): mVec{{x, y, z}} {}
Coord(const Vec3i & v)38 explicit Coord(const Vec3i& v): mVec{{v[0], v[1], v[2]}} {}
Coord(const Vec3I & v)39 explicit Coord(const Vec3I& v): mVec{{Int32(v[0]), Int32(v[1]), Int32(v[2])}} {}
Coord(const Int32 * v)40 explicit Coord(const Int32* v): mVec{{v[0], v[1], v[2]}} {}
41
42 /// @brief Return the smallest possible coordinate
min()43 static Coord min() { return Coord(Limits::min()); }
44
45 /// @brief Return the largest possible coordinate
max()46 static Coord max() { return Coord(Limits::max()); }
47
48 /// @brief Return @a xyz rounded to the closest integer coordinates
49 /// (cell centered conversion).
round(const Vec3<T> & xyz)50 template<typename T> static Coord round(const Vec3<T>& xyz)
51 {
52 return Coord(Int32(Round(xyz[0])), Int32(Round(xyz[1])), Int32(Round(xyz[2])));
53 }
54 /// @brief Return the largest integer coordinates that are not greater
55 /// than @a xyz (node centered conversion).
floor(const Vec3<T> & xyz)56 template<typename T> static Coord floor(const Vec3<T>& xyz)
57 {
58 return Coord(Int32(Floor(xyz[0])), Int32(Floor(xyz[1])), Int32(Floor(xyz[2])));
59 }
60
61 /// @brief Return the largest integer coordinates that are not greater
62 /// than @a xyz+1 (node centered conversion).
ceil(const Vec3<T> & xyz)63 template<typename T> static Coord ceil(const Vec3<T>& xyz)
64 {
65 return Coord(Int32(Ceil(xyz[0])), Int32(Ceil(xyz[1])), Int32(Ceil(xyz[2])));
66 }
67
68 /// @brief Reset all three coordinates with the specified arguments
reset(Int32 x,Int32 y,Int32 z)69 Coord& reset(Int32 x, Int32 y, Int32 z)
70 {
71 mVec[0] = x;
72 mVec[1] = y;
73 mVec[2] = z;
74 return *this;
75 }
76 /// @brief Reset all three coordinates with the same specified argument
reset(Int32 xyz)77 Coord& reset(Int32 xyz) { return this->reset(xyz, xyz, xyz); }
78
setX(Int32 x)79 Coord& setX(Int32 x) { mVec[0] = x; return *this; }
setY(Int32 y)80 Coord& setY(Int32 y) { mVec[1] = y; return *this; }
setZ(Int32 z)81 Coord& setZ(Int32 z) { mVec[2] = z; return *this; }
82
offset(Int32 dx,Int32 dy,Int32 dz)83 Coord& offset(Int32 dx, Int32 dy, Int32 dz)
84 {
85 mVec[0] += dx;
86 mVec[1] += dy;
87 mVec[2] += dz;
88 return *this;
89 }
offset(Int32 n)90 Coord& offset(Int32 n) { return this->offset(n, n, n); }
offsetBy(Int32 dx,Int32 dy,Int32 dz)91 Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
92 {
93 return Coord(mVec[0] + dx, mVec[1] + dy, mVec[2] + dz);
94 }
offsetBy(Int32 n)95 Coord offsetBy(Int32 n) const { return offsetBy(n, n, n); }
96
97 Coord& operator+=(const Coord& rhs)
98 {
99 mVec[0] += rhs[0];
100 mVec[1] += rhs[1];
101 mVec[2] += rhs[2];
102 return *this;
103 }
104 Coord& operator-=(const Coord& rhs)
105 {
106 mVec[0] -= rhs[0];
107 mVec[1] -= rhs[1];
108 mVec[2] -= rhs[2];
109 return *this;
110 }
111 Coord operator+(const Coord& rhs) const
112 {
113 return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]);
114 }
115 Coord operator-(const Coord& rhs) const
116 {
117 return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]);
118 }
119 Coord operator-() const { return Coord(-mVec[0], -mVec[1], -mVec[2]); }
120
121 Coord operator>> (size_t n) const { return Coord(mVec[0]>>n, mVec[1]>>n, mVec[2]>>n); }
122 Coord operator<< (size_t n) const { return Coord(mVec[0]<<n, mVec[1]<<n, mVec[2]<<n); }
123 Coord& operator<<=(size_t n) { mVec[0]<<=n; mVec[1]<<=n; mVec[2]<<=n; return *this; }
124 Coord& operator>>=(size_t n) { mVec[0]>>=n; mVec[1]>>=n; mVec[2]>>=n; return *this; }
125 Coord operator& (Int32 n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); }
126 Coord operator| (Int32 n) const { return Coord(mVec[0] | n, mVec[1] | n, mVec[2] | n); }
127 Coord& operator&= (Int32 n) { mVec[0]&=n; mVec[1]&=n; mVec[2]&=n; return *this; }
128 Coord& operator|= (Int32 n) { mVec[0]|=n; mVec[1]|=n; mVec[2]|=n; return *this; }
129
x()130 Int32 x() const { return mVec[0]; }
y()131 Int32 y() const { return mVec[1]; }
z()132 Int32 z() const { return mVec[2]; }
133 Int32 operator[](size_t i) const { assert(i < 3); return mVec[i]; }
x()134 Int32& x() { return mVec[0]; }
y()135 Int32& y() { return mVec[1]; }
z()136 Int32& z() { return mVec[2]; }
137 Int32& operator[](size_t i) { assert(i < 3); return mVec[i]; }
138
data()139 const Int32* data() const { return mVec.data(); }
data()140 Int32* data() { return mVec.data(); }
asPointer()141 const Int32* asPointer() const { return mVec.data(); }
asPointer()142 Int32* asPointer() { return mVec.data(); }
asVec3d()143 Vec3d asVec3d() const { return Vec3d(double(mVec[0]), double(mVec[1]), double(mVec[2])); }
asVec3s()144 Vec3s asVec3s() const { return Vec3s(float(mVec[0]), float(mVec[1]), float(mVec[2])); }
asVec3i()145 Vec3i asVec3i() const { return Vec3i(mVec.data()); }
asVec3I()146 Vec3I asVec3I() const { return Vec3I(Index32(mVec[0]), Index32(mVec[1]), Index32(mVec[2])); }
asXYZ(Int32 & x,Int32 & y,Int32 & z)147 void asXYZ(Int32& x, Int32& y, Int32& z) const { x = mVec[0]; y = mVec[1]; z = mVec[2]; }
148
149 bool operator==(const Coord& rhs) const
150 {
151 return (mVec[0] == rhs.mVec[0] && mVec[1] == rhs.mVec[1] && mVec[2] == rhs.mVec[2]);
152 }
153 bool operator!=(const Coord& rhs) const { return !(*this == rhs); }
154
155 /// Lexicographic less than
156 bool operator<(const Coord& rhs) const
157 {
158 return this->x() < rhs.x() ? true : this->x() > rhs.x() ? false
159 : this->y() < rhs.y() ? true : this->y() > rhs.y() ? false
160 : this->z() < rhs.z() ? true : false;
161 }
162 /// Lexicographic less than or equal to
163 bool operator<=(const Coord& rhs) const
164 {
165 return this->x() < rhs.x() ? true : this->x() > rhs.x() ? false
166 : this->y() < rhs.y() ? true : this->y() > rhs.y() ? false
167 : this->z() <=rhs.z() ? true : false;
168 }
169 /// Lexicographic greater than
170 bool operator>(const Coord& rhs) const { return !(*this <= rhs); }
171 /// Lexicographic greater than or equal to
172 bool operator>=(const Coord& rhs) const { return !(*this < rhs); }
173
174 /// Perform a component-wise minimum with the other Coord.
minComponent(const Coord & other)175 void minComponent(const Coord& other)
176 {
177 mVec[0] = std::min(mVec[0], other.mVec[0]);
178 mVec[1] = std::min(mVec[1], other.mVec[1]);
179 mVec[2] = std::min(mVec[2], other.mVec[2]);
180 }
181
182 /// Perform a component-wise maximum with the other Coord.
maxComponent(const Coord & other)183 void maxComponent(const Coord& other)
184 {
185 mVec[0] = std::max(mVec[0], other.mVec[0]);
186 mVec[1] = std::max(mVec[1], other.mVec[1]);
187 mVec[2] = std::max(mVec[2], other.mVec[2]);
188 }
189
190 /// Return the component-wise minimum of the two Coords.
minComponent(const Coord & lhs,const Coord & rhs)191 static inline Coord minComponent(const Coord& lhs, const Coord& rhs)
192 {
193 return Coord(std::min(lhs.x(), rhs.x()),
194 std::min(lhs.y(), rhs.y()),
195 std::min(lhs.z(), rhs.z()));
196 }
197
198 /// Return the component-wise maximum of the two Coords.
maxComponent(const Coord & lhs,const Coord & rhs)199 static inline Coord maxComponent(const Coord& lhs, const Coord& rhs)
200 {
201 return Coord(std::max(lhs.x(), rhs.x()),
202 std::max(lhs.y(), rhs.y()),
203 std::max(lhs.z(), rhs.z()));
204 }
205
206 /// Return true if any of the components of @a a are smaller than the
207 /// corresponding components of @a b.
lessThan(const Coord & a,const Coord & b)208 static inline bool lessThan(const Coord& a, const Coord& b)
209 {
210 return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]);
211 }
212
213 /// @brief Return the index (0, 1 or 2) with the smallest value.
minIndex()214 size_t minIndex() const { return MinIndex(mVec); }
215
216 /// @brief Return the index (0, 1 or 2) with the largest value.
maxIndex()217 size_t maxIndex() const { return MaxIndex(mVec); }
218
read(std::istream & is)219 void read(std::istream& is) { is.read(reinterpret_cast<char*>(mVec.data()), sizeof(mVec)); }
write(std::ostream & os)220 void write(std::ostream& os) const
221 {
222 os.write(reinterpret_cast<const char*>(mVec.data()), sizeof(mVec));
223 }
224
225 /// @brief Return a hash value for this coordinate
226 /// @note Log2N is the binary logarithm of the hash table size.
227 /// @details The hash function is taken from the SIGGRAPH paper:
228 /// "VDB: High-resolution sparse volumes with dynamic topology"
229 template<int Log2N = 20>
hash()230 size_t hash() const
231 {
232 return ((1<<Log2N)-1) & (mVec[0]*73856093 ^ mVec[1]*19349663 ^ mVec[2]*83492791);
233 }
234
235 private:
236 std::array<Int32, 3> mVec;
237 }; // class Coord
238
239
240 ////////////////////////////////////////
241
242
243 /// @brief Axis-aligned bounding box of signed integer coordinates
244 /// @note The range of the integer coordinates, [min, max], is inclusive.
245 /// Thus, a bounding box with min = max is not empty but rather encloses
246 /// a single coordinate.
247 class CoordBBox
248 {
249 public:
250 using Index64 = uint64_t;
251 using ValueType = Coord::ValueType;
252
253 /// @brief Iterator over the Coord domain covered by a CoordBBox
254 /// @note If ZYXOrder is @c true, @e z is the fastest-moving coordinate,
255 /// otherwise the traversal is in XYZ order (i.e., @e x is fastest-moving).
256 template<bool ZYXOrder>
257 class Iterator
258 {
259 public:
260 /// @brief C-tor from a bounding box
Iterator(const CoordBBox & b)261 Iterator(const CoordBBox& b): mPos(b.min()), mMin(b.min()), mMax(b.max()) {}
262 /// @brief Increment the iterator to point to the next coordinate.
263 /// @details Iteration stops one past the maximum coordinate
264 /// along the axis determined by the template parameter.
265 Iterator& operator++() { ZYXOrder ? next<2,1,0>() : next<0,1,2>(); return *this; }
266 /// @brief Return @c true if the iterator still points to a valid coordinate.
267 operator bool() const { return ZYXOrder ? (mPos[0] <= mMax[0]) : (mPos[2] <= mMax[2]); }
268 /// @brief Return a const reference to the coordinate currently pointed to.
269 const Coord& operator*() const { return mPos; }
270 /// Return @c true if this iterator and the given iterator point to the same coordinate.
271 bool operator==(const Iterator& other) const
272 {
273 return ((mPos == other.mPos) && (mMin == other.mMin) && (mMax == other.mMax));
274 }
275 /// Return @c true if this iterator and the given iterator point to different coordinates.
276 bool operator!=(const Iterator& other) const { return !(*this == other); }
277 private:
278 template<size_t a, size_t b, size_t c>
next()279 void next()
280 {
281 if (mPos[a] < mMax[a]) { ++mPos[a]; } // this is the most common case
282 else if (mPos[b] < mMax[b]) { mPos[a] = mMin[a]; ++mPos[b]; }
283 else if (mPos[c] <= mMax[c]) { mPos[a] = mMin[a]; mPos[b] = mMin[b]; ++mPos[c]; }
284 }
285 Coord mPos, mMin, mMax;
286 friend class CoordBBox; // for CoordBBox::end()
287 };// CoordBBox::Iterator
288
289 using ZYXIterator = Iterator</*ZYX=*/true>;
290 using XYZIterator = Iterator</*ZYX=*/false>;
291
292 /// @brief The default constructor produces an empty bounding box.
CoordBBox()293 CoordBBox(): mMin(Coord::max()), mMax(Coord::min()) {}
294 /// @brief Construct a bounding box with the given @a min and @a max bounds.
CoordBBox(const Coord & min,const Coord & max)295 CoordBBox(const Coord& min, const Coord& max): mMin(min), mMax(max) {}
296 /// @brief Construct from individual components of the min and max bounds.
CoordBBox(ValueType xMin,ValueType yMin,ValueType zMin,ValueType xMax,ValueType yMax,ValueType zMax)297 CoordBBox(ValueType xMin, ValueType yMin, ValueType zMin,
298 ValueType xMax, ValueType yMax, ValueType zMax)
299 : mMin(xMin, yMin, zMin), mMax(xMax, yMax, zMax)
300 {
301 }
302 /// @brief Splitting constructor for use in TBB ranges
303 /// @note The other bounding box is assumed to be divisible.
CoordBBox(CoordBBox & other,const tbb::split &)304 CoordBBox(CoordBBox& other, const tbb::split&): mMin(other.mMin), mMax(other.mMax)
305 {
306 assert(this->is_divisible());
307 const size_t n = this->maxExtent();
308 mMax[n] = (mMin[n] + mMax[n]) >> 1;
309 other.mMin[n] = mMax[n] + 1;
310 }
311
createCube(const Coord & min,ValueType dim)312 static CoordBBox createCube(const Coord& min, ValueType dim)
313 {
314 return CoordBBox(min, min.offsetBy(dim - 1));
315 }
316
317 /// Return an "infinite" bounding box, as defined by the Coord value range.
inf()318 static CoordBBox inf() { return CoordBBox(Coord::min(), Coord::max()); }
319
min()320 const Coord& min() const { return mMin; }
max()321 const Coord& max() const { return mMax; }
322
min()323 Coord& min() { return mMin; }
max()324 Coord& max() { return mMax; }
325
reset()326 void reset() { mMin = Coord::max(); mMax = Coord::min(); }
reset(const Coord & min,const Coord & max)327 void reset(const Coord& min, const Coord& max) { mMin = min; mMax = max; }
resetToCube(const Coord & min,ValueType dim)328 void resetToCube(const Coord& min, ValueType dim) { mMin = min; mMax = min.offsetBy(dim - 1); }
329
330 /// @brief Return the minimum coordinate.
331 /// @note The start coordinate is inclusive.
getStart()332 Coord getStart() const { return mMin; }
333 /// @brief Return the maximum coordinate plus one.
334 /// @note This end coordinate is exclusive.
getEnd()335 Coord getEnd() const { return mMax.offsetBy(1); }
336
337 /// @brief Return a ZYX-order iterator that points to the minimum coordinate.
begin()338 ZYXIterator begin() const { return ZYXIterator{*this}; }
339 /// @brief Return a ZYX-order iterator that points to the minimum coordinate.
beginZYX()340 ZYXIterator beginZYX() const { return ZYXIterator{*this}; }
341 /// @brief Return an XYZ-order iterator that points to the minimum coordinate.
beginXYZ()342 XYZIterator beginXYZ() const { return XYZIterator{*this}; }
343
344 /// @brief Return a ZYX-order iterator that points past the maximum coordinate.
end()345 ZYXIterator end() const { ZYXIterator it{*this}; it.mPos[0] = mMax[0] + 1; return it; }
346 /// @brief Return a ZYX-order iterator that points past the maximum coordinate.
endZYX()347 ZYXIterator endZYX() const { return end(); }
348 /// @brief Return an XYZ-order iterator that points past the maximum coordinate.
endXYZ()349 XYZIterator endXYZ() const { XYZIterator it{*this}; it.mPos[2] = mMax[2] + 1; return it; }
350
351 bool operator==(const CoordBBox& rhs) const { return mMin == rhs.mMin && mMax == rhs.mMax; }
352 bool operator!=(const CoordBBox& rhs) const { return !(*this == rhs); }
353
354 /// @brief Return @c true if this bounding box is empty (i.e., encloses no coordinates).
empty()355 bool empty() const
356 {
357 #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
358 #pragma GCC diagnostic push
359 #pragma GCC diagnostic ignored "-Wstrict-overflow"
360 #endif
361 return (mMin[0] > mMax[0] || mMin[1] > mMax[1] || mMin[2] > mMax[2]);
362 #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
363 #pragma GCC diagnostic pop
364 #endif
365 }
366 /// @brief Return @c true if this bounding box is nonempty
367 /// (i.e., encloses at least one coordinate).
368 operator bool() const { return !this->empty(); }
369 /// @brief Return @c true if this bounding box is nonempty
370 /// (i.e., encloses at least one coordinate).
hasVolume()371 bool hasVolume() const { return !this->empty(); }
372
373 /// @brief Return the floating-point position of the center of this bounding box.
getCenter()374 Vec3d getCenter() const { return 0.5 * Vec3d((mMin + mMax).asPointer()); }
375
376 /// @brief Return the dimensions of the coordinates spanned by this bounding box.
377 /// @note Since coordinates are inclusive, a bounding box with min = max
378 /// has dimensions of (1, 1, 1).
dim()379 Coord dim() const { return empty() ? Coord(0) : (mMax.offsetBy(1) - mMin); }
380 /// @todo deprecate - use dim instead
extents()381 Coord extents() const { return this->dim(); }
382 /// @brief Return the integer volume of coordinates spanned by this bounding box.
383 /// @note Since coordinates are inclusive, a bounding box with min = max has volume one.
volume()384 Index64 volume() const
385 {
386 const Coord d = this->dim();
387 return Index64(d[0]) * Index64(d[1]) * Index64(d[2]);
388 }
389 /// @brief Return @c true if this bounding box can be subdivided [mainly for use by TBB].
is_divisible()390 bool is_divisible() const { return mMin[0]<mMax[0] && mMin[1]<mMax[1] && mMin[2]<mMax[2]; }
391
392 /// @brief Return the index (0, 1 or 2) of the shortest axis.
minExtent()393 size_t minExtent() const { return this->dim().minIndex(); }
394
395 /// @brief Return the index (0, 1 or 2) of the longest axis.
maxExtent()396 size_t maxExtent() const { return this->dim().maxIndex(); }
397
398 /// @brief Return @c true if point (x, y, z) is inside this bounding box.
isInside(const Coord & xyz)399 bool isInside(const Coord& xyz) const
400 {
401 return !(Coord::lessThan(xyz,mMin) || Coord::lessThan(mMax,xyz));
402 }
403
404 /// @brief Return @c true if the given bounding box is inside this bounding box.
isInside(const CoordBBox & b)405 bool isInside(const CoordBBox& b) const
406 {
407 return !(Coord::lessThan(b.mMin,mMin) || Coord::lessThan(mMax,b.mMax));
408 }
409
410 /// @brief Return @c true if the given bounding box overlaps with this bounding box.
hasOverlap(const CoordBBox & b)411 bool hasOverlap(const CoordBBox& b) const
412 {
413 return !(Coord::lessThan(mMax,b.mMin) || Coord::lessThan(b.mMax,mMin));
414 }
415
416 /// @brief Pad this bounding box with the specified padding.
expand(ValueType padding)417 void expand(ValueType padding)
418 {
419 mMin.offset(-padding);
420 mMax.offset( padding);
421 }
422
423 /// @brief Return a new instance that is expanded by the specified padding.
expandBy(ValueType padding)424 CoordBBox expandBy(ValueType padding) const
425 {
426 return CoordBBox(mMin.offsetBy(-padding),mMax.offsetBy(padding));
427 }
428
429 /// @brief Expand this bounding box to enclose point (x, y, z).
expand(const Coord & xyz)430 void expand(const Coord& xyz)
431 {
432 mMin.minComponent(xyz);
433 mMax.maxComponent(xyz);
434 }
435
436 /// @brief Union this bounding box with the given bounding box.
expand(const CoordBBox & bbox)437 void expand(const CoordBBox& bbox)
438 {
439 mMin.minComponent(bbox.min());
440 mMax.maxComponent(bbox.max());
441 }
442 /// @brief Intersect this bounding box with the given bounding box.
intersect(const CoordBBox & bbox)443 void intersect(const CoordBBox& bbox)
444 {
445 mMin.maxComponent(bbox.min());
446 mMax.minComponent(bbox.max());
447 }
448 /// @brief Union this bounding box with the cubical bounding box
449 /// of the given size and with the given minimum coordinates.
expand(const Coord & min,Coord::ValueType dim)450 void expand(const Coord& min, Coord::ValueType dim)
451 {
452 mMin.minComponent(min);
453 mMax.maxComponent(min.offsetBy(dim-1));
454 }
455 /// @brief Translate this bounding box by
456 /// (<i>t<sub>x</sub></i>, <i>t<sub>y</sub></i>, <i>t<sub>z</sub></i>).
translate(const Coord & t)457 void translate(const Coord& t) { mMin += t; mMax += t; }
458
459 /// @brief Move this bounding box to the specified min
moveMin(const Coord & min)460 void moveMin(const Coord& min) { mMax += min - mMin; mMin = min; }
461
462 /// @brief Move this bounding box to the specified max
moveMax(const Coord & max)463 void moveMax(const Coord& max) { mMin += max - mMax; mMax = max; }
464
465 /// @brief Populates an array with the eight corner points of this bounding box.
466 /// @details The ordering of the corner points is lexicographic.
467 /// @warning It is assumed that the pointer can be incremented at
468 /// least seven times, i.e. has storage for eight Coord elements!
getCornerPoints(Coord * p)469 void getCornerPoints(Coord *p) const
470 {
471 assert(p != nullptr);
472 p->reset(mMin.x(), mMin.y(), mMin.z()); ++p;
473 p->reset(mMin.x(), mMin.y(), mMax.z()); ++p;
474 p->reset(mMin.x(), mMax.y(), mMin.z()); ++p;
475 p->reset(mMin.x(), mMax.y(), mMax.z()); ++p;
476 p->reset(mMax.x(), mMin.y(), mMin.z()); ++p;
477 p->reset(mMax.x(), mMin.y(), mMax.z()); ++p;
478 p->reset(mMax.x(), mMax.y(), mMin.z()); ++p;
479 p->reset(mMax.x(), mMax.y(), mMax.z());
480 }
481
482 //@{
483 /// @brief Bit-wise operations performed on both the min and max members
484 CoordBBox operator>> (size_t n) const { return CoordBBox(mMin>>n, mMax>>n); }
485 CoordBBox operator<< (size_t n) const { return CoordBBox(mMin<<n, mMax<<n); }
486 CoordBBox& operator<<=(size_t n) { mMin <<= n; mMax <<= n; return *this; }
487 CoordBBox& operator>>=(size_t n) { mMin >>= n; mMax >>= n; return *this; }
488 CoordBBox operator& (Coord::Int32 n) const { return CoordBBox(mMin & n, mMax & n); }
489 CoordBBox operator| (Coord::Int32 n) const { return CoordBBox(mMin | n, mMax | n); }
490 CoordBBox& operator&= (Coord::Int32 n) { mMin &= n; mMax &= n; return *this; }
491 CoordBBox& operator|= (Coord::Int32 n) { mMin |= n; mMax |= n; return *this; }
492 //@}
493
494 /// @brief Unserialize this bounding box from the given stream.
read(std::istream & is)495 void read(std::istream& is) { mMin.read(is); mMax.read(is); }
496 /// @brief Serialize this bounding box to the given stream.
write(std::ostream & os)497 void write(std::ostream& os) const { mMin.write(os); mMax.write(os); }
498
499 private:
500 Coord mMin, mMax;
501 }; // class CoordBBox
502
503
504 ////////////////////////////////////////
505
506
507 inline std::ostream& operator<<(std::ostream& os, const Coord& xyz)
508 {
509 os << xyz.asVec3i(); return os;
510 }
511
512
513 inline Coord
Abs(const Coord & xyz)514 Abs(const Coord& xyz)
515 {
516 return Coord(Abs(xyz[0]), Abs(xyz[1]), Abs(xyz[2]));
517 }
518
519
520 //@{
521 /// Allow a Coord to be added to or subtracted from a Vec3.
522 template<typename T>
523 inline Vec3<typename promote<T, typename Coord::ValueType>::type>
524 operator+(const Vec3<T>& v0, const Coord& v1)
525 {
526 Vec3<typename promote<T, typename Coord::ValueType>::type> result(v0);
527 result[0] += v1[0];
528 result[1] += v1[1];
529 result[2] += v1[2];
530 return result;
531 }
532
533 template<typename T>
534 inline Vec3<typename promote<T, typename Coord::ValueType>::type>
535 operator+(const Coord& v1, const Vec3<T>& v0)
536 {
537 Vec3<typename promote<T, typename Coord::ValueType>::type> result(v0);
538 result[0] += v1[0];
539 result[1] += v1[1];
540 result[2] += v1[2];
541 return result;
542 }
543 //@}
544
545
546 //@{
547 /// Allow a Coord to be subtracted from a Vec3.
548 template <typename T>
549 inline Vec3<typename promote<T, Coord::ValueType>::type>
550 operator-(const Vec3<T>& v0, const Coord& v1)
551 {
552 Vec3<typename promote<T, Coord::ValueType>::type> result(v0);
553 result[0] -= v1[0];
554 result[1] -= v1[1];
555 result[2] -= v1[2];
556 return result;
557 }
558
559 template <typename T>
560 inline Vec3<typename promote<T, Coord::ValueType>::type>
561 operator-(const Coord& v1, const Vec3<T>& v0)
562 {
563 Vec3<typename promote<T, Coord::ValueType>::type> result(v0);
564 result[0] -= v1[0];
565 result[1] -= v1[1];
566 result[2] -= v1[2];
567 return -result;
568 }
569 //@}
570
571 inline std::ostream&
572 operator<<(std::ostream& os, const CoordBBox& b)
573 {
574 os << b.min() << " -> " << b.max();
575 return os;
576 }
577
578 } // namespace math
579 } // namespace OPENVDB_VERSION_NAME
580 } // namespace openvdb
581
582 ////////////////////////////////////////
583
584 // template specialization of std::hash with Coord, which
585 // allows for Coord to be used as the key in std::unordered_map
586 namespace std {// injected in namespace std
587
588 template<>
589 struct hash<openvdb::math::Coord>
590 {
591 using Coord = openvdb::math::Coord;
592 using argument_type = Coord;
593 using result_type = std::size_t;
594 std::size_t operator()(const Coord& ijk) const noexcept { return ijk.Coord::hash<>(); }
595 };// std::hash<openvdb::math::Coord>
596
597 }// namespace std
598
599 #endif // OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED
600