Last active
January 25, 2021 16:58
-
-
Save gabrieloc/09da43092e63c7f129be716df3d50ef0 to your computer and use it in GitHub Desktop.
Coerce core graphics types into generic vectors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
protocol Vector { | |
associatedtype Primitive: FloatingPoint | |
var components: [Primitive] { get } | |
init(components: [Primitive]) | |
} | |
extension CGPoint: Vector { | |
var components: [CGFloat] { [x, y] } | |
init(components: [CGFloat]) { | |
self.init( | |
x: components[safe: 0] ?? 0, | |
y: components[safe: 1] ?? 0 | |
) | |
} | |
} | |
extension CGSize: Vector { | |
var components: [CGFloat] { [width, height] } | |
init(components: [CGFloat]) { | |
self.init( | |
width: components[safe: 0] ?? 0, | |
height: components[safe: 1] ?? 0 | |
) | |
} | |
} | |
extension CGRect: Vector { | |
var components: [CGFloat] { [minX, minY, width, height] } | |
init(components: [CGFloat]) { | |
self.init( | |
x: components[safe: 0] ?? 0, | |
y: components[safe: 1] ?? 0, | |
width: components[safe: 2] ?? 0, | |
height: components[safe: 3] ?? 0 | |
) | |
} | |
} | |
extension Vector { | |
static func * <V: Vector>(lhs: Self, rhs: V) -> Self where V.Primitive == Self.Primitive { | |
Self(components: lhs.components * rhs.components) | |
} | |
static var length: Int { | |
Self(components: []).components.count | |
} | |
static var one: Self { | |
Self(components: .init(repeating: 1, count: length)) | |
} | |
} | |
extension Array where Element: Numeric { | |
static func * (lhs: Self, rhs: Self) -> Self { | |
let size = Swift.max(lhs.count, rhs.count) | |
return zip(lhs.withSize(size), rhs.withSize(size)).map { $0 * $1 } | |
} | |
func withSize(_ size: Int) -> Self { | |
(0..<size).map { $0 < count ? self[$0] : 0 } | |
} | |
subscript(safe index: Index) -> Element? { | |
indices.contains(index) ? self[index] : nil | |
} | |
} | |
// Examples | |
let point = CGPoint(x: 1, y: 2) * CGSize(width: 3, height: 4) // CGPoint x: 3, y: 8 | |
let size = CGSize(width: 2, height: 2) * CGPoint.one // CGSize w: 2, h: 2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment