forked from nicklockwood/ShapeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGeometryType.swift
More file actions
137 lines (130 loc) · 4.16 KB
/
GeometryType.swift
File metadata and controls
137 lines (130 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//
// GeometryType.swift
// ShapeScript Lib
//
// Created by Nick Lockwood on 12/08/2021.
// Copyright © 2021 Nick Lockwood. All rights reserved.
//
import Euclid
public struct Camera: Hashable {
public var hasPosition: Bool
public var hasOrientation: Bool
public var hasScale: Bool
public var background: MaterialProperty?
public var fov: Angle?
public var width: Double?
public var height: Double?
}
public struct Light: Hashable {
public var hasPosition: Bool
public var hasOrientation: Bool
public var color: Color
public var spread: Angle
public var penumbra: Double
}
public enum GeometryType: Hashable {
case group
// primitives
case cone(segments: Int)
case cylinder(segments: Int)
case sphere(segments: Int)
case cube
// builders
case extrude([Path], along: [Path])
case lathe([Path], segments: Int)
case loft([Path])
case fill([Path])
// csg
case union
case difference
case intersection
case xor
case stencil
// shapes
case path(Path)
case mesh(Mesh)
// special
case camera(Camera)
case light(Light)
}
public extension GeometryType {
var isEmpty: Bool {
switch self {
case .union, .xor, .difference, .intersection, .stencil,
.group, .camera, .light:
return true
case .cone, .cylinder, .sphere, .cube:
return false
case let .extrude(shapes, _),
let .lathe(shapes, _),
let .loft(shapes),
let .fill(shapes):
return shapes.isEmpty || shapes.allSatisfy { $0.points.count < 2 }
case let .path(path):
return path.points.count < 2
case let .mesh(mesh):
return mesh.polygons.isEmpty
}
}
var bounds: Bounds {
switch self {
case .union, .xor, .difference, .intersection, .stencil,
.group, .camera, .light:
return .empty
case .cone, .cylinder, .sphere, .cube:
return .init(min: .init(-0.5, -0.5, -0.5), max: .init(0.5, 0.5, 0.5))
case let .extrude(paths, along: along):
if along.isEmpty {
return paths.reduce(into: .empty) { bounds, path in
let offset = path.faceNormal / 2
bounds.formUnion(path.bounds.translated(by: offset))
bounds.formUnion(path.bounds.translated(by: -offset))
}
}
return along.reduce(into: .empty) { bounds, along in
let alongBounds = along.bounds
bounds = paths.reduce(into: bounds) { bounds, path in
let pathBounds = path.bounds
let pathRadius = Swift.max(
pathBounds.min.length,
pathBounds.max.length
)
bounds.formUnion(Bounds(
min: alongBounds.min - Vector(size: pathRadius),
max: alongBounds.max + Vector(size: pathRadius)
))
}
}
case let .lathe(paths, _):
return .init(bounds: paths.map {
var min = $0.bounds.min, max = $0.bounds.max
min.x = Swift.min(min.x, -max.x, min.z, -max.z)
max.x = -min.x
min.z = min.x
max.z = -min.x
return .init(min: min, max: max)
})
case let .loft(paths), let .fill(paths):
return .init(bounds: paths.map { $0.bounds })
case let .path(path):
return path.bounds
case let .mesh(mesh):
return mesh.bounds
}
}
}
internal extension GeometryType {
var isLeafGeometry: Bool {
switch self {
case let .extrude(paths, along):
return paths.count == 1 && along.count <= 1
case let .lathe(paths, _), let .fill(paths):
return paths.count == 1
case .cone, .cylinder, .sphere, .cube, .loft, .path, .mesh,
.group, .camera, .light:
return true
case .union, .xor, .difference, .intersection, .stencil:
return false
}
}
}