Skip to content

Commit

Permalink
Add offsettingBounds and settingBoundsSize
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasf committed Sep 21, 2024
1 parent f5a971c commit bb2b7c6
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
54 changes: 54 additions & 0 deletions Sources/SwiftSCAD/Operations/Bounds/OffsetBounds.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Foundation

public extension Geometry2D {
/// Offsets the boundary of this geometry, leaving the geometry itself unmodified.
///
/// The geometry remains in its current position, while its boundary is moved by the specified offset.
/// - Parameter offset: A vector describing the amount by which to translate the boundary.
/// - Returns: A geometry with the boundary translated by the given offset.

func offsettingBounds(_ offset: Vector2D) -> any Geometry2D {
ReadBoundary2D(body: self) { snapshot, boundary in
SetBounds2D(body: snapshot, boundary: boundary.translated(offset))
}
}

/// Offsets the boundary of this geometry, leaving the geometry itself unmodified.
///
/// The geometry remains in its current position, while its boundary is moved by the specified offset in the `x` and `y` directions.
/// - Parameters:
/// - x: The offset along the X axis to apply to the boundary. Defaults to `0`.
/// - y: The offset along the Y axis to apply to the boundary. Defaults to `0`.
/// - Returns: A geometry with the boundary translated by the given offsets.

func offsettingBounds(x: Double = 0, y: Double = 0) -> any Geometry2D {
offsettingBounds(.init(x: x, y: y))
}
}

public extension Geometry3D {
/// Offsets the boundary of this geometry, leaving the geometry itself unmodified.
///
/// The geometry remains in its current position, while its boundary is moved by the specified offset.
/// - Parameter offset: A vector describing the amount by which to translate the boundary.
/// - Returns: A geometry with the boundary translated by the given offset.

func offsettingBounds(_ offset: Vector3D) -> any Geometry3D {
ReadBoundary3D(body: self) { snapshot, boundary in
SetBounds3D(body: snapshot, boundary: boundary.translated(offset))
}
}

/// Offsets the boundary of this geometry, leaving the geometry itself unmodified.
///
/// The geometry remains in its current position, while its boundary is moved by the specified offset in the `x` and `y` directions.
/// - Parameters:
/// - x: The offset along the X axis to apply to the boundary. Defaults to `0`.
/// - y: The offset along the Y axis to apply to the boundary. Defaults to `0`.
/// - z: The offset along the Z axis to apply to the boundary. Defaults to `0`.
/// - Returns: A geometry with the boundary translated by the given offsets.

func offsettingBounds(x: Double = 0, y: Double = 0, z: Double = 0) -> any Geometry3D {
offsettingBounds(.init(x: x, y: y, z: z))
}
}
84 changes: 84 additions & 0 deletions Sources/SwiftSCAD/Operations/Bounds/SetBoundsSize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import Foundation

public extension Geometry2D {
private func settingBounds(snapshot: GeometrySnapshot2D, currentSize: Vector2D, targetSize: Vector2D, alignment: GeometryAlignment2D) -> any Geometry2D {
let translation = (targetSize - currentSize) * alignment.factors
return snapshot
.aligned(at: .origin)
.translated(translation)
.settingBounds(.init(minimum: .zero, maximum: targetSize))
}

/// Set the size of the bounding box of this geometry.
///
/// The resulting bounding box is aligned at the origin, with a size specified by the given parameters. If a dimension is not provided, the current size for that dimension is preserved.
/// The geometry is translated within the new bounding box according to the specified alignment.
/// - Parameters:
/// - x: The new X size for the bounding box. If `nil`, the current X size is preserved.
/// - y: The new Y size for the bounding box. If `nil`, the current Y size is preserved.
/// - alignment: The alignment specification that controls how the geometry is positioned within the new bounding box.
/// - Returns: A modified geometry with the updated bounding box.

func settingBoundsSize(x: Double? = nil, y: Double? = nil, alignment: GeometryAlignment2D...) -> any Geometry2D {
measuringBounds { snapshot, box in
let newSize = Vector2D(x ?? box.size.x, y ?? box.size.y)
settingBounds(snapshot: snapshot, currentSize: box.size, targetSize: newSize, alignment: alignment.merged)
}
}

/// Set the size of the bounding box of this geometry.
///
/// The resulting bounding box is aligned at the origin with the specified size. The geometry is translated within the new bounding box according to the specified alignment.
/// - Parameters:
/// - targetSize: The new size of the bounding box.
/// - alignment: The alignment specification that controls how the geometry is positioned within the new bounding box.
/// - Returns: A modified geometry with the updated bounding box.

func settingBoundsSize(_ targetSize: Vector2D, alignment: GeometryAlignment2D...) -> any Geometry2D {
measuringBounds { snapshot, box in
settingBounds(snapshot: snapshot, currentSize: box.size, targetSize: targetSize, alignment: alignment.merged)
}
}
}

public extension Geometry3D {
private func settingBounds(snapshot: GeometrySnapshot3D, currentSize: Vector3D, targetSize: Vector3D, alignment: GeometryAlignment3D) -> any Geometry3D {
let translation = (targetSize - currentSize) * alignment.factors
return snapshot
.aligned(at: .origin)
.translated(translation)
.settingBounds(.init(minimum: .zero, maximum: targetSize))
}

/// Set the size of the bounding box of this geometry.
///
/// The resulting bounding box is aligned at the origin, with a size specified by the given parameters. If a dimension is not provided, the current size for that dimension is preserved.
/// The geometry is translated within the new bounding box according to the specified alignment.
/// - Parameters:
/// - x: The new X size for the bounding box. If `nil`, the current X size is preserved.
/// - y: The new Y size for the bounding box. If `nil`, the current Y size is preserved.
/// - z: The new Z size for the bounding box. If `nil`, the current Z size is preserved.
/// - alignment: The alignment specification that controls how the geometry is positioned within the new bounding box.
/// - Returns: A modified geometry with the updated bounding box.

func settingBoundsSize(x: Double? = nil, y: Double? = nil, z: Double? = nil, alignment: GeometryAlignment3D...) -> any Geometry3D {
measuringBounds { snapshot, box in
let newSize = Vector3D(x ?? box.size.x, y ?? box.size.y, z ?? box.size.z)
settingBounds(snapshot: snapshot, currentSize: box.size, targetSize: newSize, alignment: alignment.merged)
}
}

/// Set the size of the bounding box of this geometry.
///
/// The resulting bounding box is aligned at the origin with the specified size. The geometry is translated within the new bounding box according to the specified alignment.
/// - Parameters:
/// - targetSize: The new size of the bounding box.
/// - alignment: The alignment specification that controls how the geometry is positioned within the new bounding box.
/// - Returns: A modified geometry with the updated bounding box.

func settingBoundsSize(_ targetSize: Vector3D, alignment: GeometryAlignment3D...) -> any Geometry3D {
measuringBounds { snapshot, box in
settingBounds(snapshot: snapshot, currentSize: box.size, targetSize: targetSize, alignment: alignment.merged)
}
}
}

0 comments on commit bb2b7c6

Please sign in to comment.