@@ -168,13 +168,17 @@ extension Quaternion {
168168 ///
169169 /// Edge cases:
170170 /// -
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`:
172176 /// ```
173177 /// Quaternion(length: .zero, angle: θ, axis: axis) == .zero
174178 /// ```
175- /// - For any `θ`, even `.infinity` or `.nan`:
179+ /// - For any `θ` and any `axis` , even `.infinity` or `.nan`:
176180 /// ```
177- /// Quaternion(length: .infinity, angle: θ, axis: axis) == .ininfity
181+ /// Quaternion(length: .infinity, angle: θ, axis: axis) == .infinity
178182 /// ```
179183 /// - Otherwise, `θ` must be finite, or a precondition failure occurs.
180184 ///
@@ -215,7 +219,7 @@ extension Quaternion {
215219 " Given axis must be of unit length. "
216220 )
217221
218- self = Quaternion ( halfAngle: angle/ 2 , unitAxis: axis) . multiplied ( by: length)
222+ self = Quaternion ( halfAngle: angle/ 2 , unitAxis: axis) . multiplied ( by: length)
219223 }
220224
221225 /// Creates a unit quaternion specified with given [rotation vector][wiki].
@@ -278,23 +282,23 @@ extension Quaternion {
278282 ///
279283 /// Q = (cos(phase), axis * sin(phase)) * length
280284 ///
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 .
282286 ///
283287 /// Edge cases:
284288 /// -
285289 /// - Negative lengths are interpreted as reflecting the point through the origin, i.e.:
286290 /// ```
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)
288292 /// ```
289293 /// - For any `θ` and any `axis`, even `.infinity` or `.nan`:
290294 /// ```
291- /// Quaternion(length: .zero, angle : θ, axis: axis) == .zero
295+ /// Quaternion(length: .zero, phase : θ, axis: axis) == .zero
292296 /// ```
293297 /// - For any `θ` and any `axis`, even `.infinity` or `.nan`:
294298 /// ```
295- /// Quaternion(length: .infinity, angle : θ, axis: axis) == .infinity
299+ /// Quaternion(length: .infinity, phase : θ, axis: axis) == .infinity
296300 /// ```
297- /// - Otherwise, `θ` and `axis` must be finite, or a precondition failure occurs.
301+ /// - Otherwise, `θ` must be finite, or a precondition failure occurs.
298302 ///
299303 /// See also:
300304 /// -
@@ -303,25 +307,33 @@ extension Quaternion {
303307 /// - `.angleAxis`
304308 /// - `.rotationVector`
305309 /// - `.polar`
306- /// - `init(angle:axis)`
310+ /// - `init(length: angle:axis: )`
307311 /// - `init(rotation:)`
308312 ///
309313 /// [wiki]: https://en.wikipedia.org/wiki/Polar_decomposition#Quaternion_polar_decomposition
310314 @inlinable
311315 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 {
323317 self = Quaternion ( length)
318+ return
324319 }
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)
325337 }
326338
327339 /// Transforms a vector by this quaternion.
0 commit comments