AlignedBox.h 14.5 KB
Newer Older
LM's avatar
LM committed
1 2 3 4 5
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
Don Gagne's avatar
Don Gagne committed
6 7 8
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
LM's avatar
LM committed
9 10 11 12

#ifndef EIGEN_ALIGNEDBOX_H
#define EIGEN_ALIGNEDBOX_H

Don Gagne's avatar
Don Gagne committed
13 14
namespace Eigen { 

LM's avatar
LM committed
15 16 17 18 19 20 21
/** \geometry_module \ingroup Geometry_Module
  *
  *
  * \class AlignedBox
  *
  * \brief An axis aligned box
  *
22 23
  * \tparam _Scalar the type of the scalar coefficients
  * \tparam _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic.
LM's avatar
LM committed
24 25
  *
  * This class represents an axis aligned box as a pair of the minimal and maximal corners.
26 27
  * \warning The result of most methods is undefined when applied to an empty box. You can check for empty boxes using isEmpty().
  * \sa alignedboxtypedefs
LM's avatar
LM committed
28 29 30 31 32 33 34 35 36
  */
template <typename _Scalar, int _AmbientDim>
class AlignedBox
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
  enum { AmbientDimAtCompileTime = _AmbientDim };
  typedef _Scalar                                   Scalar;
  typedef NumTraits<Scalar>                         ScalarTraits;
37
  typedef Eigen::Index                              Index; ///< \deprecated since Eigen 3.3
LM's avatar
LM committed
38
  typedef typename ScalarTraits::Real               RealScalar;
39
  typedef typename ScalarTraits::NonInteger         NonInteger;
LM's avatar
LM committed
40
  typedef Matrix<Scalar,AmbientDimAtCompileTime,1>  VectorType;
41
  typedef CwiseBinaryOp<internal::scalar_sum_op<Scalar>, const VectorType, const VectorType> VectorTypeSum;
LM's avatar
LM committed
42 43 44 45

  /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */
  enum CornerType
  {
46
    /** 1D names @{ */
LM's avatar
LM committed
47
    Min=0, Max=1,
48
    /** @} */
LM's avatar
LM committed
49

50
    /** Identifier for 2D corner @{ */
LM's avatar
LM committed
51 52
    BottomLeft=0, BottomRight=1,
    TopLeft=2, TopRight=3,
53
    /** @} */
LM's avatar
LM committed
54

55
    /** Identifier for 3D corner  @{ */
LM's avatar
LM committed
56 57 58 59
    BottomLeftFloor=0, BottomRightFloor=1,
    TopLeftFloor=2, TopRightFloor=3,
    BottomLeftCeil=4, BottomRightCeil=5,
    TopLeftCeil=6, TopRightCeil=7
60
    /** @} */
LM's avatar
LM committed
61 62 63 64
  };


  /** Default constructor initializing a null box. */
65
  EIGEN_DEVICE_FUNC inline AlignedBox()
LM's avatar
LM committed
66 67 68
  { if (AmbientDimAtCompileTime!=Dynamic) setEmpty(); }

  /** Constructs a null box with \a _dim the dimension of the ambient space. */
69
  EIGEN_DEVICE_FUNC inline explicit AlignedBox(Index _dim) : m_min(_dim), m_max(_dim)
LM's avatar
LM committed
70 71
  { setEmpty(); }

72 73
  /** Constructs a box with extremities \a _min and \a _max.
   * \warning If either component of \a _min is larger than the same component of \a _max, the constructed box is empty. */
LM's avatar
LM committed
74
  template<typename OtherVectorType1, typename OtherVectorType2>
75
  EIGEN_DEVICE_FUNC inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {}
LM's avatar
LM committed
76 77 78

  /** Constructs a box containing a single point \a p. */
  template<typename Derived>
79
  EIGEN_DEVICE_FUNC inline explicit AlignedBox(const MatrixBase<Derived>& p) : m_min(p), m_max(m_min)
80
  { }
LM's avatar
LM committed
81

82
  EIGEN_DEVICE_FUNC ~AlignedBox() {}
LM's avatar
LM committed
83 84

  /** \returns the dimension in which the box holds */
85
  EIGEN_DEVICE_FUNC inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size() : Index(AmbientDimAtCompileTime); }
LM's avatar
LM committed
86

87
  /** \deprecated use isEmpty() */
88
  EIGEN_DEVICE_FUNC inline bool isNull() const { return isEmpty(); }
LM's avatar
LM committed
89

90
  /** \deprecated use setEmpty() */
91
  EIGEN_DEVICE_FUNC inline void setNull() { setEmpty(); }
LM's avatar
LM committed
92

93 94
  /** \returns true if the box is empty.
   * \sa setEmpty */
95
  EIGEN_DEVICE_FUNC inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); }
LM's avatar
LM committed
96

97 98
  /** Makes \c *this an empty box.
   * \sa isEmpty */
99
  EIGEN_DEVICE_FUNC inline void setEmpty()
LM's avatar
LM committed
100 101 102 103 104 105
  {
    m_min.setConstant( ScalarTraits::highest() );
    m_max.setConstant( ScalarTraits::lowest() );
  }

  /** \returns the minimal corner */
106
  EIGEN_DEVICE_FUNC inline const VectorType& (min)() const { return m_min; }
LM's avatar
LM committed
107
  /** \returns a non const reference to the minimal corner */
108
  EIGEN_DEVICE_FUNC inline VectorType& (min)() { return m_min; }
LM's avatar
LM committed
109
  /** \returns the maximal corner */
110
  EIGEN_DEVICE_FUNC inline const VectorType& (max)() const { return m_max; }
LM's avatar
LM committed
111
  /** \returns a non const reference to the maximal corner */
112
  EIGEN_DEVICE_FUNC inline VectorType& (max)() { return m_max; }
LM's avatar
LM committed
113 114

  /** \returns the center of the box */
115
  EIGEN_DEVICE_FUNC inline const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(VectorTypeSum, RealScalar, quotient)
LM's avatar
LM committed
116
  center() const
117
  { return (m_min+m_max)/RealScalar(2); }
LM's avatar
LM committed
118 119 120 121 122

  /** \returns the lengths of the sides of the bounding box.
    * Note that this function does not get the same
    * result for integral or floating scalar types: see
    */
123
  EIGEN_DEVICE_FUNC inline const CwiseBinaryOp< internal::scalar_difference_op<Scalar,Scalar>, const VectorType, const VectorType> sizes() const
LM's avatar
LM committed
124 125 126
  { return m_max - m_min; }

  /** \returns the volume of the bounding box */
127
  EIGEN_DEVICE_FUNC inline Scalar volume() const
LM's avatar
LM committed
128 129 130 131 132 133
  { return sizes().prod(); }

  /** \returns an expression for the bounding box diagonal vector
    * if the length of the diagonal is needed: diagonal().norm()
    * will provide it.
    */
134
  EIGEN_DEVICE_FUNC inline CwiseBinaryOp< internal::scalar_difference_op<Scalar,Scalar>, const VectorType, const VectorType> diagonal() const
LM's avatar
LM committed
135 136 137 138 139 140 141 142 143 144 145
  { return sizes(); }

  /** \returns the vertex of the bounding box at the corner defined by
    * the corner-id corner. It works only for a 1D, 2D or 3D bounding box.
    * For 1D bounding boxes corners are named by 2 enum constants:
    * BottomLeft and BottomRight.
    * For 2D bounding boxes, corners are named by 4 enum constants:
    * BottomLeft, BottomRight, TopLeft, TopRight.
    * For 3D bounding boxes, the following names are added:
    * BottomLeftCeil, BottomRightCeil, TopLeftCeil, TopRightCeil.
    */
146
  EIGEN_DEVICE_FUNC inline VectorType corner(CornerType corner) const
LM's avatar
LM committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
  {
    EIGEN_STATIC_ASSERT(_AmbientDim <= 3, THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE);

    VectorType res;

    Index mult = 1;
    for(Index d=0; d<dim(); ++d)
    {
      if( mult & corner ) res[d] = m_max[d];
      else                res[d] = m_min[d];
      mult *= 2;
    }
    return res;
  }

  /** \returns a random point inside the bounding box sampled with
   * a uniform distribution */
164
  EIGEN_DEVICE_FUNC inline VectorType sample() const
LM's avatar
LM committed
165
  {
166
    VectorType r(dim());
LM's avatar
LM committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    for(Index d=0; d<dim(); ++d)
    {
      if(!ScalarTraits::IsInteger)
      {
        r[d] = m_min[d] + (m_max[d]-m_min[d])
             * internal::random<Scalar>(Scalar(0), Scalar(1));
      }
      else
        r[d] = internal::random(m_min[d], m_max[d]);
    }
    return r;
  }

  /** \returns true if the point \a p is inside the box \c *this. */
  template<typename Derived>
182
  EIGEN_DEVICE_FUNC inline bool contains(const MatrixBase<Derived>& p) const
LM's avatar
LM committed
183
  {
184
    typename internal::nested_eval<Derived,2>::type p_n(p.derived());
185
    return (m_min.array()<=p_n.array()).all() && (p_n.array()<=m_max.array()).all();
LM's avatar
LM committed
186 187 188
  }

  /** \returns true if the box \a b is entirely inside the box \c *this. */
189
  EIGEN_DEVICE_FUNC inline bool contains(const AlignedBox& b) const
Don Gagne's avatar
Don Gagne committed
190
  { return (m_min.array()<=(b.min)().array()).all() && ((b.max)().array()<=m_max.array()).all(); }
LM's avatar
LM committed
191

192 193
  /** \returns true if the box \a b is intersecting the box \c *this.
   * \sa intersection, clamp */
194
  EIGEN_DEVICE_FUNC inline bool intersects(const AlignedBox& b) const
195 196 197 198
  { return (m_min.array()<=(b.max)().array()).all() && ((b.min)().array()<=m_max.array()).all(); }

  /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this.
   * \sa extend(const AlignedBox&) */
LM's avatar
LM committed
199
  template<typename Derived>
200
  EIGEN_DEVICE_FUNC inline AlignedBox& extend(const MatrixBase<Derived>& p)
LM's avatar
LM committed
201
  {
202
    typename internal::nested_eval<Derived,2>::type p_n(p.derived());
203 204
    m_min = m_min.cwiseMin(p_n);
    m_max = m_max.cwiseMax(p_n);
LM's avatar
LM committed
205 206 207
    return *this;
  }

208 209
  /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this.
   * \sa merged, extend(const MatrixBase&) */
210
  EIGEN_DEVICE_FUNC inline AlignedBox& extend(const AlignedBox& b)
LM's avatar
LM committed
211 212 213 214 215 216
  {
    m_min = m_min.cwiseMin(b.m_min);
    m_max = m_max.cwiseMax(b.m_max);
    return *this;
  }

217 218 219
  /** Clamps \c *this by the box \a b and returns a reference to \c *this.
   * \note If the boxes don't intersect, the resulting box is empty.
   * \sa intersection(), intersects() */
220
  EIGEN_DEVICE_FUNC inline AlignedBox& clamp(const AlignedBox& b)
LM's avatar
LM committed
221 222 223 224 225 226
  {
    m_min = m_min.cwiseMax(b.m_min);
    m_max = m_max.cwiseMin(b.m_max);
    return *this;
  }

227 228 229
  /** Returns an AlignedBox that is the intersection of \a b and \c *this
   * \note If the boxes don't intersect, the resulting box is empty.
   * \sa intersects(), clamp, contains()  */
230
  EIGEN_DEVICE_FUNC inline AlignedBox intersection(const AlignedBox& b) const
LM's avatar
LM committed
231 232
  {return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); }

233 234 235
  /** Returns an AlignedBox that is the union of \a b and \c *this.
   * \note Merging with an empty box may result in a box bigger than \c *this. 
   * \sa extend(const AlignedBox&) */
236
  EIGEN_DEVICE_FUNC inline AlignedBox merged(const AlignedBox& b) const
LM's avatar
LM committed
237 238 239 240
  { return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); }

  /** Translate \c *this by the vector \a t and returns a reference to \c *this. */
  template<typename Derived>
241
  EIGEN_DEVICE_FUNC inline AlignedBox& translate(const MatrixBase<Derived>& a_t)
LM's avatar
LM committed
242
  {
243
    const typename internal::nested_eval<Derived,2>::type t(a_t.derived());
LM's avatar
LM committed
244 245 246 247 248 249 250
    m_min += t;
    m_max += t;
    return *this;
  }

  /** \returns the squared distance between the point \a p and the box \c *this,
    * and zero if \a p is inside the box.
251
    * \sa exteriorDistance(const MatrixBase&), squaredExteriorDistance(const AlignedBox&)
LM's avatar
LM committed
252 253
    */
  template<typename Derived>
254
  EIGEN_DEVICE_FUNC inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& p) const;
LM's avatar
LM committed
255 256 257

  /** \returns the squared distance between the boxes \a b and \c *this,
    * and zero if the boxes intersect.
258
    * \sa exteriorDistance(const AlignedBox&), squaredExteriorDistance(const MatrixBase&)
LM's avatar
LM committed
259
    */
260
  EIGEN_DEVICE_FUNC inline Scalar squaredExteriorDistance(const AlignedBox& b) const;
LM's avatar
LM committed
261 262 263

  /** \returns the distance between the point \a p and the box \c *this,
    * and zero if \a p is inside the box.
264
    * \sa squaredExteriorDistance(const MatrixBase&), exteriorDistance(const AlignedBox&)
LM's avatar
LM committed
265 266
    */
  template<typename Derived>
267 268
  EIGEN_DEVICE_FUNC inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const
  { EIGEN_USING_STD_MATH(sqrt) return sqrt(NonInteger(squaredExteriorDistance(p))); }
LM's avatar
LM committed
269 270 271

  /** \returns the distance between the boxes \a b and \c *this,
    * and zero if the boxes intersect.
272
    * \sa squaredExteriorDistance(const AlignedBox&), exteriorDistance(const MatrixBase&)
LM's avatar
LM committed
273
    */
274 275
  EIGEN_DEVICE_FUNC inline NonInteger exteriorDistance(const AlignedBox& b) const
  { EIGEN_USING_STD_MATH(sqrt) return sqrt(NonInteger(squaredExteriorDistance(b))); }
LM's avatar
LM committed
276 277 278 279 280 281 282

  /** \returns \c *this with scalar type casted to \a NewScalarType
    *
    * Note that if \a NewScalarType is equal to the current scalar type of \c *this
    * then this function smartly returns a const reference to \c *this.
    */
  template<typename NewScalarType>
283
  EIGEN_DEVICE_FUNC inline typename internal::cast_return_type<AlignedBox,
LM's avatar
LM committed
284 285 286 287 288 289 290 291
           AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type cast() const
  {
    return typename internal::cast_return_type<AlignedBox,
                    AlignedBox<NewScalarType,AmbientDimAtCompileTime> >::type(*this);
  }

  /** Copy constructor with scalar type conversion */
  template<typename OtherScalarType>
292
  EIGEN_DEVICE_FUNC inline explicit AlignedBox(const AlignedBox<OtherScalarType,AmbientDimAtCompileTime>& other)
LM's avatar
LM committed
293
  {
Don Gagne's avatar
Don Gagne committed
294 295
    m_min = (other.min)().template cast<Scalar>();
    m_max = (other.max)().template cast<Scalar>();
LM's avatar
LM committed
296 297 298 299 300 301
  }

  /** \returns \c true if \c *this is approximately equal to \a other, within the precision
    * determined by \a prec.
    *
    * \sa MatrixBase::isApprox() */
302
  EIGEN_DEVICE_FUNC bool isApprox(const AlignedBox& other, const RealScalar& prec = ScalarTraits::dummy_precision()) const
LM's avatar
LM committed
303 304 305 306 307 308 309 310 311 312 313
  { return m_min.isApprox(other.m_min, prec) && m_max.isApprox(other.m_max, prec); }

protected:

  VectorType m_min, m_max;
};



template<typename Scalar,int AmbientDim>
template<typename Derived>
314
EIGEN_DEVICE_FUNC inline Scalar AlignedBox<Scalar,AmbientDim>::squaredExteriorDistance(const MatrixBase<Derived>& a_p) const
LM's avatar
LM committed
315
{
316
  typename internal::nested_eval<Derived,2*AmbientDim>::type p(a_p.derived());
Don Gagne's avatar
Don Gagne committed
317
  Scalar dist2(0);
LM's avatar
LM committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
  Scalar aux;
  for (Index k=0; k<dim(); ++k)
  {
    if( m_min[k] > p[k] )
    {
      aux = m_min[k] - p[k];
      dist2 += aux*aux;
    }
    else if( p[k] > m_max[k] )
    {
      aux = p[k] - m_max[k];
      dist2 += aux*aux;
    }
  }
  return dist2;
}

template<typename Scalar,int AmbientDim>
336
EIGEN_DEVICE_FUNC inline Scalar AlignedBox<Scalar,AmbientDim>::squaredExteriorDistance(const AlignedBox& b) const
LM's avatar
LM committed
337
{
Don Gagne's avatar
Don Gagne committed
338
  Scalar dist2(0);
LM's avatar
LM committed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
  Scalar aux;
  for (Index k=0; k<dim(); ++k)
  {
    if( m_min[k] > b.m_max[k] )
    {
      aux = m_min[k] - b.m_max[k];
      dist2 += aux*aux;
    }
    else if( b.m_min[k] > m_max[k] )
    {
      aux = b.m_min[k] - m_max[k];
      dist2 += aux*aux;
    }
  }
  return dist2;
}

Don Gagne's avatar
Don Gagne committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
/** \defgroup alignedboxtypedefs Global aligned box typedefs
  *
  * \ingroup Geometry_Module
  *
  * Eigen defines several typedef shortcuts for most common aligned box types.
  *
  * The general patterns are the following:
  *
  * \c AlignedBoxSizeType where \c Size can be \c 1, \c 2,\c 3,\c 4 for fixed size boxes or \c X for dynamic size,
  * and where \c Type can be \c i for integer, \c f for float, \c d for double.
  *
  * For example, \c AlignedBox3d is a fixed-size 3x3 aligned box type of doubles, and \c AlignedBoxXf is a dynamic-size aligned box of floats.
  *
  * \sa class AlignedBox
  */

#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix)    \
/** \ingroup alignedboxtypedefs */                                 \
typedef AlignedBox<Type, Size>   AlignedBox##SizeSuffix##TypeSuffix;

#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 1, 1) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X)

EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int,                  i)
EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float,                f)
EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double,               d)

#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES
#undef EIGEN_MAKE_TYPEDEFS

} // end namespace Eigen

LM's avatar
LM committed
392
#endif // EIGEN_ALIGNEDBOX_H