@@ -168,13 +168,17 @@ extension Quaternion {
168
168
///
169
169
/// Edge cases:
170
170
/// -
171
- /// - For any `θ`, even `.infinity` or `.nan`:
171
+ /// - Negative lengths are interpreted as reflecting the point through the origin, i.e.:
172
+ /// ```
173
+ /// Quaternion(length: -r, angle: θ, axis: axis) == -Quaternion(length: r, angle: θ, axis: axis)
174
+ /// ```
175
+ /// - For any `θ` and any `axis`, even `.infinity` or `.nan`:
172
176
/// ```
173
177
/// Quaternion(length: .zero, angle: θ, axis: axis) == .zero
174
178
/// ```
175
- /// - For any `θ`, even `.infinity` or `.nan`:
179
+ /// - For any `θ` and any `axis` , even `.infinity` or `.nan`:
176
180
/// ```
177
- /// Quaternion(length: .infinity, angle: θ, axis: axis) == .ininfity
181
+ /// Quaternion(length: .infinity, angle: θ, axis: axis) == .infinity
178
182
/// ```
179
183
/// - Otherwise, `θ` must be finite, or a precondition failure occurs.
180
184
///
@@ -215,7 +219,7 @@ extension Quaternion {
215
219
" Given axis must be of unit length. "
216
220
)
217
221
218
- self = Quaternion ( halfAngle: angle/ 2 , unitAxis: axis) . multiplied ( by: length)
222
+ self = Quaternion ( halfAngle: angle/ 2 , unitAxis: axis) . multiplied ( by: length)
219
223
}
220
224
221
225
/// Creates a unit quaternion specified with given [rotation vector][wiki].
@@ -278,23 +282,23 @@ extension Quaternion {
278
282
///
279
283
/// Q = (cos(phase), axis * sin(phase)) * length
280
284
///
281
- /// Given `axis` gets normalized if it is not of unit length .
285
+ /// - Note: `axis` must be of unit length, or an assertion failure occurs .
282
286
///
283
287
/// Edge cases:
284
288
/// -
285
289
/// - Negative lengths are interpreted as reflecting the point through the origin, i.e.:
286
290
/// ```
287
- /// Quaternion(length: -r, angle : θ, axis: axis) == Quaternion(length: - r, angle : θ, axis: axis)
291
+ /// Quaternion(length: -r, phase : θ, axis: axis) == - Quaternion(length: r, phase : θ, axis: axis)
288
292
/// ```
289
293
/// - For any `θ` and any `axis`, even `.infinity` or `.nan`:
290
294
/// ```
291
- /// Quaternion(length: .zero, angle : θ, axis: axis) == .zero
295
+ /// Quaternion(length: .zero, phase : θ, axis: axis) == .zero
292
296
/// ```
293
297
/// - For any `θ` and any `axis`, even `.infinity` or `.nan`:
294
298
/// ```
295
- /// Quaternion(length: .infinity, angle : θ, axis: axis) == .infinity
299
+ /// Quaternion(length: .infinity, phase : θ, axis: axis) == .infinity
296
300
/// ```
297
- /// - Otherwise, `θ` and `axis` must be finite, or a precondition failure occurs.
301
+ /// - Otherwise, `θ` must be finite, or a precondition failure occurs.
298
302
///
299
303
/// See also:
300
304
/// -
@@ -303,25 +307,33 @@ extension Quaternion {
303
307
/// - `.angleAxis`
304
308
/// - `.rotationVector`
305
309
/// - `.polar`
306
- /// - `init(angle:axis)`
310
+ /// - `init(length: angle:axis: )`
307
311
/// - `init(rotation:)`
308
312
///
309
313
/// [wiki]: https://en.wikipedia.org/wiki/Polar_decomposition#Quaternion_polar_decomposition
310
314
@inlinable
311
315
public init ( length: RealType , phase: RealType , axis: SIMD3 < RealType > ) {
312
- let axisLength : RealType = . sqrt( axis. lengthSquared)
313
- if phase. isFinite && axisLength. isNormal {
314
- self = Quaternion (
315
- halfAngle: phase,
316
- unitAxis: axis/ axisLength
317
- ) . multiplied ( by: length)
318
- } else {
319
- precondition (
320
- length. isZero || length. isInfinite,
321
- " Either angle must be finite, or length must be zero or infinite. "
322
- )
316
+ guard !length. isZero, length. isFinite else {
323
317
self = Quaternion ( length)
318
+ return
324
319
}
320
+
321
+ // Length is finite and non-zero, therefore
322
+ // 1. `phase` must be finite or a precondition failure needs to occur; as
323
+ // this is not representable.
324
+ // 2. `axis` must be of unit length or an assertion failure occurs; while
325
+ // "wrong" by definition, it is representable.
326
+ precondition (
327
+ phase. isFinite,
328
+ " Either phase must be finite, or length must be zero or infinite. "
329
+ )
330
+ assert (
331
+ // TODO: Replace with `approximateEquality()`
332
+ abs ( . sqrt( axis. lengthSquared) - 1 ) < max ( . sqrt( axis. lengthSquared) , 1 ) * RealType. ulpOfOne. squareRoot ( ) ,
333
+ " Given axis must be of unit length. "
334
+ )
335
+
336
+ self = Quaternion ( halfAngle: phase, unitAxis: axis) . multiplied ( by: length)
325
337
}
326
338
327
339
/// Transforms a vector by this quaternion.
0 commit comments