Skip to content

Instantly share code, notes, and snippets.

@narfdotpl
Last active December 27, 2023 22:49
Show Gist options
  • Save narfdotpl/b420d02ea8b2cc1c2c8a482a8a47a7d4 to your computer and use it in GitHub Desktop.
Save narfdotpl/b420d02ea8b2cc1c2c8a482a8a47a7d4 to your computer and use it in GitHub Desktop.
//
// Coordinates.swift
// Scrapyard
//
// Created by Maciej Konieczny aka narf
// https://vis.social/@narf/111654813643291716
//
import Foundation
// the protocol is not required
// but I'm using it for documentation purposes and as a "namespace"
protocol CoordinateSystemType {}
enum YDown: CoordinateSystemType {}
enum YUp: CoordinateSystemType {}
enum YUpRetina2x: CoordinateSystemType {}
/// This is shader’s `float2` with a phantom type
/// used by the compiler to make sure I won’t mix coordinate systems again.
///
/// The downside of this approach is that, since the original `float2` is hidden
/// inside, I have to implement proxies for all the operators (and protocols?)
/// that I find missing.
struct Point2D<CoordinateSystem: CoordinateSystemType> {
private let value: SIMD2<Float>
var x: Float { value.x }
var y: Float { value.y }
init(_ x: Float, _ y: Float) {
self.init(value: .init(x, y))
}
init(x: Float, y: Float) {
self.init(value: .init(x, y))
}
fileprivate init(value: SIMD2<Float>) {
self.value = value
}
static var zero: Self { .init(value: .zero) }
// TODO: could this be done with a macro?
static func == (a: Self, b: Self) -> Bool { a.value == b.value }
static func != (a: Self, b: Self) -> Bool { a.value != b.value }
static func + (a: Self, b: Self) -> Self { .init(value: a.value + b.value) }
static func - (a: Self, b: Self) -> Self { .init(value: a.value - b.value) }
static func * (a: Self, b: Self) -> Self { .init(value: a.value * b.value) }
static func / (a: Self, b: Self) -> Self { .init(value: a.value / b.value) }
}
extension Point2D: CustomDebugStringConvertible {
var debugDescription: String {
.init(format: "(%.2f, %.2f)", x, y)
}
}
let p1 = Point2D<YUp>(1, 2)
let p2 = Point2D<YUp>(2, 3)
let p3 = p1 + p2 // (3, 5)
let p4 = Point2D<YDown>(3, 1920)
let p5 = p3 + p4 // compile time error: Cannot convert value of type 'Point2D<YDown>' to expected argument type 'Point2D<YUp>'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment