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
- MakeEdge Completions, ProjOnCurve/Surf, DistShapeShape, ShapeFix Wire/Face
- TopoDS Builder, ShapeContents Expanded, FreeBoundsProperties, WireBuilder
- HelixGeom
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— aShapewith an existingPoly_Triangulationon its faces. - Returns: An iterator positioned before the first face, or
nilon failure. - OCCT:
OCCTMeshFaceIterCreate→RWMesh_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
nilon failure. - OCCT:
OCCTMeshVertexIterCreate→RWMesh_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::Pnton the currentTopoDS_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:
OCCTIntfToolCreate→Intf_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:
OCCTAsDesCreate→BRepAlgo_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::Descendantcount. - 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
nilon 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 withindomain. - 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
nilifindexis out of range. - OCCT:
TopoDS_Iterator(viaOCCTShapeChild).
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
nilifmatrix.count < 12or the operation fails. - OCCT:
TopLoc_Location+TopoDS_Shape::Located(viaOCCTShapeLocated).
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(viaOCCTShapeGetLocation).
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 ifmatrix.count < 12. - OCCT:
TopLoc_Location+TopoDS_Shape::Location(viaOCCTShapeSetLocation).
Shape.oriented(_:)
Create a copy with a specific orientation.
public func oriented(_ orientation: Int) -> Shape?
- Parameters:
orientation—0= Forward,1= Reversed,2= Internal,3= External. - Returns: Oriented copy, or
nilon failure. - OCCT:
TopoDS_Shape::Oriented(viaOCCTShapeOriented).
Shape.empty(type:)
Create an empty shape of the given topology type.
public static func empty(type: Int) -> Shape?
- Parameters:
type—0= Compound,2= Solid,3= Shell,5= Wire. - Returns: An empty shape of that type, or
nilon failure. - OCCT:
TopoDS_ShapewithTopAbs_ShapeEnum(viaOCCTShapeEmpty).
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
nilif the edges cannot be connected. - OCCT:
BRepBuilderAPI_MakeWire(viaOCCTMakeWireFromEdges). - 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
nilon failure. - OCCT:
BRepBuilderAPI_SewingorTopoDS_Builder(viaOCCTMakeShell).
Shape.checkFaceStatus(face:)
Check the validity status of a face within this shape.
public func checkFaceStatus(face: Shape) -> Int
- Returns: A
BRepCheck_Statusinteger;0=NoError. - OCCT:
BRepCheck_Analyzer→BRepCheck_Face::Status(viaOCCTCheckFaceStatus).
Shape.checkEdgeStatus(edge:)
Check the validity status of an edge within this shape.
public func checkEdgeStatus(edge: Shape) -> Int
- Returns: A
BRepCheck_Statusinteger;0=NoError. - OCCT:
BRepCheck_Analyzer→BRepCheck_Edge::Status.
Shape.checkVertexStatus(vertex:)
Check the validity status of a vertex within this shape.
public func checkVertexStatus(vertex: Shape) -> Int
- Returns: A
BRepCheck_Statusinteger;0=NoError. - OCCT:
BRepCheck_Analyzer→BRepCheck_Vertex::Status.
Shape.maxTolerance(type:)
Get the maximum tolerance of sub-shapes of the given type.
public func maxTolerance(type: Int) -> Double
- Parameters:
type—0= vertex,1= edge,2= face. - OCCT:
ShapeAnalysis_ShapeTolerance::TolerancewithStandard_True(max).
Shape.minTolerance(type:)
Get the minimum tolerance of sub-shapes of the given type.
public func minTolerance(type: Int) -> Double
- Parameters:
type—0= vertex,1= edge,2= face. - OCCT:
ShapeAnalysis_ShapeTolerance::TolerancewithStandard_False(min).
Shape.avgTolerance(type:)
Get the average tolerance of sub-shapes of the given type.
public func avgTolerance(type: Int) -> Double
- Parameters:
type—0= vertex,1= edge,2= face. - OCCT:
ShapeAnalysis_ShapeTolerance::Tolerancewith0(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:
trueif the operation succeeded. - OCCT:
ShapeFix_ShapeTolerance::SetTolerance(viaOCCTShapeFixTolerance).
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:
trueif the limit was applied. - OCCT:
ShapeFix_ShapeTolerance::LimitTolerance(viaOCCTShapeLimitMaxTolerance). - 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_Curvedynamic type check (viaOCCTCurve3DCurveType).
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
uon the curve, always inside its own domain, ornilif there is no curve to answer about. - OCCT:
occtNearestPointOnCurveRange(viaOCCTCurve3DNearestParameter) — the minimum overShapeAnalysis_Curve, everyGeomAPI_ProjectPointOnCurveextremum 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_Curvedynamic type (viaOCCTCurve2DCurveType).
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
nilif there is no curve to answer about. Agrees exactly withCurve2D.project(point:),Curve2D.project(_:)andPoint2D.distance(to:), which share its bridge path (#413, #500, #615). - OCCT:
occtNearestPointOnCurve2dRange(viaOCCTCurve2DNearestParameter) — the minimum over everyGeom2dAPI_ProjectPointOnCurveextremum in range and both ends. There is no third source:ShapeAnalysis_Curvehas 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_Surfacedynamic type (viaOCCTSurfaceGetType).
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, ornilonly if there is no curve to answer about. - OCCT:
GeomAPI_ProjectPointOnCurveover a ±10% window aroundinitParam, falling back toocctNearestPointOnCurveRangeover the whole curve (viaOCCTExtremaLocateOnCurve).
Two searches with two different contracts. The primary one reports the lowest-distance extremum inside that window — initParam 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 into0...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(viaOCCTExtremaPointCurve). - 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)ornilon failure. - OCCT:
Extrema_ExtPSlocal mode (viaOCCTExtremaLocateOnSurface).
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 into0...Sampling.maximumSampleCount(10,000,000); 0 or less returns empty (#622). - Returns: Array of
(u, v, distance)tuples for every extremum. - OCCT:
GeomAPI_ProjectPointOnSurf(viaOCCTExtremaPointSurface).
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
nilon failure. - OCCT:
BRepBuilderAPI_MakeEdge(gp_Elips)(viaOCCTMakeEdgeFromEllipse). - 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)(viaOCCTMakeEdgeFromEllipseArc).
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)(viaOCCTMakeEdgeFromHyperbolaArc).
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)(viaOCCTMakeEdgeFromParabolaArc).
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))(viaOCCTMakeEdgeFromCurve).
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)(viaOCCTMakeEdgeFromCurveParams). - 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)(viaOCCTMakeEdgeFromCurvePoints).
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))(viaOCCTMakeEdgeOnSurface).
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)(viaOCCTMakeEdgeOnSurfaceParams).
Shape.edgeVertex1()
Get the first vertex point of an edge shape.
public func edgeVertex1() -> SIMD3<Double>
- Returns: The start vertex position. Returns
SIMD3.zeroif this shape is not an edge. - OCCT:
BRep_Tool::PntonTopExp::FirstVertex(viaOCCTEdgeVertex1).
Shape.edgeVertex2()
Get the last vertex point of an edge shape.
public func edgeVertex2() -> SIMD3<Double>
- OCCT:
BRep_Tool::PntonTopExp::LastVertex(viaOCCTEdgeVertex2).
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)(viaOCCTMakeFaceFromSurfaceUV).
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)(viaOCCTMakeFaceFromGpPlane). - 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)(viaOCCTMakeFaceFromGpCylinder).
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
nilon failure. - OCCT:
GeomAPI_ProjectPointOnCurve(viaOCCTProjOnCurveCreate).
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(viaOCCTProjOnSurfCreate).
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
nilon failure. - OCCT:
BRepExtrema_DistShapeShape(viaOCCTDistSSCreate).
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
nilon failure. - OCCT:
ShapeFix_Wire(viaOCCTWireFixerCreate).
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
nilif 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(viaOCCTFaceFixerCreate).
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(viaOCCTIntCSCreate).
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(viaOCCTCurve3DBSplineSetKnot).
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(viaOCCTCurve3DBSplineGetKnotSequence).
Curve3D.bsplineWeights()
Get all pole weights (one per control point).
public func bsplineWeights() -> [Double]
- OCCT:
Geom_BSplineCurve::Weights(viaOCCTCurve3DBSplineGetWeights).
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(viaOCCTCurve3DBSplineInsertKnots).
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(viaOCCTCurve3DBSplineMovePoint).
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(viaOCCTCurve3DBSplineLocalValue).
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)whereweights.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:
trueif 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(viaOCCTBuilderMakeWire).
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:
trueif 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:
trueif 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(viaOCCTShapeGetContentsExtended). - 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
ConnectEdgesToWiresINTERNAL/EXTERNAL skip (OCCT#1408), at any tolerance; seeShape.freeBounds(sewingTolerance:)for why, on both branches. This type’s owninit?(shape:tolerance:)is where thetolerance <= 0branch (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
nilon failure. - Note: This is the call that selects the branch. Both are unaffected by OCCT 8.0.1’s
ConnectEdgesToWiresINTERNAL/EXTERNAL skip (OCCT#1408), but for different reasons and measured separately; seefreeBounds(sewingTolerance:). See #655. - OCCT:
ShapeAnalysis_FreeBoundsProperties(viaOCCTFreeBoundsPropsCreate).
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 istrueeven for a shape with no free bounds and for one never loaded, so this reportsIsLoaded()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(viaOCCTFreeBoundsPropsInfo).
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(viaOCCTFreeBoundsPropsWire).
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()(viaOCCTWireBuilderCreate).
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
nilif 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_FusewithSetFuzzyValue(viaOCCTBooleanFuseWithTolerance).
Shape.subtracted(_:tolerance:)
Cut another shape from this shape using a fuzzy Boolean tolerance.
public func subtracted(_ other: Shape, tolerance: Double) -> Shape?
- OCCT:
BRepAlgoAPI_CutwithSetFuzzyValue(viaOCCTBooleanCutWithTolerance).
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_CommonwithSetFuzzyValue(viaOCCTBooleanCommonWithTolerance).
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_FusewithSetGlue(viaOCCTBooleanFuseGlue).
Shape.subtracted(_:glue:)
Cut another shape with a glue mode hint.
public func subtracted(_ other: Shape, glue: GlueMode) -> Shape?
- OCCT:
BRepAlgoAPI_CutwithSetGlue(viaOCCTBooleanCutGlue).
Shape.intersected(with:glue:)
Compute the Boolean common with a glue mode hint.
public func intersected(with other: Shape, glue: GlueMode) -> Shape?
- OCCT:
BRepAlgoAPI_CommonwithSetGlue(viaOCCTBooleanCommonGlue). - 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(viaOCCTOffsetWireOnPlane). - 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_MakeOffseton a face (viaOCCTOffsetFace).
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(viaOCCTThickSolidWithOptions). - 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:
trueif the orientation was fixed. - OCCT:
BRepLib::OrientClosedSolid(viaOCCTBRepLibOrientClosedSolid).
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-5deviates by 2.6e-6,1e-7by 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:
falseif 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, sofalsemeans “partially built”, not “nothing happened”. - OCCT:
BRepLib::BuildCurves3d(viaOCCTBRepLibBuildCurves3dForShape). - 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-7until #498. It moved to1e-5when this method absorbedbuildCurves3dAll, whose separate C entry point had a byte-identical body and whose default was already OCCT’s 1e-5. Passtolerance: 1e-7to 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
nilon failure. - OCCT:
BRepLib::SortFaces(viaOCCTBRepLibSortFaces).
Shape.reverseSortedFaces()
Get the faces sorted by increasing area.
public func reverseSortedFaces() -> Shape?
- OCCT:
BRepLib::ReverseSortFaces(viaOCCTBRepLibReverseSortFaces).
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
nilfor 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_GPropslinear analysis plus aMass()test (viaOCCTShapeLinearProperties). - 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
nilfor 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_GPropsvolumetric analysis withOnlyClosed = trueplus aMass()test (viaOCCTShapeMomentOfInertia).
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
nilfor 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 thatmath_Jacobireturns for the zero inertia matrix (#609). - OCCT:
GProp_GProps::PrincipalPropertiesplus aMass()test (viaOCCTShapePrincipalAxes).
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
nilfor a shape with no closed volume. OCCT computes this assqrt(momentOfInertia / mass)with no guard, so it used to return NaN there, which propagates silently through any arithmetic that consumes it. ItsGProp_PrincipalPropssibling is guarded, which is why the radii-triple read 0 from the same framework that made this NaN (#609). - OCCT:
GProp_GProps::RadiusOfGyrationplus aMass()test (viaOCCTShapeRadiusOfGyration).
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_Colornamed-colour registry (viaOCCTNamedColorCount).
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), ornilif this shape is not an edge or has no 3D curve. - OCCT:
BRep_Tool::Curve(viaOCCTShapeEdgeCurve). - 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, ornilif this shape is not a face. - OCCT:
BRep_Tool::Surface(viaOCCTShapeFaceSurface).
Shape.isClosedShape
Whether this shape (wire or shell) is closed.
public var isClosedShape: Bool { get }
- OCCT:
BRep_Tool::IsClosed(viaOCCTShapeIsClosed).
Shape.uniqueEdgeCount
Number of unique (topologically distinct) edges in this shape.
public var uniqueEdgeCount: Int { get }
- OCCT:
TopExp_ExplorerwithTopAbs_EDGE, deduplicated (viaOCCTShapeUniqueEdgeCount).
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— theShapeTypeto count. - OCCT:
TopExp_Explorerdeduplicated (viaOCCTShapeUniqueSubShapeCount).
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(viaOCCTShapeEmptyCopied).
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(viaOCCTCurve3DDN).
Curve3D.typeName
The runtime OCCT class name of this curve (e.g. "Geom_Line", "Geom_BSplineCurve").
public var typeName: String? { get }
- OCCT:
Standard_Type::Nameon the curve’s dynamic type (viaOCCTCurve3DTypeName).
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(viaOCCTCurve2DDN).
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::Nameon 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(viaOCCTSurfaceDN).
Surface.typeName
The runtime OCCT class name of this surface (e.g. "Geom_Plane", "Geom_BSplineSurface").
public var typeName: String? { get }
- OCCT:
Standard_Type::Nameon 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 domaint1...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).isClockwise—truefor left-hand helix winding.tolerance— maximum approximation error.
- Returns:
BuildResultwith the BSpline curve and the achieved error, ornilon failure. - OCCT:
HelixGeom_Helix+GeomAPI_PointsToBSpline(viaOCCTHelixBuild). - 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, ornilon failure. - OCCT:
HelixGeom_Helixcoil variant (viaOCCTHelixCoilBuild).
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(viaOCCTHelixCurveEval).
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(viaOCCTHelixCurveD1).
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(viaOCCTHelixCurveD2).
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)ornilon failure. The returned BSpline is a direct approximation distinct from the helix-sampled interpolation used bybuild. - OCCT:
HelixGeom_ApproxCurveor equivalent BSpline fitting (viaOCCTHelixApproxToBSpline). - 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) } }