@@ -308,6 +308,42 @@ extension Quaternion {
308
308
self = Quaternion ( length)
309
309
}
310
310
}
311
+
312
+ /// Rotates given vector by this quaternion.
313
+ ///
314
+ /// As quaternions can be used to represent three-dimensional rotations, it is
315
+ /// is possible to also rotate a three-dimensional vector by a quaternion. The
316
+ /// rotation of an arbitrary vector by a quaternion is known as an action.
317
+ ///
318
+ /// - Note: This method assumes this quaternion is of unit length.
319
+ ///
320
+ /// Edge cases:
321
+ /// -
322
+ /// - If `vector` is `.infinity` in any of the lanes or all, the returning
323
+ /// vector is `.infinity` in all lanes:
324
+ /// ```
325
+ /// Quaternion(rotation: .zero) == .zero
326
+ /// ```
327
+ ///
328
+ /// - Parameter vector: A vector to rotate by this quaternion
329
+ /// - Returns: The vector rotated by this quaternion
330
+ @inlinable
331
+ public func act( on vector: SIMD3 < RealType > ) -> SIMD3 < RealType > {
332
+ guard vector. isFinite else { return SIMD3 ( repeating: . infinity) }
333
+
334
+ // The following expression have been split up so the type-checker
335
+ // can resolve them in a reasonable time.
336
+ let p1 = vector * ( real*real - imaginary. lengthSquared)
337
+ let p2 = 2 * imaginary * imaginary. dot ( vector)
338
+ let p3 = 2 * real * imaginary. cross ( vector)
339
+ let rotatedVector = p1 + p2 + p3
340
+ if rotatedVector. isFinite { return rotatedVector }
341
+
342
+ // If the vector is no longer finite after it is rotated, scale it down,
343
+ // rotate it again and then scale it back-up after the rotation operation
344
+ let scale = max ( abs ( vector. max ( ) ) , abs ( vector. min ( ) ) )
345
+ return act ( on: vector/ scale) * scale
346
+ }
311
347
}
312
348
313
349
// MARK: - Transformation Helper
@@ -351,19 +387,29 @@ extension Quaternion {
351
387
// and *(x,y,z)* axis representations internally to the module.
352
388
extension SIMD3 where Scalar: FloatingPoint {
353
389
354
- /// Returns the squared length of this SIMD3 instance.
390
+ /// Returns the squared length of this instance.
355
391
@usableFromInline @inline ( __always)
356
392
internal var lengthSquared : Scalar {
357
- ( self * self ) . sum ( )
393
+ dot ( self )
394
+ }
395
+
396
+ /// True if all values of this instance are finite
397
+ @usableFromInline @inline ( __always)
398
+ internal var isFinite : Bool {
399
+ x. isFinite && y. isFinite && z. isFinite
400
+ }
401
+
402
+ /// Returns the scalar/dot product of this vector with `other`.
403
+ @usableFromInline @inline ( __always)
404
+ internal func dot( _ other: SIMD3 < Scalar > ) -> Scalar {
405
+ ( self * other) . sum ( )
358
406
}
359
407
360
- /// Returns the vector/cross product of this quaternion with `other`.
408
+ /// Returns the vector/cross product of this vector with `other`.
361
409
@usableFromInline @inline ( __always)
362
- internal func vectorProduct( with other: SIMD3 < Scalar > ) -> SIMD3 < Scalar > {
363
- let selfYZW = self [ SIMD3 < Int > ( 1 , 2 , 0 ) ]
364
- let otherYZX = other [ SIMD3 < Int > ( 1 , 2 , 0 ) ]
365
- let selfZXY = self [ SIMD3 < Int > ( 2 , 0 , 1 ) ]
366
- let otherZXY = other [ SIMD3 < Int > ( 2 , 0 , 1 ) ]
367
- return ( selfYZW * otherZXY) - ( selfZXY * otherYZX)
410
+ internal func cross( _ other: SIMD3 < Scalar > ) -> SIMD3 < Scalar > {
411
+ let yzx = SIMD3 < Int > ( 1 , 2 , 0 )
412
+ let zxy = SIMD3 < Int > ( 2 , 0 , 1 )
413
+ return ( self [ yzx] * other[ zxy] ) - ( self [ zxy] * other[ yzx] )
368
414
}
369
415
}
0 commit comments