Initial Commit

This commit is contained in:
Signal 2026-06-22 16:13:41 -04:00
commit 08da5c70e1
7 changed files with 984 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

24
Package.swift Normal file
View file

@ -0,0 +1,24 @@
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ArtifactMath",
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "ArtifactMath",
targets: ["ArtifactMath"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "ArtifactMath"),
.testTarget(
name: "ArtifactMathTests",
dependencies: ["ArtifactMath"]
),
]
)

View file

@ -0,0 +1,205 @@
import Foundation
// 4x4 Matrix (column-major, common in graphics)
public struct Mat4<Component: BinaryFloatingPoint> {
// 16 elements in column-major order: m[0] = m00, m[4] = m10, etc.
private var m: [Component] = Array(repeating: 0, count: 16)
public var bytes: [UInt8] {
m.withUnsafeBytes { Array($0) }
}
// Subscript for easy access: mat[col][row]
public subscript(col: Int, row: Int) -> Component {
get {
assert(col >= 0 && col < 4 && row >= 0 && row < 4, "Index out of bounds")
return m[col * 4 + row]
}
set {
assert(col >= 0 && col < 4 && row >= 0 && row < 4, "Index out of bounds")
m[col * 4 + row] = newValue
}
}
public init() {}
// Identity matrix
public static func identity() -> Mat4 {
var mat = Mat4()
mat[0, 0] = 1
mat[1, 1] = 1
mat[2, 2] = 1
mat[3, 3] = 1
return mat
}
// Initialize from raw 16 values (column-major)
public init(_ values: [Component]) {
assert(values.count == 16, "Mat4 requires exactly 16 values")
self.m = values
}
// Convenience init from 2D array (row-major input for readability)
public init(rows: [[Component]]) {
assert(rows.count == 4 && rows.allSatisfy { $0.count == 4 }, "Must provide 4x4 rows")
for row in 0..<4 {
for col in 0..<4 {
self[col, row] = rows[row][col]
}
}
}
// Matrix multiplication: self * other
public static func * (lhs: Mat4<Component>, rhs: Mat4) -> Mat4 {
var result = Mat4()
for i in 0..<4 { // column of result
for j in 0..<4 { // row of result
var sum: Component = 0
for k in 0..<4 {
sum += lhs[k, j] * rhs[i, k] // Note: column-major access
}
result[i, j] = sum
}
}
return result
}
// Matrix * Vector4
public static func * (mat: Mat4, vec: Vec4<Component>) -> Vec4<Component> {
let x = mat[0,0]*vec.x + mat[1,0]*vec.y + mat[2,0]*vec.z + mat[3,0]*vec.w
let y = mat[0,1]*vec.x + mat[1,1]*vec.y + mat[2,1]*vec.z + mat[3,1]*vec.w
let z = mat[0,2]*vec.x + mat[1,2]*vec.y + mat[2,2]*vec.z + mat[3,2]*vec.w
let w = mat[0,3]*vec.x + mat[1,3]*vec.y + mat[2,3]*vec.z + mat[3,3]*vec.w
return Vec4(x: x, y: y, z: z, w: w)
}
// Matrix * Vector3 (treats as point, w=1)
public static func * (mat: Mat4<Component>, vec: Vec3<Component>) -> Vec3<Component> {
let v4 = mat * Vec4(x: vec.x, y: vec.y, z: vec.z, w: 1)
return Vec3(x: v4.x / v4.w, y: v4.y / v4.w, z: v4.z / v4.w)
}
// MARK: - Transformations (return new matrices)
public static func translation(_ t: Vec3<Component>) -> Mat4 {
var mat = Mat4.identity()
mat[3, 0] = t.x
mat[3, 1] = t.y
mat[3, 2] = t.z
return mat
}
public static func scale(_ s: Vec3<Component>) -> Mat4 {
var mat = Mat4.identity()
mat[0, 0] = s.x
mat[1, 1] = s.y
mat[2, 2] = s.z
return mat
}
public static func rotationX(angleRadians: Float) -> Mat4 {
let c = Component(cos(angleRadians))
let s = Component(sin(angleRadians))
var mat = Mat4.identity()
mat[1, 1] = c
mat[2, 1] = -s
mat[1, 2] = s
mat[2, 2] = c
return mat
}
public static func rotationY(angleRadians: Float) -> Mat4 {
let c = Component(cos(angleRadians))
let s = Component(sin(angleRadians))
var mat = Mat4.identity()
mat[0, 0] = c
mat[2, 0] = s
mat[0, 2] = -s
mat[2, 2] = c
return mat
}
public static func rotationZ(angleRadians: Float) -> Mat4 {
let c = Component(cos(angleRadians))
let s = Component(sin(angleRadians))
var mat = Mat4.identity()
mat[0, 0] = c
mat[1, 0] = -s
mat[0, 1] = s
mat[1, 1] = c
return mat
}
// Combined rotation (Euler angles in XYZ order)
public static func rotation(x: Float, y: Float, z: Float) -> Mat4 {
return rotationX(angleRadians: x) * rotationY(angleRadians: y) * rotationZ(angleRadians: z)
}
// Look-at matrix (common for cameras)
public static func lookAt(eye: Vec3<Component>, target: Vec3<Component>, up: Vec3<Component> = Vec3<Component>(x: 0, y: 1, z: 0)) -> Mat4<Component> {
let zAxis = (eye - target).normalized() // Note: direction from eye to target is usually negative, but convention varies
let xAxis = Vec3.cross(up, zAxis).normalized()
let yAxis = Vec3.cross(zAxis, xAxis)
var mat = Mat4.identity()
mat[0, 0] = xAxis.x; mat[1, 0] = xAxis.y; mat[2, 0] = xAxis.z
mat[0, 1] = yAxis.x; mat[1, 1] = yAxis.y; mat[2, 1] = yAxis.z
mat[0, 2] = zAxis.x; mat[1, 2] = zAxis.y; mat[2, 2] = zAxis.z
mat[3, 0] = -Vec3.dot(xAxis, eye)
mat[3, 1] = -Vec3.dot(yAxis, eye)
mat[3, 2] = -Vec3.dot(zAxis, eye)
return mat
}
// Perspective projection
public static func perspective(fovRadians: Component, aspect: Component, near: Component, far: Component) -> Mat4 {
let f = 1.0 / tan(Double(fovRadians) / 2.0)
var mat = Mat4()
mat[0, 0] = Component(f) / aspect
mat[1, 1] = Component(f)
mat[2, 2] = (far + near) / (near - far)
mat[3, 2] = (2 * far * near) / (near - far)
mat[2, 3] = -1.0
// Others remain 0
return mat
}
public static func ortho(left: Component, right: Component, bottom: Component, top: Component, near: Component, far: Component) -> Mat4 {
var mat = Mat4()
let rl = right - left
let tb = top - bottom
let fn = far - near
mat[0, 0] = 2 / rl
mat[1, 1] = 2 / tb
mat[2, 2] = -2 / fn
mat[3, 0] = -(right + left) / rl
mat[3, 1] = -(top + bottom) / tb
mat[3, 2] = -(far + near) / fn
mat[3, 3] = 1.0
return mat
}
/// Convenient version using width/height + center
public static func ortho(width: Component, height: Component, near: Component, far: Component, centerX: Component = 0, centerY: Component = 0) -> Mat4 {
let left = centerX - width / 2
let right = centerX + width / 2
let bottom = centerY - height / 2
let top = centerY + height / 2
return ortho(left: left, right: right, bottom: bottom, top: top, near: near, far: far)
}
/// Common 2D ortho (z-range -1..1, origin at center)
public static func ortho2D(width: Component, height: Component) -> Mat4 {
ortho(width: width, height: height, near: -1, far: 1)
}
}
public typealias Mat4f = Mat4<Float>
public typealias Mat4d = Mat4<Double>

View file

@ -0,0 +1,7 @@
postfix operator %
public postfix func %<T: BinaryFloatingPoint> (_ number: T) -> T {
number / 100
}

View file

@ -0,0 +1,94 @@
import Foundation
public struct Rect<Component: Numeric & Hashable & Comparable> {
public var origin: Vec2<Component>
public var size: Vec2<Component>
public var left: Component {
origin.x
}
public var right: Component {
origin.x + size.x
}
public var top: Component {
origin.y
}
public var bottom: Component {
origin.y + size.y
}
public var width: Component {
size.x
}
public var height: Component {
size.y
}
public init() {
origin = .zero
size = .zero
}
public init(origin: Vec2<Component>, size: Vec2<Component>) {
self.origin = origin
self.size = size
}
public init(x: Component, y: Component, width: Component, height: Component) {
origin = Vec2(x, y)
size = Vec2(width, height)
}
public init(left: Component, top: Component, right: Component, bottom: Component) {
origin = [left, top]
size = [right - left, bottom - top]
}
public func contains(_ point: Vec2<Component>) -> Bool {
left < point.x && point.x < right && top < point.y && point.y < bottom
}
public func inset(by offset: Component) -> Self {
return Self(origin: Vec2<Component>(origin.x + offset, origin.y + offset), size: Vec2(size.x - offset * 2, size.y - offset * 2))
}
public func offset(by offset: Vec2<Component>) -> Self {
return Self(origin: origin + offset, size: size)
}
public func clamped(_ lower: Vec2<Component>, _ upper: Vec2<Component>) -> Self {
// let origin: Vec2 = [max(origin.x, lower.x), max(origin.y, lower.y)]
// return Self(origin: origin, size: [min(upper.x, right) - origin.x, min(upper.y, bottom) - origin.y])
Self(left: min(max(left, lower.x), upper.x), top: min(max(top, lower.y), upper.y), right: min(max(right, lower.x), upper.x), bottom: min(max(bottom, lower.y), upper.y))
}
}
extension Rect where Component: BinaryFloatingPoint {
public init<T: BinaryFloatingPoint>(_ other: Rect<T>) {
origin = Vec2(other.origin)
size = Vec2(other.size)
}
public init<T: BinaryInteger>(_ other: Rect<T>) {
origin = Vec2(other.origin)
size = Vec2(other.size)
}
}
extension Rect where Component: BinaryInteger {
public init<T: BinaryFloatingPoint>(_ other: Rect<T>) {
origin = Vec2(other.origin)
size = Vec2(other.size)
}
public init<T: BinaryInteger>(_ other: Rect<T>) {
origin = Vec2(other.origin)
size = Vec2(other.size)
}
}

View file

@ -0,0 +1,632 @@
import Foundation
public struct Vec2<Component: Numeric & Hashable>: Hashable, ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Component
public typealias Tuple = (x: Component, y: Component)
public static var zero: Self { Self() }
public var x: Component
public var y: Component
public var tuple: (x: Component, y: Component) {
(x, y)
}
public var bytes: [UInt8] {
var out: [UInt8] = []
writeBytes(into: &out)
return out
}
public init() {
x = 0
y = 0
}
public init(_ x: Component, _ y: Component) {
self.x = x
self.y = y
}
public init(x: Component, y: Component) {
self.x = x
self.y = y
}
public init(arrayLiteral elements: Component...) {
x = elements[0]
y = elements[1]
}
public func applying(_ transform: (Component) -> Component) -> Self {
Self(transform(x), transform(y))
}
public mutating func apply(_ transform: (Component) -> Component) {
x = transform(x)
y = transform(y)
}
public func writeBytes(into list: inout [UInt8]) {
withUnsafeBytes(of: x, { list.append(contentsOf: $0) })
withUnsafeBytes(of: y, { list.append(contentsOf: $0) })
}
public static func dot(_ left: Self, _ right: Self) -> Component {
left.x * right.x + left.y * right.y
}
public static func ==(_ left: Self, _ right: Self) -> Bool {
left.x == right.x && left.y == right.y
}
public static func +(_ left: Self, _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y)
}
public static func +(_ left: Self, _ right: (x: Component, y: Component)) -> Self {
Self(left.x + right.x, left.y + right.y)
}
public static func +(_ left: (x: Component, y: Component), _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y)
}
public static func +=(_ left: inout Self, _ right: Self) {
left.x += right.x
left.y += right.y
}
public static func +=(_ left: inout Self, _ right: (x: Component, y: Component)) {
left.x += right.x
left.y += right.y
}
public static func -(_ left: Self, _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y)
}
public static func -(_ left: Self, _ right: (x: Component, y: Component)) -> Self {
Self(left.x - right.x, left.y - right.y)
}
public static func -(_ left: (x: Component, y: Component), _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y)
}
public static func -=(_ left: inout Self, _ right: Self) {
left.x -= right.x
left.y -= right.y
}
public static func -=(_ left: inout Self, _ right: Tuple) {
left.x -= right.x
left.y -= right.y
}
public static func *(_ left: Self, _ right: Self) -> Self {
Self(left.x * right.x, left.y * right.y)
}
public static func *(_ left: Self, _ right: Component) -> Self {
Self(left.x * right, left.y * right)
}
public static func *=(_ left: inout Self, _ right: Component) {
left.x *= right
left.y *= right
}
}
extension Vec2 where Component: BinaryFloatingPoint {
public var length: Component {
sqrt(x * x + y * y)
}
public var lengthSquared: Component {
x * x + y * y
}
public init<T: BinaryFloatingPoint>(_ other: Vec2<T>) {
x = Component(other.x)
y = Component(other.y)
}
public init<T: BinaryInteger>(_ other: Vec2<T>) {
x = Component(other.x)
y = Component(other.y)
}
public init(_ x: any BinaryFloatingPoint, _ y: any BinaryFloatingPoint) {
self.x = Component(x)
self.y = Component(y)
}
public init(_ x: any BinaryInteger, _ y: any BinaryInteger) {
self.x = Component(x)
self.y = Component(y)
}
public func normalized() -> Self {
self / length
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
}
}
extension Vec2 where Component: BinaryInteger {
public var length: Double {
Double(x * x + y * y).squareRoot()
}
public var lengthSquared: Component {
x * x + y * y
}
public init<T: BinaryFloatingPoint>(_ other: Vec2<T>) {
x = Component(other.x)
y = Component(other.y)
}
public init<T: BinaryInteger>(_ other: Vec2<T>) {
x = Component(other.x)
y = Component(other.y)
}
public init(_ x: any BinaryFloatingPoint, _ y: any BinaryFloatingPoint) {
self.x = Component(x)
self.y = Component(y)
}
public init(_ x: any BinaryInteger, _ y: any BinaryInteger) {
self.x = Component(x)
self.y = Component(y)
}
public func normalized() -> Self {
self / Component(length)
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
}
}
extension Vec2: Codable where Component: Codable {}
public typealias Vec2i = Vec2<Int>
public typealias Vec2f = Vec2<Float>
public typealias Vec2d = Vec2<Double>
public struct Vec3<Component: Numeric & Hashable>: Hashable, ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Component
public typealias Tuple = (x: Component, y: Component, z: Component)
public static var zero: Self { Self() }
public var x: Component
public var y: Component
public var z: Component
public var tuple: (x: Component, y: Component, z: Component) {
(x, y, z)
}
public var bytes: [UInt8] {
var out: [UInt8] = []
writeBytes(into: &out)
return out
}
public init() {
x = 0
y = 0
z = 0
}
public init(_ x: Component, _ y: Component, _ z: Component) {
self.x = x
self.y = y
self.z = z
}
public init(x: Component, y: Component, z: Component) {
self.x = x
self.y = y
self.z = z
}
public init(arrayLiteral elements: Component...) {
x = elements[0]
y = elements[1]
z = elements[2]
}
public func hash(into hasher: inout Hasher) {
hasher.combine(x)
hasher.combine(y)
hasher.combine(z)
}
public func writeBytes(into list: inout [UInt8]) {
withUnsafeBytes(of: x, { list.append(contentsOf: $0) })
withUnsafeBytes(of: y, { list.append(contentsOf: $0) })
withUnsafeBytes(of: z, { list.append(contentsOf: $0) })
}
public static func dot(_ a: Self, _ b: Self) -> Component {
a.x * b.x + a.y * b.y + a.z * b.z
}
public static func cross(_ a: Vec3, _ b: Vec3) -> Self {
Self(
x: a.y * b.z - a.z * b.y,
y: a.z * b.x - a.x * b.z,
z: a.x * b.y - a.y * b.x
)
}
public static func ==(_ left: Self, _ right: Self) -> Bool {
left.x == right.x && left.y == right.y && left.z == right.z
}
public static func +(_ left: Self, _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z)
}
public static func +(_ left: Self, _ right: Tuple) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z)
}
public static func +(_ left: Tuple, _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z)
}
public static func +=(_ left: inout Self, _ right: Self) {
left.x += right.x
left.y += right.y
left.z += right.z
}
public static func +=(_ left: inout Self, _ right: Tuple) {
left.x += right.x
left.y += right.y
left.z += right.z
}
public static func -(_ left: Self, _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z)
}
public static func -(_ left: Self, _ right: Tuple) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z)
}
public static func -(_ left: Tuple, _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z)
}
public static func -=(_ left: inout Self, _ right: Self) {
left.x -= right.x
left.y -= right.y
left.z -= right.z
}
public static func -=(_ left: inout Self, _ right: Tuple) {
left.x -= right.x
left.y -= right.y
left.z -= right.z
}
public static func *(_ left: Self, _ right: Component) -> Self {
Self(left.x * right, left.y * right, left.z * right)
}
public static func *=(_ left: inout Self, _ right: Component) {
left.x *= right
left.y *= right
left.z *= right
}
}
extension Vec3 where Component: BinaryFloatingPoint {
public var length: Component {
sqrt(x * x + y * y + z * z)
}
public var lengthSquared: Component {
x * x + y * y + z * z
}
public init<T: BinaryFloatingPoint>(_ other: Vec3<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
}
public init<T: BinaryInteger>(_ other: Vec3<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
}
public func normalized() -> Self {
self / Component(length)
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right, left.z / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
left.z /= right
}
}
extension Vec3 where Component: BinaryInteger {
public var length: Double {
Double(x * x + y * y + z * z).squareRoot()
}
public var lengthSquared: Component {
x * x + y * y + z * z
}
public init<T: BinaryFloatingPoint>(_ other: Vec3<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
}
public init<T: BinaryInteger>(_ other: Vec3<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
}
public func normalized() -> Self {
self / Component(length)
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right, left.z / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
left.z /= right
}
}
extension Vec3: Codable where Component: Codable {}
public typealias Vec3i = Vec3<Int>
public typealias Vec3f = Vec3<Float>
public typealias Vec3d = Vec3<Double>
public struct Vec4<Component: Numeric & Hashable>: Hashable, ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Component
public typealias Tuple = (x: Component, y: Component, z: Component, w: Component)
public static var zero: Self { Self() }
public var x: Component
public var y: Component
public var z: Component
public var w: Component
public var tuple: (x: Component, y: Component, z: Component) {
(x, y, z)
}
public var bytes: [UInt8] {
var out: [UInt8] = []
writeBytes(into: &out)
return out
}
public init() {
x = 0
y = 0
z = 0
w = 0
}
public init(_ x: Component, _ y: Component, _ z: Component, _ w: Component) {
self.x = x
self.y = y
self.z = z
self.w = w
}
public init(x: Component, y: Component, z: Component, w: Component) {
self.x = x
self.y = y
self.z = z
self.w = w
}
public init(arrayLiteral elements: Component...) {
x = elements[0]
y = elements[1]
z = elements[2]
w = elements[3]
}
public func writeBytes(into list: inout [UInt8]) {
withUnsafeBytes(of: x, { list.append(contentsOf: $0) })
withUnsafeBytes(of: y, { list.append(contentsOf: $0) })
withUnsafeBytes(of: z, { list.append(contentsOf: $0) })
withUnsafeBytes(of: w, { list.append(contentsOf: $0) })
}
public static func dot(_ a: Self, _ b: Self) -> Component {
a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
}
public static func ==(_ left: Self, _ right: Self) -> Bool {
left.x == right.x && left.y == right.y && left.z == right.z && left.w == right.w
}
public static func +(_ left: Self, _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w)
}
public static func +(_ left: Self, _ right: Tuple) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w)
}
public static func +(_ left: Tuple, _ right: Self) -> Self {
Self(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w)
}
public static func +=(_ left: inout Self, _ right: Self) {
left.x += right.x
left.y += right.y
left.z += right.z
left.w += right.w
}
public static func +=(_ left: inout Self, _ right: Tuple) {
left.x += right.x
left.y += right.y
left.z += right.z
left.w += right.w
}
public static func -(_ left: Self, _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w)
}
public static func -(_ left: Self, _ right: Tuple) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w)
}
public static func -(_ left: Tuple, _ right: Self) -> Self {
Self(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w)
}
public static func -=(_ left: inout Self, _ right: Self) {
left.x -= right.x
left.y -= right.y
left.z -= right.z
left.w -= right.w
}
public static func -=(_ left: inout Self, _ right: Tuple) {
left.x -= right.x
left.y -= right.y
left.z -= right.z
left.w -= right.w
}
public static func *(_ left: Self, _ right: Component) -> Self {
Self(left.x * right, left.y * right, left.z * right, left.w * right)
}
public static func *=(_ left: inout Self, _ right: Component) {
left.x *= right
left.y *= right
left.z *= right
left.w *= right
}
}
extension Vec4 where Component: BinaryFloatingPoint {
public var length: Component {
sqrt(x * x + y * y + z * z)
}
public var lengthSquared: Component {
x * x + y * y + z * z
}
public init<T: BinaryFloatingPoint>(_ other: Vec4<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
w = Component(other.w)
}
public init<T: BinaryInteger>(_ other: Vec4<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
w = Component(other.w)
}
public func normalized() -> Self {
self / length
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right, left.z / right, left.w / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
left.z /= right
left.w /= right
}
}
extension Vec4 where Component: BinaryInteger {
public var length: Double {
Double(x * x + y * y + z * z).squareRoot()
}
public var lengthSquared: Component {
x * x + y * y + z * z
}
public init<T: BinaryFloatingPoint>(_ other: Vec4<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
w = Component(other.w)
}
public init<T: BinaryInteger>(_ other: Vec4<T>) {
x = Component(other.x)
y = Component(other.y)
z = Component(other.z)
w = Component(other.w)
}
public func normalized() -> Self {
self / Component(length)
}
public static func /(_ left: Self, _ right: Component) -> Self {
Self(left.x / right, left.y / right, left.z / right, left.w / right)
}
public static func /=(_ left: inout Self, _ right: Component) {
left.x /= right
left.y /= right
left.z /= right
left.w /= right
}
}
extension Vec4: Codable where Component: Codable {}
public typealias Vec4i = Vec4<Int>
public typealias Vec4f = Vec4<Float>
public typealias Vec4d = Vec4<Double>

View file

@ -0,0 +1,14 @@
import XCTest
@testable import ArtifactMath
final class ArtifactMathTests: XCTestCase {
func testExample() throws {
// XCTest Documentation
// https://developer.apple.com/documentation/xctest
// Defining Test Cases and Test Methods
// https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
let set: Set<Vec3i> = []
}
}