import Foundation import simd public struct Quaternion: Equatable { public var w: T, x: T, y: T, z: T public init() { self.x = 0; self.y = 0; self.z = 0; self.w = 1 } public init(_ w: T, _ x: T, _ y: T, _ z: T) { self.w = w; self.x = x; self.y = y; self.z = z } public static var identity: Self { .init(1, 0, 0, 0) } } public extension Quaternion where T: SIMDScalar { init(real w: T, imaginary i: Vector3) { self.w = w; self.x = i.x; self.y = i.y; self.z = i.z } } #if USE_SIMD public extension Quaternion where T == Float { init(_ q: simd_quatf) { self.init(real: q.real, imaginary: q.imag) } static func lookAt(from: Vector3 = .zero, to: Vector3, up: Vector3 = .up) -> Self { let m3 = Matrix3x3.lookAt(from: from, to: to, up: up) let et_blee_eve_nyu = simd_quatf(m3) return Self(real: et_blee_eve_nyu.real, imaginary: .init( et_blee_eve_nyu.imag.x, et_blee_eve_nyu.imag.y, et_blee_eve_nyu.imag.z)) } } #else public extension Quaternion where T == Float { init(_ m3: Matrix3x3) { if m3.m22 < 0 { if m3.m00 > m3.m11 { let t = 1 + m3.m00 - m3.m11 - m3.m22 self.x = t.squareRoot() * 0.5 if m3.m21 < m3.m12 { self.x = -self.x } let ix4 = 1 / (4 * self.x) self.w = (m3.m21 - m3.m12) * ix4 self.y = (m3.m10 + m3.m01) * ix4 self.z = (m3.m02 + m3.m20) * ix4 if t == 1 && self.w == 0 && self.y == 0 && self.z == 0 { self.x = 1 } } else { let t = 1 - m3.m00 + m3.m11 - m3.m22 self.y = t.squareRoot() * 0.5 if m3.m02 < m3.m20 { self.y = -self.y } let iy4 = 1 / (4 * self.y) self.w = (m3.m02 - m3.m20) * iy4 self.x = (m3.m10 + m3.m01) * iy4 self.z = (m3.m21 + m3.m12) * iy4 if t == 1 && self.w == 0 && self.x == 0 && self.z == 0 { self.y = 1 } } } else { if m3.m00 < -m3.m11 { let t = 1 - m3.m00 - m3.m11 + m3.m22 self.z = t.squareRoot() * 0.5 if m3.m10 < m3.m01 { self.z = -self.z } let iz4 = 1 / (4 * self.z) self.w = (m3.m10 - m3.m01) * iz4 self.x = (m3.m02 + m3.m20) * iz4 self.y = (m3.m21 + m3.m12) * iz4 if t == 1 && self.w == 0 && self.x == 0 && self.y == 0 { self.z = 1 } } else { let t = 1 + m3.m00 + m3.m11 + m3.m22 self.w = t.squareRoot() * 0.5 let iw4 = 1 / (4 * self.w) self.x = (m3.m21 - m3.m12) * iw4 self.y = (m3.m02 - m3.m20) * iw4 self.z = (m3.m10 - m3.m01) * iw4 if t == 1 && self.x == 0 && self.y == 0 && self.z == 0 { self.w = 1 } } } /* let m3 = m3FUCK.transpose if m3.m22 < 0 { if m3.m00 > m3.m11 { let t = 1 + m3.m00 - m3.m11 - m3.m22 self.x = t.squareRoot() * 0.5 if m3.m12 < m3.m21 { self.x = -self.x } let ix4 = 1 / (4 * self.x) self.w = (m3.m12 - m3.m21) * ix4 self.y = (m3.m01 + m3.m10) * ix4 self.z = (m3.m20 + m3.m02) * ix4 if t == 1 && self.w == 0 && self.y == 0 && self.z == 0 { self.x = 1 } } else { let t = 1 - m3.m00 + m3.m11 - m3.m22 self.y = t.squareRoot() * 0.5 if m3.m20 < m3.m02 { self.y = -self.y } let iy4 = 1 / (4 * self.y) self.w = (m3.m20 - m3.m02) * iy4 self.x = (m3.m01 + m3.m10) * iy4 self.z = (m3.m12 + m3.m21) * iy4 if t == 1 && self.w == 0 && self.x == 0 && self.z == 0 { self.y = 1 } } } else { if m3.m00 < -m3.m11 { let t = 1 - m3.m00 - m3.m11 + m3.m22 self.z = t.squareRoot() * 0.5 if m3.m01 < m3.m10 { self.z = -self.z } let iz4 = 1 / (4 * self.z) self.w = (m3.m01 - m3.m10) * iz4 self.x = (m3.m20 + m3.m02) * iz4 self.y = (m3.m12 + m3.m21) * iz4 if t == 1 && self.w == 0 && self.x == 0 && self.y == 0 { self.z = 1 } } else { let t = 1 + m3.m00 + m3.m11 + m3.m22 self.w = t.squareRoot() * 0.5 let iw4 = 1 / (4 * self.w) self.x = (m3.m12 - m3.m21) * iw4 self.y = (m3.m20 - m3.m02) * iw4 self.z = (m3.m01 - m3.m10) * iw4 if t == 1 && self.x == 0 && self.y == 0 && self.z == 0 { self.w = 1 } } } */ /* self.w = (1 + m3.m00 + m3.m11 + m3.m22).squareRoot() * 0.5 let iw4 = 1 / (4 * self.w) self.x = (m3.m21 - m3.m12) * iw4 self.y = (m3.m02 - m3.m20) * iw4 self.z = (m3.m10 - m3.m01) * iw4 */ /* if m3.m22 < 0 { if m3.m00 > m3.m11 { self.w = (1 + m3.m00 - m3.m11 - m3.m22).squareRoot() * 0.5 let iw4 = 1 / (4 * self.w) //self.x = (m3.m01 + m3.m10) * iw4 //self.y = (m3.m20 + m3.m02) * iw4 //self.z = (m3.m12 - m3.m21) * iw4 self.x = (m3.m21 - m3.m12) * iw4 self.y = (m3.m02 - m3.m20) * iw4 self.z = (m3.m10 - m3.m01) * iw4 } else { self.x = (1 - m3.m00 + m3.m11 - m3.m22).squareRoot() * 0.5 let ix4 = 1 / (4 * self.x) //self.w = (m3.m01 + m3.m10) * ix4 //self.y = (m3.m12 + m3.m21) * ix4 //self.z = (m3.m20 - m3.m02) * ix4 self.z = (m3.m02 - m3.m20) * ix4 self.y = (m3.m21 - m3.m12) * ix4 self.w = (m3.m10 - m3.m01) * ix4 } } else { if m3.m00 < -m3.m11 { self.y = (1 - m3.m00 - m3.m11 + m3.m22).squareRoot() * 0.5 let iy4 = 1 / (4 * self.y) //self.w = (m3.m20 + m3.m02) * iy4 //self.x = (m3.m12 + m3.m21) * iy4 //self.z = (m3.m01 - m3.m10) * iy4 self.z = (m3.m10 - m3.m01) * iy4 self.x = (m3.m21 - m3.m12) * iy4 self.w = (m3.m02 - m3.m20) * iy4 } else { self.z = (1 + m3.m00 + m3.m11 + m3.m22).squareRoot() * 0.5 let iz4 = 1 / (4 * self.z) //self.w = (m3.m12 - m3.m21) * iz4 //self.x = (m3.m20 - m3.m02) * iz4 //self.y = (m3.m01 - m3.m10) * iz4 self.y = (m3.m10 - m3.m01) * iz4 self.x = (m3.m02 - m3.m20) * iz4 self.w = (m3.m21 - m3.m12) * iz4 } } */ } static func lookAt(from: Vector3 = .zero, to: Vector3, up: Vector3 = .up) -> Self { Self(Matrix3x3.lookAt(from: from, to: to, up: up)) } } #endif public extension Quaternion where T == Float { init(axis v: Vector3, angle theta: T) { let tc = (theta * 0.5).cosine, ts = (theta * 0.5).sine self.init(real: tc, imaginary: v * ts) } @inline(__always) func slerp(_ rhs: Self, _ theta: T) -> Self { var b = rhs var cosHalfTheta = self.dot(b) if abs(cosHalfTheta) >= 1 { // if a == b or a == -b then theta == 0 return self } else if cosHalfTheta < 0 { b = -b cosHalfTheta = -cosHalfTheta } let halfTheta = acos(cosHalfTheta) let sinHalfTheta = (1 - cosHalfTheta * cosHalfTheta).squareRoot() if abs(sinHalfTheta) <= .ulpOfOne { // if theta == 180 degrees then result is not fully defined // we could rotate around any axis normal to a or b return (self + b) * 0.5 } let ratioA = ((1 - theta) * halfTheta).sine / sinHalfTheta let ratioB = (theta * halfTheta).sine / sinHalfTheta return self * ratioA + b * ratioB //let piss = simd_quatf(ix: x, iy: y, iz: z, r: w) //let shit = simd_quatf(ix: b.x, iy: b.y, iz: b.z, r: b.w) //let cunt = simd_slerp(piss, shit, x) //return .init(real: cunt.real, imaginary: cunt.imag) } // Because swift type checking brain injury @inline(__always) static func * (a: Self, b: Self) -> Self { .init( a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w) } } public extension Quaternion where T: FloatingPoint { @inline(__always) static prefix func - (this: Self) -> Self { .init(-this.w, -this.x, -this.y, -this.z) } @inline(__always) static func + (lhs: Self, rhs: Self) -> Self { .init(lhs.w + rhs.w, lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z) } @inline(__always) static func * (lhs: Self, rhs: T) -> Self { .init(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs) } @inline(__always) mutating func normalise() { let invMag = 1 / self.dot(self).squareRoot() self.w *= invMag self.x *= invMag self.y *= invMag self.z *= invMag } @inline(__always) var normalised: Self { let invMag = 1 / self.dot(self).squareRoot() return self * invMag } @inline(__always) func dot(_ b: Self) -> T { x * b.x + y * b.y + z * b.z + w * b.w } } #if USE_SIMD public extension Vector3 where Scalar == Float { @inline(__always) static func * (v: Self, q: Quaternion) -> Self { return v * simd_float3x3(simd_quatf(ix: q.x, iy: q.y, iz: q.z, r: q.w)) } } #else public extension Vector3 where T: BinaryFloatingPoint { @inline(__always) static func * (v: Self, q: Quaternion) -> Self { let qw = q.w, qv = Self(q.x, q.y, q.z) var out = qv * 2.0 * qv.dot(v) out += v * (qw * qw - qv.dot(qv)) return out + qv.cross(v) * 2.0 * qw } } #endif public typealias Quatf = Quaternion public typealias Quatd = Quaternion