From 84ba85b0639e94ebe7ac9b1a4cb9bcb01f1dc730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Franze=CC=81n?= Date: Sun, 18 Feb 2024 22:09:35 +0100 Subject: [PATCH] Add Environment.Operation --- .../Environment/EnvironmentReader.swift | 12 ++++-- Sources/SwiftSCAD/Environment/Operation.swift | 38 +++++++++++++++++++ .../Operations/Boolean/Difference.swift | 2 + Tests/Tests/3DTests.swift | 27 +++++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 Sources/SwiftSCAD/Environment/Operation.swift diff --git a/Sources/SwiftSCAD/Environment/EnvironmentReader.swift b/Sources/SwiftSCAD/Environment/EnvironmentReader.swift index d06faa1..8c1771c 100644 --- a/Sources/SwiftSCAD/Environment/EnvironmentReader.swift +++ b/Sources/SwiftSCAD/Environment/EnvironmentReader.swift @@ -25,13 +25,17 @@ public func EnvironmentReader(@UnionBuilder3D body: @escaping (Environment) -> a } public extension Geometry2D { - func readingEnvironment(@UnionBuilder2D _ body: @escaping (Environment) -> any Geometry2D) -> any Geometry2D { - EnvironmentReader2D(body: body) + func readingEnvironment(@UnionBuilder2D _ body: @escaping (any Geometry2D, Environment) -> any Geometry2D) -> any Geometry2D { + EnvironmentReader2D { environment in + body(self, environment) + } } } public extension Geometry3D { - func readingEnvironment(@UnionBuilder3D _ body: @escaping (Environment) -> any Geometry3D) -> any Geometry3D { - EnvironmentReader3D(body: body) + func readingEnvironment(@UnionBuilder3D _ body: @escaping (any Geometry3D, Environment) -> any Geometry3D) -> any Geometry3D { + EnvironmentReader3D { environment in + body(self, environment) + } } } diff --git a/Sources/SwiftSCAD/Environment/Operation.swift b/Sources/SwiftSCAD/Environment/Operation.swift new file mode 100644 index 0000000..687078a --- /dev/null +++ b/Sources/SwiftSCAD/Environment/Operation.swift @@ -0,0 +1,38 @@ +import Foundation + +public extension Environment { + private static let key = Environment.ValueKey(rawValue: "SwiftSCAD.Operation") + + enum Operation { + case addition + case subtraction + + static prefix func !(_ op: Operation) -> Operation { + op == .addition ? .subtraction : .addition + } + } + + var operation: Operation { + self[Self.key] as? Operation ?? .addition + } + + internal func invertingOperation() -> Environment { + setting(key: Self.key, value: !operation) + } +} + +internal extension Geometry2D { + func invertingOperation() -> any Geometry2D { + withEnvironment { environment in + environment.invertingOperation() + } + } +} + +internal extension Geometry3D { + func invertingOperation() -> any Geometry3D { + withEnvironment { environment in + environment.invertingOperation() + } + } +} diff --git a/Sources/SwiftSCAD/Operations/Boolean/Difference.swift b/Sources/SwiftSCAD/Operations/Boolean/Difference.swift index 2eaa55e..10e489a 100644 --- a/Sources/SwiftSCAD/Operations/Boolean/Difference.swift +++ b/Sources/SwiftSCAD/Operations/Boolean/Difference.swift @@ -7,6 +7,7 @@ struct Difference3D: CoreGeometry3D { init(positive: any Geometry3D, negative: any Geometry3D) { self.positive = positive self.negative = negative + .invertingOperation() } func call(in environment: Environment) -> SCADCall { @@ -46,6 +47,7 @@ struct Difference2D: CoreGeometry2D { init(positive: any Geometry2D, negative: any Geometry2D) { self.positive = positive self.negative = negative + .invertingOperation() } func call(in environment: Environment) -> SCADCall { diff --git a/Tests/Tests/3DTests.swift b/Tests/Tests/3DTests.swift index 7d74d05..a83edfb 100644 --- a/Tests/Tests/3DTests.swift +++ b/Tests/Tests/3DTests.swift @@ -19,4 +19,31 @@ final class Geometry3DTests: XCTestCase { .adding {} .assertEqual(toFile: "empty3d") } + + func testOperations() { + let testGeometry = Box([1,2,3]) + .assertOperation(.addition) + .subtracting { + Sphere(diameter: 3) + .assertOperation(.subtraction) + .subtracting { + Box([1,2,3]) + .assertOperation(.addition) + } + .assertOperation(.subtraction) + } + .assertOperation(.addition) + + _ = testGeometry + .scadString(in: .defaultEnvironment) + } +} + +extension Geometry3D { + func assertOperation(_ expectedOperation: Environment.Operation) -> any Geometry3D { + readingEnvironment { geo, environment in + XCTAssertEqual(environment.operation, expectedOperation) + geo + } + } }