Link Search Menu Expand Document

Document — Mesh I/O, Projection & Shape Fixing

This page covers the low-level mesh-iteration types, interference and ancestry helpers, shape-manipulation extensions, curve/surface extras, full projection and distance classes, shape-fixing wrappers, BSpline mutation methods, the low-level TopoDS_Builder extensions, free-bounds analysis, incremental wire building, tolerance-aware booleans, offset and thick-solid operations, mass-property expansions, and the Helix geometry namespace. All are declared in Sources/OCCTSwift/Document.swift across four consecutive // MARK: sections.

See the main Document page for the XDE document, assembly, colour, GD&T, and OCAF attribute APIs.

Topics


RWMesh Iterators, Intf Tool, BRepAlgo AsDes, BiTgte, Shape Extras, Extrema

MeshFaceIterator

Iterator over triangulated faces of a meshed Shape.

public final class MeshFaceIterator: @unchecked Sendable

The shape must already be meshed (e.g. via Shape.mesh(linearDeflection:angularDeflection:)) before creating this iterator.

  • OCCT: RWMesh_FaceIterator.

MeshFaceIterator.init(shape:)

Create a face iterator over a meshed shape.

public init?(shape: Shape)
  • Parameters: shape — a Shape with an existing Poly_Triangulation on its faces.
  • Returns: An iterator positioned before the first face, or nil on failure.
  • OCCT: OCCTMeshFaceIterCreateRWMesh_FaceIterator.
  • Example:
    let box = Shape.box(width: 10, height: 10, depth: 10)!
    _ = box.mesh(linearDeflection: 0.1, angularDeflection: 0.5)
    if let iter = MeshFaceIterator(shape: box) {
        while iter.hasMore {
            print("triangles:", iter.triangleCount)
            iter.next()
        }
    }
    

MeshFaceIterator.hasMore

Whether the iterator has more faces remaining.

public var hasMore: Bool { get }
  • OCCT: RWMesh_FaceIterator::More.

MeshFaceIterator.next()

Advance to the next face.

public func next()
  • OCCT: RWMesh_FaceIterator::Next.

MeshFaceIterator.nodeCount

Number of nodes in the current face triangulation.

public var nodeCount: Int { get }
  • OCCT: Poly_Triangulation::NbNodes.

MeshFaceIterator.triangleCount

Number of triangles in the current face triangulation.

public var triangleCount: Int { get }
  • OCCT: Poly_Triangulation::NbTriangles.

MeshFaceIterator.node(at:)

Get the 3D position of the node at a 1-based index.

public func node(at index: Int) -> SIMD3<Double>
  • Parameters: index — 1-based node index (1 … nodeCount).
  • Returns: Node position in model space.
  • OCCT: Poly_Triangulation::Node.

MeshFaceIterator.hasNormals

Whether the current face has per-node normals.

public var hasNormals: Bool { get }
  • OCCT: Poly_Triangulation::HasNormals.

MeshFaceIterator.normal(at:)

Get the surface normal at a 1-based node index.

public func normal(at index: Int) -> SIMD3<Double>
  • Parameters: index — 1-based node index.
  • Returns: Normal vector (not guaranteed to be unit length if the mesh was built without normals).
  • OCCT: Poly_Triangulation::Normal.

MeshFaceIterator.triangle(at:)

Get the three node indices of a triangle at a 1-based triangle index.

public func triangle(at index: Int) -> (n1: Int, n2: Int, n3: Int)
  • Parameters: index — 1-based triangle index (1 … triangleCount).
  • Returns: A tuple of three 1-based node indices.
  • OCCT: Poly_Triangulation::Triangle.
  • Example:
    if let iter = MeshFaceIterator(shape: box) {
        while iter.hasMore {
            for t in 1...iter.triangleCount {
                let tri = iter.triangle(at: t)
                let p1 = iter.node(at: tri.n1)
                let p2 = iter.node(at: tri.n2)
                let p3 = iter.node(at: tri.n3)
                _ = (p1, p2, p3)
            }
            iter.next()
        }
    }
    

MeshVertexIterator

Iterator over vertices of a shape.

public final class MeshVertexIterator: @unchecked Sendable
  • OCCT: RWMesh_VertexIterator.

MeshVertexIterator.init(shape:)

Create a vertex iterator over a shape.

public init?(shape: Shape)
  • Parameters: shape — the shape to iterate.
  • Returns: An iterator, or nil on failure.
  • OCCT: OCCTMeshVertexIterCreateRWMesh_VertexIterator.
  • Example:
    if let iter = MeshVertexIterator(shape: box) {
        while iter.hasMore {
            print(iter.point)
            iter.next()
        }
    }
    

MeshVertexIterator.hasMore

Whether the iterator has more vertices remaining.

public var hasMore: Bool { get }

MeshVertexIterator.next()

Advance to the next vertex.

public func next()

MeshVertexIterator.point

The 3D position of the current vertex.

public var point: SIMD3<Double> { get }
  • OCCT: BRep_Tool::Pnt on the current TopoDS_Vertex.

IntfTool

Line-box clipping utility wrapping Intf_Tool.

public final class IntfTool: @unchecked Sendable

Computes the parameter intervals where an infinite line intersects an axis-aligned bounding box.


IntfTool.init()

Create a new IntfTool instance.

public init()
  • OCCT: OCCTIntfToolCreateIntf_Tool.

IntfTool.clipLineToBox(lineOrigin:lineDirection:boxMin:boxMax:)

Clip a line to an axis-aligned bounding box and return the number of intersection segments.

@discardableResult
public func clipLineToBox(
    lineOrigin: SIMD3<Double>, lineDirection: SIMD3<Double>,
    boxMin: SIMD3<Double>, boxMax: SIMD3<Double>
) -> Int
  • Parameters:
    • lineOrigin — any point on the line.
    • lineDirection — direction vector of the line (need not be normalised).
    • boxMin, boxMax — corner extremes of the axis-aligned bounding box.
  • Returns: Number of intersection segments (0, 1, or 2).
  • OCCT: Intf_Tool::LinBox.
  • Example:
    let tool = IntfTool()
    let n = tool.clipLineToBox(
        lineOrigin: SIMD3(0, 0, 0), lineDirection: SIMD3(1, 0, 0),
        boxMin: SIMD3(-5, -5, -5), boxMax: SIMD3(5, 5, 5))
    if n > 0 {
        print("enters at t =", tool.beginParam(segment: 1))
        print("exits at t =", tool.endParam(segment: 1))
    }
    

IntfTool.beginParam(segment:)

Get the entry parameter of a clipped segment.

public func beginParam(segment: Int) -> Double
  • Parameters: segment — 1-based segment index.
  • OCCT: Intf_Tool::BeginParam.

IntfTool.endParam(segment:)

Get the exit parameter of a clipped segment.

public func endParam(segment: Int) -> Double
  • Parameters: segment — 1-based segment index.
  • OCCT: Intf_Tool::EndParam.

AsDesTracker

Ascendant-descendant relationship tracker wrapping BRepAlgo_AsDes.

public final class AsDesTracker: @unchecked Sendable

Used internally by filleting and other operations to record how new shapes descend from originals.


AsDesTracker.init()

Create an empty ascendant-descendant tracker.

public init()
  • OCCT: OCCTAsDesCreateBRepAlgo_AsDes.

AsDesTracker.add(parent:child:)

Record a parent-child (ascendant-descendant) relationship.

public func add(parent: Shape, child: Shape)
  • OCCT: BRepAlgo_AsDes::Add.

AsDesTracker.hasDescendant(_:)

Check whether a shape has any recorded descendants.

public func hasDescendant(_ shape: Shape) -> Bool
  • OCCT: BRepAlgo_AsDes::HasDescendant.

AsDesTracker.descendantCount(_:)

Get the number of descendants recorded for a shape.

public func descendantCount(_ shape: Shape) -> Int
  • OCCT: BRepAlgo_AsDes::Descendant count.
  • Example:
    let tracker = AsDesTracker()
    let box = Shape.box(width: 10, height: 10, depth: 10)!
    let face = box.faces().first!
    tracker.add(parent: box, child: face)
    print(tracker.hasDescendant(box))        // true
    print(tracker.descendantCount(box))      // 1
    

BiTgteCurveOnEdge

A curve defined by an edge lying on another edge, from blend operations (BiTgte_CurveOnEdge).

public final class BiTgteCurveOnEdge: @unchecked Sendable

| Member | Kind | Meaning | |—|—|—|


BiTgteCurveOnEdge.init(edgeOnFace:edge:)

Create a curve-on-edge from two edge shapes.

public init?(edgeOnFace: Shape, edge: Shape)
  • Parameters: edgeOnFace — the edge lying on a face; edge — the reference edge.
  • Returns: The curve-on-edge, or nil on failure.
  • OCCT: BiTgte_CurveOnEdge.

BiTgteCurveOnEdge.domain

Parameter domain of the curve.

public var domain: ClosedRange<Double> { get }
  • OCCT: BiTgte_CurveOnEdge::FirstParameter / LastParameter.

BiTgteCurveOnEdge.point(at:)

Evaluate the curve position at parameter u.

public func point(at u: Double) -> SIMD3<Double>
  • Parameters: u — curve parameter within domain.
  • OCCT: BiTgte_CurveOnEdge::Value.
  • Example:
    if let coe = BiTgteCurveOnEdge(edgeOnFace: edgeA, edge: edgeB) {
        let mid = (coe.domain.lowerBound + coe.domain.upperBound) / 2
        print(coe.point(at: mid))
    }
    

Shape.child(at:)

Get a direct child sub-shape at a 0-based index.

public func child(at index: Int) -> Shape?
  • Parameters: index — zero-based child index.
  • Returns: The child shape, or nil if index is out of range.
  • OCCT: TopoDS_Iterator (via OCCTShapeChild).

Shape.isLocked

Whether the shape is locked against modification.

public var isLocked: Bool { get }
  • OCCT: TopoDS_Shape::Locked.

Shape.setLocked(_:)

Set the locked state of the shape.

public func setLocked(_ locked: Bool)
  • OCCT: TopoDS_Shape::Locked.

Shape.located(matrix:)

Create a copy of this shape with a new location transform applied.

public func located(matrix: [Double]) -> Shape?
  • Parameters: matrix — at least 12 elements encoding a 4×3 row-major transform matrix (rows: x-axis, y-axis, z-axis, translation).
  • Returns: A new located shape, or nil if matrix.count < 12 or the operation fails.
  • OCCT: TopLoc_Location + TopoDS_Shape::Located (via OCCTShapeLocated).

Shape.locationMatrix

Get the current location as a 4×3 row-major matrix (12 elements).

public var locationMatrix: [Double] { get }
  • Returns: 12-element array; identity if no location is set.
  • OCCT: TopLoc_Location::IsIdentity / gp_Trsf::VectorialPart (via OCCTShapeGetLocation).

Shape.setLocation(matrix:)

Set the location transform in-place (4×3 row-major matrix).

public func setLocation(matrix: [Double])
  • Parameters: matrix — at least 12 elements. Silently ignored if matrix.count < 12.
  • OCCT: TopLoc_Location + TopoDS_Shape::Location (via OCCTShapeSetLocation).

Shape.oriented(_:)

Create a copy with a specific orientation.

public func oriented(_ orientation: Int) -> Shape?
  • Parameters: orientation0 = Forward, 1 = Reversed, 2 = Internal, 3 = External.
  • Returns: Oriented copy, or nil on failure.
  • OCCT: TopoDS_Shape::Oriented (via OCCTShapeOriented).

Shape.empty(type:)

Create an empty shape of the given topology type.

public static func empty(type: Int) -> Shape?
  • Parameters: type0 = Compound, 2 = Solid, 3 = Shell, 5 = Wire.
  • Returns: An empty shape of that type, or nil on failure.
  • OCCT: TopoDS_Shape with TopAbs_ShapeEnum (via OCCTShapeEmpty).

Shape.isCompound

Whether this shape is a compound.

public var isCompound: Bool { get }
  • OCCT: TopoDS_Shape::ShapeType == TopAbs_COMPOUND.

Shape.isSolid

Whether this shape is a solid.

public var isSolid: Bool { get }
  • OCCT: TopoDS_Shape::ShapeType == TopAbs_SOLID.

Shape.isShell

Whether this shape is a shell.

public var isShell: Bool { get }

Shape.isFace

Whether this shape is a face.

public var isFace: Bool { get }

Shape.isEdge

Whether this shape is an edge.

public var isEdge: Bool { get }

Shape.wireFromEdges(_:)

Create a wire from an array of edge shapes.

public static func wireFromEdges(_ edges: [Shape]) -> Shape?
  • Parameters: edges — array of edge shapes to connect.
  • Returns: A connected wire, or nil if the edges cannot be connected.
  • OCCT: BRepBuilderAPI_MakeWire (via OCCTMakeWireFromEdges).
  • Example:
    let e1 = Shape.edgeFromLine(from: .zero, to: SIMD3(10, 0, 0))!
    let e2 = Shape.edgeFromLine(from: SIMD3(10, 0, 0), to: SIMD3(10, 10, 0))!
    if let wire = Shape.wireFromEdges([e1, e2]) {
        print(wire.isValid)
    }
    

Shape.shellFromFaces(_:)

Create a shell from an array of face shapes.

public static func shellFromFaces(_ faces: [Shape]) -> Shape?
  • Parameters: faces — face shapes to assemble into a shell.
  • Returns: A shell, or nil on failure.
  • OCCT: BRepBuilderAPI_Sewing or TopoDS_Builder (via OCCTMakeShell).

Shape.checkFaceStatus(face:)

Check the validity status of a face within this shape.

public func checkFaceStatus(face: Shape) -> Int
  • Returns: A BRepCheck_Status integer; 0 = NoError.
  • OCCT: BRepCheck_AnalyzerBRepCheck_Face::Status (via OCCTCheckFaceStatus).

Shape.checkEdgeStatus(edge:)

Check the validity status of an edge within this shape.

public func checkEdgeStatus(edge: Shape) -> Int
  • Returns: A BRepCheck_Status integer; 0 = NoError.
  • OCCT: BRepCheck_AnalyzerBRepCheck_Edge::Status.

Shape.checkVertexStatus(vertex:)

Check the validity status of a vertex within this shape.

public func checkVertexStatus(vertex: Shape) -> Int
  • Returns: A BRepCheck_Status integer; 0 = NoError.
  • OCCT: BRepCheck_AnalyzerBRepCheck_Vertex::Status.

Shape.maxTolerance(type:)

Get the maximum tolerance of sub-shapes of the given type.

public func maxTolerance(type: Int) -> Double
  • Parameters: type0 = vertex, 1 = edge, 2 = face.
  • OCCT: ShapeAnalysis_ShapeTolerance::Tolerance with Standard_True (max).

Shape.minTolerance(type:)

Get the minimum tolerance of sub-shapes of the given type.

public func minTolerance(type: Int) -> Double
  • Parameters: type0 = vertex, 1 = edge, 2 = face.
  • OCCT: ShapeAnalysis_ShapeTolerance::Tolerance with Standard_False (min).

Shape.avgTolerance(type:)

Get the average tolerance of sub-shapes of the given type.

public func avgTolerance(type: Int) -> Double
  • Parameters: type0 = vertex, 1 = edge, 2 = face.
  • OCCT: ShapeAnalysis_ShapeTolerance::Tolerance with 0 (average mode).

Shape.fixTolerance(_:)

Fix the tolerance on all sub-shapes of this shape to a specific value.

@discardableResult
public func fixTolerance(_ tolerance: Double) -> Bool
  • Parameters: tolerance — target tolerance value.
  • Returns: true if the operation succeeded.
  • OCCT: ShapeFix_ShapeTolerance::SetTolerance (via OCCTShapeFixTolerance).

Shape.limitMaxTolerance(_:)

Limit the maximum tolerance on all sub-shapes to the given value.

@discardableResult
public func limitMaxTolerance(_ maxTol: Double) -> Bool
  • Parameters: maxTol — maximum allowed tolerance.
  • Returns: true if the limit was applied.
  • OCCT: ShapeFix_ShapeTolerance::LimitTolerance (via OCCTShapeLimitMaxTolerance).
  • Example:
    if let shape = Shape.box(width: 10, height: 10, depth: 10) {
        _ = shape.limitMaxTolerance(1e-4)
        print("max vertex tol:", shape.maxTolerance(type: 0))
    }
    

Curve3D.curveType

The geometric curve type integer.

public var curveType: Int { get }

Returns: 0 = Line, 1 = Circle, 2 = Ellipse, 3 = Hyperbola, 4 = Parabola, 5 = BezierCurve, 6 = BSplineCurve, 7 = Other.

  • OCCT: Geom_Curve dynamic type check (via OCCTCurve3DCurveType).

Curve3D.nearestParameter(to:)

Find the curve parameter nearest to a 3D point.

public func nearestParameter(to point: SIMD3<Double>) -> Double?
  • Parameters: point — the 3D query point.
  • Returns: The nearest parameter u on the curve, always inside its own domain, or nil if there is no curve to answer about.
  • OCCT: occtNearestPointOnCurveRange (via OCCTCurve3DNearestParameter) — the minimum over ShapeAnalysis_Curve, every GeomAPI_ProjectPointOnCurve extremum in range, and both ends.

The true nearest point, not the nearest perpendicular foot: a point past the end of a bounded curve is nearest to that end, and that is the answer. Agrees exactly with projectPoint(_:precision:), which shares its helper; until #615 this one reported an extremum instead, so the two disagreed about which point is nearest and about whether there was one.

Replaced parameterAtPoint(_:) and closestParameter(to:), both deprecated and removed at v2.0.0 (#784): they ran the identical projection and disagreed about how to report its absence (#500).


Curve2D.curveType

The geometric 2D curve type integer.

public var curveType: Int { get }

Returns same codes as Curve3D.curveType but for Geom2d_Curve.

  • OCCT: Geom2d_Curve dynamic type (via OCCTCurve2DCurveType).

Curve2D.nearestParameter(to:)

Find the 2D curve parameter nearest to a 2D point.

public func nearestParameter(to point: SIMD2<Double>) -> Double?
  • Returns: The nearest parameter, always inside the curve’s own domain, or nil if there is no curve to answer about. Agrees exactly with Curve2D.project(point:), Curve2D.project(_:) and Point2D.distance(to:), which share its bridge path (#413, #500, #615).
  • OCCT: occtNearestPointOnCurve2dRange (via OCCTCurve2DNearestParameter) — the minimum over every Geom2dAPI_ProjectPointOnCurve extremum in range and both ends. There is no third source: ShapeAnalysis_Curve has no 2D projection.

Curve2D.allProjections(of:) is not in that agreement, by design. It asks for the extrema, so it reports none where these four answer with an end — a point past the end of a bounded curve has a nearest point but no perpendicular foot. Before #615 all five agreed only because the other four were asking the extrema question too, and so were wrong.

Replaced parameterAtPoint(_:), deprecated and removed at v2.0.0 (#784): it reported the no-projection case as the curve’s own firstParameter.


Surface.surfaceType

The geometric surface type integer.

public var surfaceType: Int { get }

Returns: 0 = Plane, 1 = Cylinder, 2 = Cone, 3 = Sphere, 4 = Torus, … 10 = Other.

  • OCCT: Geom_Surface dynamic type (via OCCTSurfaceGetType).

Curve3D.locateNearestPoint(_:initParam:tolerance:)

Local point-on-curve search from an initial parameter guess.

public func locateNearestPoint(
    _ point: SIMD3<Double>,
    initParam: Double,
    tolerance: Double = 1e-6
) -> (parameter: Double, distance: Double)?
  • Parameters:
    • point — the 3D query point.
    • initParam — starting parameter for the local search.
    • tolerance — convergence tolerance.
  • Returns: (parameter, distance) tuple, or nil only if there is no curve to answer about.
  • OCCT: GeomAPI_ProjectPointOnCurve over a ±10% window around initParam, falling back to occtNearestPointOnCurveRange over the whole curve (via OCCTExtremaLocateOnCurve).

Two searches with two different contracts. The primary one reports the lowest-distance extremum inside that windowinitParam bounds the window, it does not rank what is found in it, so the extremum returned is not necessarily the one nearest the guess; where a window holds several, the one closest to the query point wins. The window is what makes the answer local, and a windowed minimum can still be a global maximum. On a half circle of radius 5 queried from (0, -6, 0) with a guess of .pi / 2 it reports 11, where the nearest point on the curve is 7.81 away. Use nearestParameter(to:) or projectPoint(_:precision:) when you want the global answer.

The fallback fires only when the window holds no extremum, at which point the search has already abandoned locality — so since #615 it reports the whole curve’s true nearest point, agreeing with those two. Before #615 it reported an extremum instead, so a guess sitting on the nearest point returned the point diametrically opposite it, and a bounded segment queried from past its own end returned nil for every guess.


Curve3D.projectPointAll(_:maxResults:)

Global point-to-curve projection returning all extrema.

public func projectPointAll(
    _ point: SIMD3<Double>,
    maxResults: Int = 10
) -> [(parameter: Double, distance: Double)]
  • Parameters:
    • point — the 3D query point.
    • maxResults — output capacity (default 10), clamped into 0...Sampling.maximumSampleCount (10,000,000); 0 or less returns empty (#622).
  • Returns: Array of (parameter, distance) pairs for every extremum found.
  • OCCT: GeomAPI_ExtremaCurveCurve / Extrema_ExtPC (via OCCTExtremaPointCurve).
  • Example:
    if let circle = Curve3D.circle(center: .zero, normal: SIMD3(0, 0, 1), radius: 5) {
        let results = circle.projectPointAll(SIMD3(3, 4, 0))
        for r in results { print("param:", r.parameter, "dist:", r.distance) }
    }
    

Surface.locateNearestPoint(_:initU:initV:tolerance:)

Local point-on-surface search from an initial (u, v) guess.

public func locateNearestPoint(
    _ point: SIMD3<Double>,
    initU: Double,
    initV: Double,
    tolerance: Double = 1e-6
) -> (u: Double, v: Double, distance: Double)?
  • Parameters:
    • point — the 3D query point.
    • initU, initV — starting UV parameters.
    • tolerance — convergence tolerance.
  • Returns: (u, v, distance) or nil on failure.
  • OCCT: Extrema_ExtPS local mode (via OCCTExtremaLocateOnSurface).

Surface.projectPointAll(_:maxResults:)

Global point-to-surface projection returning all extrema.

public func projectPointAll(
    _ point: SIMD3<Double>,
    maxResults: Int = 10
) -> [(u: Double, v: Double, distance: Double)]
  • Parameters: point — 3D query point; maxResults — output capacity (default 10), clamped into 0...Sampling.maximumSampleCount (10,000,000); 0 or less returns empty (#622).
  • Returns: Array of (u, v, distance) tuples for every extremum.
  • OCCT: GeomAPI_ProjectPointOnSurf (via OCCTExtremaPointSurface).

MakeEdge Completions, ProjOnCurve/Surf, DistShapeShape, ShapeFix Wire/Face

Shape.edgeFromEllipse(center:normal:majorRadius:minorRadius:)

Create a full closed ellipse edge.

public static func edgeFromEllipse(
    center: SIMD3<Double> = .zero,
    normal: SIMD3<Double> = SIMD3(0, 0, 1),
    majorRadius: Double,
    minorRadius: Double
) -> Shape?
  • Parameters: center — ellipse centre; normal — plane normal; majorRadius, minorRadius — semi-axes.
  • Returns: A closed ellipse edge, or nil on failure.
  • OCCT: BRepBuilderAPI_MakeEdge(gp_Elips) (via OCCTMakeEdgeFromEllipse).
  • Example:
    if let e = Shape.edgeFromEllipse(majorRadius: 10, minorRadius: 5) {
        print(e.isValid)
    }
    

Shape.edgeFromEllipseArc(center:normal:majorRadius:minorRadius:u1:u2:)

Create an ellipse arc edge between two parameter values.

public static func edgeFromEllipseArc(
    center: SIMD3<Double> = .zero,
    normal: SIMD3<Double> = SIMD3(0, 0, 1),
    majorRadius: Double,
    minorRadius: Double,
    u1: Double,
    u2: Double
) -> Shape?
  • Parameters: u1, u2 — start and end parameter angles (radians).
  • OCCT: BRepBuilderAPI_MakeEdge(gp_Elips, u1, u2) (via OCCTMakeEdgeFromEllipseArc).

Shape.edgeFromHyperbolaArc(center:normal:majorRadius:minorRadius:u1:u2:)

Create a hyperbola arc edge between two parameter values.

public static func edgeFromHyperbolaArc(
    center: SIMD3<Double> = .zero,
    normal: SIMD3<Double> = SIMD3(0, 0, 1),
    majorRadius: Double,
    minorRadius: Double,
    u1: Double,
    u2: Double
) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(gp_Hypr, u1, u2) (via OCCTMakeEdgeFromHyperbolaArc).

Shape.edgeFromParabolaArc(center:normal:focalLength:u1:u2:)

Create a parabola arc edge between two parameter values.

public static func edgeFromParabolaArc(
    center: SIMD3<Double> = .zero,
    normal: SIMD3<Double> = SIMD3(0, 0, 1),
    focalLength: Double,
    u1: Double,
    u2: Double
) -> Shape?
  • Parameters: focalLength — focal parameter of the parabola.
  • OCCT: BRepBuilderAPI_MakeEdge(gp_Parab, u1, u2) (via OCCTMakeEdgeFromParabolaArc).

Shape.edgeFromCurve(_:) (full domain)

Create an edge from a 3D curve over its full natural domain.

public static func edgeFromCurve(_ curve: Curve3D) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(Handle(Geom_Curve)) (via OCCTMakeEdgeFromCurve).

Shape.edgeFromCurve(_:u1:u2:)

Create an edge from a 3D curve trimmed to [u1, u2].

public static func edgeFromCurve(_ curve: Curve3D, u1: Double, u2: Double) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(Handle(Geom_Curve), u1, u2) (via OCCTMakeEdgeFromCurveParams).
  • Example:
    if let bsp = Curve3D.bspline(poles: pts, knots: ks, multiplicities: ms, degree: 3),
       let edge = Shape.edgeFromCurve(bsp, u1: 0, u2: 0.5) {
        print(edge.isValid)
    }
    

Shape.edgeFromCurve(_:from:to:)

Create an edge from a 3D curve bounded by two 3D points.

public static func edgeFromCurve(
    _ curve: Curve3D,
    from p1: SIMD3<Double>,
    to p2: SIMD3<Double>
) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(Handle(Geom_Curve), P1, P2) (via OCCTMakeEdgeFromCurvePoints).

Shape.edgeOnSurface(pcurve:surface:)

Create an edge from a 2D parametric curve on a surface (full domain).

public static func edgeOnSurface(pcurve: Curve2D, surface: Surface) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(Handle(Geom2d_Curve), Handle(Geom_Surface)) (via OCCTMakeEdgeOnSurface).

Shape.edgeOnSurface(pcurve:surface:u1:u2:)

Create an edge from a 2D parametric curve on a surface trimmed to [u1, u2].

public static func edgeOnSurface(
    pcurve: Curve2D,
    surface: Surface,
    u1: Double,
    u2: Double
) -> Shape?
  • OCCT: BRepBuilderAPI_MakeEdge(Handle(Geom2d_Curve), Handle(Geom_Surface), u1, u2) (via OCCTMakeEdgeOnSurfaceParams).

Shape.edgeVertex1()

Get the first vertex point of an edge shape.

public func edgeVertex1() -> SIMD3<Double>
  • Returns: The start vertex position. Returns SIMD3.zero if this shape is not an edge.
  • OCCT: BRep_Tool::Pnt on TopExp::FirstVertex (via OCCTEdgeVertex1).

Shape.edgeVertex2()

Get the last vertex point of an edge shape.

public func edgeVertex2() -> SIMD3<Double>
  • OCCT: BRep_Tool::Pnt on TopExp::LastVertex (via OCCTEdgeVertex2).

Shape.face(from:uBounds:vBounds:tolerance:)

Create a face from a surface with explicit UV bounds and tolerance.

public static func face(
    from surface: Surface,
    uBounds: ClosedRange<Double>,
    vBounds: ClosedRange<Double>,
    tolerance: Double = 1e-6
) -> Shape?
  • Parameters: surface — the underlying surface; uBounds, vBounds — parameter ranges; tolerance — construction tolerance.
  • OCCT: BRepBuilderAPI_MakeFace(surface, u1, u2, v1, v2, tol) (via OCCTMakeFaceFromSurfaceUV).

Shape.faceFromPlane(origin:normal:uBounds:vBounds:)

Create a planar face from a gp_Plane with UV bounds.

public static func faceFromPlane(
    origin: SIMD3<Double> = .zero,
    normal: SIMD3<Double> = SIMD3(0, 0, 1),
    uBounds: ClosedRange<Double>,
    vBounds: ClosedRange<Double>
) -> Shape?
  • OCCT: BRepBuilderAPI_MakeFace(gp_Pln, u1, u2, v1, v2) (via OCCTMakeFaceFromGpPlane).
  • Example:
    if let face = Shape.faceFromPlane(uBounds: -5...5, vBounds: -5...5) {
        print(face.isFace)  // true
    }
    

Shape.faceFromCylinder(origin:axis:radius:uBounds:vBounds:)

Create a cylindrical face from a gp_Cylinder with UV bounds.

public static func faceFromCylinder(
    origin: SIMD3<Double> = .zero,
    axis: SIMD3<Double> = SIMD3(0, 0, 1),
    radius: Double,
    uBounds: ClosedRange<Double>,
    vBounds: ClosedRange<Double>
) -> Shape?
  • Parameters: radius — cylinder radius; uBounds — angular range (radians); vBounds — axial height range.
  • OCCT: BRepBuilderAPI_MakeFace(gp_Cylinder, u1, u2, v1, v2) (via OCCTMakeFaceFromGpCylinder).

ProjectionOnCurve

Multi-result projection of a 3D point onto a 3D curve, wrapping GeomAPI_ProjectPointOnCurve.

public final class ProjectionOnCurve: @unchecked Sendable

ProjectionOnCurve.init(curve:point:)

Compute projections of a point onto a curve.

public init?(curve: Curve3D, point: SIMD3<Double>)
  • Parameters: curve — the target curve; point — the 3D point to project.
  • Returns: The projection object, or nil on failure.
  • OCCT: GeomAPI_ProjectPointOnCurve (via OCCTProjOnCurveCreate).

ProjectionOnCurve.count

Number of projection results.

public var count: Int { get }
  • OCCT: GeomAPI_ProjectPointOnCurve::NbPoints.

ProjectionOnCurve.point(at:)

Get the i-th projected point (0-based).

public func point(at index: Int) -> SIMD3<Double>
  • OCCT: GeomAPI_ProjectPointOnCurve::Point (1-based internally).

ProjectionOnCurve.parameter(at:)

Get the curve parameter of the i-th projection (0-based).

public func parameter(at index: Int) -> Double
  • OCCT: GeomAPI_ProjectPointOnCurve::Parameter.

ProjectionOnCurve.distance(at:)

Get the distance from the query point to the i-th projection (0-based).

public func distance(at index: Int) -> Double
  • OCCT: GeomAPI_ProjectPointOnCurve::Distance.

ProjectionOnCurve.lowerDistance

Minimum distance across all projection results.

public var lowerDistance: Double { get }
  • OCCT: GeomAPI_ProjectPointOnCurve::LowerDistance.

ProjectionOnCurve.lowerParameter

Curve parameter of the nearest projection.

public var lowerParameter: Double { get }
  • OCCT: GeomAPI_ProjectPointOnCurve::LowerDistanceParameter.
  • Example:
    if let circ = Curve3D.circle(center: .zero, normal: SIMD3(0,0,1), radius: 5),
       let proj = ProjectionOnCurve(curve: circ, point: SIMD3(3, 4, 0)) {
        print("nearest param:", proj.lowerParameter)
        print("nearest dist:", proj.lowerDistance)
    }
    

ProjectionOnSurface

Multi-result projection of a 3D point onto a surface, wrapping GeomAPI_ProjectPointOnSurf.

public final class ProjectionOnSurface: @unchecked Sendable

ProjectionOnSurface.init(surface:point:)

Compute projections of a point onto a surface.

public init?(surface: Surface, point: SIMD3<Double>)
  • OCCT: GeomAPI_ProjectPointOnSurf (via OCCTProjOnSurfCreate).

ProjectionOnSurface.count

Number of projection results.

public var count: Int { get }

ProjectionOnSurface.point(at:)

Get the i-th projected point (0-based).

public func point(at index: Int) -> SIMD3<Double>

ProjectionOnSurface.parameters(at:)

Get the (u, v) parameters of the i-th projection (0-based).

public func parameters(at index: Int) -> (u: Double, v: Double)
  • OCCT: GeomAPI_ProjectPointOnSurf::Parameters.

ProjectionOnSurface.distance(at:)

Get the distance from the query point to the i-th projection (0-based).

public func distance(at index: Int) -> Double

ProjectionOnSurface.lowerDistance

Minimum distance across all results.

public var lowerDistance: Double { get }

ProjectionOnSurface.lowerParameters

(u, v) of the nearest projection.

public var lowerParameters: (u: Double, v: Double) { get }
  • Example:
    if let plane = Surface.plane(),
       let proj = ProjectionOnSurface(surface: plane, point: SIMD3(3, 4, 5)) {
        let (u, v) = proj.lowerParameters
        print("nearest UV:", u, v)
    }
    

DistanceSupportType

The topology type of a distance solution support entity.

public enum DistanceSupportType: Int32, Sendable {
    case vertex = 0
    case edge   = 1
    case face   = 2
}

ShapeDistance

Full multi-result shape-to-shape distance computation wrapping BRepExtrema_DistShapeShape.

public final class ShapeDistance: @unchecked Sendable

ShapeDistance.init(shape1:shape2:)

Compute the distance between two shapes.

public init?(shape1: Shape, shape2: Shape)
  • Returns: The distance object, or nil on failure.
  • OCCT: BRepExtrema_DistShapeShape (via OCCTDistSSCreate).

ShapeDistance.isDone

Whether the distance computation succeeded.

public var isDone: Bool { get }

ShapeDistance.value

The minimum distance between the two shapes.

public var value: Double { get }
  • OCCT: BRepExtrema_DistShapeShape::Value.

ShapeDistance.solutionCount

Number of distance solutions found.

public var solutionCount: Int { get }
  • OCCT: BRepExtrema_DistShapeShape::NbSolution.

ShapeDistance.pointOnShape1(at:)

Get the i-th closest point on shape 1 (0-based).

public func pointOnShape1(at index: Int) -> SIMD3<Double>
  • OCCT: BRepExtrema_DistShapeShape::PointOnShape1 (1-based internally).

ShapeDistance.pointOnShape2(at:)

Get the i-th closest point on shape 2 (0-based).

public func pointOnShape2(at index: Int) -> SIMD3<Double>

ShapeDistance.supportType1(at:)

Get the support topology type on shape 1 for the i-th solution (0-based).

public func supportType1(at index: Int) -> DistanceSupportType?

ShapeDistance.supportType2(at:)

Get the support topology type on shape 2 for the i-th solution (0-based).

public func supportType2(at index: Int) -> DistanceSupportType?

ShapeDistance.supportShape1(at:)

Get the sub-shape on shape 1 that supports the i-th solution (0-based).

public func supportShape1(at index: Int) -> Shape?

ShapeDistance.supportShape2(at:)

Get the sub-shape on shape 2 that supports the i-th solution (0-based).

public func supportShape2(at index: Int) -> Shape?
  • Example:
    let box1 = Shape.box(width: 5, height: 5, depth: 5)!
    let box2 = Shape.box(origin: SIMD3(10, 0, 0), width: 5, height: 5, depth: 5)!
    if let dist = ShapeDistance(shape1: box1, shape2: box2), dist.isDone {
        print("min distance:", dist.value)   // 5.0
        print("p1:", dist.pointOnShape1(at: 0))
        print("p2:", dist.pointOnShape2(at: 0))
    }
    

WireFixer

Individual wire repair operations using ShapeFix_Wire.

public final class WireFixer: @unchecked Sendable

WireFixer.init(wire:face:precision:)

Create a wire fixer for a wire on a face with the given precision.

public init?(wire: Shape, face: Shape, precision: Double = 1e-6)
  • Parameters: wire — the wire to fix; face — the supporting face; precision — working precision.
  • Returns: The fixer, or nil on failure.
  • OCCT: ShapeFix_Wire (via OCCTWireFixerCreate).

WireFixer.fixReorder()

Fix the order of edges in the wire.

@discardableResult public func fixReorder() -> Bool
  • OCCT: ShapeFix_Wire::FixReorder.

WireFixer.fixConnected()

Fix connectivity gaps between consecutive edges.

@discardableResult public func fixConnected() -> Bool
  • OCCT: ShapeFix_Wire::FixConnected.

WireFixer.fixSmall(precision:)

Remove or collapse edges smaller than the given precision.

@discardableResult public func fixSmall(precision: Double = 1e-6) -> Bool
  • OCCT: ShapeFix_Wire::FixSmall.

WireFixer.fixDegenerated()

Fix degenerated edges (e.g. collapsed to a point on a seam).

@discardableResult public func fixDegenerated() -> Bool
  • OCCT: ShapeFix_Wire::FixDegenerated.

WireFixer.fixSelfIntersection()

Fix self-intersecting edges in the wire.

@discardableResult public func fixSelfIntersection() -> Bool
  • OCCT: ShapeFix_Wire::FixSelfIntersection.

WireFixer.fixLacking()

Fix lacking (missing) edges that cause gaps.

@discardableResult public func fixLacking() -> Bool
  • OCCT: ShapeFix_Wire::FixLacking.

WireFixer.fixClosed()

Fix the wire closure (ensure start/end vertices coincide).

@discardableResult public func fixClosed() -> Bool
  • OCCT: ShapeFix_Wire::FixClosed.

WireFixer.fixGaps3d()

Fix 3D gaps between consecutive edges.

@discardableResult public func fixGaps3d() -> Bool
  • OCCT: ShapeFix_Wire::FixGaps3d.

WireFixer.fixEdgeCurves()

Fix the 3D and 2D curves on edges within the wire.

@discardableResult public func fixEdgeCurves() -> Bool
  • OCCT: ShapeFix_Wire::FixEdgeCurves.

WireFixer.wire

The resulting fixed wire.

public var wire: Shape? { get }
  • Returns: The repaired wire shape, or nil if the fixer has not produced a valid result.
  • OCCT: ShapeFix_Wire::Wire.
  • Example:
    let face = Shape.faceFromPlane(uBounds: -10...10, vBounds: -10...10)!
    let wire = Wire.rectangle(width: 5, height: 5)!.asShape()
    if let fixer = WireFixer(wire: wire, face: face) {
        _ = fixer.fixReorder()
        _ = fixer.fixConnected()
        if let fixed = fixer.wire { print(fixed.isValid) }
    }
    

FaceFixer

Individual face repair operations using ShapeFix_Face.

public final class FaceFixer: @unchecked Sendable

FaceFixer.init(face:precision:)

Create a face fixer with the given precision.

public init?(face: Shape, precision: Double = 1e-6)
  • OCCT: ShapeFix_Face (via OCCTFaceFixerCreate).

FaceFixer.perform()

Perform all available face fixes in one call.

@discardableResult public func perform() -> Bool
  • OCCT: ShapeFix_Face::Perform.

FaceFixer.fixOrientation()

Fix the orientation of wires on the face.

@discardableResult public func fixOrientation() -> Bool
  • OCCT: ShapeFix_Face::FixOrientation.

FaceFixer.fixAddNaturalBound()

Add a natural boundary wire if one is missing (e.g. on a periodic surface).

@discardableResult public func fixAddNaturalBound() -> Bool
  • OCCT: ShapeFix_Face::FixAddNaturalBound.

FaceFixer.fixMissingSeam()

Fix a missing seam edge on a periodic surface.

@discardableResult public func fixMissingSeam() -> Bool
  • OCCT: ShapeFix_Face::FixMissingSeam.

FaceFixer.fixSmallAreaWire()

Remove wires whose enclosed area is negligibly small.

@discardableResult public func fixSmallAreaWire() -> Bool
  • OCCT: ShapeFix_Face::FixSmallAreaWire.

FaceFixer.face

The resulting fixed face.

public var face: Shape? { get }
  • OCCT: ShapeFix_Face::Face.
  • Example:
    if let fixer = FaceFixer(face: importedFace, precision: 1e-5) {
        _ = fixer.perform()
        if let fixed = fixer.face { print("fixed:", fixed.isValid) }
    }
    

FaceFixer.setMode(_:_:) — per-pass control (#266)

Enable / disable an individual ShapeFix_Face healing pass before perform(). Previously perform() ran with hardcoded defaults; this exposes each pass so callers can, e.g., turn off the natural-bound pass that can balloon a trimmed face.

public enum Pass: Int32, Sendable {
    case wire, orientation, addNaturalBound, missingSeam, smallAreaWire,
         removeSmallAreaFace, intersectingWires, loopWires, splitFace,
         autoCorrectPrecision, periodicDegenerated
}
public enum Toggle: Int32, Sendable { case auto = -1, off = 0, on = 1 }
public func setMode(_ pass: Pass, _ toggle: Toggle)
  • OCCT: ShapeFix_Face::Fix*Mode() reference setters.
  • Example:
    let fixer = FaceFixer(face: trimmedFace)
    fixer?.setMode(.addNaturalBound, .off)   // don't add the surface's natural bound
    fixer?.perform()
    
Pass case ShapeFix_Face setter it toggles
.wire FixWireMode
.orientation FixOrientationMode
.addNaturalBound FixAddNaturalBoundMode
.missingSeam FixMissingSeamMode
.smallAreaWire FixSmallAreaWireMode
.removeSmallAreaFace RemoveSmallAreaFaceMode
.intersectingWires FixIntersectingWiresMode
.loopWires FixLoopWiresMode
.splitFace FixSplitFaceMode
.autoCorrectPrecision AutoCorrectPrecisionMode
.periodicDegenerated FixPeriodicDegeneratedMode

Pass.smallAreaWire


FaceFixer — individual fix passes (#266)

Run a single fix pass directly.

@discardableResult public func fixIntersectingWires() -> Bool
@discardableResult public func fixPeriodicDegenerated() -> Bool
@discardableResult public func fixWiresTwoCoincEdges() -> Bool
@discardableResult public func fixLoopWire() -> Bool
  • OCCT: ShapeFix_Face::FixIntersectingWires / FixPeriodicDegenerated / FixWiresTwoCoincEdges / FixLoopWire.

FaceFixer.fixPeriodicDegenerated()

Runs ShapeFix_Face::FixPeriodicDegenerated alone: heals a wire that belts the full period of a periodic surface as a single closed edge (see the ShapeFix_Face::FixPeriodicDegenerated null-Context SIGSEGV entry in CLAUDE.md’s Known OCCT Bugs, fixed upstream in OCCT 8.0.1).

@discardableResult public func fixPeriodicDegenerated() -> Bool
  • OCCT: ShapeFix_Face::FixPeriodicDegenerated.

FaceFixer.fixWiresTwoCoincEdges()

Runs ShapeFix_Face::FixWiresTwoCoincEdges alone: merges a wire’s two coincident edges.

@discardableResult public func fixWiresTwoCoincEdges() -> Bool
  • OCCT: ShapeFix_Face::FixWiresTwoCoincEdges.

FaceFixer.fixLoopWire()

Runs ShapeFix_Face::FixLoopWire alone: splits a wire that loops back on itself.

@discardableResult public func fixLoopWire() -> Bool
  • OCCT: ShapeFix_Face::FixLoopWire.

FaceFixer.result / FaceFixer.status(_:) (#266)

result returns the true fix output — a face, or a shell when fixMissingSeam() split the face into several (unlike face, which is always a face). status(_:) queries which passes fired / failed after perform().

public var result: Shape? { get }
public enum Status: Int32, Sendable { case ok, done1, /* … */ done8, fail1, /* … */ fail8, done, fail }
public func status(_ status: Status) -> Bool

Status mirrors OCCT’s ShapeExtend_Status flag space, one bit per numbered fix. ShapeFix_Face only assigns meaning to some of the numbers; the rest exist because the same 18-flag enum is shared across every ShapeFix_Root subclass, each using a different subset.

Case Meaning for ShapeFix_Face
.ok The face needed no fix at all.
.done1 Some wire was fixed (ShapeFix_Wire pass).
.done2 Wire orientation was fixed.
.done3 A missing seam was added.
.done4 A small-area wire was removed.
.done5 A natural bound was added.
.done6 Not assigned by ShapeFix_Face.
.done7 Not assigned by ShapeFix_Face.
.done8 The face may have been split.
.fail1 Some failure while fixing a wire.
.fail2 Could not fix wire orientation.
.fail3 Could not add a missing seam.
.fail4 Could not remove a small-area wire.
.fail5 Not assigned by ShapeFix_Face.
.fail6 Not assigned by ShapeFix_Face.
.fail7 Not assigned by ShapeFix_Face.
.fail8 Not assigned by ShapeFix_Face.
.done Any .done1.done8 flag is set: something was fixed.
.fail Any .fail1.fail8 flag is set: some pass failed.

Status.fail

  • OCCT: ShapeFix_Face::Result / ShapeFix_Root::Status.

FaceFixer.setMaxTolerance(_:) / setMinTolerance(_:) (#266)

Clamp the tolerance the fixer may assign to the healed face. Call before perform().

public func setMaxTolerance(_ maxTolerance: Double)
public func setMinTolerance(_ minTolerance: Double)
  • OCCT: ShapeFix_Root::SetMaxTolerance / SetMinTolerance.

IntCSResult

Full multi-result curve-surface intersection using GeomAPI_IntCS.

public final class IntCSResult: @unchecked Sendable

IntCSResult.init(curve:surface:)

Compute intersections between a 3D curve and a surface.

public init?(curve: Curve3D, surface: Surface)
  • OCCT: GeomAPI_IntCS (via OCCTIntCSCreate).

IntCSResult.pointCount

Number of intersection points.

public var pointCount: Int { get }

IntCSResult.segmentCount

Number of intersection segments.

public var segmentCount: Int { get }

IntCSResult.IntersectionPoint

A single curve-surface intersection result.

Field Meaning
point The 3D intersection point in world space.
curveParam The curve’s own parameter at the intersection.
surfaceU The surface’s U parameter at the intersection.
surfaceV The surface’s V parameter at the intersection.

IntersectionPoint.surfaceV

public struct IntersectionPoint: Sendable {
    public let point: SIMD3<Double>
    public let curveParam: Double
    public let surfaceU: Double
    public let surfaceV: Double
}

IntCSResult.point(at:)

Get the i-th intersection point (0-based).

public func point(at index: Int) -> IntersectionPoint
  • OCCT: GeomAPI_IntCS::Point (1-based internally).
  • Example:
    if let line = Curve3D.line(origin: SIMD3(0, 0, -5), direction: SIMD3(0, 0, 1)),
       let plane = Surface.plane(),
       let result = IntCSResult(curve: line, surface: plane) {
        for i in 0..<result.pointCount {
            let ip = result.point(at: i)
            print("hit:", ip.point, "at t=", ip.curveParam)
        }
    }
    

Curve3D.bsplineSetKnot(index:value:)

Set the knot value at a 1-based index on a BSpline curve.

public func bsplineSetKnot(index: Int, value: Double) -> Bool
  • OCCT: Geom_BSplineCurve::SetKnot (via OCCTCurve3DBSplineSetKnot).

Curve3D.bsplineKnotSequence()

Get the full knot sequence with multiplicities expanded.

public func bsplineKnotSequence() -> [Double]
  • Returns: Up to 1024 knot values in the flat (expanded) sequence.
  • OCCT: Geom_BSplineCurve::KnotSequence (via OCCTCurve3DBSplineGetKnotSequence).

Curve3D.bsplineWeights()

Get all pole weights (one per control point).

public func bsplineWeights() -> [Double]
  • OCCT: Geom_BSplineCurve::Weights (via OCCTCurve3DBSplineGetWeights).

Curve3D.bsplineInsertKnots(_:multiplicities:tolerance:)

Insert multiple knots at once.

public func bsplineInsertKnots(
    _ knots: [Double],
    multiplicities: [Int],
    tolerance: Double = 1e-10
) -> Bool
  • Parameters: knots — new knot values; multiplicities — insertion multiplicities; tolerance — parametric tolerance.
  • OCCT: Geom_BSplineCurve::InsertKnots (via OCCTCurve3DBSplineInsertKnots).

Curve3D.bsplineMovePoint(u:to:poleRange:)

Move the curve to pass through a new 3D point at parameter u, adjusting poles within poleRange.

public func bsplineMovePoint(
    u: Double,
    to point: SIMD3<Double>,
    poleRange: ClosedRange<Int>
) -> Bool
  • Parameters: poleRange — 1-based inclusive range of poles allowed to move.
  • OCCT: Geom_BSplineCurve::MovePoint (via OCCTCurve3DBSplineMovePoint).

Curve3D.bsplineLocalValue(u:fromKnot:toKnot:)

Evaluate the curve locally within a knot span.

public func bsplineLocalValue(u: Double, fromKnot: Int, toKnot: Int) -> SIMD3<Double>
  • Parameters: fromKnot, toKnot — 1-based knot span indices.
  • OCCT: Geom_BSplineCurve::LocalValue (via OCCTCurve3DBSplineLocalValue).

Curve3D.bsplineLocalD0(u:fromKnot:toKnot:)

Evaluate the curve point within a knot span (alias of bsplineLocalValue).

public func bsplineLocalD0(u: Double, fromKnot: Int, toKnot: Int) -> SIMD3<Double>
  • OCCT: Geom_BSplineCurve::LocalD0.

Curve3D.bsplineLocalD1(u:fromKnot:toKnot:)

Evaluate point and first derivative within a knot span.

public func bsplineLocalD1(
    u: Double,
    fromKnot: Int,
    toKnot: Int
) -> (point: SIMD3<Double>, d1: SIMD3<Double>)
  • OCCT: Geom_BSplineCurve::LocalD1.

Curve3D.bsplineLocalD2(u:fromKnot:toKnot:)

Evaluate point, first, and second derivatives within a knot span.

public func bsplineLocalD2(
    u: Double,
    fromKnot: Int,
    toKnot: Int
) -> (point: SIMD3<Double>, d1: SIMD3<Double>, d2: SIMD3<Double>)
  • OCCT: Geom_BSplineCurve::LocalD2.

Curve3D.bsplineLocalD3(u:fromKnot:toKnot:)

Evaluate point through third derivative within a knot span.

public func bsplineLocalD3(
    u: Double,
    fromKnot: Int,
    toKnot: Int
) -> (point: SIMD3<Double>, d1: SIMD3<Double>, d2: SIMD3<Double>, d3: SIMD3<Double>)
  • OCCT: Geom_BSplineCurve::LocalD3.

Curve3D.bsplineLocalDN(u:fromKnot:toKnot:n:)

Evaluate the N-th derivative within a knot span.

public func bsplineLocalDN(
    u: Double,
    fromKnot: Int,
    toKnot: Int,
    n: Int
) -> SIMD3<Double>
  • OCCT: Geom_BSplineCurve::LocalDN.

Curve3D.bsplineMaxDegree

Maximum BSpline degree supported (static property).

public static var bsplineMaxDegree: Int { get }
  • OCCT: Geom_BSplineCurve::MaxDegree.

Curve3D.bsplineLocateU(_:tolerance:)

Locate the knot span index containing parameter u.

public func bsplineLocateU(_ u: Double, tolerance: Double = 1e-10) -> Int
  • Returns: 1-based knot index of the span containing u.
  • OCCT: Geom_BSplineCurve::LocateU.
  • Example:
    if let bsp = Curve3D.bspline(poles: pts, knots: ks, multiplicities: ms, degree: 3) {
        let span = bsp.bsplineLocateU(0.5)
        let localPt = bsp.bsplineLocalValue(u: 0.5, fromKnot: span, toKnot: span + 1)
        print(localPt)
    }
    

Surface.bsplineSetUKnot(index:value:)

Set a U knot at a 1-based index on a BSpline surface.

public func bsplineSetUKnot(index: Int, value: Double) -> Bool
  • OCCT: Geom_BSplineSurface::SetUKnot.

Surface.bsplineSetVKnot(index:value:)

Set a V knot at a 1-based index on a BSpline surface.

public func bsplineSetVKnot(index: Int, value: Double) -> Bool
  • OCCT: Geom_BSplineSurface::SetVKnot.

Surface.bsplineUKnots()

Get all U knots (distinct values, without multiplicities expanded).

public func bsplineUKnots() -> [Double]
  • OCCT: Geom_BSplineSurface::UKnots.

Surface.bsplineVKnots()

Get all V knots (distinct values, without multiplicities expanded).

public func bsplineVKnots() -> [Double]
  • OCCT: Geom_BSplineSurface::VKnots.

Surface.bsplineWeights()

Get all pole weights as a row-major flat array (NbUPoles × NbVPoles).

public func bsplineWeights() -> (weights: [Double], rows: Int, cols: Int)
  • Returns: (weights, rows, cols) where weights.count == rows * cols.
  • OCCT: Geom_BSplineSurface::Weights.

Surface.bsplineRemoveUKnot(index:multiplicity:tolerance:)

Remove a U knot at the given 1-based index, reducing its multiplicity.

public func bsplineRemoveUKnot(
    index: Int,
    multiplicity: Int,
    tolerance: Double
) -> Bool
  • Parameters: multiplicity — target multiplicity after removal (0 to remove completely); tolerance — geometric tolerance.
  • Returns: true if the knot was removed within tolerance.
  • OCCT: Geom_BSplineSurface::RemoveUKnot.

TopoDS Builder, ShapeContents Expanded, FreeBoundsProperties, WireBuilder

Shape.builderMakeWire()

Create an empty wire via TopoDS_Builder.

public static func builderMakeWire() -> Shape?
  • OCCT: TopoDS_Builder::MakeWire (via OCCTBuilderMakeWire).

Shape.builderMakeShell()

Create an empty shell via TopoDS_Builder.

public static func builderMakeShell() -> Shape?
  • OCCT: TopoDS_Builder::MakeShell.

Shape.builderMakeSolid()

Create an empty solid via TopoDS_Builder.

public static func builderMakeSolid() -> Shape?
  • OCCT: TopoDS_Builder::MakeSolid.

Shape.builderMakeCompound()

Create an empty compound via TopoDS_Builder.

public static func builderMakeCompound() -> Shape?
  • OCCT: TopoDS_Builder::MakeCompound.

Shape.builderMakeCompSolid()

Create an empty comp-solid via TopoDS_Builder.

public static func builderMakeCompSolid() -> Shape?
  • OCCT: TopoDS_Builder::MakeCompSolid.

Shape.builderAdd(_:)

Add a child shape into this shape using TopoDS_Builder.

@discardableResult
public func builderAdd(_ child: Shape) -> Bool
  • Returns: true if the child was added.
  • OCCT: TopoDS_Builder::Add.
  • Example:
    let compound = Shape.builderMakeCompound()!
    let box = Shape.box(width: 5, height: 5, depth: 5)!
    _ = compound.builderAdd(box)
    print(compound.isCompound)  // true
    

Shape.builderRemove(_:)

Remove a child shape from this shape using TopoDS_Builder.

@discardableResult
public func builderRemove(_ child: Shape) -> Bool
  • Returns: true if the child was removed.
  • OCCT: TopoDS_Builder::Remove.

ShapeContentsExtended

Detailed shape-contents analysis result from ShapeAnalysis_ShapeContents.

public struct ShapeContentsExtended: Sendable {
    public let nbSolids: Int
    public let nbShells: Int
    public let nbFaces: Int
    public let nbWires: Int
    public let nbEdges: Int
    public let nbVertices: Int
    public let nbFreeEdges: Int
    public let nbFreeWires: Int
    public let nbFreeFaces: Int
    public let nbSolidsWithVoids: Int
    public let nbBigSplines: Int
    public let nbC0Surfaces: Int
    public let nbC0Curves: Int
    public let nbOffsetSurf: Int
    public let nbIndirectSurf: Int
    public let nbOffsetCurves: Int
    public let nbTrimmedCurve2d: Int
    public let nbTrimmedCurve3d: Int
    public let nbBSplineSurf: Int
    public let nbBezierSurf: Int
    public let nbTrimSurf: Int
    public let nbWireWithSeam: Int
    public let nbWireWithSevSeams: Int
    public let nbFaceWithSevWires: Int
    public let nbNoPCurve: Int
    public let nbSharedSolids: Int
    public let nbSharedShells: Int
    public let nbSharedFaces: Int
    public let nbSharedWires: Int
    public let nbSharedEdges: Int
    public let nbSharedVertices: Int
}

Every field is a direct 1:1 read of the matching ShapeAnalysis_ShapeContents accessor (NbSolids(), NbShells(), …), taken once by contentsExtended() after a single Perform() pass. “Shared” below means structural reuse in the topology graph: the same sub-shape referenced from more than one parent, not the ordinary case of an edge sitting between two faces of a solid, which every valid solid has and which NbSharedEdges() does not count.

Field Meaning
nbSolids Number of solids.
nbShells Number of shells.
nbFaces Number of faces.
nbWires Number of wires.
nbEdges Number of edges.
nbVertices Number of vertices.
nbFreeEdges Edges used by exactly one face (naked/boundary edges).
nbFreeWires Wires that belong to no face.
nbFreeFaces Faces that belong to no shell.
nbSolidsWithVoids Solids with more than one shell (an outer shell plus one or more internal void shells).
nbBigSplines B-spline curves or surfaces OCCT flags as unusually complex (a high pole/knot count).
nbC0Surfaces Surfaces that are only C0 continuous (not smooth internally).
nbC0Curves Curves that are only C0 continuous.
nbOffsetSurf Geom_OffsetSurface instances.
nbIndirectSurf Surfaces with an indirect (left-handed) parametrization.
nbOffsetCurves Geom_OffsetCurve instances.
nbTrimmedCurve2d Trimmed 2D curves (pcurves).
nbTrimmedCurve3d Trimmed 3D curves.
nbBSplineSurf B-spline surfaces.
nbBezierSurf Bezier surfaces.
nbTrimSurf Geom_RectangularTrimmedSurface instances.
nbWireWithSeam Wires containing exactly one seam edge (on a closed/periodic surface).
nbWireWithSevSeams Wires containing more than one seam edge.
nbFaceWithSevWires Faces with more than one wire (i.e. with inner boundaries/holes).
nbNoPCurve Edges on a face with no pcurve representation there.
nbSharedSolids Solids referenced from more than one parent.
nbSharedShells Shells referenced from more than one solid.
nbSharedFaces Faces referenced from more than one shell.
nbSharedWires Wires referenced from more than one face.
nbSharedEdges Edges referenced from more than one wire (structural reuse, not ordinary face adjacency).
nbSharedVertices Vertices referenced from more than one edge (structural reuse).

(Per-field anchors below, for cross-reference; the table above has the actual meaning of each.)

nbSharedVertices


Shape.contentsExtended()

Get extended shape-contents analysis with 31 topology and geometry counters.

public func contentsExtended() -> ShapeContentsExtended
  • OCCT: ShapeAnalysis_ShapeContents (via OCCTShapeGetContentsExtended).
  • Example:
    let box = Shape.box(width: 10, height: 10, depth: 10)!
    let c = box.contentsExtended()
    print("faces:", c.nbFaces, "edges:", c.nbEdges)
    print("B-spline surfaces:", c.nbBSplineSurf)
    

FreeBoundsProperties

Persistent free-bounds analysis wrapping ShapeAnalysis_FreeBoundsProperties.

public final class FreeBoundsProperties: @unchecked Sendable

A free bound is a boundary contour of the shape: a chain of edges each used by exactly one face, closed into a loop where it can be. The analysis computes area, perimeter, aspect ratio, width and notch count for each one.

The analysis runs once and every query is answered from that one result, which is the difference between this and Shape’s freeBoundsAnalysis(tolerance:) family, which analyses the shape again per call. Both have run on this one implementation since #504.

The shape needs to be a compound or shell of faces: the search runs over its direct children, so a lone face reports no free bounds. In practice the sewing pass closes essentially every contour it finds, so openCount is usually 0.

  • Note: Unaffected by OCCT 8.0.1’s ConnectEdgesToWires INTERNAL/EXTERNAL skip (OCCT#1408), at any tolerance; see Shape.freeBounds(sewingTolerance:) for why, on both branches. This type’s own init?(shape:tolerance:) is where the tolerance <= 0 branch (no sewing stage at all) is selected, so its guarantee rests directly on the two-branch measurement that note describes, not only on the sewing-branch reasoning. See #655.
// A box shell with one face removed: its free boundary is the square hole.
let faces = Shape.box(width: 10, height: 10, depth: 10)!.subShapes(ofType: .face)
let opened = Shape.compound(Array(faces.dropLast()))!

let props = FreeBoundsProperties(shape: opened, tolerance: 1e-3)!
print(props.closedCount, props.openCount, props.totalCount)   // 1 0 1

for i in 0..<props.closedCount {
    let bound = props.info(.closed, at: i)!
    print(bound.area, bound.perimeter, bound.notchCount)      // 100.0 40.0 0
    let wire = props.wire(.closed, at: i)
}

FreeBoundsProperties.init(shape:tolerance:)

Create a free-bounds properties analyser.

public init?(shape: Shape, tolerance: Double = 1e-7)
  • Parameters: tolerance, the sewing tolerance used to chain free edges into contours. 0 or below selects a different OCCT algorithm, taking free edges from the shape’s already-shared topology instead of from a sewing pass.
  • Returns: The analyser, or nil on failure.
  • Note: This is the call that selects the branch. Both are unaffected by OCCT 8.0.1’s ConnectEdgesToWires INTERNAL/EXTERNAL skip (OCCT#1408), but for different reasons and measured separately; see freeBounds(sewingTolerance:). See #655.
  • OCCT: ShapeAnalysis_FreeBoundsProperties (via OCCTFreeBoundsPropsCreate).

FreeBoundsProperties.perform()

Run the analysis, if it has not already run, and report whether results are available.

@discardableResult
public func perform() -> Bool

Calling this is optional (every query below runs it on demand) and idempotent. Both matter: OCCT’s own Perform() appends to its result sequences without clearing them, so calling it twice used to double every count (#504), and the accessors used to report 0 until it had been called.

  • OCCT: ShapeAnalysis_FreeBoundsProperties::Perform. Note that OCCT’s return value is not a success signal. It is true even for a shape with no free bounds and for one never loaded, so this reports IsLoaded() instead.

FreeBoundsProperties.BoundKind

Which of the analysis’ two result sequences a query addresses.

public enum BoundKind: Sendable { case closed, open }
Case Meaning
.closed Addresses the sequence of contours that close into a loop.
.open Addresses the sequence of contours that do not close.

FreeBoundsProperties.BoundKind.closed


FreeBoundsProperties.closedCount

Number of closed free bounds found.

public var closedCount: Int { get }

FreeBoundsProperties.openCount

Number of open free bounds found.

public var openCount: Int { get }

FreeBoundsProperties.totalCount

Total number of free bounds, closed and open.

public var totalCount: Int { get }

FreeBoundsProperties.info(_:at:)

Every property of one free bound (0-based index), or nil if the index is out of range.

public func info(_ kind: BoundKind, at index: Int) -> Shape.FreeBoundInfo?

Shape.FreeBoundInfo carries area, perimeter, ratio, width and notchCount. ratio is an aspect ratio: contour length over contour width, so 2 for a 20×10 bound, not area / perimeter². OCCT solves it from the area and perimeter and leaves both ratio and width at 0 when that solve has no real root, which an exactly square bound hits by one ulp: 0 there means “not solvable”, not “degenerate contour”.

let props = FreeBoundsProperties(shape: twoStackedRects, tolerance: 0.01)!
let bound = props.info(.closed, at: 0)!      // a 20x10 contour
print(bound.ratio, bound.width)              // 2.0 10.0
props.info(.closed, at: props.closedCount)   // nil, out of range
  • OCCT: ShapeAnalysis_FreeBoundData::Area/Perimeter/Ratio/Width/NbNotches (via OCCTFreeBoundsPropsInfo).

FreeBoundsProperties.wire(_:at:)

Contour wire of one free bound (0-based index), or nil if the index is out of range.

public func wire(_ kind: BoundKind, at index: Int) -> Shape?
  • OCCT: ShapeAnalysis_FreeBoundData::FreeBound (via OCCTFreeBoundsPropsWire).

FreeBoundsProperties.closedArea(at:)

Area enclosed by the i-th closed free bound (0-based), or 0 if the index is out of range.

public func closedArea(at index: Int) -> Double

FreeBoundsProperties.closedPerimeter(at:)

Perimeter of the i-th closed free bound (0-based), or 0 if the index is out of range.

public func closedPerimeter(at index: Int) -> Double

FreeBoundsProperties.closedRatio(at:)

Length-to-width aspect ratio of the i-th closed free bound (0-based), or 0 if the index is out of range. See info(_:at:). 0 is also what OCCT reports for a bound whose ratio it cannot solve.

public func closedRatio(at index: Int) -> Double

FreeBoundsProperties.closedWidth(at:)

Width of the i-th closed free bound (0-based), on the same “0 means unsolved” contract as closedRatio(at:).

public func closedWidth(at index: Int) -> Double

FreeBoundsProperties.closedWire(at:)

Wire shape for the i-th closed free bound (0-based).

public func closedWire(at index: Int) -> Shape?

FreeBoundsProperties.openArea(at:)

Swept area of the i-th open free bound (0-based), or 0 if the index is out of range.

public func openArea(at index: Int) -> Double

FreeBoundsProperties.openPerimeter(at:)

Length of the i-th open free bound (0-based), or 0 if the index is out of range.

public func openPerimeter(at index: Int) -> Double

FreeBoundsProperties.openWire(at:)

Wire shape for the i-th open free bound (0-based).

public func openWire(at index: Int) -> Shape?
  • Example:
    let shell = Shape.box(width: 10, height: 10, depth: 10)!  // closed — 0 free bounds
    if let fp = FreeBoundsProperties(shape: shell) {
        print("closed:", fp.closedCount, "open:", fp.openCount)   // closed: 0 open: 0
    }
    

WireBuilder

Incremental wire builder wrapping BRepBuilderAPI_MakeWire.

public final class WireBuilder: @unchecked Sendable

Unlike Shape.wireFromEdges(_:), WireBuilder lets you add edges one-by-one and inspect the error state before retrieving the result.


WireBuilder.init()

Create an empty wire builder.

public init()
  • OCCT: BRepBuilderAPI_MakeWire() (via OCCTWireBuilderCreate).

WireBuilder.addEdge(_:)

Add an edge to the wire being built.

public func addEdge(_ edge: Shape)
  • OCCT: BRepBuilderAPI_MakeWire::Add(TopoDS_Edge).

WireBuilder.addWire(_:)

Add a wire (all its edges) to the wire being built.

public func addWire(_ wire: Shape)
  • OCCT: BRepBuilderAPI_MakeWire::Add(TopoDS_Wire).

WireBuilder.wire

The resulting wire.

public var wire: Shape? { get }
  • Returns: The built wire, or nil if the builder is not done or failed.
  • OCCT: BRepBuilderAPI_MakeWire::Wire.

WireBuilder.isDone

Whether the builder has produced a valid wire.

public var isDone: Bool { get }

WireBuilder.WireError

Error status from the wire builder.

public enum WireError: Int32, Sendable {
    case wireDone        = 0
    case emptyWire       = 1
    case disconnectedWire = 2
    case nonManifoldWire  = 3
}

Case meanings, from BRepBuilderAPI_WireError:

WireBuilder.WireError.wireDone

No error occurred; the wire is correctly built.

WireBuilder.WireError.disconnectedWire

The last edge added was not connected to the wire.

WireBuilder.WireError.nonManifoldWire

The wire has some singularity.


WireBuilder.error

Get the current error status.

public var error: WireError { get }
  • OCCT: BRepBuilderAPI_MakeWire::Error.
  • Example:
    let builder = WireBuilder()
    builder.addEdge(Shape.edgeFromLine(from: .zero, to: SIMD3(5, 0, 0))!)
    builder.addEdge(Shape.edgeFromLine(from: SIMD3(5, 0, 0), to: SIMD3(5, 5, 0))!)
    if builder.isDone, let wire = builder.wire {
        print("built wire with", wire.edges().count, "edges")
    } else {
        print("error:", builder.error)
    }
    

Shape.fused(with:tolerance:)

Fuse two shapes using a fuzzy Boolean tolerance.

public func fused(with other: Shape, tolerance: Double) -> Shape?
  • Parameters: tolerance — fuzzy tolerance for coincident geometry detection.
  • OCCT: BRepAlgoAPI_Fuse with SetFuzzyValue (via OCCTBooleanFuseWithTolerance).

Shape.subtracted(_:tolerance:)

Cut another shape from this shape using a fuzzy Boolean tolerance.

public func subtracted(_ other: Shape, tolerance: Double) -> Shape?
  • OCCT: BRepAlgoAPI_Cut with SetFuzzyValue (via OCCTBooleanCutWithTolerance).

Shape.intersected(with:tolerance:)

Compute the Boolean common of two shapes using a fuzzy tolerance.

public func intersected(with other: Shape, tolerance: Double) -> Shape?
  • OCCT: BRepAlgoAPI_Common with SetFuzzyValue (via OCCTBooleanCommonWithTolerance).

Shape.GlueMode

Glue hint for Boolean operations on nearly-coincident faces.

public enum GlueMode: Int32, Sendable {
    case shift = 0   // Shift glue — one-face difference
    case full  = 1   // Full glue — all faces coincident
    case off   = 2   // No glue
}

Mirrors BOPAlgo_GlueEnum. Gluing skips real intersection computation between arguments that the caller guarantees are already coincident; setting it on shapes that are not coincident is likely to produce an incorrect result, since the algorithm does not check the guarantee itself.

Case Meaning
.off Default; gluing is disabled and full intersection computation runs.
.shift For partially-coincident arguments (overlapping but not fully coincident faces): skips FACE/FACE intersection computation; the overlapping faces are still split.
.full For fully-coincident arguments (no partial overlap): skips VERTEX/FACE, EDGE/FACE, and FACE/FACE intersection computation; faces are not split.

Shape.GlueMode.full


Shape.fused(with:glue:)

Fuse two shapes with a glue mode hint for better performance on coincident faces.

public func fused(with other: Shape, glue: GlueMode) -> Shape?
  • OCCT: BRepAlgoAPI_Fuse with SetGlue (via OCCTBooleanFuseGlue).

Shape.subtracted(_:glue:)

Cut another shape with a glue mode hint.

public func subtracted(_ other: Shape, glue: GlueMode) -> Shape?
  • OCCT: BRepAlgoAPI_Cut with SetGlue (via OCCTBooleanCutGlue).

Shape.intersected(with:glue:)

Compute the Boolean common with a glue mode hint.

public func intersected(with other: Shape, glue: GlueMode) -> Shape?
  • OCCT: BRepAlgoAPI_Common with SetGlue (via OCCTBooleanCommonGlue).
  • Example:
    let a = Shape.box(width: 10, height: 10, depth: 10)!
    let b = Shape.box(origin: SIMD3(5, 0, 0), width: 10, height: 10, depth: 10)!
    if let result = a.fused(with: b, glue: .shift) {
        print(result.isValid)
    }
    

Shape.OffsetJoinType

Join type for wire and face offset operations.

public enum OffsetJoinType: Int32, Sendable {
    case arc          = 0   // Arcs at corners
    case tangent      = 1   // Tangent extensions
    case intersection = 2   // Intersection of extended edges
}

Shape.offsetWireOnPlane(distance:joinType:)

Offset a planar wire by the given distance on its containing plane.

public func offsetWireOnPlane(
    distance: Double,
    joinType: OffsetJoinType = .arc
) -> Shape?
  • Parameters: distance — signed offset distance (positive = outward); joinType — corner handling.
  • OCCT: BRepOffsetAPI_MakeOffset (via OCCTOffsetWireOnPlane).
  • Example:
    if let rect = Wire.rectangle(width: 10, height: 5)?.asShape(),
       let offsetWire = rect.offsetWireOnPlane(distance: 2) {
        print(offsetWire.isValid)
    }
    

Shape.offsetFace(distance:joinType:)

Offset a face by the given distance.

public func offsetFace(
    distance: Double,
    joinType: OffsetJoinType = .arc
) -> Shape?
  • OCCT: BRepOffsetAPI_MakeOffset on a face (via OCCTOffsetFace).

Shape.thickSolid(facesToRemove:offset:tolerance:joinType:)

Create a thick solid by removing specified faces and offsetting the remainder.

public func thickSolid(
    facesToRemove: [Shape],
    offset: Double,
    tolerance: Double = 1e-3,
    joinType: OffsetJoinType = .arc
) -> Shape?
  • Parameters:
    • facesToRemove — faces to open (remove from the shell before offsetting).
    • offset — wall thickness (signed; positive = outward).
    • tolerance — Boolean tolerance.
    • joinType — corner type.
  • OCCT: BRepOffsetAPI_MakeThickSolid (via OCCTThickSolidWithOptions).
  • Example:
    let box = Shape.box(width: 20, height: 20, depth: 20)!
    let topFace = box.faces().max(by: { $0.area < $1.area })!
    if let hollow = box.thickSolid(facesToRemove: [topFace], offset: -2) {
        print(hollow.isValid)
    }
    

Shape.orientClosedSolid()

Orient a closed solid so that face normals point consistently outward.

@discardableResult
public func orientClosedSolid() -> Bool
  • Returns: true if the orientation was fixed.
  • OCCT: BRepLib::OrientClosedSolid (via OCCTBRepLibOrientClosedSolid).

Shape.buildCurves3d(tolerance:)

Build 3D curves for all edges in the shape that lack them. Edges from a loft, a sweep, or a surface-based face can carry a 2D curve on their support surface and no 3D curve at all; anything that walks edge geometry needs the 3D curve. Edges that already have one are left untouched, so a second call costs nothing.

@discardableResult
public func buildCurves3d(tolerance: Double = 1e-5) -> Bool
  • Parameters: tolerance — approximation tolerance, and also the rebuilt edge’s tolerance floor: OCCT sets the edge tolerance to this value rather than to the deviation it achieved. The default is OCCT’s own default for the operation. A tighter value buys a closer curve for a pole or two more (measured on a helix: 1e-5 deviates by 2.6e-6, 1e-7 by 9.0e-8) but claims an accuracy the approximation may not reach on hard geometry. Ignored when the pcurve lies on a plane — that branch is analytic and exact.
  • Returns: false if any single edge could not be given a 3D curve (a degenerate edge with no planar pcurve, or one stripped of every representation). The edges that did succeed are still modified, so false means “partially built”, not “nothing happened”.
  • OCCT: BRepLib::BuildCurves3d (via OCCTBRepLibBuildCurves3dForShape).
  • Example:
    // An edge built from a pcurve on a cylinder has no 3D curve until this runs.
    let cylinder = Surface.cylinder(origin: .zero, axis: SIMD3(0, 0, 1), radius: 10)!
    let pcurve = Curve2D.line(through: SIMD2(0.2, -3), direction: SIMD2(0.6, 0.8))!
    let edge = Shape.edgeOnSurface(pcurve: pcurve, surface: cylinder, u1: 0, u2: 2)!
    
    print(edge.extractEdgeCurve3D() == nil)   // true
    print(edge.buildCurves3d())               // true
    print(edge.extractEdgeCurve3D() != nil)   // true — a BSpline approximating the helix
    print(edge.edgeTolerance)                 // 1e-05 — the tolerance lands on the edge
    
  • Note: the default was 1e-7 until #498. It moved to 1e-5 when this method absorbed buildCurves3dAll, whose separate C entry point had a byte-identical body and whose default was already OCCT’s 1e-5. Pass tolerance: 1e-7 to keep the old behaviour.

Shape.sortedFaces()

Get the faces sorted by decreasing area.

public func sortedFaces() -> Shape?
  • Returns: A compound containing the faces in order from largest to smallest, or nil on failure.
  • OCCT: BRepLib::SortFaces (via OCCTBRepLibSortFaces).

Shape.reverseSortedFaces()

Get the faces sorted by increasing area.

public func reverseSortedFaces() -> Shape?
  • OCCT: BRepLib::ReverseSortFaces (via OCCTBRepLibReverseSortFaces).

Shape.LinearProperties

Linear properties result for edge/wire shapes.

public struct LinearProperties: Sendable {
    public let length: Double
    public let centerOfMass: SIMD3<Double>
}

Shape.linearProperties()

Get linear properties (total length and center of mass) for an edge or wire shape.

public func linearProperties() -> LinearProperties?
  • Returns: Length and length-centroid, or nil for a shape with no edges, such as a lone vertex. The centre of mass reported there was the shape’s location origin, not a recognisable zero (#609).
  • OCCT: GProp_GProps linear analysis plus a Mass() test (via OCCTShapeLinearProperties).
  • Example:
    let wire = Shape.fromWire(Wire.rectangle(width: 10, height: 5)!)!
    if let lp = wire.linearProperties() {
        print("length:", lp.length)              // 30.0
        print("centroid:", lp.centerOfMass)
    }
    

Shape.InertiaTensor

Inertia tensor components for a volumetric shape.

public struct InertiaTensor: Sendable {
    public let ixx: Double, iyy: Double, izz: Double
    public let ixy: Double, ixz: Double, iyz: Double
}

The three diagonal terms (ixx, iyy, izz) and the three off-diagonal cross terms (ixy, ixz, iyz) of the symmetric 3x3 inertia matrix, referenced to the shape’s own centre of mass.

InertiaTensor.ixy


Shape.momentOfInertia()

Get the inertia tensor for a volumetric shape. It is referenced to the shape’s centre of mass, not to the world origin (#605).

public func momentOfInertia() -> InertiaTensor?
  • Returns: The tensor, or nil for a shape with no closed volume, where it is identically zero and indistinguishable from a real answer for a shape with no moments (#609).
  • OCCT: GProp_GProps volumetric analysis with OnlyClosed = true plus a Mass() test (via OCCTShapeMomentOfInertia).

Shape.PrincipalAxes

Three orthogonal principal inertia axis directions.

public struct PrincipalAxes: Sendable {
    public let axis1: SIMD3<Double>
    public let axis2: SIMD3<Double>
    public let axis3: SIMD3<Double>
}
Field Meaning
axis1 Direction of the first principal axis of inertia.
axis2 Direction of the second principal axis of inertia.
axis3 Direction of the third principal axis of inertia.

Shape.PrincipalAxes.axis3


Shape.principalAxes()

Get the three principal axes of inertia.

public func principalAxes() -> PrincipalAxes?
  • Returns: The three axes, or nil for a shape with no closed volume. It used to return three orthonormal unit vectors there, which look like a real answer but are just the identity basis that math_Jacobi returns for the zero inertia matrix (#609).
  • OCCT: GProp_GProps::PrincipalProperties plus a Mass() test (via OCCTShapePrincipalAxes).

Shape.radiusOfGyration(axisOrigin:direction:)

Get the radius of gyration about an arbitrary axis.

public func radiusOfGyration(
    axisOrigin: SIMD3<Double>,
    direction: SIMD3<Double>
) -> Double?
  • Parameters: axisOrigin — a point on the axis; direction — axis direction vector.
  • Returns: The radius, or nil for a shape with no closed volume. OCCT computes this as sqrt(momentOfInertia / mass) with no guard, so it used to return NaN there, which propagates silently through any arithmetic that consumes it. Its GProp_PrincipalProps sibling is guarded, which is why the radii-triple read 0 from the same framework that made this NaN (#609).
  • OCCT: GProp_GProps::RadiusOfGyration plus a Mass() test (via OCCTShapeRadiusOfGyration).

Curve3D.isBounded

Whether this curve is a bounded curve (Geom_BoundedCurve subclass).

public var isBounded: Bool { get }
  • OCCT: dynamic type check against Geom_BoundedCurve.

Curve2D.isBounded

Whether this 2D curve is bounded (Geom2d_BoundedCurve subclass).

public var isBounded: Bool { get }

Color.namedColorCount

The total number of named OCCT colours available.

public static var namedColorCount: Int { get }
  • OCCT: Quantity_Color named-colour registry (via OCCTNamedColorCount).

Shape.edgeCurveWithParams()

Get the 3D geometric curve from an edge with its first and last parameters.

public func edgeCurveWithParams() -> (curve: Curve3D, first: Double, last: Double)?
  • Returns: A tuple (curve, first, last), or nil if this shape is not an edge or has no 3D curve.
  • OCCT: BRep_Tool::Curve (via OCCTShapeEdgeCurve).
  • Example:
    for edge in box.edges() {
        if let (c, t0, t1) = edge.edgeCurveWithParams() {
            let midpoint = c.point(at: (t0 + t1) / 2)
            print(midpoint)
        }
    }
    

Shape.faceSurfaceGeom()

Get the underlying geometric surface from a face shape.

public func faceSurfaceGeom() -> Surface?
  • Returns: The Surface, or nil if this shape is not a face.
  • OCCT: BRep_Tool::Surface (via OCCTShapeFaceSurface).

Shape.isClosedShape

Whether this shape (wire or shell) is closed.

public var isClosedShape: Bool { get }
  • OCCT: BRep_Tool::IsClosed (via OCCTShapeIsClosed).

Shape.uniqueEdgeCount

Number of unique (topologically distinct) edges in this shape.

public var uniqueEdgeCount: Int { get }
  • OCCT: TopExp_Explorer with TopAbs_EDGE, deduplicated (via OCCTShapeUniqueEdgeCount).

Shape.uniqueFaceCount

Number of unique faces in this shape.

public var uniqueFaceCount: Int { get }

Shape.uniqueVertexCount

Number of unique vertices in this shape.

public var uniqueVertexCount: Int { get }

Shape.uniqueSubShapeCount(ofType:)

Count unique sub-shapes of a specific topology type.

public func uniqueSubShapeCount(ofType type: ShapeType) -> Int
  • Parameters: type — the ShapeType to count.
  • OCCT: TopExp_Explorer deduplicated (via OCCTShapeUniqueSubShapeCount).

Shape.emptyCopied()

Create an empty copy of this shape (same TShape type, no sub-shapes).

public func emptyCopied() -> Shape?
  • Returns: An empty shape of the same topology type.
  • OCCT: TopoDS_Shape::EmptyCopied (via OCCTShapeEmptyCopied).

Curve3D.dn(at:order:)

Evaluate the N-th derivative at parameter u.

public func dn(at u: Double, order n: Int) -> SIMD3<Double>
  • Parameters: n — derivative order (1 = tangent, 2 = curvature vector, …).
  • OCCT: Geom_Curve::DN (via OCCTCurve3DDN).

Curve3D.typeName

The runtime OCCT class name of this curve (e.g. "Geom_Line", "Geom_BSplineCurve").

public var typeName: String? { get }
  • OCCT: Standard_Type::Name on the curve’s dynamic type (via OCCTCurve3DTypeName).

Curve2D.dn(at:order:)

Evaluate the N-th derivative at parameter u for a 2D curve.

public func dn(at u: Double, order n: Int) -> SIMD2<Double>
  • OCCT: Geom2d_Curve::DN (via OCCTCurve2DDN).

Curve2D.typeName

The runtime OCCT class name of this 2D curve (e.g. "Geom2d_Line", "Geom2d_Circle").

public var typeName: String? { get }
  • OCCT: Standard_Type::Name on the 2D curve’s dynamic type.

Surface.dn(u:v:nu:nv:)

Evaluate the (Nu, Nv) mixed partial derivative at (u, v).

public func dn(u: Double, v: Double, nu: Int, nv: Int) -> SIMD3<Double>
  • Parameters: nu, nv — partial derivative orders with respect to U and V.
  • OCCT: Geom_Surface::DN (via OCCTSurfaceDN).

Surface.typeName

The runtime OCCT class name of this surface (e.g. "Geom_Plane", "Geom_BSplineSurface").

public var typeName: String? { get }
  • OCCT: Standard_Type::Name on the surface’s dynamic type.

HelixGeom

Helix

Namespace (enum) for helix curve construction using OCCT’s HelixGeom classes.

public enum Helix

All members are static — Helix has no instances.


Helix.BuildResult

The result of a helix build operation.

public struct BuildResult: Sendable {
    public let curve: Curve3D
    public let toleranceReached: Double
}
  • curve — the resulting BSpline approximation of the helix.
  • toleranceReached — the actual approximation error achieved.

BuildResult.toleranceReached


Helix.build(origin:direction:xDirection:parameterRange:pitch:radius:taperAngle:isClockwise:tolerance:)

Build a positioned helix curve approximated as a BSpline.

public static func build(
    origin: SIMD3<Double> = .zero,
    direction: SIMD3<Double> = SIMD3(0, 0, 1),
    xDirection: SIMD3<Double> = SIMD3(1, 0, 0),
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    tolerance: Double = 0.001
) -> BuildResult?
  • Parameters:
    • origin — centre point of the helix base.
    • direction — helix axis direction.
    • xDirection — X direction defining the angular starting position.
    • parameterRange — parameter domain t1...t2 (one revolution ≈ 2π for circular cross-section).
    • pitch — axial advance per revolution.
    • radius — helix radius at the start.
    • taperAngle — cone half-angle in radians (0 = constant radius).
    • isClockwisetrue for left-hand helix winding.
    • tolerance — maximum approximation error.
  • Returns: BuildResult with the BSpline curve and the achieved error, or nil on failure.
  • OCCT: HelixGeom_Helix + GeomAPI_PointsToBSpline (via OCCTHelixBuild).
  • Example:
    if let result = Helix.build(
        parameterRange: 0...(4 * .pi),
        pitch: 5,
        radius: 10
    ) {
        let curve = result.curve
        print("error:", result.toleranceReached)
        print("start:", curve.point(at: 0))
    }
    

Helix.buildCoil(parameterRange:pitch:radius:taperAngle:isClockwise:tolerance:)

Build a helix coil (no explicit position or orientation — uses default axis).

public static func buildCoil(
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    tolerance: Double = 0.001
) -> BuildResult?
  • Parameters: Same geometric parameters as build, minus origin/direction (defaults to Z-axis origin).
  • Returns: BuildResult, or nil on failure.
  • OCCT: HelixGeom_Helix coil variant (via OCCTHelixCoilBuild).

Helix.evaluate(parameterRange:pitch:radius:taperAngle:isClockwise:at:)

Evaluate a helix curve at a single parameter without building a BSpline.

public static func evaluate(
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    at u: Double
) -> SIMD3<Double>
  • Parameters: u — the parameter value to evaluate.
  • Returns: The 3D point on the helix at u.
  • OCCT: HelixGeom_Helix::Value (via OCCTHelixCurveEval).

Helix.evaluateD1(parameterRange:pitch:radius:taperAngle:isClockwise:at:)

Evaluate helix position and tangent at a single parameter.

public static func evaluateD1(
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    at u: Double
) -> (point: SIMD3<Double>, tangent: SIMD3<Double>)
  • OCCT: HelixGeom_Helix::D1 (via OCCTHelixCurveD1).

Helix.evaluateD2(parameterRange:pitch:radius:taperAngle:isClockwise:at:)

Evaluate helix position, first, and second derivatives at a single parameter.

public static func evaluateD2(
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    at u: Double
) -> (point: SIMD3<Double>, d1: SIMD3<Double>, d2: SIMD3<Double>)
  • OCCT: HelixGeom_Helix::D2 (via OCCTHelixCurveD2).

Helix.approximateToBSpline(parameterRange:pitch:radius:taperAngle:isClockwise:tolerance:)

Directly approximate a helix to a BSpline curve and return the maximum fitting error.

public static func approximateToBSpline(
    parameterRange: ClosedRange<Double>,
    pitch: Double,
    radius: Double,
    taperAngle: Double = 0,
    isClockwise: Bool = false,
    tolerance: Double = 0.001
) -> (curve: Curve3D, maxError: Double)?
  • Returns: (curve, maxError) or nil on failure. The returned BSpline is a direct approximation distinct from the helix-sampled interpolation used by build.
  • OCCT: HelixGeom_ApproxCurve or equivalent BSpline fitting (via OCCTHelixApproxToBSpline).
  • Example:
    if let (bsp, err) = Helix.approximateToBSpline(
        parameterRange: 0...(6 * .pi),
        pitch: 3,
        radius: 8,
        tolerance: 0.01
    ) {
        print("max error:", err)
        // Use bsp as a standard Curve3D for edge creation
        if let edge = Shape.edgeFromCurve(bsp) { print(edge.isValid) }
    }