Skip to content

Commit

Permalink
Merge branch 'develop' into feature/vertex_normal_optimisation_removal
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood authored Aug 11, 2024
2 parents a0bb47c + 9643e62 commit b417ae7
Show file tree
Hide file tree
Showing 47 changed files with 2,155 additions and 1,286 deletions.
4 changes: 2 additions & 2 deletions Euclid.docc/Extensions/Color.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

### Creating a Color

- ``Color/init(r:g:b:a:)``
- ``Color/init(_:_:_:_:)``
- ``Color/init(_:_:)``
- ``Color/init(_:)-25eby``
- ``Color/init(_:)-53lhy``
- ``Color/init(_:)-7d8un``
- ``Color/init(_:)-9bvpm``

### Default Colors

Expand Down
8 changes: 3 additions & 5 deletions Euclid.docc/Extensions/Vector.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

### Creating Vectors

- ``Vector/init(_:)-228p6``
- ``Vector/init(_:)-4eop9``
- ``Vector/init(_:)-5n3j``
- ``Vector/init(_:)-63ct7``
- ``Vector/init(_:)-6nlm``
- ``Vector/init(x:y:z:)``
- ``Vector/init(_:_:_:)``
- ``Vector/init(size:)-8b34m``
- ``Vector/init(size:)-nkyk``
- ``Vector/init(_:)-63ct7``
- ``Vector/init(_:)-602vn``

### Default Vectors

Expand Down
42 changes: 27 additions & 15 deletions Euclid.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Euclid.xcodeproj/xcshareddata/xcschemes/Euclid.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
25 changes: 23 additions & 2 deletions Example/SceneKitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,36 @@ class SceneKitViewController: UIViewController {
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 2)

// create some geometry using Euclid
let start = CFAbsoluteTimeGetCurrent()
// let cube = Mesh.cube(size: 0.8, material: UIColor.red)
// let sphere = Mesh.sphere(slices: 120, material: UIColor.blue)
// let mesh = cube.subtracting(sphere).makeWatertight()

// let cube = Mesh.cube().inverted()
// let cube2 = Mesh.cube().inverted().translated(by: Vector(0.5, 0.5, 0.5))
// let mesh = cube.union(cube2).inverted()

// print("Time:", CFAbsoluteTimeGetCurrent() - start)
// print("Polygons:", mesh.polygons.count)
// print("Triangles:", mesh.triangulate().polygons.count)
// print("Watertight:", mesh.isWatertight)

let polygon1 = Path.square(color: .red)
let polygon2 = Path.square(color: .green).translated(by: Vector(0.5, 0.5, 0)) // .rotated(by: .yaw(.pi / 5))
let polygon3 = Path.square(color: .blue).translated(by: Vector(0.25, -0.25, 0)) // .rotated(by: .yaw(.pi / 5))
let result = Path.difference([polygon1, polygon2, polygon3])
let mesh = Mesh.fill(result)

// create SCNNode
let geometry = SCNGeometry(euclidMesh)
let geometry = SCNGeometry(mesh)
let node = SCNNode(geometry: geometry)
scene.rootNode.addChildNode(node)

// configure the SCNView
let scnView = view as! SCNView
scnView.scene = scene
scnView.autoenablesDefaultLighting = true
// scnView.autoenablesDefaultLighting = true
scnView.allowsCameraControl = true
scnView.backgroundColor = .white
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/Angle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ public func tan(_ angle: Angle) -> Double {

public extension Angle {
/// Angle representing a zero (identity) rotation.
static let zero = Angle.radians(0)
static let zero: Angle = .radians(0)
/// Angle representing a quarter rotation.
static let halfPi = Angle.radians(.pi / 2)
static let halfPi: Angle = .radians(.pi / 2)
/// Angle representing a half-rotation.
static let pi = Angle.radians(.pi)
static let pi: Angle = .radians(.pi)
/// Angle representing a full rotation.
static let twoPi = Angle.radians(.pi * 2)
static let twoPi: Angle = .radians(.pi * 2)

/// The angle in degrees.
var degrees: Double {
Expand Down
21 changes: 15 additions & 6 deletions Sources/BSP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
struct BSP {
private var nodes: [BSPNode]
private(set) var isConvex: Bool
private(set) var isInverted: Bool
}

extension BSP {
Expand All @@ -45,9 +46,14 @@ extension BSP {
}

init(_ mesh: Mesh, _ isCancelled: CancellationHandler) {
self.init(mesh.polygons, isConvex: mesh.isKnownConvex, isCancelled)
}

init(_ polygons: [Polygon], isConvex: Bool, _ isCancelled: CancellationHandler) {
self.nodes = [BSPNode]()
self.isConvex = mesh.isKnownConvex
initialize(mesh.polygons, isCancelled)
self.isConvex = isConvex
self.isInverted = false
initialize(polygons, isCancelled)
}

func clip(
Expand Down Expand Up @@ -136,17 +142,20 @@ private extension BSP {
}

mutating func initialize(_ polygons: [Polygon], _ isCancelled: CancellationHandler) {
guard !polygons.isEmpty else {
return
}

var rng = DeterministicRNG()

guard isConvex else {
guard !polygons.isEmpty else {
return
}
let startPlane = polygons[0].plane
// Randomly shuffle polygons to reduce average number of splits
let polygons = polygons.shuffled(using: &rng)
nodes.reserveCapacity(polygons.count)
nodes.append(BSPNode(plane: polygons[0].plane))
nodes.append(BSPNode(plane: startPlane))
insert(polygons, isCancelled)
isInverted = containsPoint(startPlane.normal * .greatestFiniteMagnitude)
return
}

Expand Down
26 changes: 6 additions & 20 deletions Sources/Bounds.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public protocol Bounded {
var bounds: Bounds { get }
}

extension Bounds: CustomStringConvertible {
public var description: String {
"Bounds(min: [\(min.components)], max: [\(max.components)])"
}
}

extension Bounds: Codable {
private enum CodingKeys: CodingKey {
case min, max
Expand Down Expand Up @@ -125,26 +131,6 @@ public extension Bounds {
}
}

/// Deprecated.
@available(*, deprecated, renamed: "init(_:)")
init(points: [Vector] = []) {
self = points.reduce(.empty) {
Bounds(min: Euclid.min($0.min, $1), max: Euclid.max($0.max, $1))
}
}

/// Deprecated.
@available(*, deprecated, renamed: "init(_:)")
init(polygons: [Polygon]) {
self.init(polygons)
}

/// Deprecated.
@available(*, deprecated, renamed: "init(_:)")
init(bounds: [Bounds]) {
self.init(bounds)
}

/// A Boolean value that indicates whether the bounds is empty (has zero volume).
var isEmpty: Bool {
size == .zero
Expand Down
58 changes: 58 additions & 0 deletions Sources/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@
// SOFTWARE.
//

/// Protocol for types that can be converted to RGBA color components.
public protocol RGBAConvertible {
/// Get RGBA color components.
var rgbaComponents: (r: Double, g: Double, b: Double, a: Double) { get }
}

/// Protocol for types that can be represented by RGBA color components.
public protocol RGBARepresentable: RGBAConvertible {
/// Initialize with RGBA components.
/// - Parameters:
/// - r: The red component of the color, from 0 to 1.
/// - g: The green component of the color, from 0 to 1.
/// - b: The blue component of the color, from 0 to 1.
/// - a: The alpha component of the color, from 0 to 1.
init(r: Double, g: Double, b: Double, a: Double)
}

public extension RGBARepresentable {
/// Initialize with an RGBAConvertible value.
init(_ value: RGBAConvertible) {
let components = value.rgbaComponents
self.init(r: components.r, g: components.g, b: components.b, a: components.a)
}
}

/// A color in RGBA format.
///
/// Color can be used as a ``Polygon/material-swift.property`` or as a ``Vertex/color``.
Expand Down Expand Up @@ -56,6 +81,39 @@ public struct Color: Hashable, Sendable {
}
}

extension Color: Comparable {
/// Returns whether the leftmost color has the lower value.
/// This provides a stable order when sorting collections of colors.
public static func < (lhs: Color, rhs: Color) -> Bool {
guard lhs.r == rhs.r else { return lhs.r < rhs.r }
guard lhs.g == rhs.g else { return lhs.g < rhs.g }
guard lhs.b == rhs.b else { return lhs.b < rhs.b }
return lhs.a < rhs.a
}
}

extension Color: RGBARepresentable {
public var rgbaComponents: (r: Double, g: Double, b: Double, a: Double) {
(r, g, b, a)
}

public init(r: Double = 0, g: Double = 0, b: Double = 0, a: Double = 1) {
self.init(r, g, b, a)
}
}

extension Color: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Double...) {
self.init(unchecked: elements)
}
}

extension Color: CustomStringConvertible {
public var description: String {
"Color(\(r), \(g), \(b)\(a == 1 ? "" : ", \(a)"))"
}
}

extension Color: Codable {
private enum CodingKeys: String, CodingKey {
case r, g, b, a
Expand Down
Loading

0 comments on commit b417ae7

Please sign in to comment.