1
+ package glm_.dualQuat
2
+
3
+ import glm_.mat2x4.Mat2x4
4
+ import glm_.mat3x4.Mat3x4
5
+ import glm_.quat.Quat
6
+ import glm_.vec3.Vec3
7
+ import glm_.vec4.Vec4
8
+ import kotlin.math.sqrt
9
+
10
+
11
+ class DualQuat (var real : Quat , var dual : Quat ) {
12
+
13
+ // -- Component accesses --
14
+
15
+ /* * Return the count of components of a dual quaternion */
16
+ val length = 2
17
+
18
+ operator fun get (index : Int ) = when (index) {
19
+ 0 -> real
20
+ 1 -> dual
21
+ else -> throw Error ()
22
+ }
23
+
24
+ operator fun set (index : Int , quat : Quat ) = when (index) {
25
+ 0 -> real put quat
26
+ 1 -> dual put quat
27
+ else -> throw Error ()
28
+ }
29
+
30
+ // -- Implicit basic constructors --
31
+
32
+ constructor () : this (Quat (), Quat (0f ))
33
+
34
+ constructor (dualQuat: DualQuat ) : this (Quat (dualQuat.real), Quat (dualQuat.dual))
35
+
36
+ constructor (realW: Float , realX: Float , realY: Float , realZ: Float ,
37
+ dualW: Float , dualX: Float , dualY: Float , dualZ: Float ) : this (
38
+ Quat (realW, realX, realY, realZ), Quat (dualW, dualX, dualY, dualZ))
39
+
40
+
41
+ // -- Explicit basic constructors --
42
+
43
+ constructor (real: Quat ) : this (real, Quat (0f ))
44
+
45
+ constructor (orientation: Quat , translation: Vec3 ) : this (orientation, Quat (
46
+ - 0.5f * (translation.x * orientation.x + translation.y * orientation.y + translation.z * orientation.z),
47
+ + 0.5f * (translation.x * orientation.w + translation.y * orientation.z - translation.z * orientation.y),
48
+ + 0.5f * (- translation.x * orientation.z + translation.y * orientation.w + translation.z * orientation.x),
49
+ + 0.5f * (translation.x * orientation.y - translation.y * orientation.x + translation.z * orientation.w)))
50
+
51
+ // -- Conversion constructors --
52
+
53
+ constructor (m: Mat2x4 ) : this () {
54
+ dualquat_cast(m, this )
55
+ }
56
+
57
+ constructor (m: Mat3x4 ) : this () {
58
+ dualquat_cast(m, this )
59
+ }
60
+
61
+ // -- Lambda constructors --
62
+
63
+ constructor (block: (Int ) -> Float ) : this (
64
+ block(0 ), block(1 ), block(2 ), block(3 ),
65
+ block(4 ), block(5 ), block(6 ), block(7 ))
66
+
67
+ // -- Unary bit operators --
68
+
69
+ operator fun unaryPlus () = this
70
+ operator fun unaryMinus () = DualQuat (- real, - dual)
71
+
72
+
73
+ fun put (real : Quat , dual : Quat ) {
74
+ real.put(real.w, real.x, real.y, real.z)
75
+ dual.put(dual.w, dual.x, dual.y, dual.z)
76
+ }
77
+
78
+ fun put (realW : Float , realX : Float , realY : Float , realZ : Float ,
79
+ dualW : Float , dualX : Float , dualY : Float , dualZ : Float ) {
80
+ real.put(realW, realX, realY, realZ)
81
+ dual.put(dualW, dualX, dualY, dualZ)
82
+ }
83
+
84
+ operator fun invoke (realW : Float , realX : Float , realY : Float , realZ : Float ,
85
+ dualW : Float , dualX : Float , dualY : Float , dualZ : Float ): DualQuat {
86
+ put(realW, realX, realY, realZ, dualW, dualX, dualY, dualZ)
87
+ return this
88
+ }
89
+
90
+ operator fun invoke (real : Quat , dual : Quat ): DualQuat {
91
+ put(real, dual)
92
+ return this
93
+ }
94
+
95
+ // -- Specific binary arithmetic operators --
96
+
97
+ infix operator fun plus (b : DualQuat ) = plus(DualQuat (), this , b)
98
+ fun plus (b : DualQuat , res : DualQuat ) = plus(res, this , b)
99
+ infix operator fun plusAssign (b : DualQuat ) {
100
+ plus(this , this , b)
101
+ }
102
+
103
+ infix operator fun times (b : DualQuat ) = times(DualQuat (), this , b)
104
+ infix operator fun times (b : Float ) = times(DualQuat (), this , b)
105
+ infix operator fun times (b : Vec3 ) = times(Vec3 (), this , b)
106
+ infix operator fun times (b : Vec4 ) = times(Vec4 (), this , b)
107
+ fun times (b : DualQuat , res : DualQuat ) = times(res, this , b)
108
+ fun times (b : Float , res : DualQuat ) = times(res, this , b)
109
+ fun times (b : Vec3 , res : Vec3 ) = times(res, this , b)
110
+ fun times (b : Vec4 , res : Vec4 ) = times(res, this , b)
111
+ infix operator fun timesAssign (b : DualQuat ) {
112
+ times(this , this , b)
113
+ }
114
+
115
+ infix operator fun timesAssign (b : Float ) {
116
+ times(this , this , b)
117
+ }
118
+
119
+ infix operator fun timesAssign (b : Vec3 ) {
120
+ times(b, this , b)
121
+ }
122
+
123
+ infix operator fun timesAssign (b : Vec4 ) {
124
+ times(b, this , b)
125
+ }
126
+
127
+
128
+ infix operator fun div (b : Float ) = div(DualQuat (), this , b)
129
+ fun div (b : Float , res : DualQuat ) = div(res, this , b)
130
+ infix operator fun divAssign (b : Float ) {
131
+ div(this , this , b)
132
+ }
133
+
134
+
135
+ // -- Operations --
136
+
137
+ /* * Set the dual quaternion as identity.
138
+ * @see gtx_dual_quaternion */
139
+ fun identity () {
140
+ real.put(1f , 0f , 0f , 0f )
141
+ dual.put(0f , 0f , 0f , 0f )
142
+ }
143
+
144
+ /* * Returns a new normalized quaternion.
145
+ * @see gtx_dual_quaternion */
146
+ fun normalize (): DualQuat = div(real.length(), DualQuat ())
147
+
148
+ /* * Normalize the quaternion itself.
149
+ * @see gtx_dual_quaternion */
150
+ fun normalizeAssign (): DualQuat {
151
+ divAssign(real.length())
152
+ return this
153
+ }
154
+
155
+ /* * Returns the linear interpolation of two dual quaternion.
156
+ * @see gtc_dual_quaternion */
157
+ fun lerp (b : DualQuat , a : Float , res : DualQuat = DualQuat ()): DualQuat {
158
+ // Dual Quaternion Linear blend aka DLB:
159
+ // Lerp is only defined in [0, 1]
160
+ assert (a in 0f .. 1f )
161
+ val k = if (real dot b.real < 0f ) - a else a
162
+ val j = 1f - a
163
+ return res(
164
+ real.w * j + b.real.w * k,
165
+ real.x * j + b.real.x * k,
166
+ real.y * j + b.real.y * k,
167
+ real.z * j + b.real.z * k,
168
+ dual.z * j + b.dual.z * k,
169
+ dual.z * j + b.dual.z * k,
170
+ dual.z * j + b.dual.z * k,
171
+ dual.z * j + b.dual.z * k)
172
+ }
173
+
174
+ /* * Returns the q inverse.
175
+ * @see gtx_dual_quaternion */
176
+ fun inverse (res : DualQuat = DualQuat ()): DualQuat {
177
+ // conjugate
178
+ val realW = real.w
179
+ val realX = - real.x
180
+ val realY = - real.y
181
+ val realZ = - real.z
182
+ // conjugate
183
+ val dualW = dual.w
184
+ val dualX = - dual.x
185
+ val dualY = - dual.y
186
+ val dualZ = - dual.z
187
+
188
+ val dot = realX * dualX + realY * dualY + realZ * dualZ + realW * dualW
189
+ val w = dualW + realW * (- 2f * dot)
190
+ val x = dualX + realX * (- 2f * dot)
191
+ val y = dualY + realY * (- 2f * dot)
192
+ val z = dualZ + realZ * (- 2f * dot)
193
+ return res(realW, realX, realY, realZ, w, x, y, z)
194
+ }
195
+
196
+ // / Converts a quaternion to a 2 * 4 matrix.
197
+ // /
198
+ // / @see gtx_dual_quaternion
199
+ // template<typename T, qualifier Q>
200
+ // GLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat<T, Q> const& x);
201
+
202
+ // / Converts a quaternion to a 3 * 4 matrix.
203
+ // /
204
+ // / @see gtx_dual_quaternion
205
+ // template<typename T, qualifier Q>
206
+ // GLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat<T, Q> const& x);
207
+
208
+ /* * Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion.
209
+ * @see gtx_dual_quaternion */
210
+ fun dualquat_cast (x : Mat2x4 , res : DualQuat = DualQuat ()): DualQuat = res(x[0 ].w, x[0 ].x, x[0 ].y, x[0 ].z, x[1 ].w, x[1 ].x, x[1 ].y, x[1 ].z)
211
+
212
+ /* * Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion.
213
+ * @see gtx_dual_quaternion */
214
+ fun dualquat_cast (m : Mat3x4 , res : DualQuat = DualQuat ()): DualQuat {
215
+
216
+ val real = Quat ()
217
+
218
+ val trace = m[0 , 0 ] + m[1 , 1 ] + m[2 , 2 ]
219
+ when {
220
+ trace > 0f -> {
221
+ val r = sqrt(1f + trace)
222
+ val invR = 0.5f / r
223
+ real.w = 0.5f * r
224
+ real.x = (m[2 , 1 ] - m[1 , 2 ]) * invR
225
+ real.y = (m[0 , 2 ] - m[2 , 0 ]) * invR
226
+ real.z = (m[1 , 0 ] - m[0 , 1 ]) * invR
227
+ }
228
+ m[0 , 0 ] > m[1 , 1 ] && m[0 , 0 ] > m[2 , 2 ] -> {
229
+ val r = sqrt(1f + m[0 , 0 ] - m[1 , 1 ] - m[2 , 2 ])
230
+ val invR = 0.5f / r
231
+ real.x = 0.5f * r
232
+ real.y = (m[1 , 0 ] + m[0 , 1 ]) * invR
233
+ real.z = (m[0 , 2 ] + m[2 , 0 ]) * invR
234
+ real.w = (m[2 , 1 ] - m[1 , 2 ]) * invR
235
+ }
236
+ m[1 , 1 ] > m[2 , 2 ] -> {
237
+ val r = sqrt(1f + m[1 , 1 ] - m[0 , 0 ] - m[2 , 2 ])
238
+ val invR = 0.5f / r
239
+ real.x = (m[1 , 0 ] + m[0 , 1 ]) * invR
240
+ real.y = 0.5f * r
241
+ real.z = (m[2 , 1 ] + m[1 , 2 ]) * invR
242
+ real.w = (m[0 , 2 ] - m[2 , 0 ]) * invR
243
+ }
244
+ else -> {
245
+ val r = sqrt(1f + m[2 , 2 ] - m[0 , 0 ] - m[1 , 1 ])
246
+ val invR = 0.5f / r
247
+ real.x = (m[0 , 2 ] + m[2 , 0 ]) * invR
248
+ real.y = (m[2 , 1 ] + m[1 , 2 ]) * invR
249
+ real.z = 0.5f * r
250
+ real.w = (m[1 , 0 ] - m[0 , 1 ]) * invR
251
+ }
252
+ }
253
+
254
+ val dual = Quat (
255
+ - 0.5f * (m[0 , 3 ] * real.x + m[1 , 3 ] * real.y + m[2 , 3 ] * real.z),
256
+ 0.5f * (m[0 , 3 ] * real.w + m[1 , 3 ] * real.z - m[2 , 3 ] * real.y),
257
+ 0.5f * (- m[0 , 3 ] * real.z + m[1 , 3 ] * real.w + m[2 , 3 ] * real.x),
258
+ 0.5f * (m[0 , 3 ] * real.y - m[1 , 3 ] * real.x + m[2 , 3 ] * real.w))
259
+ return res(real, dual)
260
+ }
261
+
262
+ companion object : dualQuat_operators() {
263
+ @JvmField
264
+ val size = Quat .size * 2
265
+
266
+ /* * Creates an identity dual quaternion.
267
+ * @see gtx_dual_quaternion */
268
+ fun identity () = DualQuat ()
269
+ }
270
+
271
+ override fun equals (other : Any? ) = other is DualQuat && real == other.real && dual == other.dual
272
+ override fun hashCode () = 31 * real.hashCode() + dual.hashCode()
273
+ }
0 commit comments