# Change Log ## [0.9.6](https://github.com/nicklockwood/Euclid/releases/tag/0.9.6) (2026-09-26) - Fixed non-zero fill normalization for detailed self-intersecting paths - Fixed watertight extrusion of overlapping compound paths - Fixed lofting of parallel transformed curved compound paths - Fixed nondeterministic cap material selection - Added additional cancellation callbacks for long-running operations ## [0.9.5](https://github.com/nicklockwood/Euclid/releases/tag/0.9.5) (2026-09-22) - Replaced the seeded convex hull implementation with Quickhull - Fixed multi-mesh union clipping against intermediate results instead of the original meshes - Fixed watertightness repair for complex meshes with large non-planar boundaries and branching edge graphs - Fixed polygon triangulation for shapes with shallow convex turns - Removed scanline artifacts and redundant cap fragments when filling or extruding compound paths - Compound path fills and extrusions now preserve vertex normals, colors, texcoords and material - Fixed compound path extrusion watertightness - Improved cancellation responsiveness for Minkowski operations and mesh repair - Updated `Color.debugDescription` to include component labels ## [0.9.4](https://github.com/nicklockwood/Euclid/releases/tag/0.9.4) (2026-09-12) - Fixed inset watertight capping for zero-area hole loops - Fixed extrusion of high-detail closed paths with repeated tail contours - Improved cancellation responsiveness for CSG, clipping, inset, fill and mesh repair operations - `Mesh.detessellate()` now works on large watertight meshes while preserving watertightness - `Mesh.detessellate()` and `Mesh.detriangulate()` now remove redundant vertices when this preserves watertightness - Added async RealityKit conversion APIs for `ModelEntity`, `ModelComponent` and `MeshResource` - Raised Xcode project deployment targets to macOS 12, iOS 15, tvOS 15 and watchOS 9 ## [0.9.3](https://github.com/nicklockwood/Euclid/releases/tag/0.9.3) (2026-09-07) - Fixed bug where `Mesh.detriangulate()` could break watertightness - `Mesh.detessellate()` no longer does expensive `isWatertight` check - `Mesh.detriangulate()` is now cancellable ## [0.9.2](https://github.com/nicklockwood/Euclid/releases/tag/0.9.2) (2026-09-02) - Fixed path extrusion when closed paths contain repeated tail points - Improved performance for complex polygon triangulation - Improved detessellation performance by pruning expensive merge candidates - Improved performance for large path geometry checks ## [0.9.1](https://github.com/nicklockwood/Euclid/releases/tag/0.9.1) (2026-08-30) - `Mesh.Faces`, `Mesh.WrapMode` and `Path.Alignment` now conform to `Hashable` and `Codable` ## [0.9.0](https://github.com/nicklockwood/Euclid/releases/tag/0.9.0) (2026-08-10) - Removed previously deprecated APIs - Dropped CocoaPods support - Raised minimum supported OS versions to macOS 10.15, iOS 14 and tvOS 14 - Updated `Color` API naming to better match Apple conventions - Added HSB support and additional named color constants - Added `MiterLimit` and `Path.withMiterLimit()` APIs - Added `WrapMode.box` and improved box, tube and cylinder texture mapping - Added `Mesh.withConsistentWinding()` method - Added `Mesh.ImportOptions` with `repairWinding` option - Enabled OBJ, OFF and STL file import/export APIs for WASM - Importing STL or OFF files now repairs inconsistent polygon winding by default - Made `Mesh.isPlanar` public and memoized - Made `Mesh.inset()`, `Mesh.detessellate()` and `Mesh.makeWatertight()` cancellable - Fixed `Mesh.convexHull()` stalling on detailed intersecting spheres - Fixed `Mesh.detessellate()` breaking watertightness in some cases - Fixed nondeterministic `Mesh.makeWatertight()` output - Fixed extrusion of multiple shapes along a path - Improved Minkowski mesh reordering heuristics ## [0.8.20](https://github.com/nicklockwood/Euclid/releases/tag/0.8.20) (2026-07-29) - Further improved `Path.inset()` and `Mesh.inset()` functionality - Inset now works more intuitively for planar meshes - Added a convenience method for extruding an array of paths - Extrude section count is now automatically computed from twist value - Fixed text paths sometimes being generated with inverted planes - Fixed assertion failures due to bad normalization assumptions - Icosphere primitive is now reliably watertight - Improved triangulation reliability ## [0.8.19](https://github.com/nicklockwood/Euclid/releases/tag/0.8.19) (2026-07-23) - Improved polygon detessellation and merge heuristics to produce cleaner output - Curvature is now preserved at the join when connecting subpaths - Fixed twisted internal faces in compound path extrusions - Fixed `Mesh.union()` behavior for disjoint watertight meshes - Fixed regression in intersecting path fill algorithm - Made polygon/path boundary edge ordering deterministic ## [0.8.18](https://github.com/nicklockwood/Euclid/releases/tag/0.8.18) (2026-07-13) - Added `Bounds.contains()` method - Fixed path extrusion regression for compound paths with multiple filled regions ## [0.8.17](https://github.com/nicklockwood/Euclid/releases/tag/0.8.17) (2026-07-13) - Compound path fills/lofts now use the even-odd fill rule again (broken in 0.8.16) - Fixed edge vertex normals for intersecting compound paths (broken in 0.8.16) - Fixed `Mesh.loft()` winding glitch when lofting closed shapes with matching edge counts - Fixed nondeterministic output from `Mesh.makeWatertight()` ## [0.8.16](https://github.com/nicklockwood/Euclid/releases/tag/0.8.16) (2026-07-10) - Added `Path.mapPoints()` and `PathPoint.withPosition()` methods - Fixed compound path transforms to preserve path planes correctly - Fixed bug where mutating a `PathPoint` position did not quantize the new value - Fixed precision issue when constructing near-vertical `Line` values - Fixed fill, loft and extrusion behavior for nested and self-intersecting paths - Improved `Mesh.makeWatertight()` so it can cap holes and repair inconsistent winding - Improved vertex normal smoothing and convex hull vertex normal extrapolation - Improved `Path.inset()`, `Polygon.inset()` and `Mesh.inset()` behavior, especially for complex shapes - Euclid now uses strict concurrency checking - Increased minimum Swift version to 5.10 ## [0.8.15](https://github.com/nicklockwood/Euclid/releases/tag/0.8.15) (2026-06-15) - Fixed bug where `Mesh.loft()` could produce invalid geometry for mismatched vertices - Importing an OFF file with negative index or face counts no longer crashes - Fixed bug when importing OBJ files that include normals but not texture coordinate - Fixed potential stack overflow in the OBJ file parser - Fixed bug where clipping a path to a mesh returned the wrong path fragment - Generation of curved primitives such as spheres or cylinders is now cancellable - Fixed bug in convex hull cancellation logic - Interleaved `SCNGeometrySource` channels are now handled correctly when importing `SCNGeometry` ## [0.8.14](https://github.com/nicklockwood/Euclid/releases/tag/0.8.14) (2026-01-03) - Fixed clampedToScaleLimit() behavior when scale is infinite (typically due to a divide by zero) - Fixed bug in `Mesh.convexHull()` when one or more mesh parameters are empty - Added `Mesh.mapPolygons()` method to optimize updates where geometry doesn't change ## [0.8.13](https://github.com/nicklockwood/Euclid/releases/tag/0.8.13) (2025-11-09) - Added `Mesh.minkowskiDifference()` function (inverse of `minkowskiSum()`) - Added divide and remainder functions for `Angle` type - Fixed missing vertices when using `Mesh.convexHull` or `minkowskiSum()` - Fixed incorrect normal calculation for extrusions along a path - Fixed angular misalignment with twisted extrusions - Fixed bug where lofting coplanar shapes produced inverted faces - Fixed `Path.orderedEdges` output for nested paths - Fixed spurious assertion when merging polygons - Improved `Mesh.convexHull()` performance by ~20% - Renamed `Polygon.center` to `centroid` ## [0.8.12](https://github.com/nicklockwood/Euclid/releases/tag/0.8.12) (2025-10-26) - Fixed crash when creating a path from empty subpaths - Fixed `Mesh.minkowskiSum()` output for off-center input meshes - Improved `Mesh.detesselate()` algorithm (now merges more polygons than before) - The `Path.closed()` method and `Path.isClosed` property now behave correctly for subpaths - Improved subpaths implementation (more reliably preserves distinct subpaths) - Fixed assertion in `Plane.init` for very small or degenerate triangles - Fixed assertion in internal `Polygon.insertPoint()` method - Fixed assertion in internal `detessellate()` method - Fixed bug with internal `sanitizePoints()` method introducing neighboring duplicate points - Deprecated optional cancellation handlers in `Path.clipped()` and `Polygon.clipped()` - Added optional `color` parameter to `Path.text()` constructor ## [0.8.11](https://github.com/nicklockwood/Euclid/releases/tag/0.8.11) (2025-10-12) - Fixed regression in `Mesh.loft()` method when one or more input paths has a single point - Made more long-running Mesh shape operations cancellable ## [0.8.10](https://github.com/nicklockwood/Euclid/releases/tag/0.8.10) (2025-10-05) - Fixed `Mesh.minkowskiSum(with: Path)` output when path has subpaths - Fixed vertex color blending logic for `Mesh.minkowskiSum()` and `Mesh.extrusion()` methods - Fixed bug with `Mesh.tessellate()` producing more than the optimal number of polygons - Added `Path.withDetail(_:twist:)` and `Path.withNormalizedPosition()` methods - Added `Path.hasColors` and `Path.hasTexcoords` properties - Improved `Path.init` ergonomics ## [0.8.9](https://github.com/nicklockwood/Euclid/releases/tag/0.8.9) (2025-09-22) - Fixed some bugs in `Polygon`/`Line` intersection logic - Fixed some bugs in `Bounds`/`Line` intersection logic - Checking if a vector lies inside a range now works as expected - Added some missing `LineComparable` conformances - Improved `Line.distance(from:)` performance ## [0.8.8](https://github.com/nicklockwood/Euclid/releases/tag/0.8.8) (2025-09-16) - Added `Path.clipped(to mesh:)` method - Added `Mesh.mapVertexColors()` method - Added `Mesh.init(objString:)` function for importing Wavefront OBJ mesh data - Added `Mesh.init(objString:)` function for importing Wavefront OBJ mesh data - Added OFF (Object File Format) import and export methods - Added memberwise multiplication operators for `Color` - Renamed `Polygon.init(shape:material:)` to `Polygon.init(_:material:)` - Renamed `Mesh.minkowskiSum(along:)` methods to `Mesh.minkowskiSum(with:)` - Deprecated `Mesh.init(url:ignoringTransforms:materialLookup:)` - The `Path.orderedEdges` property no longer returns an extra segment - Fixed crash in `Path.orderedEdges` and `Path.orderedEdges` - Fixed vertex color blending behavior for `Mesh.minkowskiSum()` methods - Fixed `Mesh.minkowskiSum()` with empty or single-point paths - Fixed `Mesh.minkowskiSum()` with non-convex polygons - Fixed `Mesh.convexHull()` bug with coplanar points - Improved mesh convexity logic ## [0.8.7](https://github.com/nicklockwood/Euclid/releases/tag/0.8.7) (2025-09-07) - Fixed bug where `convexHull()` created spurious internal polygons - Fixed precision issue with face-normal calculations - Meshes generated with `minkowskiSum()` now have deterministic polygon order - Added `Bounds.init(_ some Collection)` - Added `Bounds.minkowskiSum()` methods - Renamed `Mesh.volume` to `signedVolume` ## [0.8.6](https://github.com/nicklockwood/Euclid/releases/tag/0.8.6) (2025-08-31) - Added `Mesh.minkowskiSum()` methods - Significantly improved `Mesh.convexHull()` performance - `Mesh.convexHull()` methods are now cancellable - Added additional validation when deserializing meshes and polygons - Added `Mesh.clipped(to mesh:)` and `Polygon.clipped(to mesh:)` methods - Added `Path.clipped(to plane:)` and `Path.split(along plane:)` methods - Added methods for splitting and clipping `LineSegment` and collections of `LineSegment` - BSP (used for CSG operations) is now cached within a `Mesh` after first use - Various minor performance improvements - Added STL export options ## [0.8.5](https://github.com/nicklockwood/Euclid/releases/tag/0.8.5) (2025-08-29) - Fixed `Line.nearestPoint(to:)` method returning inverted value - The `Line.distance(from:)` method no longer returns zero for parallel lines - Fixed crashes when doing point comparisons on empty `Bounds` values - Edges split during line segment clipping are now rejoined automatically - Added some missing `Line` and `LineSegment` helpers - `Line` now conforms to the `Transformable` protocol ## [0.8.4](https://github.com/nicklockwood/Euclid/releases/tag/0.8.4) (2025-08-27) - Fixed incorrect `LineSegment.split()` function implementation - Fixed inconsistent behavior with line segment clipping at polygon edges ## [0.8.3](https://github.com/nicklockwood/Euclid/releases/tag/0.8.3) (2025-08-26) - Improved vertex merging algorithm (used to fix holes in imported meshes) - Deprecated unsafe `Polygon.mapVertices()` method - Fixed `flatteningNormals()` method ## [0.8.2](https://github.com/nicklockwood/Euclid/releases/tag/0.8.2) (2025-08-19) - Euclid `Vector` and `Color` types now conform to `ExpressibleByArrayLiteral` - Added more helpful `debugDescription` implementations for Euclid types - Added convenience initializers for `Vertex` to match `PathPoint` - Creating a Euclid `Mesh` from a RealityKit model now works more reliably - Fixed `triangulate()` failing on slightly non-planar polygons - Creating an open `Path` with collinear points no longer fails - Improved `Mesh.volume` and `Polygon.area` calculations - Improved `Plane` and face normal calculations ## [0.8.1](https://github.com/nicklockwood/Euclid/releases/tag/0.8.1) (2025-08-13) - Added volumetric 3D example for visionOS - Added support for RealityKit in tvOS 26.0 - Fixed tvOS builds in Xcode 26 ## [0.8.0](https://github.com/nicklockwood/Euclid/releases/tag/0.8.0) (2025-08-10) - Added `Interpolatable` protocol - Added `PointComparable`, `LineComparable` and `PlaneComparable` protocols - Added `Mesh.flatteningNormals()` method - Renamed `clip()` methods to `clipped()` - Renamed `Vector.distance()` to `signedDistance()` - Renamed/reordered `Transform` properties for consistency - Removed `Quaternion` type (`Rotation` is now a quaternion) - Removed deprecated methods - Updated minimum iOS/tvOS version to 12.0 - Updated to Swift 5.7 ## [0.7.16](https://github.com/nicklockwood/Euclid/releases/tag/0.7.16) (2025-07-31) - Fixed crash in `Path.curve()` when all points in the path are coincident ## [0.7.15](https://github.com/nicklockwood/Euclid/releases/tag/0.7.15) (2025-06-17) - Added `Rotation.init(from:to:)` initializer and deprecated `Vector.rotation(with:)` - Added `Path.inverted()` method - Improved `Path.rectangle()` logic and tests - Fixed incorrect `isWatertight` logic for loft shapes - Fixed several bugs in loft function that could cause corrupted output - Fixed some bugs in logic to compute rotations between vectors - Fixed incorrect logic for `Path.faceNormal` calculation - Fixed incorrect logic for negative path scaling ## [0.7.14](https://github.com/nicklockwood/Euclid/releases/tag/0.7.14) (2025-05-25) - Fixed bug with `Path.init(_ segments:)` when segments are very short - Added optional `color` parameter to `Path.init(_ segment:)` and `Path.init(_ segments:)` - Deprecated `Path.line(_ segment:color:)` ## [0.7.13](https://github.com/nicklockwood/Euclid/releases/tag/0.7.13) (2025-05-19) - Added function for subtracting a `Mesh` from a set of line segments - Fixed inverted `LineSegment.clip(to:)` plane clipping logic ## [0.7.12](https://github.com/nicklockwood/Euclid/releases/tag/0.7.12) (2025-05-10) - Added `Mesh.withoutVertexColors()` method - Added `Vector.distance(from:)` method - Fixed crash when extruding single-point paths - Fixed broken `hasVertexNormals` logic - Improved `Codable` encodings for `Polygon` and `Rotation` - Vector rotation now uses SIMD when available ## [0.7.11](https://github.com/nicklockwood/Euclid/releases/tag/0.7.11) (2025-04-15) - Added `Mesh.edges(intersecting mesh:)` method to get boundary between intersecting meshes - Added `LineSegment(undirected:)` initializers - Fixed some assertion failures in `Mesh.inset()` ## [0.7.10](https://github.com/nicklockwood/Euclid/releases/tag/0.7.10) (2025-04-05) - Added support for new RealityKit `Material` properties - Added `Mesh.volume` and `Mesh.surfaceArea` getters - Made `Mesh(_: MeshResource.Model)` and `Mesh(_: ModelComponent)` initializers public - Increased the tolerance for `isNormalized` checks - Fixed a deprecation warning ## [0.7.9](https://github.com/nicklockwood/Euclid/releases/tag/0.7.9) (2024-10-09) - Fixed extrusion along zero length path - Vertex normals are no longer automatically stripped for flat-shaded meshes - Added `Mesh.reflected(along:)`, `Polygon.reflected(along:)` and `Vertex.reflected(along:)` - Added `Mesh.inset(by:)`, `Polygon.inset(by:)` and `Path.inset(by:)` methods - Added `Mesh.icosphere()` primitive - Added `Mesh.subdivide()` and `Polygon.subdivide()` methods - Added `Polygon.mapVertices()` method ## [0.7.8](https://github.com/nicklockwood/Euclid/releases/tag/0.7.8) (2024-07-23) - Fixed some bugs with `Path` subpaths - Added support for watchOS ## [0.7.7](https://github.com/nicklockwood/Euclid/releases/tag/0.7.7) (2024-02-11) - Added method to create a `Path` from a set of `LineSegment`s - Improved decoding logic ## [0.7.6](https://github.com/nicklockwood/Euclid/releases/tag/0.7.6) (2024-01-31) - Fixed plane/line intersection bug ## [0.7.5](https://github.com/nicklockwood/Euclid/releases/tag/0.7.5) (2024-01-29) - Added I/O functions - Fixed transform not being applied to meshes created from a RealityKit `ModelEntity` - Materials are now preserved for meshes created from RealityKit models - Deprecated the `Quaternion` type in favor of `Rotation` ## [0.7.4](https://github.com/nicklockwood/Euclid/releases/tag/0.7.4) (2024-01-19) - Removed stray `print()` statement from RealityKit exporter - Added logic to correct SceneKit vertex colors - Added `Polygon.mapVertexColors()` method - Added `Path.mapColors()` method - Added vertex modifier methods ## [0.7.3](https://github.com/nicklockwood/Euclid/releases/tag/0.7.3) (2023-12-22) - Added support for converting RealityKit models to Euclid meshes - Added support for loading binary and ASCII STL files - Added visionOS support ## [0.7.2](https://github.com/nicklockwood/Euclid/releases/tag/0.7.2) (2023-12-10) - RealityKit texture downscaling now uses linear interpolation by default - Fixed edge case in `insertEdgePoint()` that caused assertion failures in debug mode - Made polygon convexity check more tolerant - Added camera controls to the RealityKit example project ## [0.7.1](https://github.com/nicklockwood/Euclid/releases/tag/0.7.1) (2023-09-27) - Added `Mesh.cubeMapped()` method - Removed stray `print()` statement ## [0.7.0](https://github.com/nicklockwood/Euclid/releases/tag/0.7.0) (2023-09-23) - Added `Mesh.icosahedron()` primitive - Added `Bounded` protocol for types that have a `bounds` property - Added `Mesh.sphereMapped()` and `Mesh.cylinderMapped()` methods - Added `Mesh.withTextureTransform()` method - Added `CGImage.checkerboard()` convenience method for testing textures - Added `WrapMode.none` option for creating meshes without texture coordinates - Added `Mesh.withMaterial()` method - Texture material coordinates now wrap by default - Texture materials now use nearest-neighbor upscaling by default - Added `stacks` parameter to cone primitive - Added `wrapMode` parameter to cube primitive - Removed minimum height for cone and cylinder primitives - Materials now use `NSSecureCoding` for serialization - Raised minimum supported macOS version to 10.14 - Raised minimum supported iOS version to 11 - Renamed various methods for consistency - Moved docs to main branch ## [0.6.18](https://github.com/nicklockwood/Euclid/releases/tag/0.6.18) (2023-09-22) - Fixed crash on iOS 16 when building with Xcode 15 - Fixed bug in `Path.subpaths` calculation - Added `Polygon.center` computed property - Added `LineSegment`/`Plane` intersection method - Added `Mesh.withoutTexcoords()` method - Redundant texture coordinates are now excluded from RealityKit export - Redundant vertex normals are now excluded from SceneKit export ## [0.6.17](https://github.com/nicklockwood/Euclid/releases/tag/0.6.17) (2023-08-22) - Added `Mesh.stlData()` function for exporting binary STL file data - Added `Mesh.objString()` function for exporting Wavefront OBJ mesh data ## [0.6.16](https://github.com/nicklockwood/Euclid/releases/tag/0.6.16) (2023-08-11) - Fixed `Mesh.stlString()` function ## [0.6.15](https://github.com/nicklockwood/Euclid/releases/tag/0.6.15) (2023-07-30) - Fixed assertion failure in `Polygon.tessellate()` function - Cone `poleDetail` now defaults to `3` instead of `sqrt(slices)` - Improved `Mesh.makeWatertight()` reliability - Improved `LineSegment` intersection detection - Increased threshold for `Plane.containsPoint()` ## [0.6.14](https://github.com/nicklockwood/Euclid/releases/tag/0.6.14) (2023-06-10) - Removed unreachable line flagged in Xcode 15 beta - Fixed some comments ## [0.6.13](https://github.com/nicklockwood/Euclid/releases/tag/0.6.13) (2023-04-22) - Added ASCII STL export function for Mesh - Added `isZero` and `isOne` convenience properties - Reduced cracking/holes for some meshes - Fixed extrusion precision issue ## [0.6.12](https://github.com/nicklockwood/Euclid/releases/tag/0.6.12) (2023-04-04) - Improved default `Path.arc()` segments heuristic - Connecting open subpaths now behaves as expected - Curved join between subpaths can now be overridden ## [0.6.11](https://github.com/nicklockwood/Euclid/releases/tag/0.6.11) (2023-03-02) - Added `Path.arc()` function - Add `Path.latheProfile` property ## [0.6.10](https://github.com/nicklockwood/Euclid/releases/tag/0.6.10) (2023-02-24) - Fixed a precision problem that caused holes when creating a `Mesh` from `SCNGeometry` - Fixed Linux and WASM builds (broken in 0.6.9) ## [0.6.9](https://github.com/nicklockwood/Euclid/releases/tag/0.6.9) (2023-02-09) - Fixed bug when triangulating convex polygons with collinear points - Fixed `Polygon.area` calculation for polygons not located on the XY plane - Fixed `submeshes` property for meshes formed using a union operation ## [0.6.8](https://github.com/nicklockwood/Euclid/releases/tag/0.6.8) (2023-01-16) - Fixed flipped front/back return values for `Mesh.split(along:)` function return value order - Fixed `Mesh.stroke(_ shapes:)` multi-path stroke function when used with open paths - Fixed `align` parameter in `Mesh.extrude(_:along:)` when the extruded shape has subpaths - Fixed internal `rotationBetweenVectors()` function when vectors are parallel and opposite - Fixed assertion failure in `Mesh.clip(to:)` when using `fill` argument - Fixed assertion inverted fill plane in `Mesh.clip(to:)` when input is inverted Z plane - Fixed bug where splitting planar mesh along its plane had no effect - Added `Polygon.split(along:)` and `Polygon.clip(to:)` methods ## [0.6.7](https://github.com/nicklockwood/Euclid/releases/tag/0.6.7) (2023-01-01) - Fixed use of duplicate cross-sections to create sharp junctions in `loft` shapes - Fixed `Path(polygon:)` initializer to create closed path and preserve colors - Added convenience initializers to convert between `Vertex` and `PathPoint` - Added `Path.with(color:)` and `PathPoint.with(color:)` helpers - Added `Mesh(submeshes:)` convenience initializer - Added convenience initializers for `Transform` - Removed obsolete backwards compatibility code ## [0.6.6](https://github.com/nicklockwood/Euclid/releases/tag/0.6.6) (2022-12-17) - Reduced compilation time for some complex expressions to fix Linux build ## [0.6.5](https://github.com/nicklockwood/Euclid/releases/tag/0.6.5) (2022-12-08) - Added `twist` and `sections` parameters for `Mesh.extrude()` methods - Angle correction is now distributed evenly along extrusion length - Added `Path.extrusionContours()` method - Fixed crash when angle is infinite or NaN - Fixed end caps for loft/extrusion shapes ## [0.6.4](https://github.com/nicklockwood/Euclid/releases/tag/0.6.4) (2022-11-21) - Improved default alignment heuristic when extruding along non-planar paths - Added `Alignment` enum for controlling shape alignment when extruding along a path - Fixed bug in face normal calculation for open paths - Added scalar multiply/divide operators for `Rotation` ## [0.6.3](https://github.com/nicklockwood/Euclid/releases/tag/0.6.3) (2022-11-17) - Fixed crash when extruding single-point path - Fixed `Quaternion.axis` when angle is zero - Disfavored `Angle.cos`/`sin`/`tan` overloads to improve ergonomics - Added `Polygon.area` property ## [0.6.2](https://github.com/nicklockwood/Euclid/releases/tag/0.6.2) (2022-11-05) - Added `Mesh.convexHull()` shape constructors - Added `Polygon.orderedEdges` property - Added `LineSegment.inverted()` method ## [0.6.1](https://github.com/nicklockwood/Euclid/releases/tag/0.6.1) (2022-11-02) - Added `Transformable` protocol for all types that can be transformed - Added initializer to create an `SCNMatrix4` from a `Transform` - Transformable types (`Vector`, `Polygon`, `Mesh`, etc.) now support in-place transforms - Swapped disfavored rotation method overloads from `Rotation` to `Quaternion` - Added transform methods and `Transformable` conformance to `LineSegment` - Normalized `Quaternion` at creation time (which fixes an assertion failure in `Plane`) - Attempting to load a `Mesh` from an inaccessible URL now throws instead of failing silently - Fixed assertion failure due to `sortedByPlane()` regression in 0.6.0 - Negative scale factors now behave as expected when applied to `Vertex` - Topology is now preserved when loading a `Mesh` from a URL ## [0.6.0](https://github.com/nicklockwood/Euclid/releases/tag/0.6.0) (2022-10-22) - Added support for rendering Euclid meshes using `RealityKit` - CSG polygon clip operations now run concurrently (Note: `isCancelled` may now be called on any thread) - Euclid `Rotation` now uses a quaternion representation internally rather than a 3x3 matrix - Rotations are now serialized as a more compact 4-element axis/angle array when using `Codable` - Added `axis` and `angle` property getters to `Rotation` and `Quaternion` - Added `slerp()` (spherical linear interpolation) method to `Rotation` - Added `Vector.unitX/Y/Z` constants - The material order when generating `SCNGeometry` is now deterministic - Euclid's `Quaternion` implementation now uses the SIMD framework if available - The `tessellate()` methods now accept an optional `maxSides:` argument - The `Angle` and `Vector` types now conform to the `AdditiveArithmetic` protocol - Polygon materials of type `CGColor` or `CGImage` are now supported automatically in SceneKit - Fixed some common assertion failures when running in debug mode - Improved performance when applying transforms with null/identity values - Removed previously deprecated methods and properties - Raised minimum supported iOS version to 11 ## [0.5.30](https://github.com/nicklockwood/Euclid/releases/tag/0.5.30) (2022-09-26) - Fixed bug where applying negative scale to bounds made it empty ## [0.5.29](https://github.com/nicklockwood/Euclid/releases/tag/0.5.29) (2022-09-03) - Fixed bug where transforming an empty bounds led to nan coordinates - Fixed assertion failure when flattening non-horizontal paths - Added `Mesh.containsPoint()` method - Improved some deprecation messages ## [0.5.28](https://github.com/nicklockwood/Euclid/releases/tag/0.5.28) (2022-08-12) - Fixed crash when bulk CSG methods were called with an empty array - Fixed incorrect result from bulk `Mesh.intersection()` method when input meshes are non-intersecting - Removed legacy behavior in `Mesh.union()` where polygon order was flipped unnecessarily - Bulk CSG methods now work with arbitrary `Collection`s of `Mesh`, not just an `Array` ## [0.5.27](https://github.com/nicklockwood/Euclid/releases/tag/0.5.27) (2022-08-06) - Added efficient methods for filling, extruding and stroking multiple paths - Imported meshes that contain non-planar polygons are now tessellated instead of having holes - Improved logic for removing hairline cracks in imported meshes - Fixed bug where material could be lost when triangulating/tessellating polygons - Fixed bug where `Mesh.submeshes` returned too many submeshes - Fixed retain cycle in `Mesh.submeshes` - Submeshes are now cached for faster access - All cancellation callbacks are now non-escaping ## [0.5.26](https://github.com/nicklockwood/Euclid/releases/tag/0.5.26) (2022-07-24) - SceneKit meshes are now more reliably sealed at import time - Improved triangulation/tessellation of complex convex polygons - Fixed case where `loft` could produce a mesh with redundant back-face polygons - You can now create `Path`s with a single point (useful when lofting) - Fixed crash when lofting zero-scale path - Fixed assertion failure when scaling path by zero vector - Reduced false negatives when comparing `Plane` equality - Improved performance of uniform `Plane` scaling - Added `Sendable` conformance to all applicable types when building with Xcode 14 - Converted unintended static `var` values to `let` - Fixed warnings in Xcode 14 beta ## [0.5.25](https://github.com/nicklockwood/Euclid/releases/tag/0.5.25) (2022-07-03) - Added `Mesh.submeshes` property - Loft now supports path sections with differing point counts - Fixed normals at joints between multipart loft or extrusion shapes - Fixed crash when lofting empty paths ## [0.5.24](https://github.com/nicklockwood/Euclid/releases/tag/0.5.24) (2022-06-26) - Fixed crash when extruding along collinear points - Fixed bug when lofting intermediate open paths - Improved `makeWatertight()` implementation - Improved vertex merging logic to only merge vertices that cause holes - Fixed bugs in triangulation logic that could introduce holes - Fixed case where mesh was incorrectly assumed to be watertight - Vector equality is now exact again, instead of using quantization internally - Fixed spurious assertion when using compound paths ## [0.5.23](https://github.com/nicklockwood/Euclid/releases/tag/0.5.23) (2022-06-09) - Fixed crash in `mergingSimilarVertices()` function - Used heuristic for `mergingSimilarVertices()` instead of hard-coded epsilon - Increased epsilon precision again to fix cracking issues (and added tests) ## [0.5.22](https://github.com/nicklockwood/Euclid/releases/tag/0.5.22) (2022-06-02) - Reduced epsilon precision to fix assertion when creating `Mesh` from `SCNGeometry` - Added WASM (Web Assembly) compatibility tests ## [0.5.21](https://github.com/nicklockwood/Euclid/releases/tag/0.5.21) (2022-05-28) - Fixed a glitch with how stroke or extrude-along was applied to paths with sharp corners - Fixed a bug where PathPoint colors were incorrectly applied for non-closed paths - The `pivot` property is now taken into account when creating `Mesh` from an `SCNNode` - Added ability to create a `Transform` from an `SCNMatrix4` - Fixed warnings in Xcode 13.4 ## [0.5.20](https://github.com/nicklockwood/Euclid/releases/tag/0.5.20) (2022-04-12) - Added input sanitization to `Angle.acos()` and `Angle.asin()` (fixes `Mesh.smoothNormals()`) - Changed `Mesh.smoothNormals()` threshold check from `<=` to `<` - Improved `Mesh.smoothNormals()` performance ## [0.5.19](https://github.com/nicklockwood/Euclid/releases/tag/0.5.19) (2022-04-11) - Improved `Mesh.makeWatertight()` reliability - Meshes created from SceneKit primitives are now watertight - Increased `LineSegment.containsPoint()` tolerance - Added `Mesh.detriangulate()` method - Added `Mesh.smoothNormals()` function ## [0.5.18](https://github.com/nicklockwood/Euclid/releases/tag/0.5.18) (2022-04-08) - Added `Mesh.empty` constant - Added `Path.roundedRectangle()` method - Fixed assertion failure due to incorrect `isWatertight` assumption - Fixed precision issue with `LineSegment.containsPoint()` method - The `Polygon(_: [Vector])` constructor now takes any `Vector` sequence - Added `Vector` -> `CGize` conversion functions - Renamed `Path(cgPath:)` to `Path(_:)` for consistency - Renamed `Mesh(text:)` constructor to `Mesh.text()` - Replaced broken `SCNNode`/`URL` Mesh initializers - Deprecated `Vector.quantized()` method - Fixed warnings in Xcode 13.3 ## [0.5.17](https://github.com/nicklockwood/Euclid/releases/tag/0.5.17) (2022-02-23) - Euclid now includes full DocC documentation (big thanks to Joseph Heck for making this happen) - Fixed unused vertex color parameter in `Path.line()` constructor - Added missing `w` component to `Quaternion.components` property - Fixed unused detail argument in `Mesh(text:)` constructor - Fixed a bug in the `faceNormalForPolygonPoints()` utility function - Fixed bug in `Plane.intersection(with: Plane)` calculation ## [0.5.16](https://github.com/nicklockwood/Euclid/releases/tag/0.5.16) (2022-01-04) - Added `Vertex.color` property - Added `PathPoint.color` property - Added `color` parameters for `Path` constructors - Added `lerp()` functions for `Color` collections - Added check to skip all-zero texture coordinates when exporting to SceneKit ## [0.5.15](https://github.com/nicklockwood/Euclid/releases/tag/0.5.15) (2021-12-22) - Added `Mesh.makeWatertight()` method, for removing hairline cracks in meshes - Vector `==` operator now returns approximate equality, solving some issues with quantization - The `Mesh.isWatertight` getter is now a stored property, so cheaper to access - Added unordered min/max point initializer for `Bounds` - Added convenience initializer for uniform-sized Vectors - Fixed assertion failure when creating a polygon with < 3 points - Improved performance for `Mesh.polygonsByMaterial` getter - Added `Mesh.edges(intersecting:)` method - Added `Bounds.inset()` methods ## [0.5.14](https://github.com/nicklockwood/Euclid/releases/tag/0.5.14) (2021-11-01) - Added support for `triangleStrip` and `polygon` primitives when creating a `Mesh` from `SCNGeometry` - Creating a `Mesh` from an `SCNGeometry` now returns nil if the mesh can't be loaded ## [0.5.13](https://github.com/nicklockwood/Euclid/releases/tag/0.5.13) (2021-10-15) - Fixed support for Mac Catalyst ## [0.5.12](https://github.com/nicklockwood/Euclid/releases/tag/0.5.12) (2021-09-12) - Added `Quaternion` type as an alternative representation for rotations - The `Rotation.pitch`/`yaw`/`roll` properties should now return correct values - Fixed bug when defining a zero-width rectangle path - Fixed bug when encoding vertices with zeroed normals ## [0.5.11](https://github.com/nicklockwood/Euclid/releases/tag/0.5.11) (2021-09-03) - Added `Mesh.stroke()` function variant for generating wireframes - Added `Mesh.loft()` optimization for common cases - Added optimized `Mesh.merge()` function for merging multiple meshes at once - Added `Bounds.formUnion()` and `Bounds.formIntersection()` functions - Added fast-path optimization for `Polygon.triangulate()` - Improved compilation time for the CSG `Mesh.union()` function - Deprecated `Mesh.scaleCorrected()` and `Polygon.scaleCorrected()` - Tweaked `Bounds.isEmpty` logic so that zero volume counts as empty ## [0.5.10](https://github.com/nicklockwood/Euclid/releases/tag/0.5.10) (2021-08-30) - Added `Color` type for convenient cross-platform color materials - Fixed bug when calculating face normal for very small paths - Texture coordinates are now preserved when using the `Path.curve()` constructor - Fixed bug where `Angle.atan()` was actually calling `tan()` instead - Added `Path.line()` constructor for creating straight lines - Added `Path.polygon()` constructor for creating regular polygons - Added `Path.text(_:font:)` convenience constructor - Improved `Mesh.stroke()` constructor to allow for variable detail ## [0.5.9](https://github.com/nicklockwood/Euclid/releases/tag/0.5.9) (2021-08-19) - Fixed relative orientation when extruding along a path - Fixed missing face polygons when extruding along a complex shape such as text - Fixed back-face duplication when lofting a line shape - Fixed assertion in `Path(points:)` when creating a simple line shape - Fixed assertion when lofting complex shapes like text ## [0.5.8](https://github.com/nicklockwood/Euclid/releases/tag/0.5.8) (2021-08-15) - Fixed several bugs in `Polygon` validation that could lead to cracks in generated meshes - Fixed spurious assertion in `Path(points:)` initializer ## [0.5.7](https://github.com/nicklockwood/Euclid/releases/tag/0.5.7) (2021-08-13) - Fixed a regression in `SCNGeometry(_ path:)` introduced in version 0.3.6 ## [0.5.6](https://github.com/nicklockwood/Euclid/releases/tag/0.5.6) (2021-08-10) - Fixed axis alignment bug when extruding complex shapes along a custom path - Increased epsilon precision to fix mesh corruption issues in extruded text paths ## [0.5.5](https://github.com/nicklockwood/Euclid/releases/tag/0.5.5) (2021-08-09) - Vertices with zero normals are automatically corrected to use the face normal - Vertex normals are now optional - Polygons can now be created from an array of vector positions (normals are set automatically) - Imported models are now converted to use Y-up automatically, matching SceneKit convention ## [0.5.4](https://github.com/nicklockwood/Euclid/releases/tag/0.5.4) (2021-08-04) - Fixed a regression in `Mesh.fill()` introduced in 0.5.0 that affected nested paths (e.g. text) - Fixed a bug in the calculation of vertex normals for non-planar paths - Fixed a bug where extruding non-planar paths could result in an inside-out mesh - Lengthy CSG operations can now be interrupted by using the optional `isCancelled` callback - Improved `Mesh.xor()` and `Mesh.stencil()` performance by merging CSG steps - Self-intersecting paths can now be lathed - Added `Path.stroke()` method ## [0.5.3](https://github.com/nicklockwood/Euclid/releases/tag/0.5.3) (2021-07-30) - Slightly improved the performance of bounds checking during CSG operations - The `Polygon.bounds` is no longer a stored property, which should reduce memory footprint - Coincident `Line`s will now always be equal, even if initialized with a different `origin` - Fixed a bug where Z component was ignored when testing for `LineSegment` intersection - Fixed a performance regression in `Vector.distance(from: Plane)`, introduced in version 0.5.0 - Added `min()`/`max()` functions for component-wise comparison of `Vector`s - Added `Line.intersection(with: Plane)` method ## [0.5.2](https://github.com/nicklockwood/Euclid/releases/tag/0.5.2) (2021-07-28) - Fixed some bugs when serializing texture coordinates with a non-zero Z component - Fixed assertion in `shortestLineBetween()` utility function - Fixed spurious assertion in `LineSegment` initializer - The identity `Rotation` is now encoded more compactly when serializing - Added a more compact serialized encoding for `Line` and `LineSegment` - Added `Vector(size:)` initializer with better defaults for size/scale vectors ## [0.5.1](https://github.com/nicklockwood/Euclid/releases/tag/0.5.1) (2021-07-25) - Added `LineSegment.containsPoint()` method - Added `Mesh.isWatertight` property to determine if a mesh contains holes - Reduced BSP construction time when performing CSG operations on convex meshes - Fixed edge case where `Mesh.detessellate()` function would fail to merge adjacent polygons - Fixed bug where CSG operations would sometimes unnecessarily tesselate polygons - Improved back-face insertion logic for lofted paths ## [0.5.0](https://github.com/nicklockwood/Euclid/releases/tag/0.5.0) (2021-07-12) - Added `Mesh.detessellate()` method and `Mesh.uniqueEdges` property - `Mesh` initializer no longer tessellates non-convex polygons automatically - Added methods for computing intersections and distances between points, planes and lines - `Line` and `LineSegment` intersection methods now correctly work for lines in different planes - `Polygon` initializer now rejects vertices that would form self-intersecting edges - Fixed crash when attempting to create fill or lathe meshes from self-intersecting paths - Fixed certain cases where `Path.edgeVertices` would produce inverted normals - Added method to easily create a `Path` from a `Polygon` - Texture coordinates with a non-zero Z component are now serialized correctly - Added optional `texcoord` property to `PathPoint`s - The `Mesh.fill()`, `Mesh.extrude()` and `Mesh.loft()` methods now work with non-planar paths - The `Path.faceVertices` property now works correctly for non-planar paths - Added `Path.facePolygons()` method for filling non-planar paths ## [0.4.7](https://github.com/nicklockwood/Euclid/releases/tag/0.4.7) (2021-07-09) - Fixed tessellation bug affecting anti-clockwise polygons - Fixed bug where `Mesh(url:materialLookup:)` initializer ignored `materialLookup:` parameter - Made `SCNGeometry(polygons:)` `materialLookup:` callback return value optional for consistency ## [0.4.6](https://github.com/nicklockwood/Euclid/releases/tag/0.4.6) (2021-07-04) - Fixed bug in Path plane calculation that could result in corrupted extrusion shapes - Fixed edge case in logic for detecting degenerate polygons - Added +=, -=, *= and /= Vector operators - Added `Vector.translated(by:)` function ## [0.4.5](https://github.com/nicklockwood/Euclid/releases/tag/0.4.5) (2021-06-26) - Rewrote CSG operations to use iteration rather than recursion, so they no longer overflow stack - Add methods to create a Mesh from an SCNNode or file url (in any ModelIO-supported format) - Removed spurious assertion failure when creating paths with multiple subpaths ## [0.4.4](https://github.com/nicklockwood/Euclid/releases/tag/0.4.4) (2021-04-27) - Fixed glitch in CSG operations on multiple meshes - Improved performance for CSG functions on non-convex meshes ## [0.4.3](https://github.com/nicklockwood/Euclid/releases/tag/0.4.3) (2021-04-24) - Added up, right, forward vectors to Rotation - Removed unused file ## [0.4.2](https://github.com/nicklockwood/Euclid/releases/tag/0.4.2) (2021-04-16) - Reduced size of serialized mesh data by ~50% - Materials are now deduplicated when encoding/decoding - Fixed bug when decoding serialized rotation values ## [0.4.1](https://github.com/nicklockwood/Euclid/releases/tag/0.4.1) (2021-04-14) - Fixed bug with encoding texture coordinates - Material property is no longer encoded for polygons if nil ## [0.4.0](https://github.com/nicklockwood/Euclid/releases/tag/0.4.0) (2021-04-04) - Added type-safe Angle API replacing raw Doubles - Added plane intersection and direction utility functions - Upgraded project to Swift 5.1 ## [0.3.6](https://github.com/nicklockwood/Euclid/releases/tag/0.3.6) (2020-11-22) - Euclid types now conform to Codable for easy serialization - Added default implementation for SCNMaterial mapping - Fixed bug where SCNGeometry detail argument was ignored - Added missing Embed Frameworks phase to example app ## [0.3.5](https://github.com/nicklockwood/Euclid/releases/tag/0.3.5) (2020-09-03) - Fixed bug with loft function when two edges are not parallel, resulting in a non-planar polygon ## [0.3.4](https://github.com/nicklockwood/Euclid/releases/tag/0.3.4) (2020-05-23) - Fixed issue where shapes extruded a long a path were sometimes tilted (not perpendicular to path) - Fixed internal random number generator (broken by a change introduced in Swift 5.2) - Simplified path to SCNGeometry conversion ## [0.3.3](https://github.com/nicklockwood/Euclid/releases/tag/0.3.3) (2020-04-13) - Fixed a precision issue when forming unions between meshes with coinciding surfaces ## [0.3.2](https://github.com/nicklockwood/Euclid/releases/tag/0.3.2) (2020-04-12) - Added ability to extrude a shape along a path ## [0.3.1](https://github.com/nicklockwood/Euclid/releases/tag/0.3.1) (2020-03-22) - Fixed a bug where cubic bezier components of `CGPath`s were not handled correctly - Fixed some bugs in the plane clipping algorithm - Slightly reduced compilation time ## [0.3.0](https://github.com/nicklockwood/Euclid/releases/tag/0.3.0) (2020-01-22) - Significantly improved performance for CSG functions, especially for convex meshes - Fixed bug where `Path.circle` and `Path.ellipse` could produce unclosed polygon - `Mesh.polygons` is now read-only. Use initializer or `merge` functions to modify mesh - Added mesh tessellation/inversion methods ## [0.2.3](https://github.com/nicklockwood/Euclid/releases/tag/0.2.3) (2020-01-14) - Improved CSG performance by another 2X by converting Polygon to a reference type internally - Improved `polygonsByMaterial` getter for Mesh, which also speeds up conversion to SceneKit Geometry ## [0.2.2](https://github.com/nicklockwood/Euclid/releases/tag/0.2.2) (2020-01-11) - Fixed infinite loop when constructing BSP for CSG operations - Clip to plane function now fills correctly if plane does not pass through the origin - LineSegment initializer is now public ## [0.2.1](https://github.com/nicklockwood/Euclid/releases/tag/0.2.1) (2020-01-11) - Improved CSG performance by 2X on average - Added methods for clipping or splitting a Mesh along a Plane - Added computed components property to Vector - Added methods to compute distance and projection between a point and Plane - Fixed some bugs relating to coplanar polygon clipping ## [0.2.0](https://github.com/nicklockwood/Euclid/releases/tag/0.2.0) (2020-01-04) - Added Swift 5 compatibility fixes - Added Line and LineSegment types - Unified iOS and macOS framework targets ## [0.1.9](https://github.com/nicklockwood/Euclid/releases/tag/0.1.9) (2019-04-03) - Fixed polygon triangulation edge case - Improved automatic sanitization of paths with degenerate vertices - Paths with subpaths now display correctly when rendered with SceneKit - Further improved text rendering performance - Added methods for transforming planes ## [0.1.8](https://github.com/nicklockwood/Euclid/releases/tag/0.1.8) (2019-03-28) - Added support for multiple subpaths within a single Path instance - CGPaths can now be converted to a single Path instead of an array of subpaths - Added methods for performing bulk CSG operations on arrays of meshes - Improved text rendering performance ## [0.1.7](https://github.com/nicklockwood/Euclid/releases/tag/0.1.7) (2019-03-11) - Added support for creating Euclid Paths from a Core Graphics CGPath - Added support for rendering 2D or extruded 3D text using Core Text - Fixed some bugs in triangulation that occasionally caused concave polygons not to render - Fixed a bug where material was not set correctly for extrusions with a depth of zero - Added XOR CSG function (useful for rendering text) - Added ellipse constructor for Path ## [0.1.6](https://github.com/nicklockwood/Euclid/releases/tag/0.1.6) (2019-02-27) - Improved CSG operations on coplanar polygons - Default radius for circle Path is now 0.5 instead of 1.0 - Added Linux test suite ## [0.1.5](https://github.com/nicklockwood/Euclid/releases/tag/0.1.5) (2019-01-21) - Reduced epsilon value in order to avoid precision-related bugs - Fixed an occasional assertion failure in triangulation logic - Polygon initializer now checks that points are planar - Mesh and Polygon now conform to Hashable - Added ability to convert SceneKit geometry back to a Mesh ## [0.1.4](https://github.com/nicklockwood/Euclid/releases/tag/0.1.4) (2019-01-09) - Fixed bug with Vector transform application order (also affected Bounds calculation) ## [0.1.3](https://github.com/nicklockwood/Euclid/releases/tag/0.1.3) (2018-12-19) - Fixed bug in Plane calculation for closed Paths ## [0.1.2](https://github.com/nicklockwood/Euclid/releases/tag/0.1.2) (2018-12-14) - Polygon constructor now accepts concave vertices - Added missing transform methods - Improved polygon merging performance - Improved tessellation algorithm ## [0.1.1](https://github.com/nicklockwood/Euclid/releases/tag/0.1.1) (2018-12-12) - Fixed some bugs in the order of application of Transforms - Fixed mixed up pitch, yaw and roll logic ## [0.1.0](https://github.com/nicklockwood/Euclid/releases/tag/0.1.0) (2018-12-11) - First release