Shape. Advanced Sweeps & API Completions
This page documents the advanced sweep, fill, proximity, and B-Rep query members of Shape from the v0.79.0–v0.128.0 range. For the primary Shape type overview, constructors, and boolean/transform/topology operations see the main Shape page (forthcoming as Shape.md).
Topics
- CoherentTriangulation · BRepFill_Evolved · BRepFill_OffsetAncestors · BRepExtrema_DistanceSS · BRepGProp_VinertGK · GeomFill_Profiler · GeomFill_Stretch · GeomFill_LocationDraft · GeomFill_GuideTrihedronAC · GeomFill_GuideTrihedronPlan · GeomFill_SectionPlacement · BRepFill_NSections · GeomFill_AppSurf · ShapeFix_ComposeShell · Transform, Boolean & Shape Query expansions (v0.115.0) · ThruSections builder · ShapeFixer builder · BRep_Tool completions v0.126.0 · Section with plane/surface & polygon queries v0.127.0 · BRep_Tool completions v0.128.0
CoherentTriangulation
Mutable coherent triangulation for mesh editing operations, wrapping Poly_CoherentTriangulation.
CoherentTriangulation.create()
Creates an empty coherent triangulation.
public static func create() -> CoherentTriangulation
- Returns: A new empty
CoherentTriangulation. - OCCT:
Poly_CoherentTriangulation(default constructor). - Example:
let ct = CoherentTriangulation.create()
CoherentTriangulation.createFromMesh(_:deflection:)
Creates a coherent triangulation from the triangulation of the first face of a meshed shape.
public static func createFromMesh(_ shape: Shape, deflection: Double = 0.1) -> CoherentTriangulation?
- Parameters:
shape, aShapethat has already been meshed.deflection, linear deflection used for auto-triangulation if the shape is not yet meshed; default0.1. - Returns: A
CoherentTriangulationpopulated from the face’s triangulation, ornilif the shape has no triangulation. - OCCT:
Poly_CoherentTriangulation,BRep_Tool::Triangulation. - Example:
let box = Shape.box(width: 10, height: 10, depth: 10)! if let ct = CoherentTriangulation.createFromMesh(box) { print(ct.triangleCount) }
setNode(x:y:z:)
Adds a node at the given coordinates.
public func setNode(x: Double, y: Double, z: Double) -> Int
- Returns: The 0-based index of the newly created node.
- OCCT:
Poly_CoherentTriangulation::SetNode. - Example:
let ct = CoherentTriangulation.create() let i0 = ct.setNode(x: 0, y: 0, z: 0)
addTriangle(_:_:_:)
Adds a triangle from three 0-based node indices.
@discardableResult
public func addTriangle(_ n0: Int, _ n1: Int, _ n2: Int) -> Bool
- Returns:
trueon success. - OCCT:
Poly_CoherentTriangulation::AddTriangle. - Example:
let ok = ct.addTriangle(0, 1, 2)
removeTriangle(at:)
Removes a triangle by its 0-based index.
@discardableResult
public func removeTriangle(at index: Int) -> Bool
- Returns:
trueon success. - OCCT:
Poly_CoherentTriangulation::RemoveTriangle.
triangleCount
Number of triangles in the coherent triangulation.
public var triangleCount: Int { get }
- OCCT:
Poly_CoherentTriangulation::NTriangles.
computeLinks()
Computes edge links between adjacent triangles.
public func computeLinks() -> Int
- Returns: The number of links computed.
- OCCT:
Poly_CoherentTriangulation::ComputeLinks.
linkCount
Number of edge links. Call computeLinks() first.
public var linkCount: Int { get }
- OCCT:
Poly_CoherentTriangulation::NLinks.
setDeflection(_:)
Sets the deflection value on the triangulation.
public func setDeflection(_ value: Double)
- OCCT:
Poly_CoherentTriangulation::SetDeflection.
deflection
The current deflection value of the triangulation.
public var deflection: Double { get }
- OCCT:
Poly_CoherentTriangulation::Deflection.
removeDegenerated(tolerance:)
Removes degenerated triangles whose area is below the given tolerance.
@discardableResult
public func removeDegenerated(tolerance: Double) -> Bool
- Returns:
trueif any degenerated triangles were removed. - OCCT:
Poly_CoherentTriangulation::RemoveDegenerated.
getResult()
Converts the coherent triangulation back to standard node/triangle counts.
public func getResult() -> (nodeCount: Int, triangleCount: Int)?
- Returns: A tuple of
(nodeCount, triangleCount), ornilon failure. - OCCT:
Poly_CoherentTriangulation.
nodeCoords(at:)
Gets the coordinates of a node by its 1-based index (after calling getResult()).
public func nodeCoords(at index: Int) -> (x: Double, y: Double, z: Double)?
- Returns: The
(x, y, z)coordinates of the node, ornilif the index is out of range. - OCCT:
Poly_CoherentTriangulation.
BRepFill_Evolved
Shape.evolved(spineFace:profileWire:axisOrigin:axisNormal:axisXDir:joinType:makeSolid:)
Creates an evolved shape by sweeping a 2D wire profile along the boundary of a planar face.
public static func evolved(spineFace: Shape, profileWire: Shape,
axisOrigin: SIMD3<Double> = SIMD3(0, 0, 0),
axisNormal: SIMD3<Double> = SIMD3(0, 0, 1),
axisXDir: SIMD3<Double> = SIMD3(1, 0, 0),
joinType: Int = 0, makeSolid: Bool = false) -> Shape?
- Parameters:
spineFace: planar face whose boundary edges define the sweep path.profileWire: 2D wire cross-section to sweep.axisOrigin,axisNormal,axisXDir, coordinate system of the profile plane; defaults to the XY plane at the origin. The profile is projected onto this frame’s YOZ plane: Y is the lateral offset from the spine, Z the height. A NaN, infinite or zero axis returnsnil(OCCT never returned from it, #3368).joinType: join strategy between adjacent sweep segments:0=Arc (round).1=Tangent and2=Intersection are not implemented by OCCT and returnnil.makeSolid:trueto cap the result into a solid.
- Returns: The evolved
Shape, ornilif the operation fails, including a profile that offsets the spine to nothing (OCCT’s empty compound is refused). - OCCT:
BRepFill_Evolved. - Example:
let spine = Shape.face(from: Wire.rectangle(width: 20, height: 20)!)! let line = Shape.fromWire( Wire.polygon3D([SIMD3(0, 0, 0), SIMD3(0, 0, 3)], closed: false)!)! let walls = Shape.evolved(spineFace: spine, profileWire: line) // four 20 x 3 walls
BRepFill_OffsetAncestors
Traces the ancestry of edges in an offset wire back to the original face edges. Wraps BRepFill_OffsetAncestors.
| Member | Kind | Meaning |
|---|---|---|
handle | internal stored property | The opaque OCCTOffsetAncestorsRef this wrapper owns; released in deinit. |
OffsetAncestors.create(face:offset:joinType:)
Creates an offset-ancestors tracker for a face offset by the given distance.
public static func create(face: Shape, offset: Double, joinType: Int = 0) -> OffsetAncestors?
- Parameters:
face: the source face.offset: signed offset distance; positive is outward, negative inward, asShape.offsetWire(face:offset:)andBRepOffsetAPI_MakeOffsetdefine them.joinType:0=Arc,1=Tangent,2=Intersection.
- Returns: An
OffsetAncestorsinstance, orniliffaceis not a face oroffsetis not finite.isDoneisfalsewhen the offset did not build or collapsed the face. - OCCT:
BRepFill_OffsetWirerun on the domainsBRepOffsetAPI_MakeOffsetbuilds, thenBRepFill_OffsetAncestors.
isDone
Whether the offset and ancestry computation succeeded.
public var isDone: Bool { get }
- OCCT:
BRepFill_OffsetAncestors::IsDone.
offsetWire
The offset wire the ancestry was computed on. Its edges are the keys hasAncestor(_:) and ancestor(of:) take: BRepFill_OffsetAncestors::HasAncestor is keyed on the offset wire’s own edges, which Shape.offsetWire(face:offset:) does not return (it builds a second, unrelated BRepFill_OffsetWire).
public var offsetWire: Shape? { get }
- Returns: The offset wire, or
nilwhen the offset was not done. - OCCT:
BRepFill_OffsetWire::Shape.
hasAncestor(_:)
Checks if an edge of the offset wire has a recorded ancestor. An edge of the original face is not an edge of the offset wire, so it has none.
public func hasAncestor(_ edge: Shape) -> Bool
- OCCT:
BRepFill_OffsetAncestors::HasAncestor.
ancestor(of:)
Returns the original edge that gave rise to the given edge of the offset wire. For a corner arc an Arc join adds on an outward offset, the ancestor is the face vertex it rounds.
public func ancestor(of edge: Shape) -> Shape?
- Returns: The ancestor
Shape, ornilif the edge has no recorded ancestor. - OCCT:
BRepFill_OffsetAncestors::Ancestor. - Example:
if let oa = OffsetAncestors.create(face: myFace, offset: -2.0), let wire = oa.offsetWire { for edge in wire.subShapes(ofType: .edge) { if let orig = oa.ancestor(of: edge) { print("traced", orig.shapeType) } } }
BRepExtrema_DistanceSS
distanceSS(to:deflection:)
Computes the minimum distance between two sub-shapes.
public func distanceSS(to other: Shape, deflection: Double = 1e-7) -> DistanceSSResult
- Parameters:
other: the second shape.deflection: maximum deviation of an extreme distance from the true minimum for it to be folded into the solution set (BRepExtrema_DistanceSS’stheDeflection). A numeric-tie tolerance, not a spatial search radius: raising it does not sample more finely, it widens how many near-minimum extrema get reported as “solutions” alongside the true one, and.point1/.point2are the first-appended solution, not guaranteed to be the minimal one. Default1e-7(Precision::Confusion()), OCCT’s own default (#1544).
- Returns: A
DistanceSSResultcontaining.distance,.point1,.point2,.solutionCount, and.isDone. - OCCT:
BRepExtrema_DistanceSS. - Example:
let a = Shape.box(width: 5, height: 5, depth: 5)! let b = Shape.box(width: 5, height: 5, depth: 5)!.translated(by: SIMD3(10, 0, 0))! let r = a.distanceSS(to: b) if r.isDone { print(r.distance) }
DistanceSSResult
Result struct returned by distanceSS(to:deflection:).
public struct DistanceSSResult {
public let distance: Double
public let point1: SIMD3<Double>
public let point2: SIMD3<Double>
public let solutionCount: Int
public let isDone: Bool
}
BRepGProp_VinertGK
vinertGK(location:tolerance:computeCG:)
Computes volume inertia properties of a face using Gauss-Kronrod numerical integration.
public func vinertGK(location: SIMD3<Double> = SIMD3(0, 0, 0),
tolerance: Double = 0.001, computeCG: Bool = true) -> VinertGKResult
- Parameters:
location: the reference point for inertia computation; defaults to the origin.tolerance: relative integration error bound; default0.001.computeCG: whether to compute the centre of gravity; defaulttrue.
- Returns: A
VinertGKResultwith.mass,.errorReached, and an optional.center. - OCCT:
BRepGProp_VinertGK. - Note: This method operates on a face shape. The
.massfield is the signed volume contribution, and stays non-optional because a zero contribution is a real answer that a caller summing over a shell needs..centerisnilwhen the contribution is 0, and whencomputeCGwasfalse; both used to report (0,0,0), which is indistinguishable from a real centroid at the origin (#609)..errorReachedisBRepGProp_VinertGK::GetErrorReached(); it used to be hardcoded to0.0on every call (#732). It is not unconditionally relative: OCCT divides the raw quadrature residual by|.mass|only when|.mass|clears an internal, near-machine-epsilon floor, and returns the undivided residual as-is below it, a distinction the return value gives no way to tell apart. That second branch could not be pinned by a test through the public API (measured: the floor needs|.mass|to underflow to essentially bit-exact0.0, far below what floating-point cancellation reaches for a real integral, ~1e-14at best); see the doc comment onVinertGKResultinShape+Analysis.swiftfor the full investigation. There is no.absoluteError: OCCT declaresGetAbsolutError()on the same class but never defines it, so calling it fails to link, and deriving one from.errorReached * .masswould go wrong exactly in that same near-zero-mass branch, so the field was removed rather than kept as a second silent zero. - A trimmed face is integrated over its trimmed region (#2806). The wrapper passed no
BRepGProp_Domain, andBRepGProp_VinertGK::PrivatePerformreads a null domain pointer as “there is only one curve to treat, the U isoline at UMax” (BRepGProp_VinertGK.cxx:271-276), so a face with a hole reported the unholed patch: the seven faces of a 20 x 20 x 2 plate with a radius-3 hole summed to 762.3008881569224 againstShape.volume743.4513322353836. It now loads the domain whenever the face has wires, which is whatBRepGProp::volumePropertiesGK(BRepGProp.cxx:698-710) does..errorReachedalso carries the failure signal: OCCT sets it to-1on each of its three failure exits (BRepGProp_VinertGK.cxx:289,:430,:455), and OCCT’s own loop abandons the whole shape when it sees a negative error, so treat.errorReached < 0as “.massis not a measurement” rather than as a large error. - Example:
let box = Shape.box(width: 10, height: 10, depth: 10)! let face = Shape.fromFace(box.faces()[0])! let gi = face.vinertGK() print(gi.mass, gi.center as Any)
VinertGKResult
Result struct returned by vinertGK(location:tolerance:computeCG:).
public struct VinertGKResult {
public let mass: Double
public let errorReached: Double
public let center: SIMD3<Double>?
}
| Field | Meaning |
|---|---|
errorReached | Actual relative error the Gauss-Kronrod integration achieved, for comparison against the requested tolerance. |
Shape.VinertGKResult.errorReached
GeomFill_Profiler
CurveProfiler homogenizes a set of Curve3D values into a single compatible BSpline representation, which is a prerequisite for multi-section surface operations. Wraps GeomFill_Profiler.
| Member | Kind | Meaning |
|---|---|---|
handle | internal stored property | The opaque OCCTGeomFillProfilerRef this wrapper owns; released in deinit. |
CurveProfiler.create()
Creates a new, empty curve profiler.
public static func create() -> CurveProfiler
- OCCT:
GeomFill_Profiler.
addCurve(_:)
Adds a curve to the profiler.
public func addCurve(_ curve: Curve3D)
- Returns:
Void. Ifcurvewraps a nullGeom_Curvehandle, it is silently dropped instead of added (#710 defensive hardening; no publicCurve3Dfactory can produce that state today), and there is nocurveCount/isValidsignal at the call site itself. A drop only shows up indirectly: the profiler ends up holding one fewer curve than the caller believes it added, so acurveIndexpassed topoles(curveIndex:)that counted the dropped curve addresses the wrong curve (or is out of range and returns[]). - OCCT:
GeomFill_Profiler::AddCurve.
perform(tolerance:)
Performs the homogenization of all added curves.
@discardableResult
public func perform(tolerance: Double = 1e-6) -> Bool
- Returns:
trueon success,falsewhen no curve has been added. - Empty profiler: refused in the bridge rather than passed on.
GeomFill_Profiler::PerformreachesUnifyByInsertingAllKnots, whose first statement indexes the first curve of the sequence, and the bound test that would refuse an empty one is compiled out of this Release kernel, so the process faults beforePerformreturns (#2884, measured inScripts/repro/2884). One curve is enough. - OCCT:
GeomFill_Profiler::Perform.
degree
Degree of the resulting homogenized BSpline curves.
public var degree: Int { get }
- OCCT:
GeomFill_Profiler::Degree.
poleCount
Number of poles per homogenized curve.
public var poleCount: Int { get }
- OCCT:
GeomFill_Profiler::NbPoles.
knotCount
Number of knots in the homogenized representation.
public var knotCount: Int { get }
- OCCT:
GeomFill_Profiler::NbKnots.
isPeriodic
Whether the homogenized curves are periodic.
public var isPeriodic: Bool { get }
- OCCT:
GeomFill_Profiler::IsPeriodic.
poles(curveIndex:)
Returns the poles for a specific curve (1-based index) after perform().
public func poles(curveIndex: Int) -> [SIMD3<Double>]
- Parameters:
curveIndex, 1-based index of the curve, in1...nwherenis the number of curvesaddCurve(_:)actually added. - Returns: An array of 3D pole positions, or empty if not computed or
curveIndexis out of range. - Range: enforced in the bridge, against a count the bridge keeps itself because
GeomFill_Profilerexposes none. The class documents the same range and tests it with twoStandard_DomainError_Raise_iflines this Release kernel compiles out, so measured on the pinned kernel with two curves loaded, index 0 faulted the process and index 5 or 1000000 returned another curve’s poles read from past the end of the sequence (#2884). - OCCT:
GeomFill_Profiler::Poles.
knotsAndMults()
Returns the knot vector and multiplicities of the homogenized representation.
public func knotsAndMults() -> (knots: [Double], mults: [Int])
- Returns: A tuple of parallel arrays; empty arrays on failure or before
perform(). - OCCT:
GeomFill_Profiler::KnotsAndMults. - Example:
let profiler = CurveProfiler.create() profiler.addCurve(c1) profiler.addCurve(c2) if profiler.perform() { let (knots, mults) = profiler.knotsAndMults() print(knots) }
GeomFill_Stretch
Surface.stretchFill(p1:p2:p3:p4:)
Computes a stretch filling pole grid from four boundary point arrays.
public static func stretchFill(p1: [SIMD3<Double>], p2: [SIMD3<Double>],
p3: [SIMD3<Double>], p4: [SIMD3<Double>]) -> StretchFillResult?
The four arrays are not in head-to-tail order round the patch. GeomFill_Stretch::Init lays the grid out the way GeomFill_Curved does, not the way GeomFill_Coons does (GeomFill_Stretch.cxx:60-99):
p1andp3are the two opposite boundaries indexed along U, on theV = firstandV = lastedges.p4lands on theU = firstedge andp2on theU = lastedge, the reverse ofGeomFill_Coons.
So for the four sides of a quadrilateral the order is (bottom, right, top, left), the same as Shape.curvedFilling and the opposite of Shape.coonsFilling’s (bottom, left, top, right). OCCT’s own production caller settles it: GeomFill_BSplineCurves::Init passes GeomFill_Stretch(P1, P2, P3, P4) and GeomFill_Curved(P1, P2, P3, P4) unswapped from the same four arranged curves and swaps only for GeomFill_Coons, which gets (P1, P4, P3, P2) (GeomFill_BSplineCurves.cxx:344-350).
The corner behaviour is Stretch’s own. The second loop runs only over the interior V range, so the four corner poles keep p1’s and p3’s values and a disagreeing p2[0], p2[n - 1], p4[0] or p4[n - 1] is dropped from the boundary rather than honoured. But GeomFill_Stretch also subtracts a bilinear patch through p1[0], p2[0], p3[n - 1] and p4[n - 1] from every interior pole (GeomFill_Stretch.cxx:92-96), a term GeomFill_Curved has no counterpart for, so p2[0] and p4[n - 1] still move the interior even while the boundary ignores them. Measured: moving p2[0] of a flat 10 x 10 square to (10, 0, 99) leaves the corner pole at (10, 0, 0) and drags the neighbouring interior pole to z = -18.5625, while the same move leaves a GeomFill_Curved grid pole for pole identical. p2[n - 1] and p4[0] are genuinely never read.
poles comes back row-major in U with V varying fastest, so the pole at (u, v), both zero-based, is poles[u * nbVPoles + v].
- Parameters:
p1, points along U on theV = firstedge;p2, points along V on theU = lastedge;p3, points along U on theV = lastedge, oppositep1;p4, points along V on theU = firstedge, oppositep2. All four of equal length ≥ 2. - Returns: A
StretchFillResultwith the pole grid dimensions and the flat pole array, ornilif the arrays have mismatched lengths, are too short, or the algorithm fails. - OCCT:
GeomFill_Stretch. - Measured in:
Scripts/repro/2795-geomfill-boundary-arrangement/, which prints every arrangement of a flat square for all threeGeomFill_Fillingclasses side by side (#2795, #2843). - Example:
// A flat 10 x 10 square, in the arrangement GeomFill_Stretch wants. let n = 5 let t = (0..<n).map { Double($0) / Double(n - 1) * 10 } let bottom = t.map { SIMD3<Double>($0, 0, 0) } // along U, the V = first edge let right = t.map { SIMD3<Double>(10, $0, 0) } // along V, the U = last edge let top = t.map { SIMD3<Double>($0, 10, 0) } // along U, the V = last edge let left = t.map { SIMD3<Double>(0, $0, 0) } // along V, the U = first edge if let r = Surface.stretchFill(p1: bottom, p2: right, p3: top, p4: left) { print(r.nbUPoles, r.nbVPoles) // 5 5 print(r.poles[12]) // (5.0, 5.0, 0.0), the square's centre }
StretchFillResult
Result struct returned by Surface.stretchFill(p1:p2:p3:p4:).
public struct StretchFillResult {
public let nbUPoles: Int
public let nbVPoles: Int
public let isRational: Bool
public let poles: [SIMD3<Double>]
}
The poles array is laid out in row-major order: poles[i * nbVPoles + j] gives the pole at (i, j).
GeomFill_LocationDraft
LocationDraft implements a draft-angle location law for pipe/sweep operations. It positions a profile along a path while applying a specified taper angle. Wraps GeomFill_LocationDraft.
LocationDraft.create(direction:angle:)
Creates a draft location law with a draft direction and angle.
public static func create(direction: SIMD3<Double>, angle: Double) -> LocationDraft
- Parameters:
direction, the draft direction vector.angle, draft angle in radians. - OCCT:
GeomFill_LocationDraft.
setCurve(_:)
Sets the sweep path curve on the location law.
@discardableResult
public func setCurve(_ curve: Curve3D) -> Bool
- Returns:
trueon success. - OCCT:
GeomFill_LocationDraft::SetCurve.
evaluate(at:)
Evaluates the location frame (rotation matrix + translation) at a path parameter.
public func evaluate(at param: Double) -> (matrix: [Double], translation: SIMD3<Double>)?
- Returns: A tuple where
matrixis a flat 9-element row-major 3×3 rotation matrix andtranslationis the origin offset, ornilon failure. - OCCT:
GeomFill_LocationDraft::D0.
setAngle(_:)
Updates the draft angle (radians).
public func setAngle(_ angle: Double)
- OCCT:
GeomFill_LocationDraft::SetAngle.
direction
The current draft direction vector.
public var direction: SIMD3<Double> { get }
- OCCT:
GeomFill_LocationDraft::Direction. - Example:
let ld = LocationDraft.create(direction: SIMD3(0, 0, 1), angle: 0.1) ld.setCurve(spine) if let frame = ld.evaluate(at: 0.5) { print(frame.translation) }
GeomFill_GuideTrihedronAC
GuideTrihedronAC computes an arc-length-corrected Frenet-like trihedron along a sweep path guided by an auxiliary curve. Wraps GeomFill_GuideTrihedronAC.
GuideTrihedronAC.create(guideCurve:)
Creates a guide trihedron law using an arc-length correction guide.
public static func create(guideCurve: Curve3D) -> GuideTrihedronAC
- Parameters:
guideCurve, the guide curve that influences the trihedron orientation. - OCCT:
GeomFill_GuideTrihedronAC.
setCurve(_:) (GuideTrihedronAC)
Sets the sweep path curve.
@discardableResult
public func setCurve(_ curve: Curve3D) -> Bool
- Returns:
trueon success. - OCCT:
GeomFill_GuideTrihedronAC::SetCurve.
evaluate(at:) (GuideTrihedronAC)
Evaluates the trihedron frame at the given path parameter.
public func evaluate(at param: Double) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)?
- Returns: The tangent, normal, and binormal vectors at
param, ornilon failure. - OCCT:
GeomFill_GuideTrihedronAC::D0. - Example:
let gta = GuideTrihedronAC.create(guideCurve: guide) gta.setCurve(spine) if let frame = gta.evaluate(at: 0.0) { print(frame.tangent) }
GeomFill_GuideTrihedronPlan
GuideTrihedronPlan computes a planar guide trihedron for sweep operations, keeping the profile in planes normal to the guide. Wraps GeomFill_GuideTrihedronPlan.
| Member | Kind | Meaning |
|---|---|---|
handle | internal stored property | The opaque OCCTGuideTrihedronPlanRef this wrapper owns; released in deinit. |
GuideTrihedronPlan.create(guideCurve:)
Creates a planar guide trihedron law from a guide curve.
public static func create(guideCurve: Curve3D) -> GuideTrihedronPlan
- OCCT:
GeomFill_GuideTrihedronPlan.
setCurve(_:) (GuideTrihedronPlan)
Sets the sweep path curve.
@discardableResult
public func setCurve(_ curve: Curve3D) -> Bool
- Returns:
trueon success. - OCCT:
GeomFill_GuideTrihedronPlan::SetCurve.
evaluate(at:) (GuideTrihedronPlan)
Evaluates the trihedron frame at the given path parameter.
public func evaluate(at param: Double) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)?
- Returns: The tangent, normal, and binormal vectors at
param, ornilon failure. - OCCT:
GeomFill_GuideTrihedronPlan::D0.
GeomFill_SectionPlacement
Curve3D.sectionPlacement(section:direction:draftAngle:tolerance:)
Places a section curve optimally onto a path curve using a draft location law, returning the closest-approach parameters and geometry.
public func sectionPlacement(section: Curve3D,
direction: SIMD3<Double> = SIMD3(0, 0, 1),
draftAngle: Double = 0,
tolerance: Double = 1e-3) -> SectionPlacementResult
Called on the path curve (self).
- Parameters:
section: the profile curve to place.direction: draft direction; defaults to +Z.draftAngle: taper angle in radians; default0.tolerance: positional tolerance; default1e-3.
- Returns: A
SectionPlacementResult(always returned; check.isDone). - OCCT:
GeomFill_SectionPlacement. - Example:
let r = spine.sectionPlacement(section: profile) if r.isDone { print(r.parameterOnPath, r.distance) }
SectionPlacementResult
Result struct returned by sectionPlacement(section:direction:draftAngle:tolerance:).
public struct SectionPlacementResult {
public let parameterOnPath: Double
public let parameterOnSection: Double
public let distance: Double
public let angle: Double
public let isDone: Bool
}
| Field | Meaning |
|---|---|
parameterOnPath | Parameter on the sweep path where the section was placed. |
parameterOnSection | Parameter on the section curve itself corresponding to that placement point. |
distance | Distance between the path point and the section curve at the placement. |
angle | Draft angle actually achieved at the placement. |
isDone | true if GeomFill_SectionPlacement::Perform succeeded. |
(Per-field anchors below, for cross-reference; the table above has the actual meaning of each.)
parameterOnSection
BRepFill_NSections
NSections encodes an N-section law describing how a set of wire cross-sections varies along a sweep or loft. Wraps BRepFill_NSections.
NSections.create(wires:)
Creates an N-section law from an array of wire shapes.
public static func create(wires: [Shape]) -> NSections?
- Parameters:
wires, two or more wire shapes representing the cross-section sequence. - Returns: An
NSectionsinstance, ornilon failure. - OCCT:
BRepFill_NSections.
lawCount
Number of section laws (one per wire pair interval).
public var lawCount: Int { get }
- OCCT:
BRepFill_NSections::NbLaw.
isConstant
Whether the section is constant (all wires are identical).
public var isConstant: Bool { get }
- OCCT:
BRepFill_NSections::IsConstant.
isVertex
Whether the section degenerates to a point vertex.
public var isVertex: Bool { get }
- OCCT:
BRepFill_NSections::IsVertex. - Example:
if let ns = NSections.create(wires: [w1, w2, w3]) { print(ns.lawCount, ns.isConstant) }
GeomFill_AppSurf
Surface.appSurf(curves:degMin:degMax:tol3d:tol2d:)
Approximates a BSpline surface from a sequence of section curves.
public static func appSurf(curves: [Curve3D], degMin: Int = 3, degMax: Int = 8,
tol3d: Double = 1e-3, tol2d: Double = 1e-3) -> AppSurfResult?
- Parameters:
curves: ordered section curves to interpolate/approximate. Requires at least 2 (#644); fewer returnsnilinstead of crashing the underlyingGeomFill_AppSurfsolver, which is never driven with fewer than 2 sections anywhere in the kernel.degMin,degMax, minimum and maximum allowed BSpline degree.tol3d,tol2d, 3D and 2D fitting tolerances.
- Returns: An
AppSurfResulton success, ornilif the algorithm fails or fewer than 2 curves are given. - OCCT:
GeomFill_AppSurf. - Example:
if let r = Surface.appSurf(curves: [c1, c2, c3]) { print(r.uDegree, r.vDegree, r.nbUPoles, r.nbVPoles) }
AppSurfResult
Result struct returned by Surface.appSurf(curves:degMin:degMax:tol3d:tol2d:).
public struct AppSurfResult {
public let uDegree: Int
public let vDegree: Int
public let nbUPoles: Int
public let nbVPoles: Int
public let nbUKnots: Int
public let nbVKnots: Int
public let isDone: Bool
}
ShapeFix_ComposeShell
composeShell(precision:uPatches:vPatches:)
Splits a face along the joint lines of a composite surface, and rebuilds its wires.
public func composeShell(precision: Double = 1e-6,
uPatches: Int = 1,
vPatches: Int = 1) -> Shape?
The grid is the face’s own surface tiled uPatches x vPatches over the face’s UV box, as Geom_RectangularTrimmedSurface patches, so subdividing needs no extra caller input. ShapeFix_ComposeShell cuts along the joints between patches, which is why the defaults, a 1 x 1 grid, split nothing: one face goes in and one comes out. That was the only behaviour available until #1638, so the defaults preserve it exactly.
Measured (Scripts/repro/1638/transcript.txt), on a 10 x 10 planar face and on a cylinder’s lateral face:
| grid | planar face out | cylinder wall out |
|---|---|---|
| 1 x 1 | 1 | 1 |
| 2 x 1 | 2 | 2 |
| 1 x 2 | 2 | 2 |
| 3 x 2 | 6 |
Even at 1 x 1 the call does the wire rebuild: ShapeFix_ComposeShell re-splits and re-orders the face’s wires against the surface and returns them as a shell, which repairs seam and degenerate-edge ordering on a face whose boundary has drifted. To subdivide a whole shape rather than one face, dividedByNumber(_:) and dividedByArea(maxArea:) are the shape-level tools.
- Parameters:
precision, the toleranceShapeFix_ComposeShell::Initreceives;uPatchesandvPatches, the grid, each at least 1. - Returns: A
Shape, the composed shell, ornilif the receiver is not a face, carries no surface, a patch count is below 1, orPerform()fails. - OCCT:
ShapeFix_ComposeShellover aShapeExtend_CompositeSurfaceofGeom_RectangularTrimmedSurfacepatches, initialised withShapeExtend_Natural(viaOCCTShapeFixComposeShell). The bridge sets aShapeBuild_ReShapecontext beforePerform(), because 8.0.0p1 null-derefs without one. - Note:
ShapeExtend_Parametrisationis not a parameter. Because the patches are sub-ranges of the face’s own surface,ShapeExtend_Naturalreproduces the face’s own parametrisation exactly and the face’s pcurves line up with the composite’s global UV; the other two modes renumber the joints away from the pcurves the face already carries. - Example:
if let face = Shape.cylinder(radius: 5, height: 10)?.subShapes(ofType: .face).first, let quarters = face.composeShell(uPatches: 4) { print(quarters.subShapes(ofType: .face).count) // 4, quarter cylinders }
Transform, Boolean & Shape Query expansions (v0.115.0)
transformed(matrix:)
Applies a rigid transformation (rotation + translation) described by a Matrix12Grouped matrix (GROUPED layout, see Matrix12Grouped in Document-Analysis-Builders.md).
public func transformed(matrix: Matrix12Grouped) -> Shape?
- Returns: The transformed
Shape, ornilif the operation fails. - OCCT:
BRepBuilderAPI_Transform,gp_Trsf. - Example:
// Identity rotation, translate by (5, 0, 0) if let m = Matrix12Grouped([1,0,0, 0,1,0, 0,0,1, 5,0,0]), let moved = box.transformed(matrix: m) { print(moved.isValid) } - Deprecated overload:
transformed(matrix: [Double]) -> Shape?still exists (@available(*, deprecated)) for source compatibility,nilifmatrix.count != 12. #835 (PR #864 review): before this,transformed(matrix:),transformed(byMatrix:), andgTransformed(matrix:)all took a plain[Double]distinguished only by which method you called, so a caller could silently garble a transform by feeding one method’s array shape to another. Passing the wrong type is now a compile error.
gTransformed(matrix:)
Applies a general affine transformation (supports non-uniform scaling/shear) described by a TransformMatrix3D matrix (INTERLEAVED layout, see TransformMatrix3D in Document-Analysis-Builders.md).
public func gTransformed(matrix: TransformMatrix3D) -> Shape?
- Returns: The transformed
Shape, ornilif the operation fails. - OCCT:
BRepBuilderAPI_GTransform,gp_GTrsf. - Note: The layout convention differs from
transformed(matrix:)’sMatrix12Grouped, this method takes the same INTERLEAVED layout astransformed(byMatrix:)instead: each row is[r_i0, r_i1, r_i2, t_i]. - Deprecated overload:
gTransformed(matrix: [Double]) -> Shape?still exists (@available(*, deprecated)) for source compatibility,nilifmatrix.count != 12. See #835 above.
section(with:tolerance:)
Computes a boolean section with a fuzzy tolerance.
public func section(with other: Shape, tolerance: Double) -> Shape?
- Parameters:
other, the tool shape.tolerance, fuzzy coincidence tolerance. - Returns: A
Shapecontaining the intersection edges/wires, ornilon failure. - OCCT:
BRepAlgoAPI_Sectionwith fuzzy value.
split(tools:tolerance:)
Splits this shape by multiple tool shapes simultaneously.
public func split(tools: [Shape], tolerance: Double = 0) -> Shape?
- Parameters:
tools, array of splitting shapes.tolerance, fuzzy tolerance; default0. - Returns: The split compound
Shape, ornilon failure. - OCCT:
BRepAlgoAPI_Splitter.
BooleanHistoryResult
Result struct for boolean operations with change-history flags.
public struct BooleanHistoryResult: Sendable {
public let shape: Shape
public let hasDeleted: Bool
public let hasModified: Bool
public let hasGenerated: Bool
}
| Field | Meaning |
|---|---|
hasDeleted | true if the operation deleted at least one sub-shape from the input with no surviving descendant. |
hasGenerated | true if the operation generated at least one new sub-shape with no ancestor in the input. |
Shape.BooleanHistoryResult.hasGenerated
subtractedWithHistory(_:tolerance:)
Performs a boolean subtraction and returns change-history flags alongside the result shape.
public func subtractedWithHistory(_ tool: Shape, tolerance: Double = 0) -> BooleanHistoryResult?
- Returns: A
BooleanHistoryResult, ornilon failure. - OCCT:
BRepAlgoAPI_Cutwith history builder. - Example:
if let r = solid.subtractedWithHistory(hole) { print(r.hasModified, r.shape.isValid) }
defeature(faces:tolerance:), the overload whose tolerance parameter BRepAlgoAPI_Defeaturing::Build never read (it forwards the input shape, the faces, the history flag and the parallel flag to BOPAlgo_RemoveFeatures, and nothing else. BOPAlgo_Options’ inherited fuzzy value is stored and never read, as its own header states outright: “the other options of the base class are not supported here and will have no effect”; measured across tolerances from 1e-7 to 100 against a BRepAlgoAPI_Cut control in Scripts/repro/497-defeaturing-fuzzy-inert/, #497), was deprecated and removed at v2.0.0 (#784). Use defeature(faces:).
triangulationNodeCount
Number of triangulation nodes on a face.
public var triangulationNodeCount: Int32 { get }
- OCCT:
BRep_Tool::Triangulation→Poly_Triangulation::NbNodes.
triangulationTriangleCount
Number of triangles in the face triangulation.
public var triangulationTriangleCount: Int32 { get }
- OCCT:
Poly_Triangulation::NbTriangles.
triangulationDeflection
The deflection value stored on the face triangulation.
public var triangulationDeflection: Double { get }
- OCCT:
Poly_Triangulation::Deflection.
triangulationNode(at:)
Returns the 3D coordinates of a triangulation node by its 1-based index.
public func triangulationNode(at index: Int32) -> SIMD3<Double>
- OCCT:
Poly_Triangulation::Node.
triangulationTriangle(at:)
Returns the three 1-based node indices of a triangle by its 1-based index.
public func triangulationTriangle(at index: Int32) -> (Int32, Int32, Int32)
- OCCT:
Poly_Triangulation::Triangle.
triangulationHasNormals
Whether the face triangulation stores per-node normals.
public var triangulationHasNormals: Bool { get }
- OCCT:
Poly_Triangulation::HasNormals.
triangulationNormal(at:)
Returns the normal vector at a triangulation node by its 1-based index.
public func triangulationNormal(at index: Int32) -> SIMD3<Double>
- OCCT:
Poly_Triangulation::Normal.
triangulationHasUVNodes
Whether the face triangulation stores per-node UV coordinates.
public var triangulationHasUVNodes: Bool { get }
- OCCT:
Poly_Triangulation::HasUVNodes.
triangulationUVNode(at:)
Returns the UV coordinates of a triangulation node by its 1-based index.
public func triangulationUVNode(at index: Int32) -> SIMD2<Double>
- OCCT:
Poly_Triangulation::UVNode.
edgeParameterAtArcLength(_:from:)
Finds the curve parameter on this edge at the given arc length from a start parameter.
public func edgeParameterAtArcLength(_ arcLength: Double, from startParam: Double) -> Double
- OCCT: the accumulated
GeomAbs_CNsub-piece lengths, with the final narrow piece handed toGCPnts_AbscissaPoint. The edge is read through aBRepAdaptor_Curve, whose constructor dereferences a null shape, so a null shape (fromShape.nullified) used to crash the process here; it answers0now (#1035). - Note: Shares the subdivided measurement with
edgeArcLength, so the two agree on the same edge. OCCT’s own root finder inverts one Gauss quadrature over[startParam, u], which on an elliptical edge disagreed with an accurate length by up to 1% in arc (#603).
edgeArcLength
The total arc length of this edge.
public var edgeArcLength: Double { get }
A null shape (from Shape.nullified) used to crash the process in the BRepAdaptor_Curve constructor behind this measurement; it answers the -1.0 failure sentinel now (#1035, measured in Scripts/repro/1035-unwrap-guard/).
- Returns: Arc length in model units, or
-1.0on failure. Arc length is otherwise always non-negative, so this is an unambiguous sentinel; it used to be0, which a genuinely zero-length edge also measures (#548). - OCCT:
BRepAdaptor_Curve+GCPnts_AbscissaPoint::LengthperGeomAbs_CNinterval, subdivided until two successive levels agree to 1e-9 relative (#603). - Note: An elliptical edge measured 1.485% long before #603, one Gauss quadrature over the edge’s whole domain. A straight or circular edge is unaffected (closed form).
edgeArcLength(from:to:)
Computes the arc length of this edge between two parameter values.
public func edgeArcLength(from u1: Double, to u2: Double) -> Double
- Parameters:
u1/u2, parameter range, either order. Both must be finite. - Returns: Arc length in model units, or
-1.0if a bound is not finite or the computation fails. - OCCT:
GCPnts_AbscissaPoint::LengthperGeomAbs_CNinterval, subdivided to convergence, the same measurement asedgeArcLength(#603). - Note:
.nanand±.infinityare rejected before OCCT sees them. This entry point used to hand a NaN bound’s result straight back: on a straight edge that was NaN itself, and on a multi-span edge0(a NaN upper bound) or the edge’s whole length (a NaN lower one), seeCurve3D.length(from:to:)for the mechanism (#548). - Note: A range reaching outside the edge’s parameter domain measures the part of it that lies on the edge (a range wholly outside measures
0); a closed periodic edge covers a whole period and so measures the whole range, winding. Shared with theCurve3D/Curve2Dspellings, so an edge and the curve it was built from answer identically (#600). - Note: A null shape (from
Shape.nullified) used to crash the process in theBRepAdaptor_Curveconstructor behind the measurement; it answers-1.0now (#1035). - Example:
let edge = Shape.edgeFromPoints(SIMD3(0, 0, 0), SIMD3(10, 0, 0))! let d = edge.edgeAdaptorDomain let half = edge.edgeArcLength(from: d.lowerBound, to: (d.lowerBound + d.upperBound) / 2) // half == 5.0
edgeParameterAtFraction(_:)
Returns the curve parameter at a fractional position (0–1) along the total edge length.
public func edgeParameterAtFraction(_ fraction: Double) -> Double
- OCCT:
edgeArcLength’s subdivided total, then the same walkedgeParameterAtArcLengthmakes. A null shape (fromShape.nullified) used to crash the process in theBRepAdaptor_Curveconstructor behind both halves; it answers0now (#1035). - Note: Both halves were biased by the same single quadrature before #603, and the two errors cancelled; both are accurate now, so
edgeParameterAtFraction(1.0)still lands on the edge’s last parameter and0.5genuinely halves the arc (it split an elliptical edge 0.74% off centre).
edgeAdaptorDomain
The parameter domain [first, last] of the edge curve via BRepAdaptor_Curve.
public var edgeAdaptorDomain: ClosedRange<Double> { get }
- OCCT:
BRepAdaptor_Curve::FirstParameter,LastParameter. A null shape (fromShape.nullified) used to crash the process in that constructor; it answers0...0now (#1035).
edgeAdaptorValue(at:)
Evaluates the edge curve at a parameter, returning the 3D point.
public func edgeAdaptorValue(at param: Double) -> SIMD3<Double>
- OCCT:
BRepAdaptor_Curve::Value. A null shape (fromShape.nullified) used to crash the process in theBRepAdaptor_Curveconstructor; it answersSIMD3(0, 0, 0)now (#1035).
edgeAdaptorCurveType
The curve type of the edge as a GeomAbs_CurveType integer (0=Line, 1=Circle, etc.).
public var edgeAdaptorCurveType: Int32 { get }
- OCCT:
BRepAdaptor_Curve::GetType. A null shape (fromShape.nullified) used to crash the process in theBRepAdaptor_Curveconstructor; it answers-1now, the value this already returned when the type could not be read (#1035).
faceAdaptorBounds
The UV parameter bounds of a face surface via BRepAdaptor_Surface.
public var faceAdaptorBounds: (uMin: Double, uMax: Double, vMin: Double, vMax: Double) { get }
- OCCT:
BRepAdaptor_Surface::FirstUParameter,LastUParameter,FirstVParameter,LastVParameter.
faceAdaptorValue(u:v:)
Evaluates the face surface at (u, v), returning the 3D point.
public func faceAdaptorValue(u: Double, v: Double) -> SIMD3<Double>
- OCCT:
BRepAdaptor_Surface::Value.
faceAdaptorSurfaceType
The surface type of the face as a GeomAbs_SurfaceType integer (0=Plane, 1=Cylinder, etc.).
public var faceAdaptorSurfaceType: Int32 { get }
- OCCT:
BRepAdaptor_Surface::GetType.
obbVolume
Volume of the oriented bounding box (OBB) of this shape.
public var obbVolume: Double { get }
- OCCT:
Bnd_OBBviaBRepBndLib::AddOBB.
maxEdgeTolerance
Maximum tolerance across all edges in this shape.
public var maxEdgeTolerance: Double { get }
- OCCT:
ShapeAnalysis_ShapeTolerance::Tolerance(shape, 1, TopAbs_EDGE)(viaOCCTShapeMaxEdgeTolerance). NotBRep_Tool::MaxTolerance, which this entry also used to name and which the bridge does not call here; that one is wrapped separately asmaxTolerance(subShapeType:). (#808)
maxFaceTolerance
Maximum tolerance across all faces in this shape.
public var maxFaceTolerance: Double { get }
- OCCT:
ShapeAnalysis_ShapeTolerance.
maxVertexTolerance
Maximum tolerance across all vertices in this shape.
public var maxVertexTolerance: Double { get }
- OCCT:
ShapeAnalysis_ShapeTolerance.
hasFreeEdges
Whether this shape contains free (non-shared) edges.
public var hasFreeEdges: Bool { get }
- OCCT:
TopExp::MapShapesAndAncestors(shape, TopAbs_EDGE, TopAbs_FACE, map)into aTopTools_IndexedDataMapOfShapeListOfShape, then true as soon as one edge has fewer than two faces (viaOCCTShapeHasFreeEdges). NeitherShapeAnalysis_FreeBoundsnorBRepCheck_Analyzer, which this entry used to name and neither of which is called here. This is a pure incidence count, so unlikefreeBounds(sewingTolerance:)it applies no tolerance and chains nothing into wires. (#808)
hasFreeWires
Whether this shape contains free (non-shared) wires.
public var hasFreeWires: Bool { get }
- OCCT:
TopExp::MapShapesAndAncestors, reporting any child with no parent.
hasFreeFaces
Whether this shape contains free (non-shared) faces.
public var hasFreeFaces: Bool { get }
- OCCT:
TopExp::MapShapesAndAncestors, reporting any child with no parent.
boundingDiagonal
Length of the axis-aligned bounding box diagonal.
public var boundingDiagonal: Double { get }
- OCCT:
BRepBndLib::Add,Bnd_Box::CornerMin/CornerMax.
centroid
Volumetric centroid of this shape, or nil when the shape encloses no volume.
public var centroid: SIMD3<Double>? { get }
- Returns: The volume centroid, or
nilfor a face, wire, edge, vertex or open shell. - OCCT:
GProp_GPropsviaBRepGProp::VolumePropertieswithOnlyClosed = true, plus aMass()test. - Was non-optional before #609, and outside the volume domain it returned the shape’s location origin rather than a recognisable zero: a face moved to (100,200,300) reported exactly that, and moved again reported (200,400,600). No caller could defend itself with
if c == .zero. - See also:
surfaceInertiafor an area centroid,linearProperties()for a length centroid,vertices()for a vertex position.
totalEdgeLength
Sum of arc lengths of all edges in this shape, one term per edge occurrence: an edge shared by two faces is counted once for each, so a box reads twice the sum of its 12 distinct edges. A degenerate edge adds 0.
public var totalEdgeLength: Double { get }
Each edge is measured as Edge.length measures it, so an elliptical edge no longer reads up to 1.485% long (10 x 1) and the total agrees with Wire.length and Curve3D.length (#3074).
let ellipse = Curve2D.ellipse(center: .zero, majorRadius: 10, minorRadius: 1)!
let shape = Shape.fromWire(Wire.fromCurve2D(ellipse)!)!
shape.totalEdgeLength // 40.6397418010, was 41.2431578703
Shape.box(width: 2, height: 3, depth: 5)!.totalEdgeLength // 80, each of 12 edges bounds two faces
- OCCT:
BRepAdaptor_Curveper edge, measured by the bridge’socctAdaptorArcLength(the same subdividedCPnts_AbscissaPointintegrationEdge.lengthuses). Edges that carry only a polygon fall back toBRepGProp::LinearProperties.
ThruSections builder (v0.115.0)
ThruSectionsBuilder drives BRepOffsetAPI_ThruSections through a builder pattern, providing full control over smoothing, degree, and continuity before building.
ThruSectionsBuilder.init(isSolid:isRuled:precision:)
Creates a loft builder.
public init(isSolid: Bool = true, isRuled: Bool = false, precision: Double = 1e-6)
- Parameters:
isSolid:true(default) caps the ends to produce a solid;falsegives a shell.isRuled:trueuses ruled (linear) surfaces between sections;false(default) uses BSpline.precision: 3D tolerance; default1e-6.
- OCCT:
BRepOffsetAPI_ThruSections. - Note: Mixing closed and open profiles causes a SIGSEGV inside OCCT (
BRepFill_CompatibleWires). A source patch shipped with this xcframework guards the iterator; still, ensure all profiles have the same open/closed status.
addWire(_:) (ThruSectionsBuilder)
Adds a wire profile as the next cross-section.
public func addWire(_ wire: Shape)
- OCCT:
BRepOffsetAPI_ThruSections::AddWire.
addVertex(_:) (ThruSectionsBuilder)
Adds a vertex (degenerate point) as a tip section.
public func addVertex(_ vertex: Shape)
- OCCT:
BRepOffsetAPI_ThruSections::AddVertex.
setSmoothing(_:)
Enables or disables smoothing of the loft surface.
public func setSmoothing(_ smoothing: Bool)
- OCCT:
BRepOffsetAPI_ThruSections::SetSmoothing.
setMaxDegree(_:)
Sets the maximum BSpline degree used for the loft.
public func setMaxDegree(_ maxDeg: Int)
- OCCT:
BRepOffsetAPI_ThruSections::SetMaxDegree.
setContinuity(_:) (ThruSectionsBuilder)
Sets the desired continuity of the lofted surface.
public func setContinuity(_ continuity: Int)
- Parameters:
continuity,0=C0,1=C1,2=C2. - OCCT:
BRepOffsetAPI_ThruSections::SetContinuity.
build() (ThruSectionsBuilder)
Executes the loft algorithm.
@discardableResult
public func build() -> Bool
- Returns:
trueon success. - OCCT:
BRepOffsetAPI_ThruSections::Build.
shape (ThruSectionsBuilder)
The result shape after a successful build().
public var shape: Shape? { get }
- Returns: The lofted
Shape, ornilunless abuild()call has succeeded since the most recent change to this builder’s sections (addWire(_:)/addVertex(_:)) or settings (setSmoothing(_:),setMaxDegree(_:),setContinuity(_:),checkCompatibility(_:),setParType(_:),setCriteriumWeight(w1:w2:w3:)), every one of those invalidates a prior successful build’s result, including on a builder reused across multiplebuild()calls. - OCCT:
BRepOffsetAPI_ThruSections::Shape. - Example:
let builder = ThruSectionsBuilder(isSolid: true) builder.addWire(bottomWire) builder.addWire(topWire) builder.setSmoothing(true) if builder.build(), let loft = builder.shape { print(loft.isValid) }
ShapeFixer builder (v0.115.0)
ShapeFixer provides configurable shape repair via ShapeFix_Shape, exposing precision, tolerance bounds, and per-fix status reporting.
ShapeFixer.init(shape:)
Creates a fixer for the given shape.
public init(shape: Shape)
- OCCT:
ShapeFix_Shape. TheShapeFix_Shapeconstructor accepts a null shape and returns;Perform()is the half that dereferences it, so a fixer built on a null shape (fromShape.nullified) used to crash the process on the laterperform()call. The fixer is now built empty for a null shape: the three setters become no-ops,perform()answersfalse,shapeanswersnil, and bothstatusoverloads answerfalse(#1035, measured inScripts/repro/1035-unwrap-guard/).
setPrecision(_:) (ShapeFixer)
Sets the working precision for repair algorithms.
public func setPrecision(_ precision: Double)
- OCCT:
ShapeFix_Root::SetPrecision.
setMaxTolerance(_:)
Sets the upper bound on tolerances that the fixer may assign.
public func setMaxTolerance(_ maxTol: Double)
- OCCT:
ShapeFix_Root::SetMaxTolerance.
setMinTolerance(_:)
Sets the lower bound on tolerances that the fixer may assign.
public func setMinTolerance(_ minTol: Double)
- OCCT:
ShapeFix_Root::SetMinTolerance.
perform() (ShapeFixer)
Runs all applicable shape-fixing algorithms.
@discardableResult
public func perform() -> Bool
- Returns:
trueif any fix was applied. - OCCT:
ShapeFix_Shape::Perform. Answersfalsewithout calling OCCT when the fixer was built on a null shape, which used to crash the process here (#1035).
shape (ShapeFixer)
The repaired shape after perform().
public var shape: Shape? { get }
- Returns: The fixed
Shape, ornilifperform()has not been called or produced nothing. - OCCT:
ShapeFix_Shape::Shape. Answersnilwhen the fixer was built on a null shape (#1035).
status(_:) (ShapeFixStatus overload)
Queries whether a specific ShapeExtend_Status flag is set after perform(), the full granularity ShapeFix_Shape::Status actually reports, not just the three combined flags the legacy Int overload below exposes (#849).
public func status(_ status: ShapeFixStatus) -> Bool
- Parameters:
status, seeShapeFixStatusbelow for the flag space and theShapeFix_Shapemeaning table. - Returns:
trueif the queried status flag is set. - OCCT:
ShapeFix_Shape::Status. - Example:
let fixer = ShapeFixer(shape: badShape) fixer.setPrecision(1e-4) fixer.perform() if fixer.status(.done3) { /* some free face was fixed */ }
status(_:) (Int overload, legacy)
Queries the fix result status via an undocumented 1/2/3 remap.
public func status(_ type: Int) -> Bool
- Parameters:
type,1=OK (no fix needed),2=DONE (fix applied),3=FAIL (fix attempted but failed). - Returns:
trueif the queried status flag is set;falsefor anytypeoutside1...3, there is no way to ask through this overload whether a specificDONEi/FAILi sub-flag fired. - OCCT:
ShapeFix_Shape::Status. - Note: Legacy. Prefer the
ShapeFixStatusoverload above (#849). Kept unchanged for source compatibility. - Example:
let fixer = ShapeFixer(shape: badShape) fixer.setPrecision(1e-4) fixer.perform() if let fixed = fixer.shape { print(fixer.status(2)) } // true = something was fixed
ShapeFixStatus
A status flag from OCCT’s ShapeExtend_Status enum, the flag space every ShapeFix_Root subclass (ShapeFix_Shape, ShapeFix_Face, ShapeFix_Wire, …) reports its fix result through. DONE1…DONE8 and FAIL1…FAIL8 are per-class: each subclass assigns its own meaning to the numbered slots, and a slot it does not use is simply never set. Shared by ShapeFixer.status(_:) above and FaceFixer.status(_:) (see Document-Mesh-Fixing.md), each with its own meaning table.
public enum ShapeFixStatus: Int32, Sendable, CaseIterable {
case ok = 0
case done1 = 1, done2, done3, done4, done5, done6, done7, done8
case done = 9
case fail1 = 10, fail2, fail3, fail4, fail5, fail6, fail7, fail8
case fail = 18
}
Raw values mirror the real OCCT ordinals exactly (ShapeExtend_Status.hxx, pinned V8_0_1):
| Case | Raw | Meaning for ShapeFix_Shape |
|---|---|---|
.ok | 0 | The shape needed no fix at all. |
.done1 | 1 | Some free edges were fixed. |
.done2 | 2 | Some free wires were fixed. |
.done3 | 3 | Some free faces were fixed. |
.done4 | 4 | Some free shells were fixed. |
.done5 | 5 | Some free solids were fixed. |
.done6 | 6 | Shapes in a compound were fixed. |
.done7 | 7 | Not assigned by ShapeFix_Shape. |
.done8 | 8 | Not assigned by ShapeFix_Shape. |
.done | 9 | Any .done1….done8 flag is set: something was fixed. |
.fail1….fail8 | 10…17 | Not assigned by ShapeFix_Shape. |
.fail | 18 | Any .fail1….fail8 flag is set: some pass failed. |
- Note: #849, this replaces a previous pair of independently-wrong encodings:
ShapeFixer’s ownstatus(Int)exposed only 3 of the 19 ordinals, andFaceFixer’s previous localStatusenum shifted everything from.fail1through.doneby one ordinal.FaceFixer.Statusis now a typealias for this type.
BRep_Tool completions (v0.126.0)
Shape.curveOnSurface(edge:face:)
Returns the 2D parametric curve (pcurve) of an edge on a face, with its parameter range.
public static func curveOnSurface(edge: Shape, face: Shape) -> (curve: Curve2D, first: Double, last: Double)?
- Returns: A tuple of the 2D
Curve2Dand itsfirst/lastparameter range, ornilif no pcurve exists. - OCCT:
BRep_Tool::CurveOnSurface.
Shape.hasContinuity(edge:face1:face2:)
Checks whether an edge has recorded continuity regularity between two adjacent faces.
public static func hasContinuity(edge: Shape, face1: Shape, face2: Shape) -> Bool
- OCCT:
BRep_Tool::HasContinuity.
Shape.continuity(edge:face1:face2:)
Returns the continuity order of an edge between two faces as a GeomAbs_Shape integer.
public static func continuity(edge: Shape, face1: Shape, face2: Shape) -> Int
- Returns:
GeomAbs_Shapeinteger:0=C0,1=G1,2=C1,3=G2,4=C2,5=C3,6=CN. - OCCT:
BRep_Tool::Continuity.
Shape.hasAnyContinuity(edge:)
Checks whether an edge has any recorded continuity on any pair of its surfaces.
public static func hasAnyContinuity(edge: Shape) -> Bool
- OCCT:
BRep_Tool::HasContinuity(any-surface overload).
Shape.maxContinuity(edge:)
Returns the maximum continuity of an edge across all surface pairs it belongs to.
public static func maxContinuity(edge: Shape) -> Int
- Returns: The highest
GeomAbs_Shapeinteger found. - OCCT:
BRep_Tool::MaxContinuity.
Shape.isDegenerated(edge:)
Returns true if the edge is degenerated (collapsed to a point in 3D).
public static func isDegenerated(edge: Shape) -> Bool
- OCCT:
BRep_Tool::Degenerated.
Shape.naturalRestriction(face:)
Returns the value of the NaturalRestriction flag on a face.
public static func naturalRestriction(face: Shape) -> Bool
A face with natural restriction uses the full parameter domain of its surface as its boundary without additional wire loops.
- OCCT:
BRep_Tool::NaturalRestriction.
Shape.rangeOnFace(edge:face:)
Returns the parameter range of an edge’s pcurve on a given face.
public static func rangeOnFace(edge: Shape, face: Shape) -> (first: Double, last: Double)?
- Returns: The
(first, last)parameter range, ornilif no pcurve exists. - OCCT:
BRep_Tool::Range.
Shape.parameterOnFace(vertex:edge:face:)
Returns the parameter of a vertex on the pcurve of an edge on a face.
public static func parameterOnFace(vertex: Shape, edge: Shape, face: Shape) -> Double?
- Returns: The parameter value, or
nilon failure. - OCCT:
BRep_Tool::Parameter.
Shape.parametersOnFace(vertex:face:)
Returns the UV parameters of a vertex on a face.
public static func parametersOnFace(vertex: Shape, face: Shape) -> (u: Double, v: Double)?
- Returns: The
(u, v)parameter pair, ornilif the vertex does not lie on the face. - OCCT:
BRep_Tool::Parameters.
Shape.uvPoints(edge:face:)
Returns the UV coordinates at both endpoints of an edge on a face.
public static func uvPoints(edge: Shape, face: Shape) -> (firstU: Double, firstV: Double, lastU: Double, lastV: Double)?
- Returns: Four UV values describing the start and end 2D positions, or
nilon failure. - OCCT:
BRep_Tool::UVPoints.
maxTolerance(subShapeType:)
Returns the maximum tolerance of all sub-shapes of the specified type within this shape.
public func maxTolerance(subShapeType: Int) -> Double
- Parameters:
subShapeType, OCCTTopAbs_ShapeEnuminteger:4=FACE,6=EDGE,7=VERTEX. - OCCT:
BRep_Tool::MaxTolerance(shape, TopAbs_ShapeEnum)(viaOCCTBRepToolMaxTolerance). NotShapeAnalysis_ShapeTolerance, which this entry also used to name and which is not in this chain; that one backsmaxEdgeToleranceinstead. The same wrong pairing appeared on both entries with the two classes the wrong way round; #808 corrected both. - Note: This is the real
TopAbs_ShapeEnumordinal, the same conventionShapeType’s raw values use, and the oneShape.maxTolerance(type:)’sShapeTypeoverload (see “Document-Mesh-Fixing”) passes through unchanged. It is NOT the same as that method’s legacyIntoverload, which uses a different, compressed0/1/2encoding for the same idea (#833).
Section with plane/surface & BRep_Tool Polygon queries (v0.127.0)
sectionWithPlane(normal:origin:)
Computes the section (intersection edges) of this shape with a plane.
public func sectionWithPlane(normal: SIMD3<Double>, origin: SIMD3<Double>) -> Shape?
- Parameters:
normal, outward normal of the cutting plane.origin, any point on the plane. - Returns: A
Shapecontaining the section edges/wires, ornilon failure. - OCCT:
BRepAlgoAPI_Sectionwith an internalgp_Pln. - Example:
if let section = solid.sectionWithPlane(normal: SIMD3(0,0,1), origin: SIMD3(0,0,5)) { print(section.edges.count) }
sectionWithSurface(_:)
Computes the section (intersection curves) of this shape with an arbitrary surface.
public func sectionWithSurface(_ surface: Surface) -> Shape?
- Returns: A
Shapecontaining the section edges, ornilon failure. - OCCT:
BRepAlgoAPI_Sectionwith aGeom_Surfacetool.
Shape.curveOnPlane(edge:surface:)
Returns the 2D projection of an edge onto a planar surface, with parameter range.
public static func curveOnPlane(edge: Shape, surface: Surface) -> (curve: Curve2D, first: Double, last: Double)?
- Returns: A
Curve2Dand its parameter range, ornilif projection fails. - OCCT:
BRep_Tool::CurveOnPlane.
Shape.polygon3D(edge:)
Returns the 3D polygon of a meshed edge (discrete approximation from triangulation).
public static func polygon3D(edge: Shape) -> [SIMD3<Double>]?
The shape must have been meshed (mesh(deflection:)) before calling this.
- Returns: An ordered array of 3D points along the edge, or
nilif no polygon is stored. - OCCT:
BRep_Tool::Polygon3D,Poly_Polygon3D::Nodes.
Shape.polygonOnTriangulation(edge:)
Returns the triangulation-node indices of a meshed edge as a 1-based index array.
public static func polygonOnTriangulation(edge: Shape) -> [Int]?
The shape must have been meshed first.
- Returns: An array of 1-based indices into the parent face’s
Poly_Triangulation, ornilif not available. - OCCT:
BRep_Tool::PolygonOnTriangulation,Poly_PolygonOnTriangulation::Nodes.
BRep_Tool completions (v0.128.0)
Shape.isClosedOnFace(edge:face:)
Checks whether an edge is topologically closed on a face (i.e., the edge has two pcurves on the face with opposing orientations).
public static func isClosedOnFace(edge: Shape, face: Shape) -> Bool
- OCCT:
BRep_Tool::IsClosed.
Shape.polygonOnSurface(edge:face:)
Returns the 2D polygon (UV) of a meshed edge on a face.
public static func polygonOnSurface(edge: Shape, face: Shape) -> [SIMD2<Double>]?
The shape must have been meshed first.
- Returns: An ordered array of 2D UV points, or
nilif not available. - OCCT:
BRep_Tool::PolygonOnSurface,Poly_Polygon2D::Nodes.
Shape.setUVPoints(edge:face:first:last:)
Sets the UV endpoint coordinates of an edge on a face (updates the stored 2D boundary).
@discardableResult
public static func setUVPoints(edge: Shape, face: Shape,
first: SIMD2<Double>, last: SIMD2<Double>) -> Bool
- Returns:
trueon success. - OCCT:
BRep_Tool::SetUVPoints(edge, face, first, last)(viaOCCTBRepToolSetUVPoints). Not a “setter overload ofBRep_Tool::UVPoints”, and notBRep_Builder, which this entry named until #808:SetUVPointsis its own static and writes through the edge’sBRep_CurveOnSurfacerepresentation directly. (#808) - Example:
let ok = Shape.setUVPoints(edge: e, face: f, first: SIMD2(0, 0), last: SIMD2(1, 0))
Bnd_OBB
OBB wraps OCCT’s Bnd_OBB: an oriented (rotated) bounding box, as opposed to the axis-aligned box Shape.bounds returns. Construct directly from a center, local axes, and half-sizes, or via OBB.fromShape(_:).
public final class OBB: @unchecked Sendable
| Member | Kind | Meaning |
|---|---|---|
handle | internal stored property | The opaque OCCTOBBRef this wrapper owns; released in deinit. |