Blender V4.3
BLI_math_basis_types.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
26#include <iosfwd>
27
28#include "BLI_math_base.hh"
30
31namespace blender::math {
32
33/* -------------------------------------------------------------------- */
42class Axis {
43 public:
44 enum class Value : int8_t {
45 /* Must start at 0. Used as indices in tables and vectors. */
46 X = 0,
47 Y,
48 Z,
49 };
50
51 constexpr static Value X = Value::X;
52 constexpr static Value Y = Value::Y;
53 constexpr static Value Z = Value::Z;
54
55 private:
56 Value axis_;
57
58 public:
59 Axis() = default;
60
61 constexpr Axis(const Value axis) : axis_(axis){};
62
64 constexpr static Axis from_char(char axis_char)
65 {
66 const Axis axis = static_cast<Value>(axis_char - 'X');
67 BLI_assert(int(Value::X) <= axis.as_int() && axis.as_int() <= int(Value::Z));
68 return axis;
69 }
70
72 constexpr static Axis from_int(const int axis_int)
73 {
74 const Axis axis = static_cast<Value>(axis_int);
75 BLI_assert(Axis::X <= axis && axis <= Axis::Z);
76 return axis;
77 }
78
79 /* Allow usage in `switch()` statements and comparisons. */
80 constexpr operator Value() const
81 {
82 return axis_;
83 }
84
85 constexpr int as_int() const
86 {
87 return int(axis_);
88 }
89
91 explicit operator bool() const = delete;
92
93 friend std::ostream &operator<<(std::ostream &stream, const Axis axis);
94};
95
102 public:
103 enum class Value : int8_t {
104 /* Match #eTrackToAxis_Modes */
105 /* Must start at 0. Used as indices in tables and vectors. */
106 X_POS = 0,
107 Y_POS = 1,
108 Z_POS = 2,
109 X_NEG = 3,
110 Y_NEG = 4,
111 Z_NEG = 5,
112 };
113
114 constexpr static Value X_POS = Value::X_POS;
115 constexpr static Value Y_POS = Value::Y_POS;
116 constexpr static Value Z_POS = Value::Z_POS;
117 constexpr static Value X_NEG = Value::X_NEG;
118 constexpr static Value Y_NEG = Value::Y_NEG;
119 constexpr static Value Z_NEG = Value::Z_NEG;
120
121 private:
122 Value axis_;
123
124 public:
125 AxisSigned() = default;
126
127 constexpr AxisSigned(Value axis) : axis_(axis){};
128 constexpr AxisSigned(Axis axis) : axis_(from_int(axis.as_int())){};
129
131 constexpr static AxisSigned from_int(int axis_int)
132 {
133 const AxisSigned axis = static_cast<Value>(axis_int);
135 return axis;
136 }
137
139 constexpr Axis axis() const
140 {
141 return Axis::from_int(this->as_int() % 3);
142 }
143
146 {
147 return from_int((this->as_int() + 3) % 6);
148 }
149
152 {
153 return from_int((this->as_int() + 1) % 6);
154 }
155
157 constexpr operator Value() const
158 {
159 return axis_;
160 }
161
162 constexpr int as_int() const
163 {
164 return int(axis_);
165 }
166
168 constexpr int sign() const
169 {
170 return is_negative() ? -1 : 1;
171 }
172
174 constexpr bool is_negative() const
175 {
176 return int(axis_) > int(Value::Z_POS);
177 }
178
180 explicit operator bool() const = delete;
181
182 friend std::ostream &operator<<(std::ostream &stream, const AxisSigned axis);
183};
184
185constexpr bool operator<=(const Axis::Value a, const Axis::Value b)
186{
187 return int(a) <= int(b);
188}
189
190constexpr bool operator<=(const AxisSigned::Value a, const AxisSigned::Value b)
191{
192 return int(a) <= int(b);
193}
194
197/* -------------------------------------------------------------------- */
201template<> inline AxisSigned abs(const AxisSigned &axis)
202{
203 return axis.axis();
204}
205
206[[nodiscard]] inline int sign(const AxisSigned &axis)
207{
208 return axis.sign();
209}
210
217[[nodiscard]] inline AxisSigned cross(const AxisSigned a, const AxisSigned b)
218{
219 BLI_assert_msg(abs(a) != abs(b), "Axes must not be colinear.");
220 switch (a) {
222 switch (b) {
224 break; /* Ill-defined. */
226 return AxisSigned::Z_POS;
228 return AxisSigned::Y_NEG;
230 break; /* Ill-defined. */
232 return AxisSigned::Z_NEG;
234 return AxisSigned::Y_POS;
235 }
236 break;
238 switch (b) {
240 return AxisSigned::Z_NEG;
242 break; /* Ill-defined. */
244 return AxisSigned::X_POS;
246 return AxisSigned::Z_POS;
248 break; /* Ill-defined. */
250 return AxisSigned::X_NEG;
251 }
252 break;
254 switch (b) {
256 return AxisSigned::Y_POS;
258 return AxisSigned::X_NEG;
260 break; /* Ill-defined. */
262 return AxisSigned::Y_NEG;
264 return AxisSigned::X_POS;
266 break; /* Ill-defined. */
267 }
268 break;
270 switch (b) {
272 break; /* Ill-defined. */
274 return AxisSigned::Z_NEG;
276 return AxisSigned::Y_POS;
278 break; /* Ill-defined. */
280 return AxisSigned::Z_POS;
282 return AxisSigned::Y_NEG;
283 }
284 break;
286 switch (b) {
288 return AxisSigned::Z_POS;
290 break; /* Ill-defined. */
292 return AxisSigned::X_NEG;
294 return AxisSigned::Z_NEG;
296 break; /* Ill-defined. */
298 return AxisSigned::X_POS;
299 }
300 break;
302 switch (b) {
304 return AxisSigned::Y_NEG;
306 return AxisSigned::X_POS;
308 break; /* Ill-defined. */
310 return AxisSigned::Y_POS;
312 return AxisSigned::X_NEG;
314 break; /* Ill-defined. */
315 }
316 break;
317 }
318 return a.next_after();
319}
320
322template<typename T> T to_vector(const Axis axis)
323{
324 BLI_assert(axis.as_int() < T::type_length);
325 T vec{};
326 vec[axis.as_int()] = 1;
327 return vec;
328}
329
331template<typename T> T to_vector(const AxisSigned axis)
332{
333 BLI_assert(abs(axis) <= AxisSigned::from_int(T::type_length - 1));
334 T vec{};
335 vec[abs(axis).as_int()] = axis.is_negative() ? -1 : 1;
336 return vec;
337}
338
341/* -------------------------------------------------------------------- */
351
352 CartesianBasis() = default;
353
358 CartesianBasis(const AxisSigned x, const AxisSigned y, const AxisSigned z) : axes(x, y, z)
359 {
360 BLI_assert(abs(x) != abs(y));
361 BLI_assert(abs(y) != abs(z));
362 BLI_assert(abs(z) != abs(x));
363 }
364
365 const AxisSigned &x() const
366 {
367 return axes.x;
368 }
369
370 const AxisSigned &y() const
371 {
372 return axes.y;
373 }
374
375 const AxisSigned &z() const
376 {
377 return axes.z;
378 }
379
381 {
382 return axes.x;
383 }
384
386 {
387 return axes.y;
388 }
389
391 {
392 return axes.z;
393 }
394
395 friend std::ostream &operator<<(std::ostream &stream, const CartesianBasis &rot);
396};
397
405[[nodiscard]] inline CartesianBasis from_orthonormal_axes(const AxisSigned forward,
406 const AxisSigned up)
407{
408 BLI_assert(math::abs(forward) != math::abs(up));
409 return {cross(forward, up), forward, up};
410}
411
415[[nodiscard]] inline CartesianBasis rotation_between(const CartesianBasis &a,
416 const CartesianBasis &b)
417{
418 CartesianBasis basis;
419 basis.axes[abs(b.x()).as_int()] = (sign(b.x()) != sign(a.x())) ? -abs(a.x()) : abs(a.x());
420 basis.axes[abs(b.y()).as_int()] = (sign(b.y()) != sign(a.y())) ? -abs(a.y()) : abs(a.y());
421 basis.axes[abs(b.z()).as_int()] = (sign(b.z()) != sign(a.z())) ? -abs(a.z()) : abs(a.z());
422 return basis;
423}
424
430[[nodiscard]] inline CartesianBasis rotation_between(const AxisSigned a_forward,
431 const AxisSigned b_forward)
432{
433 /* Pick predictable next axis. */
434 AxisSigned a_up = abs(a_forward.next_after());
435 AxisSigned b_up = abs(b_forward.next_after());
436
437 if (sign(a_forward) != sign(b_forward)) {
438 /* Flip both axis (up and right) so resulting rotation matrix sign remains positive. */
439 b_up = -b_up;
440 }
441 return rotation_between(from_orthonormal_axes(a_forward, a_up),
442 from_orthonormal_axes(b_forward, b_up));
443}
444
445template<typename T>
446[[nodiscard]] inline VecBase<T, 3> transform_point(const CartesianBasis &basis,
447 const VecBase<T, 3> &v)
448{
450 result[basis.x().axis().as_int()] = basis.x().is_negative() ? -v[0] : v[0];
451 result[basis.y().axis().as_int()] = basis.y().is_negative() ? -v[1] : v[1];
452 result[basis.z().axis().as_int()] = basis.z().is_negative() ? -v[2] : v[2];
453 return result;
454}
455
460[[nodiscard]] inline CartesianBasis invert(const CartesianBasis &basis)
461{
462 /* Returns the column where the `axis` is found in. The sign is taken from the axis value. */
463 auto search_axis = [](const CartesianBasis &basis, const Axis axis) {
464 if (basis.x().axis() == axis) {
466 }
467 if (basis.y().axis() == axis) {
469 }
471 };
473 result.x() = search_axis(basis, Axis::X);
474 result.y() = search_axis(basis, Axis::Y);
475 result.z() = search_axis(basis, Axis::Z);
476 return result;
477}
478
481} // namespace blender::math
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr AxisSigned(Value axis)
static constexpr AxisSigned from_int(int axis_int)
constexpr bool is_negative() const
friend std::ostream & operator<<(std::ostream &stream, const AxisSigned axis)
constexpr int as_int() const
friend std::ostream & operator<<(std::ostream &stream, const Axis axis)
static constexpr Axis from_char(char axis_char)
static constexpr Value Z
constexpr Axis(const Value axis)
static constexpr Axis from_int(const int axis_int)
static constexpr Value X
static constexpr Value Y
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define rot(x, k)
T sign(const T &a)
T to_vector(const Axis axis)
CartesianBasis rotation_between(const CartesianBasis &a, const CartesianBasis &b)
CartesianBasis invert(const CartesianBasis &basis)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
constexpr bool operator<=(const Axis::Value a, const Axis::Value b)
T abs(const T &a)
CartesianBasis from_orthonormal_axes(const AxisSigned forward, const AxisSigned up)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
signed char int8_t
Definition stdint.h:75
CartesianBasis(const AxisSigned x, const AxisSigned y, const AxisSigned z)
friend std::ostream & operator<<(std::ostream &stream, const CartesianBasis &rot)