Skip to content

Commit 7f26b67

Browse files
committed
Rename Geometry.bounds to overestimatedBounds
1 parent 03950d5 commit 7f26b67

9 files changed

Lines changed: 61 additions & 68 deletions

ShapeScript/Geometry.swift

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,22 @@ public final class Geometry: Hashable {
2525
public let smoothing: Angle?
2626
public let children: [Geometry]
2727
public let isOpaque: Bool // Computed
28-
/// The overestimated Geometry bounds *without* the local transform applied
29-
public let bounds: Bounds
28+
private let _overestimatedBounds: Bounds
3029
private let _sourceLocation: (() -> SourceLocation?)?
3130
public private(set) lazy var sourceLocation: SourceLocation? = _sourceLocation?()
3231
public private(set) weak var parent: Geometry?
3332

33+
/// The overestimated Geometry bounds *with* local transform applied
34+
public var overestimatedBounds: Bounds {
35+
_overestimatedBounds.transformed(by: transform)
36+
}
37+
38+
/// The overestimated Geometry bounds *without* the local transform applied
39+
@available(*, deprecated, message: "Use overestimatedBounds instead")
40+
public var bounds: Bounds {
41+
_overestimatedBounds
42+
}
43+
3444
public func hash(into hasher: inout Hasher) {
3545
hasher.combine(type)
3646
hasher.combine(name)
@@ -310,33 +320,22 @@ public final class Geometry: Hashable {
310320
// Compute the overestimated, non-transformed bounds
311321
switch type {
312322
case .difference, .stencil:
313-
self.bounds = children.first.map {
314-
$0.bounds.transformed(by: $0.transform)
315-
} ?? .empty
323+
self._overestimatedBounds = children.first.map(\.overestimatedBounds) ?? .empty
316324
case .intersection:
317-
self.bounds = children.dropFirst().reduce(into: children.first.map {
318-
$0.bounds.transformed(by: $0.transform)
319-
} ?? .empty) { bounds, child in
320-
bounds.formIntersection(child.bounds.transformed(by: child.transform))
321-
}
325+
self._overestimatedBounds = (children.first?.overestimatedBounds ?? .empty)
326+
.intersection(Bounds(children.dropFirst().map(\.overestimatedBounds)))
322327
case .union, .xor, .group:
323-
self.bounds = Bounds(children.map {
324-
$0.bounds.transformed(by: $0.transform)
325-
})
328+
self._overestimatedBounds = Bounds(children.map(\.overestimatedBounds))
326329
case .lathe, .fill, .extrude, .loft, .mesh, .hull:
327-
self.bounds = type.bounds.union(Bounds(children.map {
328-
$0.bounds.transformed(by: $0.transform)
329-
}))
330+
self._overestimatedBounds = type.bounds.union(Bounds(children.map(\.overestimatedBounds)))
330331
case .minkowski:
331-
var bounds = Bounds(min: .zero, max: .zero)
332-
for child in children {
333-
bounds.formMinkowskiSum(with: child.bounds.transformed(by: child.transform))
332+
self._overestimatedBounds = children.reduce(.empty) {
333+
$0.minkowskiSum(with: $1.overestimatedBounds)
334334
}
335-
self.bounds = bounds
336335
case .cone, .cylinder, .sphere, .cube, .path:
337-
self.bounds = type.bounds
336+
self._overestimatedBounds = type.bounds
338337
case .camera, .light:
339-
self.bounds = .empty
338+
self._overestimatedBounds = .empty
340339
}
341340

342341
// Must be set after all other properties

ShapeScript/Scene+SceneKit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public extension Scene {
112112
) -> OutputOptions {
113113
var options = OutputOptions.default
114114
let color = backgroundColor ?? .gray
115-
let size = bounds.size
115+
let size = overestimatedBounds.size
116116
options.lineWidth = max(0.005, 0.002 * max(size.x, size.y, size.z))
117117
let background = camera?.background ?? background
118118
options.lineColor = background.brightness(over: color) > 0.5 ? .black : .white

ShapeScript/Scene.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,17 @@ public extension Scene {
4242
static let empty = Scene(background: .color(.clear), children: [], cache: nil)
4343

4444
/// Returns the approximate (overestimated) bounds of the scene geometry.
45+
var overestimatedBounds: Bounds {
46+
Bounds(children.map(\.overestimatedBounds))
47+
}
48+
49+
/// Returns the approximate (overestimated) bounds of the scene geometry.
50+
@available(*, deprecated, renamed: "overestimatedBounds")
4551
var bounds: Bounds {
46-
children.reduce(into: .empty) {
47-
$0.formUnion($1.bounds.transformed(by: $1.transform))
48-
}
52+
overestimatedBounds
4953
}
5054

51-
func build(_ callback: @escaping () -> Bool) -> Bool {
55+
func build(_ callback: @escaping LegacyCallback) -> Bool {
5256
for geometry in children where !geometry.build(callback) {
5357
return false
5458
}

ShapeScriptTests/GeometryTests.swift

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ final class GeometryTests: XCTestCase {
5454
children: [cube, camera],
5555
sourceLocation: nil
5656
)
57-
XCTAssert(camera.bounds.transformed(by: camera.transform).isEmpty)
58-
XCTAssertEqual(group.bounds, cube.bounds)
57+
XCTAssert(camera.overestimatedBounds.isEmpty)
58+
XCTAssertEqual(group.overestimatedBounds, cube.overestimatedBounds)
5959
}
6060

6161
func testLowDetailPrimitiveBounds() {
@@ -105,11 +105,9 @@ final class GeometryTests: XCTestCase {
105105
context.transform = .translation(offset)
106106
let shape = Geometry(type: GeometryType.fill([.square()]), in: context)
107107
XCTAssertEqual(shape.exactBounds(with: shape.transform).center, offset)
108-
XCTAssertEqual(shape.bounds.size, [1, 1, 0])
109-
XCTAssertEqual(shape.bounds.center, [0, 0, 0])
110-
let exactBounds = shape.exactBounds(with: shape.transform)
111-
XCTAssertEqual(exactBounds.size, shape.bounds.size)
112-
XCTAssertEqual(exactBounds.center, [1, 2, 3])
108+
XCTAssertEqual(shape.overestimatedBounds.size, [1, 1, 0])
109+
XCTAssertEqual(shape.overestimatedBounds.center, [1, 2, 3])
110+
XCTAssertEqual(shape.exactBounds(with: shape.transform), shape.overestimatedBounds)
113111
}
114112

115113
func testTransformedMultipleFilledPathBounds() {
@@ -120,11 +118,9 @@ final class GeometryTests: XCTestCase {
120118
.square(),
121119
.circle(radius: 0.5).translated(by: [1, 0, 0]),
122120
]), in: context)
123-
XCTAssertEqual(shape.bounds.size, [2, 1, 0])
124-
XCTAssertEqual(shape.bounds.center, [0.5, 0, 0])
125-
let exactBounds = shape.exactBounds(with: shape.transform)
126-
XCTAssertEqual(exactBounds.size, shape.bounds.size)
127-
XCTAssertEqual(exactBounds.center, [1.5, 2, 3])
121+
XCTAssertEqual(shape.overestimatedBounds.size, [2, 1, 0])
122+
XCTAssertEqual(shape.overestimatedBounds.center, [1.5, 2, 3])
123+
XCTAssertEqual(shape.exactBounds(with: shape.transform), shape.overestimatedBounds)
128124
}
129125

130126
func testTransformedMultipleExtrudedPathBounds() {
@@ -135,11 +131,9 @@ final class GeometryTests: XCTestCase {
135131
.square(),
136132
.circle(radius: 0.5).translated(by: [1, 0, 0]),
137133
], .default), in: context)
138-
XCTAssertEqual(shape.bounds.size, [2, 1, 1])
139-
XCTAssertEqual(shape.bounds.center, [0.5, 0, 0])
140-
let exactBounds = shape.exactBounds(with: shape.transform)
141-
XCTAssertEqual(exactBounds.size, shape.bounds.size)
142-
XCTAssertEqual(exactBounds.center, [1.5, 2, 3])
134+
XCTAssertEqual(shape.overestimatedBounds.size, [2, 1, 1])
135+
XCTAssertEqual(shape.overestimatedBounds.center, [1.5, 2, 3])
136+
XCTAssertEqual(shape.exactBounds(with: shape.transform), shape.overestimatedBounds)
143137
}
144138

145139
func testTransformedMultipleExtrudedPathBoundsWithTwist() {
@@ -154,11 +148,9 @@ final class GeometryTests: XCTestCase {
154148
twist: .halfPi,
155149
align: nil
156150
)), in: context)
157-
XCTAssertEqual(shape.bounds.size, [2, 2, 1])
158-
XCTAssertEqual(shape.bounds.center, [0.5, -0.5, 0])
159-
let exactBounds = shape.exactBounds(with: shape.transform)
160-
XCTAssertEqual(exactBounds.size, shape.bounds.size)
161-
XCTAssertEqual(exactBounds.center, [1.5, 1.5, 3])
151+
XCTAssertEqual(shape.overestimatedBounds.size, [2, 2, 1])
152+
XCTAssertEqual(shape.overestimatedBounds.center, [1.5, 1.5, 3])
153+
XCTAssertEqual(shape.exactBounds(with: shape.transform), shape.overestimatedBounds)
162154
}
163155

164156
func testTransformedMultipleLathedPathBounds() {
@@ -169,11 +161,9 @@ final class GeometryTests: XCTestCase {
169161
.square(),
170162
.circle(radius: 0.5).translated(by: [0, 1, 0]),
171163
], segments: 4), in: context)
172-
XCTAssertEqual(shape.bounds.size, [1, 2, 1])
173-
XCTAssertEqual(shape.bounds.center, [0, 0.5, 0])
174-
let exactBounds = shape.exactBounds(with: shape.transform)
175-
XCTAssertEqual(exactBounds.size, shape.bounds.size)
176-
XCTAssertEqual(exactBounds.center, [1, 2.5, 3])
164+
XCTAssertEqual(shape.overestimatedBounds.size, [1, 2, 1])
165+
XCTAssertEqual(shape.overestimatedBounds.center, [1, 2.5, 3])
166+
XCTAssertEqual(shape.exactBounds(with: shape.transform), shape.overestimatedBounds)
177167
}
178168

179169
// MARK: Intersection
@@ -201,7 +191,7 @@ final class GeometryTests: XCTestCase {
201191
}
202192
}
203193
"""), delegate: nil)
204-
XCTAssertEqual(a.bounds, b.bounds)
194+
XCTAssertEqual(a.overestimatedBounds, b.overestimatedBounds)
205195
XCTAssertEqual(a.children.count, b.children.count)
206196
XCTAssertEqual(a.children.map(\.mesh), b.children.map(\.mesh))
207197
XCTAssertEqual(a.children.map {

ShapeScriptTests/InterpreterTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4442,7 +4442,7 @@ final class InterpreterTests: XCTestCase {
44424442
#if canImport(CoreText)
44434443
let chars = context.children.compactMap { $0.value as? Geometry }
44444444
XCTAssertEqual(chars.count, 4)
4445-
XCTAssertEqual(chars.first?.bounds.min.y, chars.last?.bounds.min.y)
4445+
XCTAssertEqual(chars.first?.overestimatedBounds.min.y, chars.last?.overestimatedBounds.min.y)
44464446
#endif
44474447
}
44484448

@@ -4457,7 +4457,7 @@ final class InterpreterTests: XCTestCase {
44574457
#if canImport(CoreText)
44584458
let chars = context.children.compactMap { $0.value as? Geometry }
44594459
XCTAssertEqual(chars.count, 2)
4460-
XCTAssertNotEqual(chars.first?.bounds.size, chars.last?.bounds.size)
4460+
XCTAssertNotEqual(chars.first?.overestimatedBounds.size, chars.last?.overestimatedBounds.size)
44614461
#endif
44624462
}
44634463

@@ -4475,7 +4475,7 @@ final class InterpreterTests: XCTestCase {
44754475
#if canImport(CoreText)
44764476
let chars = context.children.compactMap { $0.value as? Geometry }
44774477
XCTAssertEqual(chars.count, 2)
4478-
XCTAssertNotEqual(chars.first?.bounds.size, chars.last?.bounds.size)
4478+
XCTAssertNotEqual(chars.first?.overestimatedBounds.size, chars.last?.overestimatedBounds.size)
44794479
#endif
44804480
}
44814481

@@ -4490,7 +4490,7 @@ final class InterpreterTests: XCTestCase {
44904490
#if canImport(CoreText)
44914491
let chars = context.children.compactMap { $0.value as? Geometry }
44924492
XCTAssertEqual(chars.count, 2)
4493-
XCTAssertNotEqual(chars.first?.bounds.size, chars.last?.bounds.size)
4493+
XCTAssertNotEqual(chars.first?.overestimatedBounds.size, chars.last?.overestimatedBounds.size)
44944494
#endif
44954495
}
44964496

@@ -4508,7 +4508,7 @@ final class InterpreterTests: XCTestCase {
45084508
#if canImport(CoreText)
45094509
let chars = context.children.compactMap { $0.value as? Geometry }
45104510
XCTAssertEqual(chars.count, 2)
4511-
XCTAssertNotEqual(chars.first?.bounds.size, chars.last?.bounds.size)
4511+
XCTAssertNotEqual(chars.first?.overestimatedBounds.size, chars.last?.overestimatedBounds.size)
45124512
#endif
45134513
}
45144514

@@ -4525,7 +4525,7 @@ final class InterpreterTests: XCTestCase {
45254525
#if canImport(CoreText)
45264526
let chars = context.children.compactMap { $0.value as? Geometry }
45274527
XCTAssertEqual(chars.count, 2)
4528-
XCTAssertNotEqual(chars.first?.bounds.size, chars.last?.bounds.size)
4528+
XCTAssertNotEqual(chars.first?.overestimatedBounds.size, chars.last?.overestimatedBounds.size)
45294529
#endif
45304530
}
45314531

ShapeScriptTests/StandardLibraryTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ final class StandardLibraryTests: XCTestCase {
10791079
XCTAssertNoThrow(try program.evaluate(in: context))
10801080
let geometry = try XCTUnwrap(context.children.first?.value as? Geometry)
10811081
let expected = Mesh.cube(size: 1.5)
1082-
XCTAssertEqual(geometry.bounds, expected.bounds)
1082+
XCTAssertEqual(geometry.overestimatedBounds, expected.bounds)
10831083
_ = geometry.build { true }
10841084
XCTAssertEqual(geometry.mesh?.bounds, expected.bounds)
10851085
}

Viewer/CLI/Geometry+ModelInfo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ extension Geometry {
1919
"Objects: \(objectCount)",
2020
triangles == polygons ? nil : "Polygons: \(polygons)",
2121
hasMesh ? "Triangles: \(triangles)" : nil,
22-
bounds.isEmpty ? nil : "Dimensions: \(dimensions)",
22+
overestimatedBounds.isEmpty ? nil : "Dimensions: \(dimensions)",
2323
hasMesh ? "Watertight: \(watertight)" : nil,
2424
].compactMap { $0 }.joined(separator: "\n")
2525
}

Viewer/Shared/Document+ModelInfo.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ extension Document {
108108
childCount == 0 ? nil : "Children: \(childCount)",
109109
triangles == polygons ? nil : "Polygons: \(polygons)",
110110
isMesh ? "Triangles: \(triangles)" : nil,
111-
geometry.bounds.isEmpty ? nil : "Dimensions: \(dimensions)",
111+
geometry.overestimatedBounds.isEmpty ? nil : "Dimensions: \(dimensions)",
112112
isMesh ? "Volume: \(volume)" : nil,
113113
isMesh ? "Watertight: \(watertight)" : nil,
114114
// "Size: \(selectedGeometry.transform.scale.logDescription)",
@@ -124,7 +124,7 @@ extension Document {
124124
"Objects: \(objectCount)",
125125
triangles == polygons ? nil : "Polygons: \(polygons)",
126126
hasMeshes ? "Triangles: \(triangles)" : nil,
127-
geometry.bounds.isEmpty ? nil : "Dimensions: \(dimensions)",
127+
geometry.overestimatedBounds.isEmpty ? nil : "Dimensions: \(dimensions)",
128128
hasMeshes ? "Volume: \(volume)" : nil,
129129
hasMeshes ? "Watertight: \(watertight)" : nil,
130130
"",

Viewer/Shared/DocumentViewController+View.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ extension DocumentViewController {
6262
}
6363

6464
var axesSize: Double {
65-
let bounds = geometry?.bounds ?? .empty
65+
let bounds = geometry?.overestimatedBounds ?? .empty
6666
let m = max(-bounds.min, bounds.max)
6767
return max(m.x, m.y, m.z) * 1.1
6868
}
6969

7070
var viewCenter: Vector {
71-
showAxes ? .zero : (geometry?.bounds ?? .empty).center
71+
showAxes ? .zero : (geometry?.overestimatedBounds ?? .empty).center
7272
}
7373

7474
func resetView() {
@@ -151,7 +151,7 @@ extension DocumentViewController {
151151
self.axesNode = axesNode
152152
}
153153
// Update camera node
154-
let bounds = geometry?.bounds ?? .empty
154+
let bounds = geometry?.overestimatedBounds ?? .empty
155155
let axisScale = axesSize * 2.2
156156
let size = bounds.size
157157
var distance, scale: Double

0 commit comments

Comments
 (0)