|
||||
File indexing completed on 2025-01-18 09:11:12
0001 // This file is part of the ACTS project. 0002 // 0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project 0004 // 0005 // This Source Code Form is subject to the terms of the Mozilla Public 0006 // License, v. 2.0. If a copy of the MPL was not distributed with this 0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 0008 0009 #pragma once 0010 0011 #include <algorithm> 0012 #include <array> 0013 #include <cassert> 0014 #include <limits> 0015 #include <sstream> 0016 #include <string> 0017 0018 namespace Acts { 0019 /// @brief An orthogonal range in an arbitrary number of dimensions 0020 /// 0021 /// By combining a number one-dimensional ranges we can (under the assumption 0022 /// that our axes are orthogonal) construct an orthogonal range of values. In 0023 /// other words, a hyperrectangular volume in space. 0024 /// 0025 /// @tparam Dims The number of dimensions in our range 0026 /// @tparam Type The scalar type of our ranges 0027 /// @tparam Vector The vector type used to define coordinates 0028 template <std::size_t Dims, typename Type, 0029 template <typename, std::size_t> typename Vector = std::array> 0030 class RangeXD { 0031 private: 0032 // @TODO: Replace with std::span or boost::span once available 0033 template <typename, std::size_t> 0034 struct SingleElementContainer { 0035 Type* element; 0036 0037 Type& operator[](std::size_t i) { 0038 (void)i; 0039 assert(i == 0); 0040 0041 return *element; 0042 } 0043 }; 0044 0045 public: 0046 RangeXD() { 0047 for (std::size_t i = 0; i < Dims; ++i) { 0048 min(i) = std::numeric_limits<Type>::lowest(); 0049 max(i) = std::numeric_limits<Type>::max(); 0050 } 0051 } 0052 0053 /// @brief Construct a range from a pair of minimum and maximum values 0054 /// @param minima The minimum values of the range 0055 /// @param maxima The maximum values of the range 0056 RangeXD(Vector<Type, Dims> minima, Vector<Type, Dims> maxima) 0057 : m_minima(minima), m_maxima(maxima) {} 0058 0059 /// @brief Construct a range from a pair of single minimum and maximum values 0060 /// @note Only available for one-dimensional ranges 0061 /// @param minimum The minimum value of the range 0062 /// @param maximum The maximum value of the range 0063 RangeXD(Type minimum, Type maximum) 0064 requires(Dims == 1) 0065 : m_minima({minimum}), m_maxima({maximum}) {} 0066 0067 /// @brief Construct a range from a pair of minimum and maximum values 0068 /// @note Only available for one-dimensional ranges 0069 /// @param p The pair of minimum and maximum values 0070 RangeXD(const std::pair<Type, Type>& p) 0071 requires(Dims == 1) 0072 : m_minima({p.first}), m_maxima({p.second}) {} 0073 0074 /// @brief Determine whether this range is degenerate 0075 /// 0076 /// A degenerate multi-dimensional range has no volume and cannot contain 0077 /// any values. This is the case if any of its dimensions are degenerate. 0078 /// 0079 /// @return true The range is degenerate 0080 /// @return false The range is not degenerate 0081 bool degenerate() const { 0082 for (std::size_t i = 0; i < Dims; ++i) { 0083 if (min(i) >= max(i)) { 0084 return true; 0085 } 0086 } 0087 return false; 0088 } 0089 0090 /// @brief Determine whether the range contains a certain point 0091 /// 0092 /// This is true if and only if the range contains the point in all of its 0093 /// dimensions. 0094 /// 0095 /// @param v The coordinate to check for membership in the range 0096 /// 0097 /// @return true The coordinate is inside the range 0098 /// @return false The coordinate is outside the range 0099 template <template <typename, std::size_t> typename coordinate_t = std::array> 0100 bool contains(const coordinate_t<Type, Dims>& v) const { 0101 for (std::size_t i = 0; i < Dims; ++i) { 0102 if (!(min(i) <= v[i] && v[i] < max(i))) { 0103 return false; 0104 } 0105 } 0106 0107 return true; 0108 } 0109 0110 /// @brief Access one of the dimensional ranges of the volume 0111 /// 0112 /// @param i The index of the dimension to access 0113 /// @return A reference to the dimension contained in this range 0114 RangeXD<1, Type, SingleElementContainer> operator[](const std::size_t& i) { 0115 return RangeXD<1, Type, SingleElementContainer>{{&min(i)}, {&max(i)}}; 0116 } 0117 0118 /// @brief Access one of the dimensional ranges of the volume 0119 /// 0120 /// @param i The index of the dimension to access 0121 /// @return A reference to the dimension contained in this range 0122 RangeXD<1, Type> operator[](const std::size_t& i) const { 0123 return RangeXD<1, Type>{{min(i)}, {max(i)}}; 0124 } 0125 0126 /// @brief Assignment operator 0127 /// 0128 /// Copy the right-hand range into the left-hand range, which means setting 0129 /// the minimum and maximum to equal the minimum and maximum of the 0130 /// right-hand side. 0131 /// 0132 /// @param o The range of values to copy 0133 /// 0134 /// @return This range 0135 template <template <typename, std::size_t> typename V> 0136 RangeXD& operator=(const RangeXD<Dims, Type, V>& o) { 0137 for (std::size_t i = 0; i < Dims; ++i) { 0138 min(i) = o.min(i); 0139 max(i) = o.max(i); 0140 } 0141 0142 return *this; 0143 } 0144 0145 /// @brief Determine whether two ranges are equal 0146 /// 0147 /// Two n-dimensional ranges are equal if and only if they are equal in each 0148 /// of their n dimensions. 0149 /// 0150 /// @param o The other range to check for equality 0151 /// 0152 /// @return true The ranges are equal 0153 /// @return false The ranges are not equal 0154 bool operator==(const RangeXD<Dims, Type, Vector>& o) const { 0155 for (std::size_t i = 0; i < Dims; ++i) { 0156 if (!(min(i) == o.min(i) && max(i) == o.max(i))) { 0157 return false; 0158 } 0159 } 0160 0161 return true; 0162 } 0163 0164 /// @brief Determine whether one range is a subset of another range 0165 /// 0166 /// One range is a subset of another range if and only if all points 0167 /// contained within the first set are also contained within the second set. 0168 /// Alternatively, this is equivalent to each of the first range's 0169 /// one-dimensional ranges being a subset of the second range's equivalent 0170 /// one-dimensional range. 0171 /// 0172 /// @param o The other range to compare to 0173 /// 0174 /// @return true The first range is a subset of the second range 0175 /// @return false The first range is not a subset of the second range 0176 bool operator<=(const RangeXD<Dims, Type, Vector>& o) const { 0177 for (std::size_t i = 0; i < Dims; ++i) { 0178 if (!(min(i) >= o.min(i) && max(i) <= o.max(i))) { 0179 return false; 0180 } 0181 } 0182 0183 return true; 0184 } 0185 0186 /// @brief Determine whether one range is a superset of another range 0187 /// 0188 /// One range is a superset of another range if and only if all points 0189 /// contained within the second range are also contained within the first 0190 /// range. Alternatively, this is equivalent to each of the one-dimensional 0191 /// ranges in the first range being a superset of the corresponding 0192 /// one-dimensional range in the second range. 0193 /// 0194 /// @param o The other range to compare to 0195 /// 0196 /// @return true The left-hand range is a superset of the right-hand range 0197 /// @return false The left-hand range is not a superset of the right-hand 0198 /// range 0199 bool operator>=(const RangeXD<Dims, Type, Vector>& o) const { 0200 for (std::size_t i = 0; i < Dims; ++i) { 0201 if (!(min(i) <= o.min(i) && max(i) >= o.max(i))) { 0202 return false; 0203 } 0204 } 0205 0206 return true; 0207 } 0208 0209 /// @brief Compute the intersection of this range with another range 0210 /// 0211 /// The intersection of one orthogonal range with another orthogonal range 0212 /// is in itself an orthogonal range. This operation is commutative. This 0213 /// intersection between two n-dimensional ranges is defined simply as the 0214 /// intersection in each dimension of the two ranges. 0215 /// 0216 /// @param o The orthogonal range to compute the intersection with 0217 /// 0218 /// @return The intersection between the ranges 0219 RangeXD<Dims, Type, Vector> operator&( 0220 const RangeXD<Dims, Type, Vector>& o) const { 0221 RangeXD<Dims, Type> res; 0222 0223 for (std::size_t i = 0; i < Dims; ++i) { 0224 res.min(i) = std::max(min(i), o.min(i)); 0225 res.max(i) = std::min(max(i), o.max(i)); 0226 } 0227 0228 return res; 0229 } 0230 0231 /// @brief Update the range to the intersection with another range 0232 /// 0233 /// This is the assignment version of the operator& method, meaning that it 0234 /// updates the object on which it is called rather than producing a new 0235 /// range. 0236 /// 0237 /// @param o The range to compute the intersection with 0238 /// 0239 /// @return This object 0240 RangeXD<Dims, Type, Vector>& operator&=( 0241 const RangeXD<Dims, Type, Vector>& o) { 0242 for (std::size_t i = 0; i < Dims; ++i) { 0243 min(i) = std::max(min(i), o.min(i)); 0244 max(i) = std::min(max(i), o.max(i)); 0245 } 0246 0247 return *this; 0248 } 0249 0250 /// @brief Determine whether this range intersects another 0251 /// 0252 /// Two n-dimensional ranges intersect if and only if they intersect in 0253 /// every one of their n dimensions. Otherwise, they are disjoint. 0254 /// 0255 /// @param r The other range to check 0256 /// 0257 /// @return true The ranges intersect 0258 /// @return false The ranges do not intersect 0259 bool operator&&(const RangeXD<Dims, Type, Vector>& r) const { 0260 for (std::size_t i = 0; i < Dims; ++i) { 0261 if (!(min(i) < r.max(i) && r.min(i) < max(i))) { 0262 return false; 0263 } 0264 } 0265 0266 return true; 0267 } 0268 0269 /// @brief Represent the range as a string 0270 /// 0271 /// This method produces a helpful string that can be used to debug the 0272 /// range if needed. Not really designed to be used in production code. 0273 /// 0274 /// @return A string representing the range 0275 std::string toString(void) const { 0276 std::stringstream s; 0277 0278 for (std::size_t i = 0; i < Dims; ++i) { 0279 s << min(i) << " <= v[" << i << "] <= " << max(i); 0280 if (i != Dims - 1) { 0281 s << ", "; 0282 } 0283 } 0284 0285 return s.str(); 0286 } 0287 0288 /// @brief Shrink a range by increasing the minimum value 0289 /// 0290 /// Shrink the range by increasing the minimum value. If the given value is 0291 /// smaller than the current minimum (in other words, if the proposed new 0292 /// range would be larger than the current range), this is a no-op. 0293 /// 0294 /// @param i The index of the dimension to shrink 0295 /// @param v The proposed new minimum for the range 0296 void shrinkMin(std::size_t i, const Type& v) { min(i) = std::max(min(i), v); } 0297 0298 /// @brief Shrink a range by decreasing the maximum value 0299 /// 0300 /// Shrink the range by decreasing the maximum value. If the given value is 0301 /// larger than the current maximum (in other words, if the proposed new 0302 /// range would be larger than the current range), this is a no-op. 0303 /// 0304 /// @param i The index of the dimension to shrink 0305 /// @param v The proposed new maximum for the range 0306 void shrinkMax(std::size_t i, const Type& v) { max(i) = std::min(max(i), v); } 0307 0308 /// @brief Shrink a range on both ends 0309 /// 0310 /// Shrink a range by increasing the minimum value as well as decreasing the 0311 /// maximum value. If either of the values are already smaller or larger 0312 /// (respectively) than the proposed values, then that particular boundary 0313 /// of the interval is not shrunk. 0314 /// 0315 /// @note After this operation, the range is always equal to or smaller than 0316 /// [min, max]. 0317 /// 0318 /// @param i The index of the dimension to shrink 0319 /// @param min The proposed new minimum for the range 0320 /// @param max The proposed new maximum for the range 0321 void shrink(std::size_t i, const Type& min, const Type& max) { 0322 shrinkMin(i, min); 0323 shrinkMax(i, max); 0324 } 0325 0326 /// @brief Expand a range by decreasing the minimum value 0327 /// 0328 /// Expand the range by decreasing the minimum value. If the given value is 0329 /// larger than the current minimum (in other words, if the proposed new 0330 /// range would be smaller than the current range), this is a no-op. 0331 /// 0332 /// @param i The index of the dimension to expand 0333 /// @param v The proposed new minimum for the range 0334 void expandMin(std::size_t i, const Type& v) { min(i) = std::min(min(i), v); } 0335 0336 /// @brief Expand a range by increasing the maximum value 0337 /// 0338 /// Expand the range by increasing the maximum value. If the given value is 0339 /// smaller than the current maximum (in other words, if the proposed new 0340 /// range would be smaller than the current range), this is a no-op. 0341 /// 0342 /// @param i The index of the dimension to expand 0343 /// @param v The proposed new maximum for the range 0344 void expandMax(std::size_t i, const Type& v) { max(i) = std::max(max(i), v); } 0345 0346 /// @brief Expand a range on both ends 0347 /// 0348 /// Expand a range by decreasing the minimum value as well as increasing the 0349 /// maximum value. If either of the values are already larger or smaller 0350 /// (respectively) than the proposed values, then that particular boundary 0351 /// of the interval is not expanded. 0352 /// 0353 /// @note After this operation, the range is always equal to or larger than 0354 /// [min, max]. 0355 /// 0356 /// @param i The index of the dimension to expand 0357 /// @param min The proposed new minimum for the range 0358 /// @param max The proposed new maximum for the range 0359 void expand(std::size_t i, const Type& min, const Type& max) { 0360 expandMin(i, min); 0361 expandMax(i, max); 0362 } 0363 0364 /// @brief Set the minimum value 0365 /// 0366 /// Override the minimum value of the range, regardless of what was already 0367 /// set. 0368 /// 0369 /// @note If you want to shrink or expand the range, use the shrink and 0370 /// expand methods. 0371 /// 0372 /// @param i The index of the dimension to set 0373 /// @param v The value to use as the new minimum 0374 void setMin(std::size_t i, const Type& v) { min(i) = v; } 0375 0376 /// @brief Set the maximum value 0377 /// 0378 /// Override the maximum value of the range, regardless of what was already 0379 /// set. 0380 /// 0381 /// @note If you want to shrink or expand the range, use the shrink and 0382 /// expand methods. 0383 /// 0384 /// @param i The index of the dimension to set 0385 /// @param v The value to use as the new maximum 0386 void setMax(std::size_t i, const Type& v) { max(i) = v; } 0387 0388 /// @brief Set the minimum and maximum value 0389 /// 0390 /// Override both the minimum and maximum value of the range, regardless of 0391 /// what they were set to. 0392 /// 0393 /// @note If you want to shrink or expand the range, use the shrink and 0394 /// expand methods. 0395 /// 0396 /// @note After this operation, the range should be exactly equal to [min, 0397 /// max] 0398 /// 0399 /// @param i The index of the dimension to set 0400 /// @param min The new minimum value of the range 0401 /// @param max The new maximum value of the range 0402 void set(std::size_t i, const Type& min, const Type& max) { 0403 setMin(i, min); 0404 setMax(i, max); 0405 } 0406 0407 /// @brief Return the minimum value of the range @p i (inclusive) 0408 /// @param i The index of the dimension to access 0409 Type& min(std::size_t i) { return m_minima[i]; } 0410 0411 /// @brief Return the maximum value of the range @p i (inclusive) 0412 /// @param i The index of the dimension to access 0413 Type& max(std::size_t i) { return m_maxima[i]; } 0414 0415 /// @brief Return the minimum value of the range @p i (inclusive) 0416 /// @param i The index of the dimension to access 0417 Type min(std::size_t i) const { return m_minima[i]; } 0418 0419 /// @brief Return the maximum value of the range @p i (inclusive) 0420 /// @param i The index of the dimension to access 0421 Type max(std::size_t i) const { return m_maxima[i]; } 0422 0423 /// Methods for manipulating a range of dimension 1 0424 /// @{ 0425 0426 /// @brief Expand a range by decreasing the minimum value 0427 /// 0428 /// Expand the range by decreasing the minimum value. If the given value is 0429 /// larger than the current minimum (in other words, if the proposed new 0430 /// range would be smaller than the current range), this is a no-op. 0431 /// 0432 /// @param v The proposed new minimum for the range 0433 void expandMin(const Type& v) 0434 requires(Dims == 1) 0435 { 0436 min() = std::min(min(), v); 0437 } 0438 0439 /// @brief Expand a range by increasing the maximum value 0440 /// 0441 /// Expand the range by increasing the maximum value. If the given value is 0442 /// smaller than the current maximum (in other words, if the proposed new 0443 /// range would be smaller than the current range), this is a no-op. 0444 /// 0445 /// @param v The proposed new maximum for the range 0446 void expandMax(const Type& v) 0447 requires(Dims == 1) 0448 { 0449 max() = std::max(max(), v); 0450 } 0451 0452 /// @brief Expand a range on both ends 0453 /// 0454 /// Expand a range by decreasing the minimum value as well as increasing the 0455 /// maximum value. If either of the values are already larger or smaller 0456 /// (respectively) than the proposed values, then that particular boundary 0457 /// of the interval is not expanded. 0458 /// 0459 /// @note After this operation, the range is always equal to or larger than 0460 /// [min, max]. 0461 /// 0462 /// @param min The proposed new minimum for the range 0463 /// @param max The proposed new maximum for the range 0464 void expand(const Type& min, const Type& max) 0465 requires(Dims == 1) 0466 { 0467 expandMin(min); 0468 expandMax(max); 0469 } 0470 0471 /// @brief Shrink a range by increasing the minimum value 0472 /// 0473 /// Shrink the range by increasing the minimum value. If the given value is 0474 /// smaller than the current minimum (in other words, if the proposed new 0475 /// range would be larger than the current range), this is a no-op. 0476 /// 0477 /// @param v The proposed new minimum for the range 0478 void shrinkMin(const Type& v) 0479 requires(Dims == 1) 0480 { 0481 min() = std::max(min(), v); 0482 } 0483 0484 /// @brief Shrink a range by decreasing the maximum value 0485 /// 0486 /// Shrink the range by decreasing the maximum value. If the given value is 0487 /// larger than the current maximum (in other words, if the proposed new 0488 /// range would be larger than the current range), this is a no-op. 0489 /// 0490 /// @param v The proposed new maximum for the range 0491 void shrinkMax(const Type& v) 0492 requires(Dims == 1) 0493 { 0494 max() = std::min(max(), v); 0495 } 0496 0497 /// @brief Shrink a range on both ends 0498 /// 0499 /// Shrink a range by increasing the minimum value as well as decreasing the 0500 /// maximum value. If either of the values are already smaller or larger 0501 /// (respectively) than the proposed values, then that particular boundary 0502 /// of the interval is not shrunk. 0503 /// 0504 /// @note After this operation, the range is always equal to or smaller than 0505 /// [min, max]. 0506 /// 0507 /// @param min The proposed new minimum for the range 0508 /// @param max The proposed new maximum for the range 0509 void shrink(const Type& min, const Type& max) 0510 requires(Dims == 1) 0511 { 0512 shrinkMin(min); 0513 shrinkMax(max); 0514 } 0515 0516 /// @brief Set the minimum value 0517 /// 0518 /// Override the minimum value of the range, regardless of what was already 0519 /// set. 0520 /// 0521 /// @note If you want to shrink or expand the range, use the shrink and 0522 /// expand methods. 0523 /// 0524 /// @param v The value to use as the new minimum 0525 void setMin(const Type& v) 0526 requires(Dims == 1) 0527 { 0528 min() = v; 0529 } 0530 0531 /// @brief Set the maximum value 0532 /// 0533 /// Override the maximum value of the range, regardless of what was already 0534 /// set. 0535 /// 0536 /// @note If you want to shrink or expand the range, use the shrink and 0537 /// expand methods. 0538 /// 0539 /// @param v The value to use as the new maximum 0540 void setMax(const Type& v) 0541 requires(Dims == 1) 0542 { 0543 max() = v; 0544 } 0545 0546 /// @brief Set the minimum and maximum value 0547 /// 0548 /// Override both the minimum and maximum value of the range, regardless of 0549 /// what they were set to. 0550 /// 0551 /// @note If you want to shrink or expand the range, use the shrink and 0552 /// expand methods. 0553 /// 0554 /// @note After this operation, the range should be exactly equal to [min, 0555 /// max] 0556 /// 0557 /// @param min The new minimum value of the range 0558 /// @param max The new maximum value of the range 0559 void set(const Type& min, const Type& max) 0560 requires(Dims == 1) 0561 { 0562 setMin(min); 0563 setMax(max); 0564 } 0565 0566 /// @brief Return the minimum value of the range (inclusive) 0567 Type min() const 0568 requires(Dims == 1) 0569 { 0570 return min(0); 0571 } 0572 0573 /// @brief Return the minimum value of the range (inclusive) 0574 Type& min() 0575 requires(Dims == 1) 0576 { 0577 return min(0); 0578 } 0579 0580 /// @brief Return the maximum value of the range (inclusive) 0581 Type max() const 0582 requires(Dims == 1) 0583 { 0584 return max(0); 0585 } 0586 0587 /// @brief Return the maximum value of the range (inclusive) 0588 Type& max() 0589 requires(Dims == 1) 0590 { 0591 return max(0); 0592 } 0593 0594 /// @brief Compute the size of the range 0595 /// 0596 /// The size of a range is defined as the difference between the minimum and 0597 /// the maximum. For degenerate ranges, this is zero. 0598 /// 0599 /// @warning Due to the nature of numbers, the result of this function can be 0600 /// somewhat ambiguous. For natural numbers, you could argue that the range 0601 /// [n, n] has size 0 or size 1. In this case we say it has size 0. The 0602 /// uncountable nature of the reals means this doesn't matter for them, but 0603 /// this can be awkward when working with integers. 0604 /// 0605 /// @return The size of the range 0606 Type size() const 0607 requires(Dims == 1) 0608 { 0609 return std::max(static_cast<Type>(0), max() - min()); 0610 } 0611 0612 /// @brief Determine if the range contains a given value 0613 /// 0614 /// A value is inside a range if and only if it is greater than the minimum 0615 /// and smaller than the maximum. 0616 /// 0617 /// @param v The value to check 0618 /// 0619 /// @return true The value is inside the range 0620 /// @return false The value is not inside the range 0621 bool contains(const Type& v) const 0622 requires(Dims == 1) 0623 { 0624 return min() <= v && v < max(); 0625 } 0626 0627 /// @} 0628 0629 private: 0630 Vector<Type, Dims> m_minima{}; 0631 Vector<Type, Dims> m_maxima{}; 0632 }; 0633 0634 template <typename Type, 0635 template <typename, std::size_t> typename Vector = std::array> 0636 using Range1D = RangeXD<1, Type, Vector>; 0637 0638 } // namespace Acts
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |