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