Skip to content

Instantly share code, notes, and snippets.

@erynofwales
Created November 2, 2015 02:36
Show Gist options
  • Save erynofwales/9e132cfaaacd9f2c5ffe to your computer and use it in GitHub Desktop.
Save erynofwales/9e132cfaaacd9f2c5ffe to your computer and use it in GitHub Desktop.
Structs with subscript() setter don't actually set
//
// Matrices.swift
// Game
//
// Created by Eryn Wells on 2015-10-24.
// Copyright © 2015 Eryn Wells. All rights reserved.
//
/** A square matrix. */
public protocol Matrix {
/** The identity matrix. */
static var identity: Self { get }
/** Number of elements in the underlying container. */
static var count: Int { get }
/**
* Number of elements in a single row or column of the matrix. Since
* matrices are always square, this applies to row and column.
*/
static var dimension: Int { get }
/** Initialize a Matrix filled with zeroes. */
init()
/**
* Initialize a Matrix with a given array of values. The number of values
* must match the count of the array; otherwise, a MatrixError.InvalidSize
* error is thrown.
*/
init(values: [Float]) throws
/** The underlying data array. */
var data: [Float] { get }
/**
* Element access
* @{
*/
subscript(idx: Int) -> Float { get set }
subscript(row: Int, col: Int) -> Float { get set }
/** @} */
}
extension Matrix {
public static var count: Int {
return dimension * dimension
}
}
public enum MatrixError: ErrorType {
case InvalidSize(given: Int, expected: Int)
}
// MARK: - Matrices
public struct Matrix4: Matrix {
public static var identity: Matrix4 = {
var matrix = Matrix4()
for i in 0..<Matrix4.dimension {
matrix[i,i] = 1.0
}
return matrix
}()
public private(set) var data: [Float]
public init() {
data = [Float](count: Matrix4.count, repeatedValue: Float(0))
}
public init(values: [Float]) throws {
guard values.count == Matrix4.count else {
throw MatrixError.InvalidSize(given: values.count, expected: Matrix4.count)
}
data = values
}
init(translationWithX x: Float, y: Float, z: Float) {
// NOTE: Call will never fail.
try! self.init(values: [1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1])
}
init(scaleWithX x: Float, y: Float, z: Float) {
// NOTE: Call will never fail.
try! self.init(values: [x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1])
}
init(rotationAboutX x: Float) {
let c = cos(x)
let s = sin(x)
try! self.init(values: [1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1])
}
init(rotationAboutY y: Float) {
let c = cos(y)
let s = sin(y)
try! self.init(values: [c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1])
}
init(rotationAboutZ z: Float) {
let c = cos(z)
let s = sin(z)
try! self.init(values: [ c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1])
}
init(rotationAboutX x: Float, y: Float, z: Float) {
let r = Matrix4(rotationAboutX: x) * Matrix4(rotationAboutY: y) * Matrix4(rotationAboutZ: z)
try! self.init(values: r.data)
}
public static var dimension: Int {
return 4
}
public subscript(idx: Int) -> Float {
get {
print("Matrix4.subscript(\(idx)) -> \(data[idx])")
return data[idx]
}
mutating set(value) {
data[idx] = value
print("Matrix4.subscript(\(idx)) = \(value) -> \(data[idx])")
}
}
public subscript(row: Int, col: Int) -> Float {
get {
return data[indexFromCoordinates(row, col)]
}
mutating set(value) {
data[indexFromCoordinates(row, col)] = value
}
}
/** Convert a (row, col) pair into an index into the data array. */
private func indexFromCoordinates(row: Int, _ col: Int) -> Int {
return row * Matrix4.dimension + col
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment