|
| 1 | +/* |
| 2 | + This file is part of the Geometry library. |
| 3 | + Copyright (C) 2007-2012 Benjamin Eikel <[email protected]> |
| 4 | + Copyright (C) 2007-2012 Claudius Jähn <[email protected]> |
| 5 | + Copyright (C) 2007-2012 Ralf Petring <[email protected]> |
| 6 | + Copyright (C) 2020 Sascha Brandt <[email protected]> |
| 7 | +
|
| 8 | + This library is subject to the terms of the Mozilla Public License, v. 2.0. |
| 9 | + You should have received a copy of the MPL along with this library; see the |
| 10 | + file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/. |
| 11 | +*/ |
| 12 | +#ifndef GEOMETRY_SQT_H |
| 13 | +#define GEOMETRY_SQT_H |
| 14 | + |
| 15 | +#include "Angle.h" |
| 16 | +#include "Interpolation.h" |
| 17 | +#include "Quaternion.h" |
| 18 | +#include "Matrix3x3.h" |
| 19 | +#include "Vec3.h" |
| 20 | +#include "SRT.h" |
| 21 | +#include <array> |
| 22 | +#include <istream> |
| 23 | +#include <ostream> |
| 24 | + |
| 25 | +namespace Geometry { |
| 26 | + |
| 27 | +/** |
| 28 | + * SQT - scale, quaternion and translate. |
| 29 | + * A more compact qay to store scale, rotation & translation. |
| 30 | + * |
| 31 | + * @note internally the values are stored as translate, scale, quaternion to get a more GPU friendly memory layout (2 x vec4). |
| 32 | + * |
| 33 | + * [SQT] |
| 34 | + */ |
| 35 | +template <typename T_> |
| 36 | +class _SQT { |
| 37 | +public: |
| 38 | + typedef T_ value_t; |
| 39 | + typedef _Quaternion<value_t> quaternion_t; |
| 40 | + typedef _Angle<value_t> angle_t; |
| 41 | + typedef _Vec3<value_t> vec3_t; |
| 42 | + |
| 43 | +private: |
| 44 | + //! Translation |
| 45 | + vec3_t t; |
| 46 | + //! Scale |
| 47 | + value_t s; |
| 48 | + //! Rotation |
| 49 | + quaternion_t q; |
| 50 | + |
| 51 | +public: |
| 52 | + /** |
| 53 | + * @name Mainvec3_t |
| 54 | + */ |
| 55 | + //@{ |
| 56 | + /** |
| 57 | + * [ctor] |
| 58 | + */ |
| 59 | + _SQT() : t(), s(static_cast<value_t>(1.0)), q() { |
| 60 | + } |
| 61 | + /** |
| 62 | + * [ctor] interpolation between sqt1 and sqt2, according to the factor blend (should be between 0 and 1); |
| 63 | + */ |
| 64 | + _SQT(const _SQT<value_t> & sqt1, const _SQT<value_t> & sqt2, float blend) |
| 65 | + : t(sqt1.t, sqt2.t, blend), |
| 66 | + s(Interpolation::linear(sqt1.s, sqt2.s, blend)), |
| 67 | + q(Interpolation::linear(sqt1.q, sqt2.q, blend)){ |
| 68 | + } |
| 69 | + |
| 70 | + //! Create an SQT by specifying all components explicitly. |
| 71 | + _SQT(const vec3_t & translation, const quaternion_t & rotation, value_t scaling) |
| 72 | + : t(translation), s(scaling), q(rotation) { |
| 73 | + q.normOrthoLize(); |
| 74 | + } |
| 75 | + |
| 76 | + /** |
| 77 | + * [ctor] Create an SQT from an SRT |
| 78 | + */ |
| 79 | + _SQT(const _SRT<value_t> & srt) |
| 80 | + : t(srt.getTranslation()), |
| 81 | + s(srt.getScale()), |
| 82 | + q(quaternion_t::matrixToQuaternion(srt.getRotation())) { |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * [ctor] pos, dir, up [,scale] |
| 87 | + * \note dir and up are normalized automatically. |
| 88 | + */ |
| 89 | + _SQT(vec3_t _pos, const vec3_t & _dir, const vec3_t & _up, value_t _scale = 1.0) : _SQT(_SRT<value_t>(_pos, _dir, _up, _scale)) { |
| 90 | + } |
| 91 | + |
| 92 | + /*! [ x,y,z, scale, rx,ry,rz,rw ] |
| 93 | + \see toArray() */ |
| 94 | + _SQT(const std::array<value_t, 8> & arr) |
| 95 | + : t(arr[0], arr[1], arr[2]), |
| 96 | + s(arr[3]), |
| 97 | + q(Quaternion(arr[4], arr[5], arr[6], arr[7])) { |
| 98 | + } |
| 99 | + |
| 100 | + /** |
| 101 | + * @name Information |
| 102 | + */ |
| 103 | + //@{ |
| 104 | + value_t getScale() const { |
| 105 | + return s; |
| 106 | + } |
| 107 | + const vec3_t & getTranslation() const { |
| 108 | + return t; |
| 109 | + } |
| 110 | + const quaternion_t & getRotation() const { |
| 111 | + return q; |
| 112 | + } |
| 113 | + const _Matrix3x3<value_t> & getRotationMatrix() const { |
| 114 | + return q.toMatrix(); |
| 115 | + } |
| 116 | + _SRT<value_t> toSRT() const { |
| 117 | + return _SRT<value_t>(t, q.toMatrix(), s); |
| 118 | + } |
| 119 | + //@} |
| 120 | + |
| 121 | + /** |
| 122 | + * @name Modification |
| 123 | + */ |
| 124 | + //@{ |
| 125 | + void reset() { |
| 126 | + q.set(static_cast<value_t>(0.0), static_cast<value_t>(0.0), static_cast<value_t>(0.0), static_cast<value_t>(1.0)); |
| 127 | + t.setValue(static_cast<value_t>(0.0)); |
| 128 | + s = 1.0; |
| 129 | + } |
| 130 | + void setScale(value_t x) { |
| 131 | + s = x; |
| 132 | + } |
| 133 | + void scale(value_t x) { |
| 134 | + s *= x; |
| 135 | + } |
| 136 | + |
| 137 | + void resetRotation() { |
| 138 | + q.set(static_cast<value_t>(0.0), static_cast<value_t>(0.0), static_cast<value_t>(0.0), static_cast<value_t>(1.0)); |
| 139 | + } |
| 140 | + void setRotation(const quaternion_t & x) { |
| 141 | + q = x; |
| 142 | + } |
| 143 | + void setRotation(const vec3_t & dir, const vec3_t & up) { |
| 144 | + _Matrix3x3<value_t> m; |
| 145 | + m.setRotation(dir, up); |
| 146 | + q = quaternion_t::matrixToQuaternion(m); |
| 147 | + } |
| 148 | + |
| 149 | + void setTranslation(const vec3_t & x) { |
| 150 | + t = x; |
| 151 | + } |
| 152 | + void translate(const vec3_t & v) { |
| 153 | + t += v; |
| 154 | + } |
| 155 | + void translateLocal(const vec3_t & v) { |
| 156 | + t += q.rotatePoint(v * s); |
| 157 | + } |
| 158 | + |
| 159 | + void rotateLocal(const angle_t & angle, const vec3_t & axis) { |
| 160 | + quaternion_t q2; |
| 161 | + q2.makeRotate(angle, axis); |
| 162 | + q *= q2; |
| 163 | + } |
| 164 | + void rotateLocal_rad(float rad, const vec3_t & axis) { |
| 165 | + rotateLocal(angle_t::rad(rad), axis); |
| 166 | + } |
| 167 | + void rotateLocal_deg(float deg, const vec3_t & axis) { |
| 168 | + rotateLocal(angle_t::deg(deg), axis); |
| 169 | + } |
| 170 | + |
| 171 | + void rotateRel(const angle_t & angle, const vec3_t & axis) { |
| 172 | + quaternion_t q2; |
| 173 | + q2.makeRotate(angle, axis); |
| 174 | + q = q2 * q; |
| 175 | + } |
| 176 | + |
| 177 | + void rotateRel_rad(value_t rad, const vec3_t & axis) { |
| 178 | + rotateRel(angle_t::rad(rad), axis); |
| 179 | + } |
| 180 | + void rotateRel_deg(value_t deg, const vec3_t & axis) { |
| 181 | + rotateRel(angle_t::deg(deg), axis); |
| 182 | + } |
| 183 | + //@} |
| 184 | + |
| 185 | + /** |
| 186 | + * @name Creation |
| 187 | + */ |
| 188 | + //@{ |
| 189 | + const vec3_t operator*(const vec3_t & v) const { |
| 190 | + return q.rotatePoint(v * s) + t; |
| 191 | + } |
| 192 | + const _SQT<value_t> operator*(const _SQT<value_t> & sqt) const { |
| 193 | + _SQT<value_t> e; |
| 194 | + e.s = s * sqt.s; |
| 195 | + e.t = q.rotatePoint(sqt.t * e.s) + t; |
| 196 | + e.q = q * sqt.q; |
| 197 | + return e; |
| 198 | + } |
| 199 | + |
| 200 | + /*! Like a multiplication, but applies the rotation of this sqt to translation |
| 201 | + of the given sqt which results in the same behaviour as |
| 202 | + ( Matrix4x4 (*this) * Matrix4x4(sqt) )._toSQT() */ |
| 203 | + _SQT<value_t> getTransformation(const _SQT<value_t> & sqt) const { |
| 204 | + const vec3_t pos((*this) * sqt.getTranslation()); |
| 205 | + const vec3_t dir((*this) * (sqt.getDirVector() + sqt.getTranslation()) - pos); |
| 206 | + const vec3_t up((*this) * (sqt.getUpVector() + sqt.getTranslation()) - pos); |
| 207 | + return _SQT<value_t>(pos, dir, up, dir.length() * sqt.getScale()); |
| 208 | + } |
| 209 | + _SQT<value_t> inverse() const { |
| 210 | + _SQT<value_t> e; |
| 211 | + e.s = 1 / s; |
| 212 | + e.q = q.inverse(); |
| 213 | + e.t = e.q.rotatePoint(t * (-e.s)); |
| 214 | + return e; |
| 215 | + } |
| 216 | + //@} |
| 217 | + |
| 218 | + /** |
| 219 | + * @name Comparators |
| 220 | + */ |
| 221 | + //@{ |
| 222 | + /*! compares this with other componentwise |
| 223 | + @param other the object to compare with |
| 224 | + @param epsilon the maximum allowed difference between the component pairs |
| 225 | + @return true iff any the absolute difference between any pai of components is larger than epsilon */ |
| 226 | + bool equals(const _SQT & other, value_t epsilon) const { |
| 227 | + return t.equals(other.t, epsilon) && q.equals(other.q, epsilon) && std::abs(s - other.s) <= epsilon; |
| 228 | + } |
| 229 | + bool operator==(const _SQT<value_t> & sqt) const { |
| 230 | + return sqt.t == (*this).t && sqt.q == (*this).q && sqt.s == (*this).s; |
| 231 | + } |
| 232 | + bool operator!=(const _SQT<value_t> & sqt) const { |
| 233 | + return !((*this) == sqt); |
| 234 | + } |
| 235 | + //@} |
| 236 | + |
| 237 | + /** |
| 238 | + * @name Conversion |
| 239 | + */ |
| 240 | + //@{ |
| 241 | + void toArray(value_t fa[8]) const { |
| 242 | + fa[0] = static_cast<value_t>(t.getX()); |
| 243 | + fa[1] = static_cast<value_t>(t.getY()); |
| 244 | + fa[2] = static_cast<value_t>(t.getZ()); |
| 245 | + fa[3] = static_cast<value_t>(s); |
| 246 | + fa[4] = static_cast<value_t>(q.x()); |
| 247 | + fa[5] = static_cast<value_t>(q.y()); |
| 248 | + fa[6] = static_cast<value_t>(q.z()); |
| 249 | + fa[7] = static_cast<value_t>(q.w()); |
| 250 | + } |
| 251 | + |
| 252 | + std::array<value_t, 8> toArray() const { |
| 253 | + std::array<value_t, 8> arr; |
| 254 | + arr[0] = t.x(), arr[1] = t.y(), arr[2] = t.z(); |
| 255 | + arr[3] = s; |
| 256 | + arr[4] = q.x(), arr[5] = q.y(), arr[6] = q.z(), arr[7] = q.w(); |
| 257 | + return arr; |
| 258 | + } |
| 259 | + //@} |
| 260 | + |
| 261 | + //! @name Serialization |
| 262 | + //@{ |
| 263 | + friend std::ostream & operator<<(std::ostream & out, const _SQT & sqt) { |
| 264 | + return out << sqt.t << ' ' << sqt.s << ' ' << sqt.q; |
| 265 | + } |
| 266 | + friend std::istream & operator>>(std::istream & in, _SQT & sqt) { |
| 267 | + return in >> sqt.t >> sqt.s >> sqt.q; |
| 268 | + } |
| 269 | + //@} |
| 270 | +}; |
| 271 | +typedef _SQT<float> SQT; |
| 272 | +typedef _SQT<float> SQTf; |
| 273 | +typedef _SQT<double> SQTd; |
| 274 | +} |
| 275 | + |
| 276 | +#endif /* GEOMETRY_SQT_H */ |
0 commit comments