vsg  1.0.4
VulkanSceneGraph library
quat.h
1 #pragma once
2 
3 /* <editor-fold desc="MIT License">
4 
5 Copyright(c) 2018 Robert Osfield
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 
9 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 
13 </editor-fold> */
14 
15 // we can't implement the anonymous union/structs combination without causing warnings, so disabled them for just this header
16 
17 #include <vsg/maths/mat4.h>
18 
19 #if defined(__GNUC__)
20 # pragma GCC diagnostic push
21 # pragma GCC diagnostic ignored "-Wpedantic"
22 #endif
23 #if defined(__clang__)
24 # pragma clang diagnostic push
25 # pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
26 # pragma clang diagnostic ignored "-Wnested-anon-types"
27 #endif
28 
29 namespace vsg
30 {
31 
33  template<typename T>
34  struct t_quat
35  {
36  using value_type = T;
37 
38  union
39  {
40  value_type value[4];
41  struct
42  {
43  value_type x, y, z, w;
44  };
45  };
46 
47  constexpr t_quat() :
48  value{} {}
49  constexpr t_quat(const t_quat& v) :
50  value{v.x, v.y, v.z, v.w} {}
51  constexpr t_quat(value_type in_x, value_type in_y, value_type in_z, value_type in_w) :
52  value{in_x, in_y, in_z, in_w} {}
53  constexpr t_quat(value_type angle_radians, const t_vec3<value_type>& axis)
54  {
55  set(angle_radians, axis);
56  }
57  constexpr t_quat(const t_vec3<value_type>& from, const t_vec3<value_type>& to)
58  {
59  set(from, to);
60  }
61 
62  template<typename R>
63  constexpr explicit t_quat(const t_quat<R>& v) :
64  value{static_cast<T>(v.x), static_cast<T>(v.y), static_cast<T>(v.z), static_cast<T>(v.w)} {}
65 
66  constexpr t_quat& operator=(const t_quat&) = default;
67 
68  constexpr std::size_t size() const { return 4; }
69 
70  value_type& operator[](std::size_t i) { return value[i]; }
71  value_type operator[](std::size_t i) const { return value[i]; }
72 
73  template<typename R>
74  t_quat& operator=(const t_quat<R>& rhs)
75  {
76  value[0] = static_cast<value_type>(rhs[0]);
77  value[1] = static_cast<value_type>(rhs[1]);
78  value[2] = static_cast<value_type>(rhs[2]);
79  value[3] = static_cast<value_type>(rhs[3]);
80  return *this;
81  }
82 
83  T* data() { return value; }
84  const T* data() const { return value; }
85 
86  void set(value_type in_x, value_type in_y, value_type in_z, value_type in_w)
87  {
88  x = in_x;
89  y = in_y;
90  z = in_z;
91  w = in_w;
92  }
93 
94  void set(value_type angle_radians, const t_vec3<value_type>& axis)
95  {
96  const value_type epsilon = 1e-7;
97  value_type len = length(axis);
98  if (len < epsilon)
99  {
100  // ~zero length axis, so reset rotation to zero.
101  *this = {};
102  return;
103  }
104 
105  value_type inversenorm = 1.0 / len;
106  value_type coshalfangle = cos(0.5 * angle_radians);
107  value_type sinhalfangle = sin(0.5 * angle_radians);
108 
109  x = axis.x * sinhalfangle * inversenorm;
110  y = axis.y * sinhalfangle * inversenorm;
111  z = axis.z * sinhalfangle * inversenorm;
112  w = coshalfangle;
113  }
114 
115  void set(const t_vec3<value_type>& from, const t_vec3<value_type>& to)
116  {
117  const value_type epsilon = 1e-7;
118 
119  value_type dot_pd = vsg::dot(from, to);
120  value_type div = std::sqrt(length2(from) * length2(to));
121  vsg::dvec3 axis;
122  if (div - dot_pd < epsilon)
123  {
124  axis = orthogonal(from);
125  }
126  else
127  {
128  axis = cross(from, to);
129  }
130 
131  value_type len = length(axis);
132 
133  double angle_radians = acos(dot_pd / div);
134 
135  value_type inversenorm = 1.0 / len;
136  value_type coshalfangle = cos(0.5 * angle_radians);
137  value_type sinhalfangle = sin(0.5 * angle_radians);
138 
139  x = axis.x * sinhalfangle * inversenorm;
140  y = axis.y * sinhalfangle * inversenorm;
141  z = axis.z * sinhalfangle * inversenorm;
142  w = coshalfangle;
143  }
144  };
145 
146  using quat = t_quat<float>;
147  using dquat = t_quat<double>;
148 
149  VSG_type_name(vsg::quat);
150  VSG_type_name(vsg::dquat);
151 
152  template<typename T>
153  constexpr bool operator==(const t_quat<T>& lhs, const t_quat<T>& rhs)
154  {
155  return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2] && lhs[3] == rhs[3];
156  }
157 
158  template<typename T>
159  constexpr bool operator!=(const t_quat<T>& lhs, const t_quat<T>& rhs)
160  {
161  return lhs[0] != rhs[0] || lhs[1] != rhs[1] || lhs[2] != rhs[2] || lhs[3] != rhs[3];
162  }
163 
164  template<typename T>
165  constexpr bool operator<(const t_quat<T>& lhs, const t_quat<T>& rhs)
166  {
167  if (lhs[0] < rhs[0]) return true;
168  if (lhs[0] > rhs[0]) return false;
169  if (lhs[1] < rhs[1]) return true;
170  if (lhs[1] > rhs[1]) return false;
171  if (lhs[2] < rhs[2]) return true;
172  if (lhs[2] > rhs[2]) return false;
173  return lhs[3] < rhs[3];
174  }
175 
176  template<typename T>
177  constexpr t_quat<T> operator-(const t_quat<T>& lhs, const t_quat<T>& rhs)
178  {
179  return t_quat<T>(lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2], lhs[3] - rhs[3]);
180  }
181 
182  template<typename T>
183  constexpr t_quat<T> conjugate(const t_quat<T>& v)
184  {
185  return t_quat<T>(-v[0], -v[1], -v[2], -v[3]);
186  }
187 
188  template<typename T>
189  constexpr t_quat<T> operator-(const t_quat<T>& v)
190  {
191  return conjugate(v);
192  }
193 
194  template<typename T>
195  constexpr t_quat<T> operator+(const t_quat<T>& lhs, const t_quat<T>& rhs)
196  {
197  return t_quat<T>(lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2], lhs[3] + rhs[3]);
198  }
199 
200  // Rotate a quaternion by another quaternion
201  template<typename T>
202  constexpr t_quat<T> operator*(const t_quat<T>& lhs, const t_quat<T>& rhs)
203  {
204  t_quat<T> q(rhs[3] * lhs[0] + rhs[0] * lhs[3] + rhs[1] * lhs[2] - rhs[2] * lhs[1],
205  rhs[3] * lhs[1] - rhs[0] * lhs[2] + rhs[1] * lhs[3] + rhs[2] * lhs[0],
206  rhs[3] * lhs[2] + rhs[0] * lhs[1] - rhs[1] * lhs[0] + rhs[2] * lhs[3],
207  rhs[3] * lhs[3] - rhs[0] * lhs[0] - rhs[1] * lhs[1] - rhs[2] * lhs[2]);
208 
209  return q;
210  }
211 
212  // Rotate a vector by a quaternion
213  template<typename T>
214  constexpr t_vec3<T> operator*(const t_quat<T>& q, const t_vec3<T>& v)
215  {
216  // nVidia SDK implementation
217  t_vec3<T> uv, uuv;
218  t_vec3<T> qvec(q[0], q[1], q[2]);
219  uv = cross(qvec, v);
220  uuv = cross(qvec, uv);
221  T two(2.0);
222  uv *= (two * q[3]);
223  uuv *= two;
224  return v + uv + uuv;
225  }
226 
227  template<typename T>
228  constexpr t_quat<T> operator*(const t_quat<T>& lhs, T rhs)
229  {
230  return t_quat<T>(lhs[0] * rhs, lhs[1] * rhs, lhs[2] * rhs, lhs[3] * rhs);
231  }
232 
233  template<typename T>
234  constexpr t_quat<T> operator/(const t_quat<T>& lhs, T rhs)
235  {
236  T inv = static_cast<T>(1.0) / rhs;
237  return t_quat<T>(lhs[0] * inv, lhs[1] * inv, lhs[2] * inv, lhs[3] * inv);
238  }
239 
240  template<typename T>
241  constexpr T length(const t_quat<T>& v)
242  {
243  return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
244  }
245 
246  template<typename T>
247  constexpr t_quat<T> normalize(const t_quat<T>& v)
248  {
249  T inverse_len = static_cast<T>(1.0) / length(v);
250  return t_quat<T>(v[0] * inverse_len, v[1] * inverse_len, v[2] * inverse_len, v[3] * inverse_len);
251  }
252 
253  template<typename T>
254  constexpr T dot(const t_quat<T>& lhs, const t_quat<T>& rhs)
255  {
256  return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2] + lhs[3] * rhs[3];
257  }
258 
259  template<typename T>
260  constexpr t_quat<T> inverse(const t_quat<T>& v)
261  {
262  t_quat<T> c = conjugate(v);
263  T inverse_len = static_cast<T>(1.0) / length(v);
264  return t_quat<T>(c[0] * inverse_len, c[1] * inverse_len, c[2] * inverse_len, c[3] * inverse_len);
265  }
266 
267  template<typename T>
268  constexpr t_quat<T> mix(const t_quat<T>& from, t_quat<T> to, T r)
269  {
270  T epsilon = std::numeric_limits<T>::epsilon();
271  T one(1.0);
272 
273  T cosomega = dot(from, to);
274  if (cosomega < 0.0)
275  {
276  cosomega = -cosomega;
277  to.x = -to.x;
278  to.y = -to.y;
279  to.z = -to.z;
280  to.w = -to.w;
281  }
282 
283  if ((one - cosomega) > epsilon)
284  {
285  T omega = acos(cosomega);
286  T sinomega = sin(omega);
287  T scale_from = sin((one - r) * omega) / sinomega;
288  T scale_to = sin(r * omega) / sinomega;
289  return (from * scale_from) + (to * scale_to);
290  }
291  else
292  {
293  // quaternion's are very close so just linearly interpolate
294  return (from * (one - r)) + (to * r);
295  }
296  }
297 
298 } // namespace vsg
299 
300 #if defined(__clang__)
301 # pragma clang diagnostic pop
302 #endif
303 #if defined(__GNUC__)
304 # pragma GCC diagnostic pop
305 #endif
t_quat template class that a represents quaternion
Definition: quat.h:35