Skip to content

Instantly share code, notes, and snippets.

@JKalash
Last active June 11, 2019 09:04
Show Gist options
  • Save JKalash/04da800716d515f4d6a9a638f8615b0b to your computer and use it in GitHub Desktop.
Save JKalash/04da800716d515f4d6a9a638f8615b0b to your computer and use it in GitHub Desktop.
Trilateration algorithm in Swift 3. [Requires VectorMath.swift]
//
// JKTrilateration
//
// Created by Joseph Kalash on 6/9/17.
// Copyright © 2017 Joseph Kalash. All rights reserved.
//
import Foundation
extension Double {
var radians : Double {
return self * Double.pi / Double(180)
}
var degrees : Double {
return self * Double(180) / Double.pi
}
}
struct JKTrilateration {
struct Circle {
var center : Vector2
var radius : Double
}
static func trilaterate(circles : [Circle]) -> Vector2? {
guard circles.count >= 3 else {
return nil
}
let c1 = circles[0]
let c2 = circles[1]
let c3 = circles[2]
let earthR : Double = 6371
let LatA = c1.center.y.radians, LonA = c1.center.x.radians
let LatB = c2.center.y.radians, LonB = c2.center.x.radians
let LatC = c3.center.y.radians, LonC = c3.center.x.radians
let DistA = c1.radius / 1000, DistB = c2.radius / 1000, DistC = c3.radius / 1000
//using authalic sphere
//if using an ellipsoid this step is slightly different
//Convert geodetic Lat/Long to ECEF xyz
// 1. Convert Lat/Long to radians
// 2. Convert Lat/Long(radians) to ECEF
let xA = earthR * (cos(LatA) * cos(LonA))
let yA = earthR * (cos(LatA) * sin(LonA))
let zA = earthR * (sin(LatA))
let P1 = Vector3(xA, yA, zA)
let xB = earthR * (cos(LatB) * cos(LonB))
let yB = earthR * (cos(LatB) * sin(LonB))
let zB = earthR * (sin(LatB))
let P2 = Vector3(xB, yB, zB)
let xC = earthR * (cos(LatC) * cos(LonC))
let yC = earthR * (cos(LatC) * sin(LonC))
let zC = earthR * (sin(LatC))
let P3 = Vector3(xC, yC, zC)
//from wikipedia
//transform to get circle 1 at origin
//transform to get circle 2 on x axis
let ex = (P2 - P1) / (P2 - P1).length
let P3P1 = P3 - P1
let i = ex.dot(P3P1)
let idotex = ex * i
let ey = (P3P1 - idotex) / (P3P1 - idotex).length
let ez = ex.cross(ey)
let d = (P2 - P1).length
let j = ey.dot(P3P1)
//from wikipedia
//plug and chug using above values
let x = (pow(DistA,2) - pow(DistB,2) + pow(d,2)) / (2*d)
let y = (pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j) - ((i/j)*x)
// only one case shown here
let z = sqrt(Swift.abs(pow(DistA, 2) - pow(x, 2) - pow(y, 2)))
//triPt is an array with ECEF x,y,z of trilateration point
let xEx = ex * x
let yEy = ey * y
let zEz = ez * z
let triPt = P1 + xEx + yEy + zEz
//convert back to lat/long from ECEF, and make sure it's in degrees
let lat = asin(triPt.z / earthR).degrees
let lon = atan2(triPt.y,triPt.x).degrees
return Vector2(lon, lat)
}
}
//
// VectorMath.swift
// VectorMath
//
// Version 0.3
//
// Created by Nick Lockwood on 24/11/2014.
// Copyright (c) 2014 Nick Lockwood. All rights reserved.
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/VectorMath
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
import Foundation
//MARK: Types
public typealias Scalar = Double
public struct Vector2 {
public var x: Scalar
public var y: Scalar
}
public struct Vector3 {
public var x: Scalar
public var y: Scalar
public var z: Scalar
}
public struct Vector4 {
public var x: Scalar
public var y: Scalar
public var z: Scalar
public var w: Scalar
}
public struct Matrix3 {
public var m11: Scalar
public var m12: Scalar
public var m13: Scalar
public var m21: Scalar
public var m22: Scalar
public var m23: Scalar
public var m31: Scalar
public var m32: Scalar
public var m33: Scalar
}
public struct Matrix4 {
public var m11: Scalar
public var m12: Scalar
public var m13: Scalar
public var m14: Scalar
public var m21: Scalar
public var m22: Scalar
public var m23: Scalar
public var m24: Scalar
public var m31: Scalar
public var m32: Scalar
public var m33: Scalar
public var m34: Scalar
public var m41: Scalar
public var m42: Scalar
public var m43: Scalar
public var m44: Scalar
}
public struct Quaternion {
public var x: Scalar
public var y: Scalar
public var z: Scalar
public var w: Scalar
}
//MARK: Scalar
public extension Scalar {
public static let halfPi = Scalar(pi / 2)
public static let quarterPi = Scalar(pi / 4)
public static let twoPi = Scalar(pi * 2)
public static let degreesPerRadian = 180 / pi
public static let radiansPerDegree = pi / 180
public static let epsilon: Scalar = 0.0001
public static func ~=(lhs: Scalar, rhs: Scalar) -> Bool {
return Swift.abs(lhs - rhs) < .epsilon
}
}
//MARK: Vector2
extension Vector2: Equatable, Hashable {
public static let zero = Vector2(0, 0)
public static let x = Vector2(1, 0)
public static let y = Vector2(0, 1)
public var hashValue: Int {
return x.hashValue &+ y.hashValue
}
public var lengthSquared: Scalar {
return x * x + y * y
}
public var length: Scalar {
return sqrt(lengthSquared)
}
public var inverse: Vector2 {
return -self
}
public init(_ x: Scalar, _ y: Scalar) {
self.init(x: x, y: y)
}
public init(_ v: [Scalar]) {
assert(v.count == 2, "array must contain 2 elements, contained \(v.count)")
self.init(v[0], v[1])
}
public func toArray() -> [Scalar] {
return [x, y]
}
public func dot(_ v: Vector2) -> Scalar {
return x * v.x + y * v.y
}
public func cross(_ v: Vector2) -> Scalar {
return x * v.y - y * v.x
}
public func normalized() -> Vector2 {
let lengthSquared = self.lengthSquared
if lengthSquared ~= 0 || lengthSquared ~= 1 {
return self
}
return self / sqrt(lengthSquared)
}
public func rotated(by radians: Scalar) -> Vector2 {
let cs = cos(radians)
let sn = sin(radians)
return Vector2(x * cs - y * sn, x * sn + y * cs)
}
public func rotated(by radians: Scalar, around pivot: Vector2) -> Vector2 {
return (self - pivot).rotated(by: radians) + pivot
}
public func angle(with v: Vector2) -> Scalar {
if self == v {
return 0
}
let t1 = normalized()
let t2 = v.normalized()
let cross = t1.cross(t2)
let dot = max(-1, min(1, t1.dot(t2)))
return atan2(cross, dot)
}
public func interpolated(with v: Vector2, by t: Scalar) -> Vector2 {
return self + (v - self) * t
}
public static prefix func -(v: Vector2) -> Vector2 {
return Vector2(-v.x, -v.y)
}
public static func +(lhs: Vector2, rhs: Vector2) -> Vector2 {
return Vector2(lhs.x + rhs.x, lhs.y + rhs.y)
}
public static func -(lhs: Vector2, rhs: Vector2) -> Vector2 {
return Vector2(lhs.x - rhs.x, lhs.y - rhs.y)
}
public static func *(lhs: Vector2, rhs: Vector2) -> Vector2 {
return Vector2(lhs.x * rhs.x, lhs.y * rhs.y)
}
public static func *(lhs: Vector2, rhs: Scalar) -> Vector2 {
return Vector2(lhs.x * rhs, lhs.y * rhs)
}
public static func *(lhs: Vector2, rhs: Matrix3) -> Vector2 {
return Vector2(
lhs.x * rhs.m11 + lhs.y * rhs.m21 + rhs.m31,
lhs.x * rhs.m12 + lhs.y * rhs.m22 + rhs.m32
)
}
public static func /(lhs: Vector2, rhs: Vector2) -> Vector2 {
return Vector2(lhs.x / rhs.x, lhs.y / rhs.y)
}
public static func /(lhs: Vector2, rhs: Scalar) -> Vector2 {
return Vector2(lhs.x / rhs, lhs.y / rhs)
}
public static func ==(lhs: Vector2, rhs: Vector2) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
public static func ~=(lhs: Vector2, rhs: Vector2) -> Bool {
return lhs.x ~= rhs.x && lhs.y ~= rhs.y
}
}
//MARK: Vector3
extension Vector3: Equatable, Hashable {
public static let zero = Vector3(0, 0, 0)
public static let x = Vector3(1, 0, 0)
public static let y = Vector3(0, 1, 0)
public static let z = Vector3(0, 0, 1)
public var hashValue: Int {
return x.hashValue &+ y.hashValue &+ z.hashValue
}
public var lengthSquared: Scalar {
return x * x + y * y + z * z
}
public var length: Scalar {
return sqrt(lengthSquared)
}
public var inverse: Vector3 {
return -self
}
public var xy: Vector2 {
get {
return Vector2(x, y)
}
set (v) {
x = v.x
y = v.y
}
}
public var xz: Vector2 {
get {
return Vector2(x, z)
}
set (v) {
x = v.x
z = v.y
}
}
public var yz: Vector2 {
get {
return Vector2(y, z)
}
set (v) {
y = v.x
z = v.y
}
}
public init(_ x: Scalar, _ y: Scalar, _ z: Scalar) {
self.init(x: x, y: y, z: z)
}
public init(_ v: [Scalar]) {
assert(v.count == 3, "array must contain 3 elements, contained \(v.count)")
self.init(v[0], v[1], v[2])
}
public func toArray() -> [Scalar] {
return [x, y, z]
}
public func dot(_ v: Vector3) -> Scalar {
return x * v.x + y * v.y + z * v.z
}
public func cross(_ v: Vector3) -> Vector3 {
return Vector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x)
}
public func normalized() -> Vector3 {
let lengthSquared = self.lengthSquared
if lengthSquared ~= 0 || lengthSquared ~= 1 {
return self
}
return self / sqrt(lengthSquared)
}
public func interpolated(with v: Vector3, by t: Scalar) -> Vector3 {
return self + (v - self) * t
}
public static prefix func -(v: Vector3) -> Vector3 {
return Vector3(-v.x, -v.y, -v.z)
}
public static func +(lhs: Vector3, rhs: Vector3) -> Vector3 {
return Vector3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z)
}
public static func -(lhs: Vector3, rhs: Vector3) -> Vector3 {
return Vector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
}
public static func *(lhs: Vector3, rhs: Vector3) -> Vector3 {
return Vector3(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z)
}
public static func *(lhs: Vector3, rhs: Scalar) -> Vector3 {
return Vector3(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs)
}
public static func *(lhs: Vector3, rhs: Matrix3) -> Vector3 {
return Vector3(
lhs.x * rhs.m11 + lhs.y * rhs.m21 + lhs.z * rhs.m31,
lhs.x * rhs.m12 + lhs.y * rhs.m22 + lhs.z * rhs.m32,
lhs.x * rhs.m13 + lhs.y * rhs.m23 + lhs.z * rhs.m33
)
}
public static func *(lhs: Vector3, rhs: Matrix4) -> Vector3 {
return Vector3(
lhs.x * rhs.m11 + lhs.y * rhs.m21 + lhs.z * rhs.m31 + rhs.m41,
lhs.x * rhs.m12 + lhs.y * rhs.m22 + lhs.z * rhs.m32 + rhs.m42,
lhs.x * rhs.m13 + lhs.y * rhs.m23 + lhs.z * rhs.m33 + rhs.m43
)
}
public static func *(v: Vector3, q: Quaternion) -> Vector3 {
let qv = q.xyz
let uv = qv.cross(v)
let uuv = qv.cross(uv)
return v + (uv * 2 * q.w) + (uuv * 2)
}
public static func /(lhs: Vector3, rhs: Vector3) -> Vector3 {
return Vector3(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z)
}
public static func /(lhs: Vector3, rhs: Scalar) -> Vector3 {
return Vector3(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs)
}
public static func ==(lhs: Vector3, rhs: Vector3) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z
}
public static func ~=(lhs: Vector3, rhs: Vector3) -> Bool {
return lhs.x ~= rhs.x && lhs.y ~= rhs.y && lhs.z ~= rhs.z
}
}
//MARK: Vector4
extension Vector4: Equatable, Hashable {
public static let zero = Vector4(0, 0, 0, 0)
public static let x = Vector4(1, 0, 0, 0)
public static let y = Vector4(0, 1, 0, 0)
public static let z = Vector4(0, 0, 1, 0)
public static let w = Vector4(0, 0, 0, 1)
public var hashValue: Int {
return x.hashValue &+ y.hashValue &+ z.hashValue &+ w.hashValue
}
public var lengthSquared: Scalar {
return x * x + y * y + z * z + w * w
}
public var length: Scalar {
return sqrt(lengthSquared)
}
public var inverse: Vector4 {
return -self
}
public var xyz: Vector3 {
get {
return Vector3(x, y, z)
}
set (v) {
x = v.x
y = v.y
z = v.z
}
}
public var xy: Vector2 {
get {
return Vector2(x, y)
}
set (v) {
x = v.x
y = v.y
}
}
public var xz: Vector2 {
get {
return Vector2(x, z)
}
set (v) {
x = v.x
z = v.y
}
}
public var yz: Vector2 {
get {
return Vector2(y, z)
}
set (v) {
y = v.x
z = v.y
}
}
public init(_ x: Scalar, _ y: Scalar, _ z: Scalar, _ w: Scalar) {
self.init(x: x, y: y, z: z, w: w)
}
public init(_ v: [Scalar]) {
assert(v.count == 4, "array must contain 4 elements, contained \(v.count)")
self.init(v[0], v[1], v[2], v[3])
}
public init(_ v: Vector3, w: Scalar) {
self.init(v.x, v.y, v.z, w)
}
public func toArray() -> [Scalar] {
return [x, y, z, w]
}
public func toVector3() -> Vector3 {
if w ~= 0 {
return xyz
} else {
return xyz / w
}
}
public func dot(_ v: Vector4) -> Scalar {
return x * v.x + y * v.y + z * v.z + w * v.w
}
public func normalized() -> Vector4 {
let lengthSquared = self.lengthSquared
if lengthSquared ~= 0 || lengthSquared ~= 1 {
return self
}
return self / sqrt(lengthSquared)
}
public func interpolated(with v: Vector4, by t: Scalar) -> Vector4 {
return self + (v - self) * t
}
public static prefix func -(v: Vector4) -> Vector4 {
return Vector4(-v.x, -v.y, -v.z, -v.w)
}
public static func +(lhs: Vector4, rhs: Vector4) -> Vector4 {
return Vector4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w)
}
public static func -(lhs: Vector4, rhs: Vector4) -> Vector4 {
return Vector4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w)
}
public static func *(lhs: Vector4, rhs: Vector4) -> Vector4 {
return Vector4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w)
}
public static func *(lhs: Vector4, rhs: Scalar) -> Vector4 {
return Vector4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs)
}
public static func *(lhs: Vector4, rhs: Matrix4) -> Vector4 {
return Vector4(
lhs.x * rhs.m11 + lhs.y * rhs.m21 + lhs.z * rhs.m31 + lhs.w * rhs.m41,
lhs.x * rhs.m12 + lhs.y * rhs.m22 + lhs.z * rhs.m32 + lhs.w * rhs.m42,
lhs.x * rhs.m13 + lhs.y * rhs.m23 + lhs.z * rhs.m33 + lhs.w * rhs.m43,
lhs.x * rhs.m14 + lhs.y * rhs.m24 + lhs.z * rhs.m34 + lhs.w * rhs.m44
)
}
public static func /(lhs: Vector4, rhs: Vector4) -> Vector4 {
return Vector4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w)
}
public static func /(lhs: Vector4, rhs: Scalar) -> Vector4 {
return Vector4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs)
}
public static func ==(lhs: Vector4, rhs: Vector4) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w
}
public static func ~=(lhs: Vector4, rhs: Vector4) -> Bool {
return lhs.x ~= rhs.x && lhs.y ~= rhs.y && lhs.z ~= rhs.z && lhs.w ~= rhs.w
}
}
//MARK: Matrix3
extension Matrix3: Equatable, Hashable {
public static let identity = Matrix3(1, 0 ,0 ,0, 1, 0, 0, 0, 1)
public var hashValue: Int {
var hash = m11.hashValue &+ m12.hashValue &+ m13.hashValue
hash = hash &+ m21.hashValue &+ m22.hashValue &+ m23.hashValue
hash = hash &+ m31.hashValue &+ m32.hashValue &+ m33.hashValue
return hash
}
public init(_ m11: Scalar, _ m12: Scalar, _ m13: Scalar,
_ m21: Scalar, _ m22: Scalar, _ m23: Scalar,
_ m31: Scalar, _ m32: Scalar, _ m33: Scalar) {
self.m11 = m11 // 0
self.m12 = m12 // 1
self.m13 = m13 // 2
self.m21 = m21 // 3
self.m22 = m22 // 4
self.m23 = m23 // 5
self.m31 = m31 // 6
self.m32 = m32 // 7
self.m33 = m33 // 8
}
public init(scale: Vector2) {
self.init(
scale.x, 0, 0,
0, scale.y, 0,
0, 0, 1
)
}
public init(translation: Vector2) {
self.init(
1, 0, 0,
0, 1, 0,
translation.x, translation.y, 1
)
}
public init(rotation radians: Scalar) {
let cs = cos(radians)
let sn = sin(radians)
self.init(
cs, sn, 0,
-sn, cs, 0,
0, 0, 1
)
}
public init(_ m: [Scalar]) {
assert(m.count == 9, "array must contain 9 elements, contained \(m.count)")
self.init(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8])
}
public func toArray() -> [Scalar] {
return [m11, m12, m13, m21, m22, m23, m31, m32, m33]
}
public var adjugate: Matrix3 {
return Matrix3(
m22 * m33 - m23 * m32,
m13 * m32 - m12 * m33,
m12 * m23 - m13 * m22,
m23 * m31 - m21 * m33,
m11 * m33 - m13 * m31,
m13 * m21 - m11 * m23,
m21 * m32 - m22 * m31,
m12 * m31 - m11 * m32,
m11 * m22 - m12 * m21
)
}
public var determinant: Scalar {
return (m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
- (m13 * m22 * m31 + m11 * m23 * m32 + m12 * m21 * m33)
}
public var transpose: Matrix3 {
return Matrix3(m11, m21, m31, m12, m22, m32, m13, m23, m33)
}
public var inverse: Matrix3 {
return adjugate * (1 / determinant)
}
public func interpolated(with m: Matrix3, by t: Scalar) -> Matrix3 {
return Matrix3(
m11 + (m.m11 - m11) * t,
m12 + (m.m12 - m12) * t,
m13 + (m.m13 - m13) * t,
m21 + (m.m21 - m21) * t,
m22 + (m.m22 - m22) * t,
m23 + (m.m23 - m23) * t,
m31 + (m.m31 - m31) * t,
m32 + (m.m32 - m32) * t,
m33 + (m.m33 - m33) * t
)
}
public static prefix func -(m: Matrix3) -> Matrix3 {
return m.inverse
}
public static func *(lhs: Matrix3, rhs: Matrix3) -> Matrix3 {
return Matrix3(
lhs.m11 * rhs.m11 + lhs.m21 * rhs.m12 + lhs.m31 * rhs.m13,
lhs.m12 * rhs.m11 + lhs.m22 * rhs.m12 + lhs.m32 * rhs.m13,
lhs.m13 * rhs.m11 + lhs.m23 * rhs.m12 + lhs.m33 * rhs.m13,
lhs.m11 * rhs.m21 + lhs.m21 * rhs.m22 + lhs.m31 * rhs.m23,
lhs.m12 * rhs.m21 + lhs.m22 * rhs.m22 + lhs.m32 * rhs.m23,
lhs.m13 * rhs.m21 + lhs.m23 * rhs.m22 + lhs.m33 * rhs.m23,
lhs.m11 * rhs.m31 + lhs.m21 * rhs.m32 + lhs.m31 * rhs.m33,
lhs.m12 * rhs.m31 + lhs.m22 * rhs.m32 + lhs.m32 * rhs.m33,
lhs.m13 * rhs.m31 + lhs.m23 * rhs.m32 + lhs.m33 * rhs.m33
)
}
public static func *(lhs: Matrix3, rhs: Vector2) -> Vector2 {
return rhs * lhs
}
public static func *(lhs: Matrix3, rhs: Vector3) -> Vector3 {
return rhs * lhs
}
public static func *(lhs: Matrix3, rhs: Scalar) -> Matrix3 {
return Matrix3(
lhs.m11 * rhs, lhs.m12 * rhs, lhs.m13 * rhs,
lhs.m21 * rhs, lhs.m22 * rhs, lhs.m23 * rhs,
lhs.m31 * rhs, lhs.m32 * rhs, lhs.m33 * rhs
)
}
public static func ==(lhs: Matrix3, rhs: Matrix3) -> Bool {
if lhs.m11 != rhs.m11 { return false }
if lhs.m12 != rhs.m12 { return false }
if lhs.m13 != rhs.m13 { return false }
if lhs.m21 != rhs.m21 { return false }
if lhs.m22 != rhs.m22 { return false }
if lhs.m23 != rhs.m23 { return false }
if lhs.m31 != rhs.m31 { return false }
if lhs.m32 != rhs.m32 { return false }
if lhs.m33 != rhs.m33 { return false }
return true
}
public static func ~=(lhs: Matrix3, rhs: Matrix3) -> Bool {
if !(lhs.m11 ~= rhs.m11) { return false }
if !(lhs.m12 ~= rhs.m12) { return false }
if !(lhs.m13 ~= rhs.m13) { return false }
if !(lhs.m21 ~= rhs.m21) { return false }
if !(lhs.m22 ~= rhs.m22) { return false }
if !(lhs.m23 ~= rhs.m23) { return false }
if !(lhs.m31 ~= rhs.m31) { return false }
if !(lhs.m32 ~= rhs.m32) { return false }
if !(lhs.m33 ~= rhs.m33) { return false }
return true
}
}
//MARK: Matrix4
extension Matrix4: Equatable, Hashable {
public static let identity = Matrix4(1, 0 ,0 ,0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
public var hashValue: Int {
var hash = m11.hashValue &+ m12.hashValue &+ m13.hashValue &+ m14.hashValue
hash = hash &+ m21.hashValue &+ m22.hashValue &+ m23.hashValue &+ m24.hashValue
hash = hash &+ m31.hashValue &+ m32.hashValue &+ m33.hashValue &+ m34.hashValue
hash = hash &+ m41.hashValue &+ m42.hashValue &+ m43.hashValue &+ m44.hashValue
return hash
}
public init(_ m11: Scalar, _ m12: Scalar, _ m13: Scalar, _ m14: Scalar,
_ m21: Scalar, _ m22: Scalar, _ m23: Scalar, _ m24: Scalar,
_ m31: Scalar, _ m32: Scalar, _ m33: Scalar, _ m34: Scalar,
_ m41: Scalar, _ m42: Scalar, _ m43: Scalar, _ m44: Scalar) {
self.m11 = m11 // 0
self.m12 = m12 // 1
self.m13 = m13 // 2
self.m14 = m14 // 3
self.m21 = m21 // 4
self.m22 = m22 // 5
self.m23 = m23 // 6
self.m24 = m24 // 7
self.m31 = m31 // 8
self.m32 = m32 // 9
self.m33 = m33 // 10
self.m34 = m34 // 11
self.m41 = m41 // 12
self.m42 = m42 // 13
self.m43 = m43 // 14
self.m44 = m44 // 15
}
public init(scale s: Vector3) {
self.init(
s.x, 0, 0, 0,
0, s.y, 0, 0,
0, 0, s.z, 0,
0, 0, 0, 1
)
}
public init(translation t: Vector3) {
self.init(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
t.x, t.y, t.z, 1
)
}
public init(rotation axisAngle: Vector4) {
self.init(quaternion: Quaternion(axisAngle: axisAngle))
}
public init(quaternion q: Quaternion) {
self.init(
1 - 2 * (q.y * q.y + q.z * q.z), 2 * (q.x * q.y + q.z * q.w), 2 * (q.x * q.z - q.y * q.w), 0,
2 * (q.x * q.y - q.z * q.w), 1 - 2 * (q.x * q.x + q.z * q.z), 2 * (q.y * q.z + q.x * q.w), 0,
2 * (q.x * q.z + q.y * q.w), 2 * (q.y * q.z - q.x * q.w), 1 - 2 * (q.x * q.x + q.y * q.y), 0,
0, 0, 0, 1
)
}
public init(fovx: Scalar, fovy: Scalar, near: Scalar, far: Scalar) {
self.init(fovy: fovy, aspect: fovx / fovy, near: near, far: far)
}
public init(fovx: Scalar, aspect: Scalar, near: Scalar, far: Scalar) {
self.init(fovy: fovx / aspect, aspect: aspect, near: near, far: far)
}
public init(fovy: Scalar, aspect: Scalar, near: Scalar, far: Scalar) {
let dz = far - near
assert(dz > 0, "far value must be greater than near")
assert(fovy > 0, "field of view must be nonzero and positive")
assert(aspect > 0, "aspect ratio must be nonzero and positive")
let r = fovy / 2
let cotangent = cos(r) / sin(r)
self.init(
cotangent / aspect, 0, 0, 0,
0, cotangent, 0, 0,
0, 0, -(far + near) / dz, -1,
0, 0, -2 * near * far / dz, 0
)
}
public init(top: Scalar, right: Scalar, bottom: Scalar, left: Scalar, near: Scalar, far: Scalar) {
let dx = right - left
let dy = top - bottom
let dz = far - near
self.init(
2 / dx, 0, 0, 0,
0, 2 / dy, 0, 0,
0, 0, -2 / dz, 0,
-(right + left) / dx, -(top + bottom) / dy, -(far + near) / dz, 1
)
}
public init(_ m: [Scalar]) {
assert(m.count == 16, "array must contain 16 elements, contained \(m.count)")
m11 = m[0]
m12 = m[1]
m13 = m[2]
m14 = m[3]
m21 = m[4]
m22 = m[5]
m23 = m[6]
m24 = m[7]
m31 = m[8]
m32 = m[9]
m33 = m[10]
m34 = m[11]
m41 = m[12]
m42 = m[13]
m43 = m[14]
m44 = m[15]
}
public func toArray() -> [Scalar] {
return [m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44]
}
public var adjugate: Matrix4 {
var m = Matrix4.identity
m.m11 = m22 * m33 * m44 - m22 * m34 * m43
m.m11 += -m32 * m23 * m44 + m32 * m24 * m43
m.m11 += m42 * m23 * m34 - m42 * m24 * m33
m.m21 = -m21 * m33 * m44 + m21 * m34 * m43
m.m21 += m31 * m23 * m44 - m31 * m24 * m43
m.m21 += -m41 * m23 * m34 + m41 * m24 * m33
m.m31 = m21 * m32 * m44 - m21 * m34 * m42
m.m31 += -m31 * m22 * m44 + m31 * m24 * m42
m.m31 += m41 * m22 * m34 - m41 * m24 * m32
m.m41 = -m21 * m32 * m43 + m21 * m33 * m42
m.m41 += m31 * m22 * m43 - m31 * m23 * m42
m.m41 += -m41 * m22 * m33 + m41 * m23 * m32
m.m12 = -m12 * m33 * m44 + m12 * m34 * m43
m.m12 += m32 * m13 * m44 - m32 * m14 * m43
m.m12 += -m42 * m13 * m34 + m42 * m14 * m33
m.m22 = m11 * m33 * m44 - m11 * m34 * m43
m.m22 += -m31 * m13 * m44 + m31 * m14 * m43
m.m22 += m41 * m13 * m34 - m41 * m14 * m33
m.m32 = -m11 * m32 * m44 + m11 * m34 * m42
m.m32 += m31 * m12 * m44 - m31 * m14 * m42
m.m32 += -m41 * m12 * m34 + m41 * m14 * m32
m.m42 = m11 * m32 * m43 - m11 * m33 * m42
m.m42 += -m31 * m12 * m43 + m31 * m13 * m42
m.m42 += m41 * m12 * m33 - m41 * m13 * m32
m.m13 = m12 * m23 * m44 - m12 * m24 * m43
m.m13 += -m22 * m13 * m44 + m22 * m14 * m43
m.m13 += m42 * m13 * m24 - m42 * m14 * m23
m.m23 = -m11 * m23 * m44 + m11 * m24 * m43
m.m23 += m21 * m13 * m44 - m21 * m14 * m43
m.m23 += -m41 * m13 * m24 + m41 * m14 * m23
m.m33 = m11 * m22 * m44 - m11 * m24 * m42
m.m33 += -m21 * m12 * m44 + m21 * m14 * m42
m.m33 += m41 * m12 * m24 - m41 * m14 * m22
m.m43 = -m11 * m22 * m43 + m11 * m23 * m42
m.m43 += m21 * m12 * m43 - m21 * m13 * m42
m.m43 += -m41 * m12 * m23 + m41 * m13 * m22
m.m14 = -m12 * m23 * m34 + m12 * m24 * m33
m.m14 += m22 * m13 * m34 - m22 * m14 * m33
m.m14 += -m32 * m13 * m24 + m32 * m14 * m23
m.m24 = m11 * m23 * m34 - m11 * m24 * m33
m.m24 += -m21 * m13 * m34 + m21 * m14 * m33
m.m24 += m31 * m13 * m24 - m31 * m14 * m23
m.m34 = -m11 * m22 * m34 + m11 * m24 * m32
m.m34 += m21 * m12 * m34 - m21 * m14 * m32
m.m34 += -m31 * m12 * m24 + m31 * m14 * m22
m.m44 = m11 * m22 * m33 - m11 * m23 * m32
m.m44 += -m21 * m12 * m33 + m21 * m13 * m32
m.m44 += m31 * m12 * m23 - m31 * m13 * m22
return m
}
private func determinant(forAdjugate m: Matrix4) -> Scalar {
return m11 * m.m11 + m12 * m.m21 + m13 * m.m31 + m14 * m.m41
}
public var determinant: Scalar {
return determinant(forAdjugate: adjugate)
}
public var transpose: Matrix4 {
return Matrix4(
m11, m21, m31, m41,
m12, m22, m32, m42,
m13, m23, m33, m43,
m14, m24, m34, m44
)
}
public var inverse: Matrix4 {
let adjugate = self.adjugate // avoid recalculating
return adjugate * (1 / determinant(forAdjugate: adjugate))
}
public static prefix func -(m: Matrix4) -> Matrix4 {
return m.inverse
}
public static func *(lhs: Matrix4, rhs: Matrix4) -> Matrix4 {
var m = Matrix4.identity
m.m11 = lhs.m11 * rhs.m11 + lhs.m21 * rhs.m12
m.m11 += lhs.m31 * rhs.m13 + lhs.m41 * rhs.m14
m.m12 = lhs.m12 * rhs.m11 + lhs.m22 * rhs.m12
m.m12 += lhs.m32 * rhs.m13 + lhs.m42 * rhs.m14
m.m13 = lhs.m13 * rhs.m11 + lhs.m23 * rhs.m12
m.m13 += lhs.m33 * rhs.m13 + lhs.m43 * rhs.m14
m.m14 = lhs.m14 * rhs.m11 + lhs.m24 * rhs.m12
m.m14 += lhs.m34 * rhs.m13 + lhs.m44 * rhs.m14
m.m21 = lhs.m11 * rhs.m21 + lhs.m21 * rhs.m22
m.m21 += lhs.m31 * rhs.m23 + lhs.m41 * rhs.m24
m.m22 = lhs.m12 * rhs.m21 + lhs.m22 * rhs.m22
m.m22 += lhs.m32 * rhs.m23 + lhs.m42 * rhs.m24
m.m23 = lhs.m13 * rhs.m21 + lhs.m23 * rhs.m22
m.m23 += lhs.m33 * rhs.m23 + lhs.m43 * rhs.m24
m.m24 = lhs.m14 * rhs.m21 + lhs.m24 * rhs.m22
m.m24 += lhs.m34 * rhs.m23 + lhs.m44 * rhs.m24
m.m31 = lhs.m11 * rhs.m31 + lhs.m21 * rhs.m32
m.m31 += lhs.m31 * rhs.m33 + lhs.m41 * rhs.m34
m.m32 = lhs.m12 * rhs.m31 + lhs.m22 * rhs.m32
m.m32 += lhs.m32 * rhs.m33 + lhs.m42 * rhs.m34
m.m33 = lhs.m13 * rhs.m31 + lhs.m23 * rhs.m32
m.m33 += lhs.m33 * rhs.m33 + lhs.m43 * rhs.m34
m.m34 = lhs.m14 * rhs.m31 + lhs.m24 * rhs.m32
m.m34 += lhs.m34 * rhs.m33 + lhs.m44 * rhs.m34
m.m41 = lhs.m11 * rhs.m41 + lhs.m21 * rhs.m42
m.m41 += lhs.m31 * rhs.m43 + lhs.m41 * rhs.m44
m.m42 = lhs.m12 * rhs.m41 + lhs.m22 * rhs.m42
m.m42 += lhs.m32 * rhs.m43 + lhs.m42 * rhs.m44
m.m43 = lhs.m13 * rhs.m41 + lhs.m23 * rhs.m42
m.m43 += lhs.m33 * rhs.m43 + lhs.m43 * rhs.m44
m.m44 = lhs.m14 * rhs.m41 + lhs.m24 * rhs.m42
m.m44 += lhs.m34 * rhs.m43 + lhs.m44 * rhs.m44
return m
}
public static func *(lhs: Matrix4, rhs: Vector3) -> Vector3 {
return rhs * lhs
}
public static func *(lhs: Matrix4, rhs: Vector4) -> Vector4 {
return rhs * lhs
}
public static func *(lhs: Matrix4, rhs: Scalar) -> Matrix4 {
return Matrix4(
lhs.m11 * rhs, lhs.m12 * rhs, lhs.m13 * rhs, lhs.m14 * rhs,
lhs.m21 * rhs, lhs.m22 * rhs, lhs.m23 * rhs, lhs.m24 * rhs,
lhs.m31 * rhs, lhs.m32 * rhs, lhs.m33 * rhs, lhs.m34 * rhs,
lhs.m41 * rhs, lhs.m42 * rhs, lhs.m43 * rhs, lhs.m44 * rhs
)
}
public static func ==(lhs: Matrix4, rhs: Matrix4) -> Bool {
if lhs.m11 != rhs.m11 { return false }
if lhs.m12 != rhs.m12 { return false }
if lhs.m13 != rhs.m13 { return false }
if lhs.m14 != rhs.m14 { return false }
if lhs.m21 != rhs.m21 { return false }
if lhs.m22 != rhs.m22 { return false }
if lhs.m23 != rhs.m23 { return false }
if lhs.m24 != rhs.m24 { return false }
if lhs.m31 != rhs.m31 { return false }
if lhs.m32 != rhs.m32 { return false }
if lhs.m33 != rhs.m33 { return false }
if lhs.m34 != rhs.m34 { return false }
if lhs.m41 != rhs.m41 { return false }
if lhs.m42 != rhs.m42 { return false }
if lhs.m43 != rhs.m43 { return false }
if lhs.m44 != rhs.m44 { return false }
return true
}
public static func ~=(lhs: Matrix4, rhs: Matrix4) -> Bool {
if !(lhs.m11 ~= rhs.m11) { return false }
if !(lhs.m12 ~= rhs.m12) { return false }
if !(lhs.m13 ~= rhs.m13) { return false }
if !(lhs.m14 ~= rhs.m14) { return false }
if !(lhs.m21 ~= rhs.m21) { return false }
if !(lhs.m22 ~= rhs.m22) { return false }
if !(lhs.m23 ~= rhs.m23) { return false }
if !(lhs.m24 ~= rhs.m24) { return false }
if !(lhs.m31 ~= rhs.m31) { return false }
if !(lhs.m32 ~= rhs.m32) { return false }
if !(lhs.m33 ~= rhs.m33) { return false }
if !(lhs.m34 ~= rhs.m34) { return false }
if !(lhs.m41 ~= rhs.m41) { return false }
if !(lhs.m42 ~= rhs.m42) { return false }
if !(lhs.m43 ~= rhs.m43) { return false }
if !(lhs.m44 ~= rhs.m44) { return false }
return true
}
}
//MARK: Quaternion
extension Quaternion: Equatable, Hashable {
public static let zero = Quaternion(0, 0, 0, 0)
public static let identity = Quaternion(0, 0, 0, 1)
public var hashValue: Int {
return x.hashValue &+ y.hashValue &+ z.hashValue &+ w.hashValue
}
public var lengthSquared: Scalar {
return x * x + y * y + z * z + w * w
}
public var length: Scalar {
return sqrt(lengthSquared)
}
public var inverse: Quaternion {
return -self
}
public var xyz: Vector3 {
get {
return Vector3(x, y, z)
}
set (v) {
x = v.x
y = v.y
z = v.z
}
}
public var pitch: Scalar {
return atan2(2 * (y * z + w * x), w * w - x * x - y * y + z * z)
}
public var yaw: Scalar {
return asin(-2 * (x * z - w * y))
}
public var roll: Scalar {
return atan2(2 * (x * y + w * z), w * w + x * x - y * y - z * z)
}
public init(_ x: Scalar, _ y: Scalar, _ z: Scalar, _ w: Scalar) {
self.init(x: x, y: y, z: z, w: w)
}
public init(axisAngle: Vector4) {
let r = axisAngle.w * 0.5
let scale = sin(r)
let a = axisAngle.xyz * scale
self.init(a.x, a.y, a.z, cos(r))
}
public init(pitch: Scalar, yaw: Scalar, roll: Scalar) {
let quatPitch = Quaternion(axisAngle: Vector4(1, 0, 0, pitch))
let quatYaw = Quaternion(axisAngle: Vector4(0, 1, 0, yaw))
let quatRoll = Quaternion(axisAngle: Vector4(0, 0, 1, roll))
self = quatPitch * quatYaw * quatRoll
}
public init(rotationMatrix m: Matrix4) {
let diagonal = m.m11 + m.m22 + m.m33 + 1
if diagonal ~= 0 {
let scale = sqrt(diagonal) * 2
self.init(
(m.m32 - m.m23) / scale,
(m.m13 - m.m31) / scale,
(m.m21 - m.m12) / scale,
0.25 * scale
)
} else if m.m11 > max(m.m22, m.m33) {
let scale = sqrt(1 + m.m11 - m.m22 - m.m33) * 2
self.init(
0.25 * scale,
(m.m21 + m.m12) / scale,
(m.m13 + m.m31) / scale,
(m.m32 - m.m23) / scale
)
} else if m.m22 > m.m33 {
let scale = sqrt(1 + m.m22 - m.m11 - m.m33) * 2
self.init(
(m.m21 + m.m12) / scale,
0.25 * scale,
(m.m32 + m.m23) / scale,
(m.m13 - m.m31) / scale
)
} else {
let scale = sqrt(1 + m.m33 - m.m11 - m.m22) * 2
self.init(
(m.m13 + m.m31) / scale,
(m.m32 + m.m23) / scale,
0.25 * scale,
(m.m21 - m.m12) / scale
)
}
}
public init(_ v: [Scalar]) {
assert(v.count == 4, "array must contain 4 elements, contained \(v.count)")
x = v[0]
y = v[1]
z = v[2]
w = v[3]
}
public func toAxisAngle() -> Vector4 {
let scale = xyz.length
if scale ~= 0 || scale ~= .twoPi {
return .z
} else {
return Vector4(x / scale, y / scale, z / scale, acos(w) * 2)
}
}
public func toPitchYawRoll() -> (pitch: Scalar, yaw: Scalar, roll: Scalar) {
return (pitch, yaw, roll)
}
public func toArray() -> [Scalar] {
return [x, y, z, w]
}
public func dot(_ v: Quaternion) -> Scalar {
return x * v.x + y * v.y + z * v.z + w * v.w
}
public func normalized() -> Quaternion {
let lengthSquared = self.lengthSquared
if lengthSquared ~= 0 || lengthSquared ~= 1 {
return self
}
return self / sqrt(lengthSquared)
}
public func interpolated(with q: Quaternion, by t: Scalar) -> Quaternion {
let dot = max(-1, min(1, self.dot(q)))
if dot ~= 1 {
return (self + (q - self) * t).normalized()
}
let theta = acos(dot) * t
let t1 = self * cos(theta)
let t2 = (q - (self * dot)).normalized() * sin(theta)
return t1 + t2
}
public static prefix func -(q: Quaternion) -> Quaternion {
return Quaternion(-q.x, -q.y, -q.z, q.w)
}
public static func +(lhs: Quaternion, rhs: Quaternion) -> Quaternion {
return Quaternion(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w)
}
public static func -(lhs: Quaternion, rhs: Quaternion) -> Quaternion {
return Quaternion(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w)
}
public static func *(lhs: Quaternion, rhs: Quaternion) -> Quaternion {
return Quaternion(
lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y,
lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z,
lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x,
lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z
)
}
public static func *(lhs: Quaternion, rhs: Vector3) -> Vector3 {
return rhs * lhs
}
public static func *(lhs: Quaternion, rhs: Scalar) -> Quaternion {
return Quaternion(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs)
}
public static func /(lhs: Quaternion, rhs: Scalar) -> Quaternion {
return Quaternion(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs)
}
public static func ==(lhs: Quaternion, rhs: Quaternion) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w
}
public static func ~=(lhs: Quaternion, rhs: Quaternion) -> Bool {
return lhs.x ~= rhs.x && lhs.y ~= rhs.y && lhs.z ~= rhs.z && lhs.w ~= rhs.w
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment