-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
134 additions
and
137 deletions.
There are no files selected for viewing
64 changes: 24 additions & 40 deletions
64
Sources/SwiftSCAD/Values/Bezier/Path Builder/BezierPath.Builder.swift
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,40 @@ | ||
import Foundation | ||
|
||
public extension BezierPath { | ||
@resultBuilder struct Builder { | ||
public typealias Component = BezierPath<V>.Component | ||
typealias Builder = ArrayBuilder<BezierPath<V>.Component> | ||
|
||
public static func buildExpression(_ expression: Component) -> [Component] { | ||
[expression] | ||
} | ||
|
||
public static func buildBlock(_ children: [Component]...) -> [Component] { | ||
children.flatMap { $0 } | ||
} | ||
init(from: V = .zero, mode defaultMode: PathBuilderPositioning = .absolute, @Builder builder: () -> [Component]) { | ||
var start = from | ||
self.init(startPoint: from, curves: builder().flatMap { | ||
$0.bezierCurves(start: &start, defaultMode: defaultMode) | ||
}) | ||
} | ||
|
||
// If without else | ||
public static func buildOptional(_ children: [Component]?) -> [Component] { | ||
if let children { | ||
[.init(group: children)] | ||
} else { | ||
[] | ||
} | ||
} | ||
struct Component { | ||
private let points: [PathBuilderVector<V>] | ||
|
||
// If | ||
public static func buildEither(first child: [Component]) -> [Component] { | ||
[.init(group: child)] | ||
internal init(_ points: [PathBuilderVector<V>]) { | ||
self.points = points | ||
} | ||
|
||
// Else | ||
public static func buildEither(second child: [Component]) -> [Component] { | ||
[.init(group: child)] | ||
internal func bezierCurves(start: inout V, defaultMode: PathBuilderPositioning) -> [Curve] { | ||
let controlPoints = [start] + points.map { | ||
$0.value(relativeTo: start, defaultMode: defaultMode) | ||
} | ||
start = controlPoints.last! | ||
return [Curve(controlPoints: controlPoints)] | ||
} | ||
|
||
// Loops | ||
public static func buildArray(_ children: [[Component]]) -> [Component] { | ||
children.flatMap { $0 } | ||
internal func withDefaultMode(_ mode: PathBuilderPositioning) -> Self { | ||
.init(points.map { $0.withDefaultMode(mode) }) | ||
} | ||
|
||
public static func buildExpression(_ void: Void) -> [Component] { [] } | ||
public static func buildExpression(_ never: Never) -> [Component] {} | ||
public var relative: Component { withDefaultMode(.relative) } | ||
public var absolute: Component { withDefaultMode(.absolute) } | ||
} | ||
} | ||
|
||
public extension BezierPath { | ||
enum BuilderPositioning { | ||
case relative | ||
case absolute | ||
} | ||
|
||
init(from: V = .zero, _ positioning: BuilderPositioning = .absolute, @Builder builder: () -> [Component]) { | ||
var start = from | ||
self.init(startPoint: from, curves: builder().flatMap { | ||
$0.bezierCurves(start: &start, positioning: positioning) | ||
}) | ||
} | ||
public enum PathBuilderPositioning: Sendable { | ||
case absolute | ||
case relative | ||
} |
40 changes: 0 additions & 40 deletions
40
Sources/SwiftSCAD/Values/Bezier/Path Builder/BezierPath.Component.swift
This file was deleted.
Oops, something went wrong.
This file contains 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
73 changes: 73 additions & 0 deletions
73
Sources/SwiftSCAD/Values/Bezier/Path Builder/PathBuilderValue.swift
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import Foundation | ||
|
||
public protocol PathBuilderValue: Sendable {} | ||
|
||
extension Double: PathBuilderValue { | ||
public var relative: any PathBuilderValue { | ||
PositionedValue(value: self, mode: .relative) | ||
} | ||
|
||
public var absolute: any PathBuilderValue { | ||
PositionedValue(value: self, mode: .absolute) | ||
} | ||
} | ||
|
||
public extension PathBuilderValue where Self == Double { | ||
static var unchanged: any PathBuilderValue { 0.relative } | ||
} | ||
|
||
internal struct PositionedValue: PathBuilderValue { | ||
var value: Double | ||
var mode: PathBuilderPositioning? | ||
|
||
func value(relativeTo base: Double, defaultMode: PathBuilderPositioning) -> Double { | ||
switch mode ?? defaultMode { | ||
case .relative: base + value | ||
case .absolute: value | ||
} | ||
} | ||
|
||
func withDefaultMode(_ defaultMode: PathBuilderPositioning) -> PositionedValue { | ||
.init(value: value, mode: mode ?? defaultMode) | ||
} | ||
} | ||
|
||
internal extension PathBuilderValue { | ||
var positionedValue: PositionedValue { | ||
if let self = self as? Double { | ||
PositionedValue(value: self, mode: nil) | ||
} else if let self = self as? PositionedValue { | ||
self | ||
} else { | ||
preconditionFailure("Unknown BezierBuilderValue type.") | ||
} | ||
} | ||
} | ||
|
||
internal typealias PathBuilderVector<V: Vector> = DimensionalValue<PositionedValue, V> | ||
|
||
internal extension PathBuilderVector where Element == PositionedValue { | ||
init(_ vector: V) { | ||
self.init { | ||
PositionedValue(value: vector[$0], mode: nil) | ||
} | ||
} | ||
|
||
init(_ x: any PathBuilderValue, _ y: any PathBuilderValue) where V == Vector2D { | ||
self.init(x: x.positionedValue, y: y.positionedValue) | ||
} | ||
|
||
init(_ x: any PathBuilderValue, _ y: any PathBuilderValue, _ z: any PathBuilderValue) where V == Vector3D { | ||
self.init(x: x.positionedValue, y: y.positionedValue, z: z.positionedValue) | ||
} | ||
|
||
func withDefaultMode(_ mode: PathBuilderPositioning) -> Self { | ||
map { $1.withDefaultMode(mode) } | ||
} | ||
|
||
func value(relativeTo base: V, defaultMode: PathBuilderPositioning) -> V { | ||
map { | ||
$1.value(relativeTo: base[$0], defaultMode: defaultMode) | ||
}.vector | ||
} | ||
} |
This file contains 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
This file was deleted.
Oops, something went wrong.
This file contains 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