HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
rotate.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "matrix.hpp"
8#include "identity.hpp"
9
10namespace hi::inline v1 {
11namespace geo {
12
13template<int D>
14class rotate {
15public:
16 static_assert(D == 2 || D == 3, "Only 2D or 3D rotation-matrices are supported");
17
18 rotate(rotate const &) noexcept = default;
19 rotate(rotate &&) noexcept = default;
20 rotate &operator=(rotate const &) noexcept = default;
21 rotate &operator=(rotate &&) noexcept = default;
22
23 [[nodiscard]] rotate(float angle, vector<3> axis) noexcept requires(D == 3) : _v()
24 {
25 hi_axiom(axis.holds_invariant());
26 hi_axiom(std::abs(hypot(axis) - 1.0f) < 0.0001f);
27
28 hilet half_angle = angle * 0.5f;
29 hilet C = std::cos(half_angle);
30 hilet S = std::sin(half_angle);
31
32 _v = static_cast<f32x4>(axis) * S;
33 _v.w() = C;
34 }
35
36 [[nodiscard]] rotate(float angle) noexcept requires(D == 2) : _v()
37 {
38 hilet half_angle = angle * 0.5f;
39 hilet C = std::cos(half_angle);
40 hilet S = std::sin(half_angle);
41
42 _v = f32x4{0.0f, 0.0f, 1.0f, 0.0f} * S;
43 _v.w() = C;
44 }
45
49 [[nodiscard]] constexpr operator matrix<D>() const noexcept
50 {
51 // Original from https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
52 // 1 - 2(yy + zz) | 2(xy - zw) | 2(xz + yw)
53 // 2(xy + zw) | 1 - 2(xx + zz) | 2(yz - xw)
54 // 2(xz - yw) | 2(yz + xw) | 1 - 2(xx + yy)
55
56 // Flipping adds and multiplies:
57 // 1 - 2(zz + yy) | 2(xy - zw) | 2(yw + xz)
58 // 2(zw + yx) | 1 - 2(xx + zz) | 2(yz - xw)
59 // 2(zx - yw) | 2(xw + zy) | 1 - 2(yy + xx)
60
61 // All multiplies.
62 hilet x_mul = _v.xxxx() * _v;
63 hilet y_mul = _v.yyyy() * _v;
64 hilet z_mul = _v.zzzz() * _v;
65
66 auto twos = f32x4(-2.0f, 2.0f, 2.0f, 0.0f);
67 auto one = f32x4(1.0f, 0.0f, 0.0f, 0.0f);
68 hilet col0 = one + addsub<0b0011>(z_mul.zwxy(), y_mul.yxwz()) * twos;
69 one = one.yxzw();
70 twos = twos.yxzw();
71 hilet col1 = one + addsub<0b0110>(x_mul.yxwz(), z_mul.wzyx()) * twos;
72 one = one.xzyw();
73 twos = twos.xzyw();
74 hilet col2 = one + addsub<0b0101>(y_mul.wzyx(), x_mul.zwxy()) * twos;
75 one = one.xywz();
76 return matrix<D>{col0, col1, col2, one};
77 }
78
79 std::pair<float, vector<3>> angle_and_axis() const noexcept requires(D == 3)
80 {
81 hilet rcp_length = rcp_hypot<0b0111>(_v);
82 hilet length = 1.0f / rcp_length;
83
84 return {2.0f * std::atan2(length), vector<3>{_v.xyz0() * rcp_length}};
85 }
86
87private :
91 f32x4 _v;
92};
93
94} // namespace geo
95
96using rotate2 = geo::rotate<2>;
97using rotate3 = geo::rotate<3>;
98
99} // namespace hi::inline v1
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Definition matrix.hpp:22
Definition rotate.hpp:14
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector.hpp:20
T atan2(T... args)
T cos(T... args)
T sin(T... args)