Skip to content

Commit

Permalink
sugar (TMP)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Dec 22, 2023
1 parent f9105ba commit 5f50396
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 55 deletions.
6 changes: 6 additions & 0 deletions Sources/Bounds.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public protocol Bounded {
var bounds: Bounds { get }
}

extension Bounds: CustomStringConvertible {
public var description: String {
"Bounds(min: [\(min.components)], max: [\(max.components)])"
}
}

extension Bounds: Codable {
private enum CodingKeys: CodingKey {
case min, max
Expand Down
12 changes: 12 additions & 0 deletions Sources/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ extension Color: RGBARepresentable {
}
}

extension Color: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Double...) {
self.init(unchecked: elements)
}
}

extension Color: CustomStringConvertible {
public var description: String {
"Color(\(r), \(g), \(b)\(a == 1 ? "" : ", \(a)"))"
}
}

extension Color: Codable {
private enum CodingKeys: String, CodingKey {
case r, g, b, a
Expand Down
39 changes: 29 additions & 10 deletions Sources/PathPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ public struct PathPoint: Hashable, Sendable {
public var isCurved: Bool
}

extension PathPoint: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Double...) {
self = .point(Vector(elements))
}
}

extension PathPoint: CustomStringConvertible {
public var description: String {
let p = "\(position.x), \(position.y)\(position.z == 0 ? "" : ", \(position.z)")"
let t = texcoord.map {
", texcoord: [\($0.x), \($0.y)\($0.z == 0 ? "" : ", \($0.z)")]"
} ?? ""
let c = color.map {
", color: [\($0.r), \($0.g), \($0.b)\($0.a == 1 ? "" : ", \($0.a)")]"
} ?? ""
return "PathPoint.\(isCurved ? "curve" : "point")(\(p)\(t)\(c))"
}
}

extension PathPoint: Codable {
/// Creates a new path point by decoding from the given decoder.
/// - Parameter decoder: The decoder to read data from.
Expand All @@ -57,28 +76,28 @@ extension PathPoint: Codable {
let y = try container.decode(Double.self)
switch container.count {
case 2:
self.init(Vector(x, y), texcoord: nil, color: nil, isCurved: false)
self = [x, y]
case 3:
let isCurved: Bool, position: Vector
do {
isCurved = try container.decodeIfPresent(Bool.self) ?? false
position = Vector(x, y)
position = [x, y]
} catch {
isCurved = false
position = try Vector(x, y, container.decode(Double.self))
position = try [x, y, container.decode(Double.self)]
}
self.init(position, texcoord: nil, color: nil, isCurved: isCurved)
case 4:
let zOrU = try container.decode(Double.self)
let isCurved: Bool, position: Vector, texcoord: Vector?
do {
isCurved = try container.decodeIfPresent(Bool.self) ?? false
position = Vector(x, y, zOrU)
position = [x, y, zOrU]
texcoord = nil
} catch {
isCurved = false
position = Vector(x, y)
texcoord = try Vector(zOrU, container.decode(Double.self))
position = [x, y]
texcoord = try [zOrU, container.decode(Double.self)]
}
self.init(position, texcoord: texcoord, color: nil, isCurved: isCurved)
case 5:
Expand All @@ -87,12 +106,12 @@ extension PathPoint: Codable {
let isCurved: Bool, position: Vector, texcoord: Vector?
do {
isCurved = try container.decodeIfPresent(Bool.self) ?? false
position = Vector(x, y)
texcoord = Vector(zOrU, uOrV)
position = [x, y]
texcoord = [zOrU, uOrV]
} catch {
isCurved = false
position = Vector(x, y, zOrU)
texcoord = try Vector(uOrV, container.decode(Double.self))
position = [x, y, zOrU]
texcoord = try [uOrV, container.decode(Double.self)]
}
self.init(position, texcoord: texcoord, color: nil, isCurved: isCurved)
case 6:
Expand Down
6 changes: 6 additions & 0 deletions Sources/Quaternion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ extension Quaternion: Codable {
}
}

extension Quaternion: CustomStringConvertible {
public var description: String {
"Quaternion(\(x), \(y), \(z), \(w))"
}
}

public extension Quaternion {
/// The zero quaternion.
static let zero = Quaternion(unchecked: 0, 0, 0, 0)
Expand Down
12 changes: 12 additions & 0 deletions Sources/Vector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ extension Vector: XYZRepresentable {
}
}

extension Vector: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Double...) {
self.init(elements)
}
}

extension Vector: CustomStringConvertible {
public var description: String {
"Vector(\(x), \(y)\(z == 0 ? "" : ", \(z)"))"
}
}

extension Vector: Comparable {
/// Returns whether the leftmost vector has the lower value.
/// This provides a stable order when sorting collections of vectors.
Expand Down
18 changes: 18 additions & 0 deletions Sources/Vertex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ extension Vertex: Comparable {
}
}

extension Vertex: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Double...) {
self.init(Vector(elements))
}
}

extension Vertex: CustomStringConvertible {
public var description: String {
let p = "[\(position.x), \(position.y)\(position.z == 0 ? "" : ", \(position.z)")]"
let t = texcoord == .zero ? "" :
", [\(texcoord.x), \(texcoord.y)\(texcoord.z == 0 ? "" : ", \(texcoord.z)")]"
let n = texcoord == .zero && normal == .zero ? "" :
", [\(normal.x), \(normal.y), \(normal.z)]"
let c = color == .white ? "" : ", \(color)"
return "Vertex(\(p)\(n)\(t)\(c))"
}
}

extension Vertex: Codable {
private enum CodingKeys: CodingKey {
case position, normal, texcoord, color
Expand Down
73 changes: 28 additions & 45 deletions Tests/PolygonTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
@testable import Euclid
import XCTest

extension Euclid.Polygon {
/// Convenience constructor for testing
extension Euclid.Polygon: ExpressibleByArrayLiteral {
// Convenience constructor for testing
init(unchecked vertices: [Vertex], plane: Plane? = nil) {
self.init(
unchecked: vertices,
Expand All @@ -26,6 +26,10 @@ extension Euclid.Polygon {
let normal = faceNormalForPolygonPoints(points, convex: nil, closed: nil)
self.init(unchecked: points.map { Vertex($0, normal) })
}

public init(arrayLiteral elements: Vector...) {
self.init(unchecked: elements)
}
}

class PolygonTests: XCTestCase {
Expand Down Expand Up @@ -927,14 +931,13 @@ class PolygonTests: XCTestCase {
}

func testPolygonWithCollinearPointsCorrectlyDetessellated() {
let normal = -Vector.unitZ
let polygon = Polygon(unchecked: [
Vertex(Vector(0, 0), normal),
Vertex(Vector(0.5, 0), normal),
Vertex(Vector(0.5, 1), normal),
Vertex(Vector(-0.5, 1), normal),
Vertex(Vector(-0.5, 0), normal),
])
let polygon: Euclid.Polygon = [
[0, 0],
[0.5, 0],
[0.5, 1],
[-0.5, 1],
[-0.5, 0],
]
let triangles = polygon.triangulate()
XCTAssertEqual(triangles.count, 3)
let result = triangles.detessellate()
Expand All @@ -944,53 +947,33 @@ class PolygonTests: XCTestCase {
}

func testHouseShapedPolygonCorrectlyDetessellated() {
let normal = -Vector.unitZ
let polygon = Polygon(unchecked: [
Vertex(Vector(0, 0.5), normal),
Vertex(Vector(1, 0), normal),
Vertex(Vector(0.5, 0), normal),
Vertex(Vector(0.5, -1), normal),
Vertex(Vector(-0.5, -1), normal),
Vertex(Vector(-0.5, 0), normal),
Vertex(Vector(-1, 0), normal),
])
let polygon: Euclid.Polygon = [
[0, 0.5],
[1, 0],
[0.5, 0],
[0.5, -1],
[-0.5, -1],
[-0.5, 0],
[-1, 0],
]
let triangles = polygon.triangulate()
XCTAssertEqual(triangles.count, 5)
let result = triangles.detessellate()
XCTAssertEqual(result.count, 1)
XCTAssertEqual(result.first?.undirectedEdges, polygon.undirectedEdges)
XCTAssert(result.flatMap { $0.vertices }.allSatisfy { $0.normal == -.unitZ })
XCTAssertEqual(Set(result.first?.vertices ?? []), Set(polygon.vertices))
}

func testNonWatertightPolygonsCorrectlyDetessellated() {
let normal = -Vector.unitZ
let triangles = [
Polygon(unchecked: [
Vertex(Vector(0, -1), normal),
Vertex(Vector(-2, 0), normal),
Vertex(Vector(2, 0), normal),
]),
Polygon(unchecked: [
Vertex(Vector(-2, 0), normal),
Vertex(Vector(0, 1), normal),
Vertex(Vector(0, 0), normal),
]),
Polygon(unchecked: [
Vertex(Vector(2, 0), normal),
Vertex(Vector(0, 0), normal),
Vertex(Vector(0, 1), normal),
]),
let triangles: [Euclid.Polygon] = [
[[0, -1], [-2, 0], [2, 0]],
[[-2, 0], [0, 1], [0, 0]],
[[2, 0], [0, 0], [0, 1]],
]
let result = triangles.detessellate()
XCTAssertEqual(result.count, 1)
XCTAssertEqual(result, [
Polygon(unchecked: [
Vertex(Vector(0, -1), normal),
Vertex(Vector(-2, 0), normal),
Vertex(Vector(0, 1), normal),
Vertex(Vector(2, 0), normal),
]),
])
XCTAssertEqual(result, [[[0, -1], [-2, 0], [0, 1], [2, 0]]])
}

// MARK: area
Expand Down

0 comments on commit 5f50396

Please sign in to comment.