MeshLib C++ Docs
Loading...
Searching...
No Matches
MRMesh/MRBox.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRMacros.h"
4#include "MRMeshFwd.h"
5#include "MRAffineXf3.h"
6#include "MRVectorTraits.h"
7#include <algorithm>
8#include <cassert>
9#include <iosfwd>
10#include <limits>
11#include <type_traits>
12
13namespace MR
14{
15
19
21template <typename T>
22std::array<Vector3<T>, 8> getCorners( const Box<Vector3<T>> & box );
23
25template <typename V>
26struct Box
27{
28public:
30 using T = typename VTraits::BaseType;
31 static constexpr int elements = VTraits::size;
32 using Vb = typename VTraits::template ChangeBaseType<bool>; //if V is Vector3<T> then Vb is Vector3b
34
35 V min, max;
36
38 const V & operator []( int e ) const { return *( &min + e ); }
39 V & operator []( int e ) { return *( &min + e ); }
40
42 Box() : min{ VTraits::diagonal( std::numeric_limits<T>::max() ) }, max{ VTraits::diagonal( std::numeric_limits<T>::lowest() ) } { }
43 Box( const V& min, const V& max ) : min{ min }, max{ max } { }
44
46 #if MR_HAS_REQUIRES
47 // If the compiler supports `requires`, use that instead of `std::enable_if` here.
48 // Not (only) because it looks cooler, but because of a bug in our binding generator that makes it choke on it: https://github.com/MeshInspector/mrbind/issues/19
49 explicit Box( NoInit ) requires (VectorTraits<V>::supportNoInit) : min{ noInit }, max{ noInit } { }
50 explicit Box( NoInit ) requires (!VectorTraits<V>::supportNoInit) { }
51 #else
52 template <typename VV = V, typename std::enable_if_t<VectorTraits<VV>::supportNoInit, int> = 0>
53 explicit Box( NoInit ) : min{ noInit }, max{ noInit } { }
54 template <typename VV = V, typename std::enable_if_t<!VectorTraits<VV>::supportNoInit, int> = 0>
55 explicit Box( NoInit ) { }
56 #endif
57
58 // Here `V == U` doesn't seem to cause any issues in the C++ code, but we're still disabling it because it somehow gets emitted
59 // when generating the bindings, and results in duplicate functions in C#.
60 template <typename U> MR_REQUIRES_IF_SUPPORTED( !std::is_same_v<V, U> )
61 explicit Box( const Box<U> & a ) : min{ a.min }, max{ a.max } { }
62
63 static Box fromMinAndSize( const V& min, const V& size ) { return Box{ min, V( min + size ) }; }
64
66 bool valid() const
67 {
68 for ( int i = 0; i < elements; ++i )
69 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, max ) )
70 return false;
71 return true;
72 }
73
75 V center() const { assert( valid() ); return ( min + max ) / T(2); }
76
80 V corner( const Vb& c ) const
81 {
82 V res;
83 for ( int i = 0; i < elements; ++i )
84 VTraits::getElem( i, res ) = VTraits::getElem( i, operator[]( VbTraits::getElem( i, c ) ) );
85 return res;
86 }
87
90 static Vb getMinBoxCorner( const V & n )
91 {
92 Vb res;
93 for ( int i = 0; i < elements; ++i )
94 VbTraits::getElem( i, res ) = VTraits::getElem( i, n ) < 0;
95 return res;
96 }
97
100 static Vb getMaxBoxCorner( const V & n )
101 {
102 return getMinBoxCorner( -n );
103 }
104
106 V size() const { assert( valid() ); return max - min; }
107
109 T diagonal() const { return std::sqrt( sqr( size() ) ); }
110
112 T volume() const
113 {
114 assert( valid() );
115 T res{ 1 };
116 for ( int i = 0; i < elements; ++i )
117 res *= VTraits::getElem( i, max ) - VTraits::getElem( i, min );
118 return res;
119 }
120
122 void include( const V & pt )
123 {
124 for ( int i = 0; i < elements; ++i )
125 {
126 if ( VTraits::getElem( i, pt ) < VTraits::getElem( i, min ) ) VTraits::getElem( i, min ) = VTraits::getElem( i, pt );
127 if ( VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) ) VTraits::getElem( i, max ) = VTraits::getElem( i, pt );
128 }
129 }
130
132 void include( const Box & b )
133 {
134 for ( int i = 0; i < elements; ++i )
135 {
136 if ( VTraits::getElem( i, b.min ) < VTraits::getElem( i, min ) ) VTraits::getElem( i, min ) = VTraits::getElem( i, b.min );
137 if ( VTraits::getElem( i, b.max ) > VTraits::getElem( i, max ) ) VTraits::getElem( i, max ) = VTraits::getElem( i, b.max );
138 }
139 }
140
142 bool contains( const V & pt ) const
143 {
144 for ( int i = 0; i < elements; ++i )
145 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, pt ) || VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) )
146 return false;
147 return true;
148 }
149
151 bool contains( const Box& otherbox ) const
152 {
153 for ( int i = 0; i < elements; ++i )
154 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, otherbox.min ) || VTraits::getElem( i, otherbox.max ) > VTraits::getElem( i, max ) )
155 return false;
156 return true;
157 }
158
160 V getBoxClosestPointTo( const V & pt ) const
161 {
162 assert( valid() );
163 V res;
164 for ( int i = 0; i < elements; ++i )
165 VTraits::getElem( i, res ) = std::clamp( VTraits::getElem( i, pt ), VTraits::getElem( i, min ), VTraits::getElem( i, max ) );
166 return res;
167 }
168
170 bool intersects( const Box & b ) const
171 {
172 for ( int i = 0; i < elements; ++i )
173 {
174 if ( VTraits::getElem( i, b.max ) < VTraits::getElem( i, min ) || VTraits::getElem( i, b.min ) > VTraits::getElem( i, max ) )
175 return false;
176 }
177 return true;
178 }
179
181 Box intersection( const Box & b ) const
182 {
183 Box res;
184 for ( int i = 0; i < elements; ++i )
185 {
186 VTraits::getElem( i, res.min ) = std::max( VTraits::getElem( i, min ), VTraits::getElem( i, b.min ) );
187 VTraits::getElem( i, res.max ) = std::min( VTraits::getElem( i, max ), VTraits::getElem( i, b.max ) );
188 }
189 return res;
190 }
191 Box & intersect( const Box & b ) { return *this = intersection( b ); }
192
195 T getDistanceSq( const Box & b ) const
196 {
197 auto ibox = intersection( b );
198 T distSq = 0;
199 for ( int i = 0; i < elements; ++i )
200 if ( VTraits::getElem( i, ibox.min ) > VTraits::getElem( i, ibox.max ) )
201 distSq += sqr( VTraits::getElem( i, ibox.min ) - VTraits::getElem( i, ibox.max ) );
202 return distSq;
203 }
204
207 T getDistanceSq( const V & pt ) const
208 {
209 assert( valid() );
210 T res{};
211 for ( int i = 0; i < elements; ++i )
212 {
213 if ( VTraits::getElem( i, pt ) < VTraits::getElem( i, min ) )
214 res += sqr( VTraits::getElem( i, pt ) - VTraits::getElem( i, min ) );
215 else
216 if ( VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) )
217 res += sqr( VTraits::getElem( i, pt ) - VTraits::getElem( i, max ) );
218 }
219 return res;
220 }
221
224 V getProjection( const V & pt ) const
225 {
226 assert( valid() );
227 if ( !contains( pt ) )
228 return getBoxClosestPointTo( pt );
229
230 T minDist = std::numeric_limits<T>::max();
231 int minDistDim {};
232 T minDistPos {};
233
234 for ( auto dim = 0; dim < elements; ++dim )
235 {
236 for ( const auto& border : { min, max } )
237 {
238 if ( auto dist = std::abs( VTraits::getElem( dim, border ) - VTraits::getElem( dim, pt ) ); dist < minDist )
239 {
240 minDist = dist;
241 minDistDim = dim;
242 minDistPos = VTraits::getElem( dim, border );
243 }
244 }
245 }
246
247 auto proj = pt;
248 VTraits::getElem( minDistDim, proj ) = minDistPos;
249 return proj;
250 }
251
253 Box expanded( const V & expansion ) const
254 {
255 assert( valid() );
256 return Box( min - expansion, max + expansion );
257 }
258
261 {
262 assert( valid() );
263 Box res;
264 for ( int i = 0; i < elements; ++i )
265 {
266 VTraits::getElem( i, res.min ) = std::nextafter( VTraits::getElem( i, min ), std::numeric_limits<T>::lowest() );
267 VTraits::getElem( i, res.max ) = std::nextafter( VTraits::getElem( i, max ), std::numeric_limits<T>::max() );
268 }
269 return res;
270 }
271
272 bool operator == ( const Box & a ) const
273 { return min == a.min && max == a.max; }
274 bool operator != ( const Box & a ) const
275 { return !( *this == a ); }
276
277 friend std::ostream& operator<<( std::ostream& s, const Box<V>& box )
278 {
279 return s << box.min << '\n' << box.max;
280 }
281
282 friend std::istream& operator>>( std::istream& s, Box<V>& box )
283 {
284 return s >> box.min >> box.max;
285 }
286};
287
288template <typename T>
289inline std::array<Vector3<T>, 8> getCorners( const Box<Vector3<T>> & box )
290{
291 assert( box.valid() );
292 return
293 {
294 Vector3<T>{ box.min.x, box.min.y, box.min.z },
295 Vector3<T>{ box.max.x, box.min.y, box.min.z },
296 Vector3<T>{ box.min.x, box.max.y, box.min.z },
297 Vector3<T>{ box.max.x, box.max.y, box.min.z },
298 Vector3<T>{ box.min.x, box.min.y, box.max.z },
299 Vector3<T>{ box.max.x, box.min.y, box.max.z },
300 Vector3<T>{ box.min.x, box.max.y, box.max.z },
301 Vector3<T>{ box.max.x, box.max.y, box.max.z }
302 };
303}
304
305template <typename T>
306inline std::array<Vector2<T>, 4> getCorners( const Box<Vector2<T>> & box )
307{
308 assert( box.valid() );
309 return
310 {
311 Vector2<T>{ box.min.x, box.min.y },
312 Vector2<T>{ box.max.x, box.min.y },
313 Vector2<T>{ box.min.x, box.max.y },
314 Vector2<T>{ box.max.x, box.max.y }
315 };
316}
317
320template <typename V>
322{
323 auto minCorner = box.getMinBoxCorner( n );
324 auto maxCorner = minCorner;
325 for ( auto & v : maxCorner )
326 v = !v;
327 return
328 {
329 dot( n, box.corner( minCorner ) ),
330 dot( n, box.corner( maxCorner ) )
331 };
332}
333
335template <typename V>
336inline Box<V> transformed( const Box<V> & box, const AffineXf<V> & xf )
337{
338 if ( !box.valid() )
339 return {};
340 Box<V> res;
341 for ( const auto & p : getCorners( box ) )
342 res.include( xf( p ) );
343 return res;
344}
346template <typename V>
347inline Box<V> transformed( const Box<V> & box, const AffineXf<V> * xf )
348{
349 return xf ? transformed( box, *xf ) : box;
350}
351
353template <typename V>
354inline auto width( const Box<V>& box )
355{
356 return box.max.x - box.min.x;
357}
358
360template <typename V>
361inline auto height( const Box<V>& box )
362{
363 return box.max.y - box.min.y;
364}
365
367template <typename V>
368inline auto depth( const Box<V>& box )
369{
370 return box.max.z - box.min.z;
371}
372
377template <typename V>
378inline auto findSortedBoxDims( const Box<V>& box ) -> typename VectorTraits<V>::template ChangeBaseType<int>
379{
380 constexpr auto es = Box<V>::elements;
381 auto boxDiag = box.max - box.min;
382 std::pair<float, int> ps[es];
383 for ( int i = 0; i < es; ++i )
384 ps[i] = { boxDiag[i], i };
385
386 // bubble sort (optimal for small array)
387 for ( int i = 0; i + 1 < es; ++i )
388 for ( int j = i + 1; j < es; ++j )
389 if ( ps[j] < ps[i] )
390 std::swap( ps[i], ps[j] );
391
392 typename VectorTraits<V>::template ChangeBaseType<int> res( noInit );
393 for ( int i = 0; i < es; ++i )
394 res[i] = ps[i].second;
395 return res;
396}
397
399template<size_t I, typename V>
400constexpr const V& get( const Box<V>& box ) noexcept { return box[int( I )]; }
401template<size_t I, typename V>
402constexpr V& get( Box<V>& box ) noexcept { return box[int( I )]; }
403
405
406} // namespace MR
407
408namespace std
409{
410
411template<size_t I, typename V>
412struct tuple_element<I, MR::Box<V>> { using type = V; };
413
414template <typename V>
415struct tuple_size<MR::Box<V>> : integral_constant<size_t, 2> {};
416
417} //namespace std
auto width(const Box< V > &box)
returns size along x axis
Definition MRMesh/MRBox.h:354
constexpr const V & get(const Box< V > &box) noexcept
get<0> returns min, get<1> returns max
Definition MRMesh/MRBox.h:400
std::array< Vector3< T >, 8 > getCorners(const Box< Vector3< T > > &box)
returns all corners of given box
Definition MRMesh/MRBox.h:289
auto findSortedBoxDims(const Box< V > &box) -> typename VectorTraits< V >::template ChangeBaseType< int >
Definition MRMesh/MRBox.h:378
auto height(const Box< V > &box)
returns size along y axis
Definition MRMesh/MRBox.h:361
auto depth(const Box< V > &box)
returns size along z axis
Definition MRMesh/MRBox.h:368
Box< V > transformed(const Box< V > &box, const AffineXf< V > &xf)
find the tightest box enclosing this one after transformation
Definition MRMesh/MRBox.h:336
MinMax< typename Box< V >::T > getTouchPlanes(const Box< V > &box, const V &n)
Definition MRMesh/MRBox.h:321
Definition MRCameraOrientationPlugin.h:8
constexpr T sqr(T x) noexcept
squared value
Definition MRMeshFwd.h:752
Box
Definition MRMeshFwd.h:394
constexpr NoInit noInit
Definition MRMeshFwd.h:95
I
Definition MRMeshFwd.h:134
Definition MRMesh/MRAffineXf.h:23
Box given by its min- and max- corners.
Definition MRMesh/MRBox.h:27
friend std::ostream & operator<<(std::ostream &s, const Box< V > &box)
Definition MRMesh/MRBox.h:277
Box(const V &min, const V &max)
Definition MRMesh/MRBox.h:43
typename VTraits::BaseType T
Definition MRMesh/MRBox.h:30
void include(const V &pt)
minimally increases the box to include given point
Definition MRMesh/MRBox.h:122
typename VTraits::template ChangeBaseType< bool > Vb
Definition MRMesh/MRBox.h:32
V getBoxClosestPointTo(const V &pt) const
returns closest point in the box to given point
Definition MRMesh/MRBox.h:160
T getDistanceSq(const Box &b) const
Definition MRMesh/MRBox.h:195
T diagonal() const
computes length from min to max
Definition MRMesh/MRBox.h:109
void include(const Box &b)
minimally increases the box to include another box
Definition MRMesh/MRBox.h:132
V getProjection(const V &pt) const
Definition MRMesh/MRBox.h:224
Box expanded(const V &expansion) const
decreases min and increased max on given value
Definition MRMesh/MRBox.h:253
V max
Definition MRMesh/MRBox.h:35
Box insignificantlyExpanded() const
decreases min and increases max to their closest representable value
Definition MRMesh/MRBox.h:260
static Vb getMaxBoxCorner(const V &n)
Definition MRMesh/MRBox.h:100
V corner(const Vb &c) const
Definition MRMesh/MRBox.h:80
V center() const
computes center of the box
Definition MRMesh/MRBox.h:75
T getDistanceSq(const V &pt) const
Definition MRMesh/MRBox.h:207
V size() const
computes size of the box in all dimensions
Definition MRMesh/MRBox.h:106
static Vb getMinBoxCorner(const V &n)
Definition MRMesh/MRBox.h:90
bool intersects(const Box &b) const
checks whether this box intersects or touches given box
Definition MRMesh/MRBox.h:170
static constexpr int elements
Definition MRMesh/MRBox.h:31
T volume() const
computes the volume of this box
Definition MRMesh/MRBox.h:112
static Box fromMinAndSize(const V &min, const V &size)
Definition MRMesh/MRBox.h:63
Box()
create invalid box by default
Definition MRMesh/MRBox.h:42
MR_REQUIRES_IF_SUPPORTED(!std::is_same_v< V, U >) explicit Box(const Box< U > &a)
Definition MRMesh/MRBox.h:60
const V & operator[](int e) const
min/max access by 0/1 index
Definition MRMesh/MRBox.h:38
bool operator!=(const Box &a) const
Definition MRMesh/MRBox.h:274
V min
Definition MRMesh/MRBox.h:35
Box intersection(const Box &b) const
computes intersection between this and other box
Definition MRMesh/MRBox.h:181
friend std::istream & operator>>(std::istream &s, Box< V > &box)
Definition MRMesh/MRBox.h:282
bool contains(const Box &otherbox) const
checks whether given box is fully inside (the surfaces may touch) of this box
Definition MRMesh/MRBox.h:151
bool contains(const V &pt) const
checks whether given point is inside (including the surface) of this box
Definition MRMesh/MRBox.h:142
Box & intersect(const Box &b)
Definition MRMesh/MRBox.h:191
bool valid() const
true if the box contains at least one point
Definition MRMesh/MRBox.h:66
Box(NoInit)
skip initialization of min/max
Definition MRMesh/MRBox.h:53
bool operator==(const Box &a) const
Definition MRMesh/MRBox.h:272
Definition MRMeshFwd.h:94
Definition MRVector2.h:29
T x
Definition MRVector2.h:35
Definition MRMesh/MRVector3.h:30
T x
Definition MRMesh/MRVector3.h:36
Definition MRMesh/MRVectorTraits.h:15
static constexpr int size
Definition MRMesh/MRVectorTraits.h:19
static constexpr auto && getElem(int i, U &&value)
Definition MRMesh/MRVectorTraits.h:29
static constexpr bool supportNoInit
Definition MRMesh/MRVectorTraits.h:20
T BaseType
Definition MRMesh/MRVectorTraits.h:18