Gamp v0.0.7-36-g24b1eb6
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
affine_transform.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11#ifndef JAU_AFFINETRANSFORM_HPP_
12#define JAU_AFFINETRANSFORM_HPP_
13
14#include <jau/functional.hpp>
15#include <jau/enum_util.hpp>
16#include <jau/float_math.hpp>
18#include <jau/math/vec2f.hpp>
19#include <jau/math/vec3f.hpp>
20#include <jau/math/vec4f.hpp>
22
24 using namespace jau::enums;
25
26 /** \addtogroup Math
27 *
28 * @{
29 */
30
31 enum class AffineTransformType : uint16_t {
32 /** The <code>AffineTransformType::unknown</code> is the initial value */
34 identity = 1 << 0,
35 translation = 1 << 1,
36 uniform_scale = 1 << 2,
37 general_scale = 1 << 3,
41 flip = 1 << 7,
44 };
46
47 /**
48 * Represents a affine 2x3 transformation matrix in column major order (memory layout).
49 *
50 * Field notation row-column: m10 (row 1, column 0).
51 */
53 private:
54 // 2x3 matrix in column major order, notation row-column: m10 (row 1, column 0)
55
56 /** scale-x */
57 float m00;
58 /** shear-y */
59 float m10;
60 /** shear-x */
61 float m01;
62 /** scale-x */
63 float m11;
64 /** translate-x */
65 float m02;
66 /** translate-y */
67 float m12;
68
70
71 constexpr static const char* determinantIsZero = "Zero Determinante";
72
73 public:
74
75 /** The min absolute value equivalent to zero, aka EPSILON. */
76 constexpr static const float ZERO = (float)1E-10;
77
78 /** Initialized to identity. */
79 constexpr AffineTransform() noexcept
80 : m00(1.0f), m10(0.0f),
81 m01(0.0f), m11(1.0f),
82 m02(0.0f), m12(0.0f),
84 { }
85
86 constexpr AffineTransform(const float m00_, const float m10_, const float m01_, const float m11_, const float m02_, const float m12_) noexcept
87 : m00(m00_), m10(m10_),
88 m01(m01_), m11(m11_),
89 m02(m02_), m12(m12_),
91 { }
92
93 /**
94 * @param mat2xN either a 2x2 or 2x3 matrix depending on mat_len
95 * @param mat_len either 6 for 2x3 matrix or 4 for 2x2 matrix
96 */
97 AffineTransform(const float mat2xN[], const jau::nsize_t mat_len) noexcept
98 : m00(mat2xN[0]), m10(mat2xN[1]),
99 m01(mat2xN[2]), m11(mat2xN[3]),
100 m02(0.0f), m12(0.0f),
102 {
103 if (mat_len > 4) {
104 m02 = mat2xN[4];
105 m12 = mat2xN[5];
106 }
107 }
108
109 constexpr AffineTransform(const AffineTransform& o) noexcept = default;
110 constexpr AffineTransform(AffineTransform&& o) noexcept = default;
111 constexpr AffineTransform& operator=(const AffineTransform&) noexcept = default;
112 constexpr AffineTransform& operator=(AffineTransform&&) noexcept = default;
113
114 /*
115 * Method returns type of affine transformation.
116 *
117 * Transform matrix is
118 * m00 m01 m02
119 * m10 m11 m12
120 *
121 * According analytic geometry new basis vectors are (m00, m01) and (m10, m11),
122 * translation vector is (m02, m12). Original basis vectors are (1, 0) and (0, 1).
123 * Type transformations classification:
124 * AffineTransformType::TYPE_IDENTITY - new basis equals original one and zero translation
125 * AffineTransformType::TYPE_TRANSLATION - translation vector isn't zero
126 * AffineTransformType::TYPE_UNIFORM_SCALE - vectors length of new basis equals
127 * AffineTransformType::TYPE_GENERAL_SCALE - vectors length of new basis doesn't equal
128 * AffineTransformType::TYPE_FLIP - new basis vector orientation differ from original one
129 * AffineTransformType::TYPE_QUADRANT_ROTATION - new basis is rotated by 90, 180, 270, or 360 degrees
130 * AffineTransformType::TYPE_GENERAL_ROTATION - new basis is rotated by arbitrary angle
131 * AffineTransformType::TYPE_GENERAL_TRANSFORM - transformation can't be inversed
132 */
133 AffineTransformType getType() const noexcept {
134 if (m_type != AffineTransformType::unknown) {
135 return m_type;
136 }
137
139
140 if (m00 * m01 + m10 * m11 != 0.0f) {
142 return type;
143 }
144
145 if ( !jau::is_zero(m02) || !jau::is_zero(m12) ) {
147 } else if ( jau::equals(m00, 1.0f) && jau::equals(m11, 1.0f) &&
148 jau::is_zero(m01) && jau::is_zero(m10) ) {
150 return type;
151 }
152
153 if (m00 * m11 - m01 * m10 < 0.0f) {
155 }
156
157 const float dx = m00 * m00 + m10 * m10;
158 const float dy = m01 * m01 + m11 * m11;
159 if ( !jau::equals(dx, dy) ) {
161 } else if ( !jau::equals(dx, 1.0f) ) {
163 }
164
165 if ( ( jau::is_zero( m00 ) && jau::is_zero( m11 ) ) ||
166 ( jau::is_zero( m10 ) && jau::is_zero( m01 ) && (m00 < 0.0f || m11 < 0.0f) ) )
167 {
169 } else if ( !jau::is_zero( m01 ) || !jau::is_zero( m10 ) ) {
171 }
172 return type;
173 }
174
175 float scaleX() const noexcept { return m00; }
176
177 float scaleY() const noexcept { return m11; }
178
179 float shearX() const noexcept { return m01; }
180
181 float shearY() const noexcept { return m10; }
182
183 float translateX() const noexcept { return m02; }
184
185 float translateY() const noexcept { return m12; }
186
187 bool isIdentity() const noexcept { return getType() == AffineTransformType::identity; }
188
189 /**
190 * @param mat2xN either a 2x2 or 2x3 matrix depending on mat_len
191 * @param mat_len either 6 for 2x3 matrix or 4 for 2x2 matrix
192 */
193 void getMatrix(float mat2xN[], const jau::nsize_t mat_len) const noexcept {
194 mat2xN[0] = m00;
195 mat2xN[1] = m10;
196 mat2xN[2] = m01;
197 mat2xN[3] = m11;
198 if (mat_len > 4) {
199 mat2xN[4] = m02;
200 mat2xN[5] = m12;
201 }
202 }
203
204 float determinant() const noexcept { return m00 * m11 - m01 * m10; }
205
206 AffineTransform& set(const float m00_, const float m10_, const float m01_, const float m11_, const float m02_, const float m12_) noexcept {
208 m00 = m00_;
209 m10 = m10_;
210 m01 = m01_;
211 m11 = m11_;
212 m02 = m02_;
213 m12 = m12_;
214 return *this;
215 }
216
219 m00 = m11 = 1.0f;
220 m10 = m01 = m02 = m12 = 0.0f;
221 return *this;
222 }
223
224 AffineTransform& setToTranslation(const float mx, const float my) noexcept {
225 m00 = m11 = 1.0f;
226 m01 = m10 = 0.0f;
227 m02 = mx;
228 m12 = my;
229 if ( jau::is_zero(mx) && jau::is_zero(my) ) {
231 } else {
233 }
234 return *this;
235 }
236
237 AffineTransform& setToScale(const float scx, const float scy) noexcept {
238 m00 = scx;
239 m11 = scy;
240 m10 = m01 = m02 = m12 = 0.0f;
241 if ( !jau::equals(scx, 1.0f) || !jau::equals(scy, 1.0f) ) {
243 } else {
245 }
246 return *this;
247 }
248
249 AffineTransform& setToShear(const float shx, const float shy) noexcept {
250 m00 = m11 = 1.0f;
251 m02 = m12 = 0.0f;
252 m01 = shx;
253 m10 = shy;
254 if ( !jau::is_zero(shx) || !jau::is_zero(shy) ) {
256 } else {
258 }
259 return *this;
260 }
261
262 AffineTransform& setToRotation(const float angle) noexcept {
263 float sin = std::sin(angle);
264 float cos = std::cos(angle);
265 if (std::abs(cos) < ZERO) {
266 cos = 0.0f;
267 sin = sin > 0.0f ? 1.0f : -1.0f;
268 } else if (std::abs(sin) < ZERO) {
269 sin = 0.0f;
270 cos = cos > 0.0f ? 1.0f : -1.0f;
271 }
272 m00 = m11 = cos;
273 m01 = -sin;
274 m10 = sin;
275 m02 = m12 = 0.0f;
277 return *this;
278 }
279
280 AffineTransform& setToRotation(const float angle, const float px, const float py) noexcept {
281 setToRotation(angle);
282 m02 = px * (1.0f - m00) + py * m10;
283 m12 = py * (1.0f - m00) - px * m10;
285 return *this;
286 }
287
288 AffineTransform& translate(const float mx, const float my, AffineTransform& tmp) noexcept {
289 return concat(tmp.setToTranslation(mx, my));
290 }
291
292 AffineTransform& scale(const float scx, const float scy, AffineTransform& tmp) noexcept {
293 return concat(tmp.setToScale(scx, scy));
294 }
295
296 AffineTransform& shear(const float shx, const float shy, AffineTransform& tmp) noexcept {
297 return concat(tmp.setToShear(shx, shy));
298 }
299
300 AffineTransform& rotate(const float angle, AffineTransform& tmp) noexcept {
301 return concat(tmp.setToRotation(angle));
302 }
303
304 AffineTransform& rotate(const float angle, const float px, const float py, AffineTransform& tmp) noexcept {
305 return concat(tmp.setToRotation(angle, px, py));
306 }
307
308 /**
309 * Multiply matrix of two AffineTransform objects.
310 * @param tL - the AffineTransform object is a multiplicand (left argument)
311 * @param tR - the AffineTransform object is a multiplier (right argument)
312 *
313 * @return A new AffineTransform object containing the result of [tL] X [tR].
314 */
315 static AffineTransform mul(const AffineTransform& tL, const AffineTransform& tR) noexcept {
316 return AffineTransform(
317 tR.m00 * tL.m00 + tR.m10 * tL.m01, // m00
318 tR.m00 * tL.m10 + tR.m10 * tL.m11, // m10
319 tR.m01 * tL.m00 + tR.m11 * tL.m01, // m01
320 tR.m01 * tL.m10 + tR.m11 * tL.m11, // m11
321 tR.m02 * tL.m00 + tR.m12 * tL.m01 + tL.m02, // m02
322 tR.m02 * tL.m10 + tR.m12 * tL.m11 + tL.m12);// m12
323 }
324
325 /**
326 * Concatenates the given matrix to this.
327 * <p>
328 * Implementations performs the matrix multiplication:
329 * <pre>
330 * [this] = [this] X [tR]
331 * </pre>
332 * </p>
333 * @param tR the right-argument of the matrix multiplication
334 * @return this transform for chaining
335 */
337 // set(mul(this, tR));
339 set( tR.m00 * m00 + tR.m10 * m01, // m00
340 tR.m00 * m10 + tR.m10 * m11, // m10
341 tR.m01 * m00 + tR.m11 * m01, // m01
342 tR.m01 * m10 + tR.m11 * m11, // m11
343 tR.m02 * m00 + tR.m12 * m01 + m02, // m02
344 tR.m02 * m10 + tR.m12 * m11 + m12);// m12
345 return *this;
346 }
347
348 /**
349 * Pre-concatenates the given matrix to this.
350 * <p>
351 * Implementations performs the matrix multiplication:
352 * <pre>
353 * [this] = [tL] X [this]
354 * </pre>
355 * </p>
356 * @param tL the left-argument of the matrix multiplication
357 * @return this transform for chaining
358 */
360 // setTransform(multiply(tL, this));
362 set( m00 * tL.m00 + m10 * tL.m01, // m00
363 m00 * tL.m10 + m10 * tL.m11, // m10
364 m01 * tL.m00 + m11 * tL.m01, // m01
365 m01 * tL.m10 + m11 * tL.m11, // m11
366 m02 * tL.m00 + m12 * tL.m01 + tL.m02, // m02
367 m02 * tL.m10 + m12 * tL.m11 + tL.m12);// m12
368 return *this;
369 }
370
372 const float det = determinant();
373 if (std::abs(det) < ZERO) {
374 throw MathDomainError(determinantIsZero, E_FILE_LINE);
375 }
376 return AffineTransform(
377 m11 / det, // m00
378 -m10 / det, // m10
379 -m01 / det, // m01
380 m00 / det, // m11
381 (m01 * m12 - m11 * m02) / det, // m02
382 (m10 * m02 - m00 * m12) / det // m12
383 );
384 }
385
386 /**
387 *
388 * @param src
389 * @param dst
390 * @return dst for chaining
391 */
392 AABBox3f& transform(const AABBox3f& src, AABBox3f& dst) const noexcept {
393 const Vec3f& lo = src.low();
394 const Vec3f& hi = src.high();
395 dst.setSize(lo.x * m00 + lo.y * m01 + m02, lo.x * m10 + lo.y * m11 + m12, lo.z,
396 hi.x * m00 + hi.y * m01 + m02, hi.x * m10 + hi.y * m11 + m12, hi.z);
397 return dst;
398 }
399
400 /**
401 * @param src
402 * @param dst
403 * @return dst for chaining
404 Vertex& transform(const Vertex& src, const Vertex& dst) const noexcept {
405 const float x = src.x();
406 const float y = src.y();
407 dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, src.z());
408 return dst;
409 }
410 void transform(const Vertex src[], const Vertex dst[], size_t length) const noexcept {
411 size_t srcOff=0;
412 size_t dstOff=0;
413 while (--length >= 0) {
414 const Vertex& srcPoint = src[srcOff++];
415 Vertex& dstPoint = dst[dstOff++];
416 const float x = srcPoint.x();
417 const float y = srcPoint.y();
418 dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, srcPoint.z());
419 }
420 } */
421
422 /**
423 * @param src float[2] source of transformation
424 * @param dst float[2] destination of transformation, maybe be equal to <code>src</code>
425 * @return dst for chaining
426 */
427 float* transform(const float src[], float dst[]) const noexcept {
428 const float x = src[0];
429 const float y = src[1];
430 dst[0] = x * m00 + y * m01 + m02;
431 dst[1] = x * m10 + y * m11 + m12;
432 return dst;
433 }
434
435 void transform(const float src[], float dst[], size_t length) const noexcept {
436 const float* src_end = src + length * 2;
437 if (src <= dst && dst < src_end ) {
438 // overlap -> reverse
439 size_t srcOff = length * 2 - 2;
440 size_t dstOff = length * 2 - 2;
441 while (length-- > 0) {
442 const float x = src[srcOff + 0];
443 const float y = src[srcOff + 1];
444 dst[dstOff + 0] = x * m00 + y * m01 + m02;
445 dst[dstOff + 1] = x * m10 + y * m11 + m12;
446 srcOff -= 2;
447 dstOff -= 2;
448 }
449 } else {
450 size_t srcOff = 0;
451 size_t dstOff = 0;
452 while (length-- > 0) {
453 const float x = src[srcOff++];
454 const float y = src[srcOff++];
455 dst[dstOff++] = x * m00 + y * m01 + m02;
456 dst[dstOff++] = x * m10 + y * m11 + m12;
457 }
458 }
459 }
460
461 /**
462 * @param src source of transformation
463 * @param dst destination of transformation, maybe be equal to <code>src</code>
464 * @return dst for chaining
465 */
466 Vec2f& transform(const Vec2f& src, Vec2f& dst) const noexcept {
467 const float x = src.x;
468 const float y = src.y;
469 dst.x = x * m00 + y * m01 + m02;
470 dst.y = x * m10 + y * m11 + m12;
471 return dst;
472 }
473
474 /**
475 * @param src source of transformation
476 * @return resulting Vec2f
477 */
478 Vec2f transform(const Vec2f& src) const noexcept {
479 const float x = src.x;
480 const float y = src.y;
481 return Vec2f( x * m00 + y * m01 + m02,
482 x * m10 + y * m11 + m12 );
483 }
484
485 /**
486 * @param src source of transformation
487 * @param dst destination of transformation, maybe be equal to <code>src</code>
488 * @return dst for chaining
489 */
490 Vec3f& transform(const Vec3f& src, Vec3f& dst) const noexcept {
491 const float x = src.x;
492 const float y = src.y;
493 dst.x = x * m00 + y * m01 + m02;
494 dst.y = x * m10 + y * m11 + m12;
495 dst.z = src.z; // just copy z
496 return dst;
497 }
498
499 private:
500 Vec3f transformVec3f(const Vec3f& src) noexcept {
501 const float x = src.x;
502 const float y = src.y;
503 return Vec3f( x * m00 + y * m01 + m02,
504 x * m10 + y * m11 + m12,
505 src.z
506 ); // just copy z
507 }
508
509 public:
510 /**
511 * @param src source of transformation
512 * @param dst destination of transformation, maybe be equal to <code>src</code>
513 * @return resulting Vec3f
514 */
515 Vec3f transform(const Vec3f& src) const noexcept {
516 const float x = src.x;
517 const float y = src.y;
518 return Vec3f( x * m00 + y * m01 + m02,
519 x * m10 + y * m11 + m12,
520 src.z
521 ); // just copy z
522 }
523
524 /**
525 * Resize the aabbox3f to encapsulate another AABox, which will be <i>transformed</i> on the fly first.
526 * @param newBox aabbox3f to be encapsulated in
527 * @param t the {@link AffineTransform} applied on <i>newBox</i> on the fly
528 * @param tmpV3 temporary storage
529 * @return this aabbox3f for chaining
530 */
531 AABBox3f& resizeBox(AABBox3f& box, const AABBox3f& newBox) noexcept {
532 AABBox3f::transform_vec3f_func transform = jau::bind_member(this, &AffineTransform::transformVec3f);
533 return box.resize(newBox, transform);
534 }
535
536 /**
537 *
538 * @param src
539 * @param dst
540 * @return return dst for chaining
541 Vertex& deltaTransform(const Vertex& src, Vertex& dst) const noexcept {
542 const float x = src.x();
543 const float y = src.y();
544 dst.setCoord(x * m00 + y * m01, x * m10 + y * m11, src.z());
545 return dst;
546 }
547 */
548
549 void deltaTransform(const float src[], float dst[], size_t length) const noexcept {
550 size_t srcOff = 0;
551 size_t dstOff = 0;
552 while (length-- > 0) {
553 const float x = src[srcOff++];
554 const float y = src[srcOff++];
555 dst[dstOff++] = x * m00 + y * m01;
556 dst[dstOff++] = x * m10 + y * m11;
557 }
558 }
559
560 /**
561 *
562 * @param src
563 * @param dst
564 * @return return dst for chaining
565 * @throws NoninvertibleTransformException
566 Vertex& inverseTransform(const Vertex& src, Vertex& dst) const {
567 const float det = getDeterminant();
568 if (std::abs(det) < ZERO) {
569 throw new NoninvertibleTransformException(determinantIsZero);
570 }
571 const float x = src.x() - m02;
572 const float y = src.y() - m12;
573 dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det, src.z());
574 return dst;
575 } */
576
577 void inverseTransform(const float src[], float dst[], size_t length) const {
578 size_t srcOff = 0;
579 size_t dstOff = 0;
580 const float det = determinant();
581 if (std::abs(det) < ZERO) {
582 throw MathDomainError(determinantIsZero, E_FILE_LINE);
583 }
584 while (length-- > 0) {
585 const float x = src[srcOff++] - m02;
586 const float y = src[srcOff++] - m12;
587 dst[dstOff++] = (x * m11 - y * m01) / det;
588 dst[dstOff++] = (y * m00 - x * m10) / det;
589 }
590 }
591
592 std::string toString() const noexcept {
593 return "AffineTransform[[" + std::to_string(m00) + ", " + std::to_string(m01) + ", " + std::to_string(m02) + "], ["
594 + std::to_string(m10) + ", " + std::to_string(m11) + ", " + std::to_string(m12) + "]]";
595 }
596
597 constexpr bool equals(const AffineTransform& o, const float epsilon=std::numeric_limits<float>::epsilon()) const noexcept {
598 if( this == &o ) {
599 return true;
600 } else {
601 return jau::equals(m00, o.m00, epsilon) &&
602 jau::equals(m01, o.m01, epsilon) &&
603 jau::equals(m02, o.m02, epsilon) &&
604 jau::equals(m10, o.m10, epsilon) &&
605 jau::equals(m11, o.m11, epsilon) &&
606 jau::equals(m12, o.m12, epsilon);
607 }
608 }
609 constexpr bool operator==(const AffineTransform& rhs) const noexcept {
610 return equals(rhs);
611 }
612 };
613
614/**@}*/
615
616} // namespace jau::math::geom::plane
617
618#endif /* JAU_AFFINETRANSFORM_HPP_ */
619
#define E_FILE_LINE
constexpr AffineTransform() noexcept
Initialized to identity.
math_error_t::invalid
value_type x
Definition vec3f.hpp:69
value_type y
Definition vec3f.hpp:70
value_type z
Definition vec3f.hpp:71
Axis Aligned Bounding Box.
Definition aabbox3f.hpp:43
jau::function< jau::math::Vec3f(const jau::math::Vec3f &)> transform_vec3f_func
General purpose Vec3f transform function.
Definition aabbox3f.hpp:257
constexpr AffineTransform(const float m00_, const float m10_, const float m01_, const float m11_, const float m02_, const float m12_) noexcept
Vec2f transform(const Vec2f &src) const noexcept
AffineTransform & shear(const float shx, const float shy, AffineTransform &tmp) noexcept
static constexpr const float ZERO
The min absolute value equivalent to zero, aka EPSILON.
void deltaTransform(const float src[], float dst[], size_t length) const noexcept
void transform(const float src[], float dst[], size_t length) const noexcept
AffineTransform(const float mat2xN[], const jau::nsize_t mat_len) noexcept
AffineTransform & translate(const float mx, const float my, AffineTransform &tmp) noexcept
Vec3f & transform(const Vec3f &src, Vec3f &dst) const noexcept
AffineTransformType getType() const noexcept
static AffineTransform mul(const AffineTransform &tL, const AffineTransform &tR) noexcept
Multiply matrix of two AffineTransform objects.
AffineTransform & setToShear(const float shx, const float shy) noexcept
float * transform(const float src[], float dst[]) const noexcept
constexpr AffineTransform & operator=(AffineTransform &&) noexcept=default
constexpr bool operator==(const AffineTransform &rhs) const noexcept
AffineTransform & concat(const AffineTransform &tR) noexcept
Concatenates the given matrix to this.
AffineTransform & setToRotation(const float angle) noexcept
AffineTransform & setToRotation(const float angle, const float px, const float py) noexcept
AffineTransform & preConcat(const AffineTransform &tL) noexcept
Pre-concatenates the given matrix to this.
constexpr AffineTransform() noexcept
Initialized to identity.
AABBox3f & resizeBox(AABBox3f &box, const AABBox3f &newBox) noexcept
Resize the aabbox3f to encapsulate another AABox, which will be transformed on the fly first.
AffineTransform & scale(const float scx, const float scy, AffineTransform &tmp) noexcept
AffineTransform & setToScale(const float scx, const float scy) noexcept
constexpr AffineTransform & operator=(const AffineTransform &) noexcept=default
constexpr AffineTransform(const AffineTransform &o) noexcept=default
void getMatrix(float mat2xN[], const jau::nsize_t mat_len) const noexcept
AffineTransform & rotate(const float angle, const float px, const float py, AffineTransform &tmp) noexcept
AffineTransform & setToIdentity() noexcept
AffineTransform & setToTranslation(const float mx, const float my) noexcept
AffineTransform & set(const float m00_, const float m10_, const float m01_, const float m11_, const float m02_, const float m12_) noexcept
void inverseTransform(const float src[], float dst[], size_t length) const
AffineTransform & rotate(const float angle, AffineTransform &tmp) noexcept
constexpr AffineTransform(AffineTransform &&o) noexcept=default
constexpr bool equals(const AffineTransform &o, const float epsilon=std::numeric_limits< float >::epsilon()) const noexcept
AABBox3f & transform(const AABBox3f &src, AABBox3f &dst) const noexcept
Vec2f & transform(const Vec2f &src, Vec2f &dst) const noexcept
Vec3f transform(const Vec3f &src) const noexcept
#define JAU_MAKE_BITFIELD_ENUM_STRING(type,...)
std::enable_if_t< std::is_floating_point_v< T >, bool > constexpr equals(const T &a, const T &b, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if both values are equal, i.e.
std::enable_if_t< std::is_floating_point_v< T >, bool > constexpr is_zero(const T &a, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if the given value is less than epsilon, w/ epsilon > 0.
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition int_types.hpp:55
Vector2F< float > Vec2f
Definition vec2f.hpp:416
Vector3F< float > Vec3f
Definition vec3f.hpp:436
@ unknown
The AffineTransformType::unknown is the initial value.
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
Definition enum_util.hpp:65