geometry/bounds.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | /// @file bounds.h | ||
| 3 | /// @brief Axis-aligned boxes in double precision. | ||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <glm/glm.hpp> | ||
| 7 | |||
| 8 | #include <cmath> | ||
| 9 | #include <limits> | ||
| 10 | |||
| 11 | namespace ernie { | ||
| 12 | |||
| 13 | /// @brief An axis-aligned box; the default one is empty and grows to hold what it is given. | ||
| 14 | 832 | struct Box { | |
| 15 | 2 | glm::dvec3 min{std::numeric_limits<double>::infinity()}; | |
| 16 | 2 | glm::dvec3 max{-std::numeric_limits<double>::infinity()}; | |
| 17 | |||
| 18 | 12805 | static Box Around(const glm::dvec3& center, const glm::dvec3& halfSize) { | |
| 19 | 12805 | return {center - halfSize, center + halfSize}; | |
| 20 | } | ||
| 21 | |||
| 22 | 201 | bool Empty() const { | |
| 23 | 169 | return !(min.x <= max.x && min.y <= max.y && min.z <= max.z); | |
| 24 | } | ||
| 25 | 4 | glm::dvec3 Center() const { | |
| 26 | 4 | return 0.5 * (min + max); | |
| 27 | } | ||
| 28 | 3 | glm::dvec3 Size() const { | |
| 29 | 5 | return Empty() ? glm::dvec3(0.0) : max - min; | |
| 30 | } | ||
| 31 | |||
| 32 | 2 | Box& Extend(const glm::dvec3& point) { | |
| 33 | 2 | min = glm::min(min, point); | |
| 34 | 2 | max = glm::max(max, point); | |
| 35 | 2 | return *this; | |
| 36 | } | ||
| 37 | 88 | Box& Extend(const Box& other) { | |
| 38 | 88 | if (!other.Empty()) { | |
| 39 | 72 | min = glm::min(min, other.min); | |
| 40 | 144 | max = glm::max(max, other.max); | |
| 41 | } | ||
| 42 | 88 | return *this; | |
| 43 | } | ||
| 44 | 5 | Box Grown(double margin) const { | |
| 45 | 10 | return Empty() ? *this : Box{min - margin, max + margin}; | |
| 46 | } | ||
| 47 | |||
| 48 | /// @return The box holding this one after `transform` (Arvo's method, exact for affine maps). | ||
| 49 | 73 | Box Transformed(const glm::dmat4& transform) const { | |
| 50 | 73 | if (Empty()) { | |
| 51 | 15 | return *this; | |
| 52 | } | ||
| 53 | 58 | const glm::dvec3 translation(transform[3]); | |
| 54 | 58 | Box out{translation, translation}; | |
| 55 | 232 | for (int column = 0; column < 3; ++column) { | |
| 56 | 696 | for (int row = 0; row < 3; ++row) { | |
| 57 | 522 | const double a = transform[column][row] * min[column]; | |
| 58 | 522 | const double b = transform[column][row] * max[column]; | |
| 59 | 526 | out.min[row] += std::min(a, b); | |
| 60 | 696 | out.max[row] += std::max(a, b); | |
| 61 | } | ||
| 62 | } | ||
| 63 | 58 | return out; | |
| 64 | } | ||
| 65 | |||
| 66 | 4 | bool operator==(const Box&) const = default; | |
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace ernie | ||
| 70 |