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 <limits>
10#include <type_traits>
11
12namespace MR
13{
14
18
20template <typename T>
21std::array<Vector3<T>, 8> getCorners( const Box<Vector3<T>> & box );
22
24template <typename V>
25struct Box
26{
27public:
29 using T = typename VTraits::BaseType;
30 static constexpr int elements = VTraits::size;
31 using Vb = typename VTraits::template ChangeBaseType<bool>; //if V is Vector3<T> then Vb is Vector3b
33
34 V min, max;
35
37 const V & operator []( int e ) const { return *( &min + e ); }
38 V & operator []( int e ) { return *( &min + e ); }
39
41 Box() : min{ VTraits::diagonal( std::numeric_limits<T>::max() ) }, max{ VTraits::diagonal( std::numeric_limits<T>::lowest() ) } { }
42 Box( const V& min, const V& max ) : min{ min }, max{ max } { }
43
45 #if MR_HAS_REQUIRES
46 // If the compiler supports `requires`, use that instead of `std::enable_if` here.
47 // 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
48 explicit Box( NoInit ) requires (VectorTraits<V>::supportNoInit) : min{ noInit }, max{ noInit } { }
49 explicit Box( NoInit ) requires (!VectorTraits<V>::supportNoInit) { }
50 #else
51 template <typename VV = V, typename std::enable_if_t<VectorTraits<VV>::supportNoInit, int> = 0>
52 explicit Box( NoInit ) : min{ noInit }, max{ noInit } { }
53 template <typename VV = V, typename std::enable_if_t<!VectorTraits<VV>::supportNoInit, int> = 0>
54 explicit Box( NoInit ) { }
55 #endif
56
57 template <typename U>
58 explicit Box( const Box<U> & a ) : min{ a.min }, max{ a.max } { }
59
60 static Box fromMinAndSize( const V& min, const V& size ) { return Box{ min, V( min + size ) }; }
61
63 bool valid() const
64 {
65 for ( int i = 0; i < elements; ++i )
66 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, max ) )
67 return false;
68 return true;
69 }
70
72 V center() const { assert( valid() ); return ( min + max ) / T(2); }
73
77 V corner( const Vb& c ) const
78 {
79 V res;
80 for ( int i = 0; i < elements; ++i )
81 VTraits::getElem( i, res ) = VTraits::getElem( i, operator[]( VbTraits::getElem( i, c ) ) );
82 return res;
83 }
84
87 static Vb getMinBoxCorner( const V & n )
88 {
89 Vb res;
90 for ( int i = 0; i < elements; ++i )
91 VbTraits::getElem( i, res ) = VTraits::getElem( i, n ) < 0;
92 return res;
93 }
94
97 static Vb getMaxBoxCorner( const V & n )
98 {
99 return getMinBoxCorner( -n );
100 }
101
103 V size() const { assert( valid() ); return max - min; }
104
106 T diagonal() const { return std::sqrt( sqr( size() ) ); }
107
109 T volume() const
110 {
111 assert( valid() );
112 T res{ 1 };
113 for ( int i = 0; i < elements; ++i )
114 res *= VTraits::getElem( i, max ) - VTraits::getElem( i, min );
115 return res;
116 }
117
119 void include( const V & pt )
120 {
121 for ( int i = 0; i < elements; ++i )
122 {
123 if ( VTraits::getElem( i, pt ) < VTraits::getElem( i, min ) ) VTraits::getElem( i, min ) = VTraits::getElem( i, pt );
124 if ( VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) ) VTraits::getElem( i, max ) = VTraits::getElem( i, pt );
125 }
126 }
127
129 void include( const Box & b )
130 {
131 for ( int i = 0; i < elements; ++i )
132 {
133 if ( VTraits::getElem( i, b.min ) < VTraits::getElem( i, min ) ) VTraits::getElem( i, min ) = VTraits::getElem( i, b.min );
134 if ( VTraits::getElem( i, b.max ) > VTraits::getElem( i, max ) ) VTraits::getElem( i, max ) = VTraits::getElem( i, b.max );
135 }
136 }
137
139 bool contains( const V & pt ) const
140 {
141 for ( int i = 0; i < elements; ++i )
142 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, pt ) || VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) )
143 return false;
144 return true;
145 }
146
148 bool contains( const Box& otherbox ) const
149 {
150 for ( int i = 0; i < elements; ++i )
151 if ( VTraits::getElem( i, min ) > VTraits::getElem( i, otherbox.min ) || VTraits::getElem( i, otherbox.max ) > VTraits::getElem( i, max ) )
152 return false;
153 return true;
154 }
155
157 V getBoxClosestPointTo( const V & pt ) const
158 {
159 assert( valid() );
160 V res;
161 for ( int i = 0; i < elements; ++i )
162 VTraits::getElem( i, res ) = std::clamp( VTraits::getElem( i, pt ), VTraits::getElem( i, min ), VTraits::getElem( i, max ) );
163 return res;
164 }
165
167 bool intersects( const Box & b ) const
168 {
169 for ( int i = 0; i < elements; ++i )
170 {
171 if ( VTraits::getElem( i, b.max ) < VTraits::getElem( i, min ) || VTraits::getElem( i, b.min ) > VTraits::getElem( i, max ) )
172 return false;
173 }
174 return true;
175 }
176
178 Box intersection( const Box & b ) const
179 {
180 Box res;
181 for ( int i = 0; i < elements; ++i )
182 {
183 VTraits::getElem( i, res.min ) = std::max( VTraits::getElem( i, min ), VTraits::getElem( i, b.min ) );
184 VTraits::getElem( i, res.max ) = std::min( VTraits::getElem( i, max ), VTraits::getElem( i, b.max ) );
185 }
186 return res;
187 }
188 Box & intersect( const Box & b ) { return *this = intersection( b ); }
189
192 T getDistanceSq( const Box & b ) const
193 {
194 auto ibox = intersection( b );
195 T distSq = 0;
196 for ( int i = 0; i < elements; ++i )
197 if ( VTraits::getElem( i, ibox.min ) > VTraits::getElem( i, ibox.max ) )
198 distSq += sqr( VTraits::getElem( i, ibox.min ) - VTraits::getElem( i, ibox.max ) );
199 return distSq;
200 }
201
204 T getDistanceSq( const V & pt ) const
205 {
206 assert( valid() );
207 T res{};
208 for ( int i = 0; i < elements; ++i )
209 {
210 if ( VTraits::getElem( i, pt ) < VTraits::getElem( i, min ) )
211 res += sqr( VTraits::getElem( i, pt ) - VTraits::getElem( i, min ) );
212 else
213 if ( VTraits::getElem( i, pt ) > VTraits::getElem( i, max ) )
214 res += sqr( VTraits::getElem( i, pt ) - VTraits::getElem( i, max ) );
215 }
216 return res;
217 }
218
221 V getProjection( const V & pt ) const
222 {
223 assert( valid() );
224 if ( !contains( pt ) )
225 return getBoxClosestPointTo( pt );
226
227 T minDist = std::numeric_limits<T>::max();
228 int minDistDim {};
229 T minDistPos {};
230
231 for ( auto dim = 0; dim < elements; ++dim )
232 {
233 for ( const auto& border : { min, max } )
234 {
235 if ( auto dist = std::abs( VTraits::getElem( dim, border ) - VTraits::getElem( dim, pt ) ); dist < minDist )
236 {
237 minDist = dist;
238 minDistDim = dim;
239 minDistPos = VTraits::getElem( dim, border );
240 }
241 }
242 }
243
244 auto proj = pt;
245 VTraits::getElem( minDistDim, proj ) = minDistPos;
246 return proj;
247 }
248
250 Box expanded( const V & expansion ) const
251 {
252 assert( valid() );
253 return Box( min - expansion, max + expansion );
254 }
255
258 {
259 assert( valid() );
260 Box res;
261 for ( int i = 0; i < elements; ++i )
262 {
263 VTraits::getElem( i, res.min ) = std::nextafter( VTraits::getElem( i, min ), std::numeric_limits<T>::lowest() );
264 VTraits::getElem( i, res.max ) = std::nextafter( VTraits::getElem( i, max ), std::numeric_limits<T>::max() );
265 }
266 return res;
267 }
268
269 bool operator == ( const Box & a ) const
270 { return min == a.min && max == a.max; }
271 bool operator != ( const Box & a ) const
272 { return !( *this == a ); }
273};
274
275template <typename T>
276inline std::array<Vector3<T>, 8> getCorners( const Box<Vector3<T>> & box )
277{
278 assert( box.valid() );
279 return
280 {
281 Vector3<T>{ box.min.x, box.min.y, box.min.z },
282 Vector3<T>{ box.max.x, box.min.y, box.min.z },
283 Vector3<T>{ box.min.x, box.max.y, box.min.z },
284 Vector3<T>{ box.max.x, box.max.y, box.min.z },
285 Vector3<T>{ box.min.x, box.min.y, box.max.z },
286 Vector3<T>{ box.max.x, box.min.y, box.max.z },
287 Vector3<T>{ box.min.x, box.max.y, box.max.z },
288 Vector3<T>{ box.max.x, box.max.y, box.max.z }
289 };
290}
291
292template <typename T>
293inline std::array<Vector2<T>, 4> getCorners( const Box<Vector2<T>> & box )
294{
295 assert( box.valid() );
296 return
297 {
298 Vector2<T>{ box.min.x, box.min.y },
299 Vector2<T>{ box.max.x, box.min.y },
300 Vector2<T>{ box.min.x, box.max.y },
301 Vector2<T>{ box.max.x, box.max.y }
302 };
303}
304
307template <typename V>
309{
310 auto minCorner = box.getMinBoxCorner( n );
311 auto maxCorner = minCorner;
312 for ( auto & v : maxCorner )
313 v = !v;
314 return
315 {
316 dot( n, box.corner( minCorner ) ),
317 dot( n, box.corner( maxCorner ) )
318 };
319}
320
322template <typename V>
323inline Box<V> transformed( const Box<V> & box, const AffineXf<V> & xf )
324{
325 if ( !box.valid() )
326 return {};
327 Box<V> res;
328 for ( const auto & p : getCorners( box ) )
329 res.include( xf( p ) );
330 return res;
331}
333template <typename V>
334inline Box<V> transformed( const Box<V> & box, const AffineXf<V> * xf )
335{
336 return xf ? transformed( box, *xf ) : box;
337}
338
340template <typename V>
341inline auto width( const Box<V>& box )
342{
343 return box.max.x - box.min.x;
344}
345
347template <typename V>
348inline auto height( const Box<V>& box )
349{
350 return box.max.y - box.min.y;
351}
352
354template <typename V>
355inline auto depth( const Box<V>& box )
356{
357 return box.max.z - box.min.z;
358}
359
364template <typename V>
365inline auto findSortedBoxDims( const Box<V>& box ) -> typename VectorTraits<V>::template ChangeBaseType<int>
366{
367 constexpr auto es = Box<V>::elements;
368 auto boxDiag = box.max - box.min;
369 std::pair<float, int> ps[es];
370 for ( int i = 0; i < es; ++i )
371 ps[i] = { boxDiag[i], i };
372
373 // bubble sort (optimal for small array)
374 for ( int i = 0; i + 1 < es; ++i )
375 for ( int j = i + 1; j < es; ++j )
376 if ( ps[j] < ps[i] )
377 std::swap( ps[i], ps[j] );
378
379 typename VectorTraits<V>::template ChangeBaseType<int> res( noInit );
380 for ( int i = 0; i < es; ++i )
381 res[i] = ps[i].second;
382 return res;
383}
384
386template<size_t I, typename V>
387constexpr const V& get( const Box<V>& box ) noexcept { return box[int( I )]; }
388template<size_t I, typename V>
389constexpr V& get( Box<V>& box ) noexcept { return box[int( I )]; }
390
392
393} // namespace MR
394
395namespace std
396{
397
398template<size_t I, typename V>
399struct tuple_element<I, MR::Box<V>> { using type = V; };
400
401template <typename V>
402struct tuple_size<MR::Box<V>> : integral_constant<size_t, 2> {};
403
404} //namespace std
auto width(const Box< V > &box)
returns size along x axis
Definition MRMesh/MRBox.h:341
constexpr const V & get(const Box< V > &box) noexcept
get<0> returns min, get<1> returns max
Definition MRMesh/MRBox.h:387
std::array< Vector3< T >, 8 > getCorners(const Box< Vector3< T > > &box)
returns all corners of given box
Definition MRMesh/MRBox.h:276
auto findSortedBoxDims(const Box< V > &box) -> typename VectorTraits< V >::template ChangeBaseType< int >
Definition MRMesh/MRBox.h:365
auto height(const Box< V > &box)
returns size along y axis
Definition MRMesh/MRBox.h:348
auto depth(const Box< V > &box)
returns size along z axis
Definition MRMesh/MRBox.h:355
Box< V > transformed(const Box< V > &box, const AffineXf< V > &xf)
find the tightest box enclosing this one after transformation
Definition MRMesh/MRBox.h:323
MinMax< typename Box< V >::T > getTouchPlanes(const Box< V > &box, const V &n)
Definition MRMesh/MRBox.h:308
Definition MRCameraOrientationPlugin.h:8
constexpr T sqr(T x) noexcept
squared value
Definition MRMesh/MRMeshFwd.h:753
Box
Definition MRMesh/MRMeshFwd.h:390
constexpr NoInit noInit
Definition MRMesh/MRMeshFwd.h:91
I
Definition MRMesh/MRMeshFwd.h:130
Definition MRMesh/MRAffineXf.h:21
Box given by its min- and max- corners.
Definition MRMesh/MRBox.h:26
Box(const V &min, const V &max)
Definition MRMesh/MRBox.h:42
typename VTraits::BaseType T
Definition MRMesh/MRBox.h:29
void include(const V &pt)
minimally increases the box to include given point
Definition MRMesh/MRBox.h:119
typename VTraits::template ChangeBaseType< bool > Vb
Definition MRMesh/MRBox.h:31
V getBoxClosestPointTo(const V &pt) const
returns closest point in the box to given point
Definition MRMesh/MRBox.h:157
T getDistanceSq(const Box &b) const
Definition MRMesh/MRBox.h:192
T diagonal() const
computes length from min to max
Definition MRMesh/MRBox.h:106
void include(const Box &b)
minimally increases the box to include another box
Definition MRMesh/MRBox.h:129
V getProjection(const V &pt) const
Definition MRMesh/MRBox.h:221
Box expanded(const V &expansion) const
decreases min and increased max on given value
Definition MRMesh/MRBox.h:250
V max
Definition MRMesh/MRBox.h:34
Box insignificantlyExpanded() const
decreases min and increases max to their closest representable value
Definition MRMesh/MRBox.h:257
static Vb getMaxBoxCorner(const V &n)
Definition MRMesh/MRBox.h:97
V corner(const Vb &c) const
Definition MRMesh/MRBox.h:77
V center() const
computes center of the box
Definition MRMesh/MRBox.h:72
T getDistanceSq(const V &pt) const
Definition MRMesh/MRBox.h:204
V size() const
computes size of the box in all dimensions
Definition MRMesh/MRBox.h:103
static Vb getMinBoxCorner(const V &n)
Definition MRMesh/MRBox.h:87
bool intersects(const Box &b) const
checks whether this box intersects or touches given box
Definition MRMesh/MRBox.h:167
static constexpr int elements
Definition MRMesh/MRBox.h:30
T volume() const
computes the volume of this box
Definition MRMesh/MRBox.h:109
static Box fromMinAndSize(const V &min, const V &size)
Definition MRMesh/MRBox.h:60
Box()
create invalid box by default
Definition MRMesh/MRBox.h:41
const V & operator[](int e) const
min/max access by 0/1 index
Definition MRMesh/MRBox.h:37
bool operator!=(const Box &a) const
Definition MRMesh/MRBox.h:271
V min
Definition MRMesh/MRBox.h:34
Box intersection(const Box &b) const
computes intersection between this and other box
Definition MRMesh/MRBox.h:178
bool contains(const Box &otherbox) const
checks whether given box is fully inside (the surfaces may touch) of this box
Definition MRMesh/MRBox.h:148
bool contains(const V &pt) const
checks whether given point is inside (including the surface) of this box
Definition MRMesh/MRBox.h:139
Box & intersect(const Box &b)
Definition MRMesh/MRBox.h:188
Box(const Box< U > &a)
Definition MRMesh/MRBox.h:58
bool valid() const
true if the box contains at least one point
Definition MRMesh/MRBox.h:63
Box(NoInit)
skip initialization of min/max
Definition MRMesh/MRBox.h:52
bool operator==(const Box &a) const
Definition MRMesh/MRBox.h:269
Definition MRMesh/MRMeshFwd.h:90
Definition MRVector2.h:27
T x
Definition MRVector2.h:33
Definition MRMesh/MRVector3.h:28
T x
Definition MRMesh/MRVector3.h:34
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