Blender V5.0
BLI_bounds.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
12
13#include <optional>
14
15#include "BLI_bounds_types.hh"
16#include "BLI_index_mask.hh"
17#include "BLI_math_matrix.hh"
18#include "BLI_math_vector.hh"
19#include "BLI_task.hh"
20#include "BLI_virtual_array.hh"
21
22namespace blender {
23
24namespace bounds {
25
26template<typename T> [[nodiscard]] inline Bounds<T> merge(const Bounds<T> &a, const Bounds<T> &b)
27{
28 return {math::min(a.min, b.min), math::max(a.max, b.max)};
30
31template<typename T>
32[[nodiscard]] inline std::optional<Bounds<T>> merge(const std::optional<Bounds<T>> &a,
33 const std::optional<Bounds<T>> &b)
34{
35 if (a.has_value() && b.has_value()) {
36 return merge(*a, *b);
37 }
38 if (a.has_value()) {
39 return a;
40 }
41 if (b.has_value()) {
42 return b;
43 }
44 return std::nullopt;
45}
47template<typename T>
48[[nodiscard]] inline std::optional<Bounds<T>> merge(const std::optional<Bounds<T>> &a,
49 const Bounds<T> &b)
50{
51 return merge(a, std::optional<Bounds<T>>(b));
52}
54template<typename T>
55[[nodiscard]] inline std::optional<Bounds<T>> min_max(const std::optional<Bounds<T>> &a,
56 const T &b)
57{
58 if (a.has_value()) {
59 return merge(*a, {b, b});
60 }
61 return Bounds<T>{b, b};
62}
63
64/**
65 * Find the smallest and largest values element-wise in the span.
66 */
67template<typename T> [[nodiscard]] inline std::optional<Bounds<T>> min_max(const Span<T> values)
68{
69 if (values.is_empty()) {
70 return std::nullopt;
71 }
72 const Bounds<T> init{values.first(), values.first()};
74 values.index_range(),
75 1024,
76 init,
77 [&](const IndexRange range, const Bounds<T> &init) {
78 Bounds<T> result = init;
79 for (const int i : range) {
80 math::min_max(values[i], result.min, result.max);
81 }
82 return result;
83 },
84 [](const Bounds<T> &a, const Bounds<T> &b) { return merge(a, b); });
85}
86
87template<typename T>
88[[nodiscard]] inline std::optional<Bounds<T>> min_max(const IndexMask &mask, const Span<T> values)
89{
90 if (values.is_empty() || mask.is_empty()) {
91 return std::nullopt;
92 }
93 if (mask.size() == values.size()) {
94 /* To avoid mask slice/lookup. */
95 return min_max(values);
96 }
97 const Bounds<T> init{values.first(), values.first()};
99 mask.index_range(),
100 1024,
101 init,
102 [&](const IndexRange range, const Bounds<T> &init) {
103 Bounds<T> result = init;
104 mask.slice(range).foreach_index_optimized<int64_t>(
105 [&](const int i) { math::min_max(values[i], result.min, result.max); });
106 return result;
107 },
108 [](const Bounds<T> &a, const Bounds<T> &b) { return merge(a, b); });
109}
110
115template<typename T, typename RadiusT>
116[[nodiscard]] inline std::optional<Bounds<T>> min_max_with_radii(const Span<T> values,
117 const Span<RadiusT> radii)
118{
119 BLI_assert(values.size() == radii.size());
120 if (values.is_empty()) {
121 return std::nullopt;
122 }
123 const Bounds<T> init{values.first(), values.first()};
125 values.index_range(),
126 1024,
127 init,
128 [&](const IndexRange range, const Bounds<T> &init) {
129 Bounds<T> result = init;
130 for (const int i : range) {
131 result.min = math::min(values[i] - radii[i], result.min);
132 result.max = math::max(values[i] + radii[i], result.max);
133 }
134 return result;
135 },
136 [](const Bounds<T> &a, const Bounds<T> &b) { return merge(a, b); });
137}
138
143template<typename T>
144[[nodiscard]] inline std::optional<Bounds<T>> intersect(const Bounds<T> &a, const Bounds<T> &b)
145{
146 const Bounds<T> result{math::max(a.min, b.min), math::min(a.max, b.max)};
147 if (result.is_empty()) {
148 return std::nullopt;
149 }
150 return result;
151}
152template<typename T>
153[[nodiscard]] inline std::optional<Bounds<T>> intersect(const std::optional<Bounds<T>> &a,
154 const std::optional<Bounds<T>> &b)
155{
156 if (!a.has_value() || !b.has_value()) {
157 return std::nullopt;
158 }
159 return intersect(*a, *b);
160}
161
165template<typename T> inline std::optional<T> max(const VArray<T> &values)
166{
167 if (values.is_empty()) {
168 return std::nullopt;
169 }
170 if (const std::optional<T> value = values.get_if_single()) {
171 return value;
172 }
173 const VArraySpan<int> values_span = values;
175 values_span.index_range(),
176 2048,
177 std::numeric_limits<T>::min(),
178 [&](const IndexRange range, int current_max) {
179 for (const int value : values_span.slice(range)) {
180 current_max = std::max(current_max, value);
181 }
182 return current_max;
183 },
184 [](const int a, const int b) { return std::max(a, b); });
185}
186
206template<typename T>
207inline std::array<VecBase<T, 3>, 8> corners(const Bounds<VecBase<T, 3>> &bounds)
208{
209 return {
210 VecBase<T, 3>{bounds.min[0], bounds.min[1], bounds.min[2]},
211 VecBase<T, 3>{bounds.min[0], bounds.min[1], bounds.max[2]},
212 VecBase<T, 3>{bounds.min[0], bounds.max[1], bounds.max[2]},
213 VecBase<T, 3>{bounds.min[0], bounds.max[1], bounds.min[2]},
214 VecBase<T, 3>{bounds.max[0], bounds.min[1], bounds.min[2]},
215 VecBase<T, 3>{bounds.max[0], bounds.min[1], bounds.max[2]},
216 VecBase<T, 3>{bounds.max[0], bounds.max[1], bounds.max[2]},
217 VecBase<T, 3>{bounds.max[0], bounds.max[1], bounds.min[2]},
218 };
219}
220
231template<typename T, int D>
234{
235 std::array<VecBase<T, 3>, 8> points = corners(bounds);
236 for (VecBase<T, 3> &p : points) {
237 p = math::transform_point(matrix, p);
238 }
239 return {math::min(Span(points)), math::max(Span(points))};
240}
241
242} // namespace bounds
243
244namespace detail {
245
246template<typename T, int Size>
247[[nodiscard]] inline bool any_less_or_equal_than(const VecBase<T, Size> &a,
248 const VecBase<T, Size> &b)
249{
250 for (int i = 0; i < Size; i++) {
251 if (a[i] <= b[i]) {
252 return true;
253 }
254 }
255 return false;
256}
257
258} // namespace detail
259
260template<typename T> inline bool Bounds<T>::is_empty() const
261{
262 if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
263 return this->max <= this->min;
264 }
265 else {
266 return detail::any_less_or_equal_than(this->max, this->min);
267 }
268}
269
270template<typename T> inline T Bounds<T>::center() const
271{
272 return math::midpoint(this->min, this->max);
273}
274
275template<typename T> inline T Bounds<T>::size() const
276{
277 return math::abs(max - min);
278}
279
280template<typename T> inline void Bounds<T>::translate(const T &offset)
281{
282 this->min += offset;
283 this->max += offset;
284}
285
286template<typename T> inline void Bounds<T>::scale_from_center(const T &scale)
287{
288 const T center = this->center();
289 const T new_half_size = this->size() / T(2) * scale;
290 this->min = center - new_half_size;
291 this->max = center + new_half_size;
292}
293
294template<typename T> inline void Bounds<T>::resize(const T &new_size)
295{
296 this->min = this->center() - (new_size / T(2));
297 this->max = this->min + new_size;
298}
299
300template<typename T> inline void Bounds<T>::recenter(const T &new_center)
301{
302 const T offset = new_center - this->center();
303 this->translate(offset);
304}
305
306template<typename T>
307template<typename PaddingT>
308inline void Bounds<T>::pad(const PaddingT &padding)
309{
310 this->min = this->min - padding;
311 this->max = this->max + padding;
312}
313
314} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b)
Definition boundbox.h:184
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
std::optional< T > get_if_single() const
uint padding(uint offset, uint alignment)
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define T
Bounds< VecBase< T, 3 > > transform_bounds(const MatBase< T, D, D > &matrix, const Bounds< VecBase< T, 3 > > &bounds)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:26
std::array< VecBase< T, 3 >, 8 > corners(const Bounds< VecBase< T, 3 > > &bounds)
std::optional< Bounds< T > > min_max_with_radii(const Span< T > values, const Span< RadiusT > radii)
std::optional< Bounds< T > > min_max(const std::optional< Bounds< T > > &a, const T &b)
Definition BLI_bounds.hh:55
bool any_less_or_equal_than(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T min(const T &a, const T &b)
T midpoint(const T &a, const T &b)
T max(const T &a, const T &b)
T abs(const T &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
static void init(bNodeTree *, bNode *node)
void scale_from_center(const T &scale)
void recenter(const T &new_center)
void resize(const T &new_size)
void pad(const PaddingT &padding)
void translate(const T &offset)
T size() const
T center() const
bool is_empty() const
void translate(const T &offset)
T center() const
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251