Shape. Builders & Boolean Internals II
Continuation of the low-level builder and algorithm wrappers on Shape, covering GeomFill sweep/evolved-section, projection, offset, iso-curve evaluation, parameter transfer, boolean section/feature removal, shape build/extend/upgrade utilities, 2D vector math, topological transition analysis, GeomFill trihedrons, 2D polygon interference, analytical 2D circle construction, IntTools intersection, BOPAlgo builders, BRepFeat split/hole/glue, LocOpe split/glue, and 2D chamfer/fillet APIs.
See also: Shape (index).
Topics
- GeomFill_Sweep · GeomFill_EvolvedSection · ProjLib_ComputeApprox · BRepOffset_Offset · Adaptor3d_IsoCurve · ShapeAnalysis_TransferParametersProj · BOPAlgo_RemoveFeatures · BOPAlgo_Section · ShapeBuild_Edge · ShapeBuild_Vertex · ShapeExtend_Explorer · ShapeUpgrade_FaceDivide · ShapeUpgrade_WireDivide · ShapeUpgrade_EdgeDivide · ShapeUpgrade_ClosedEdgeDivide · ShapeUpgrade_ConvertCurve3dToBezier · ShapeUpgrade_ConvertSurfaceToBezierBasis · 2D Vector/Direction Utilities & LProp · TopTrans Surface Transition · TopTrans Curve Transition · GeomFill Trihedrons · Polygon Interference · GccAna_Circ2d3Tan · IntTools · BOPAlgo Builder · BOPTools · IntTools_BeanFaceIntersector · BOPAlgo_WireSplitter · BRepFeat_SplitShape · BRepFeat_MakeCylindricalHole · BRepFeat_Gluer · LocOpe_WiresOnShape + LocOpe_Spliter · LocOpe_Gluer · ChFi2d_Builder · ChFi2d_ChamferAPI · ChFi2d_FilletAPI · FilletSurf_Builder
GeomFill_Sweep
Shape.geomFillSweep(path:section:)
Sweep a section edge along a path edge to create a surface face.
public static func geomFillSweep(path: Shape, section: Shape) -> Shape?
- Parameters:
path, edge defining the sweep path.section, edge defining the cross-section profile. - Returns: A
Shapewrapping the swept face, ornilon failure, including whenGeomFill_Sweepfits the surface but misses its own 1e-4 tolerance (ErrorOnSurface()); a surface reportedIsDone()is not necessarily within the tolerance it was built at, so this is checked rather than assumed (#597). - OCCT:
GeomFill_Sweep - Example:
if let face = Shape.geomFillSweep(path: pathEdge, section: sectionEdge) { // face is a swept surface }
GeomFill_EvolvedSection
evolvedSectionInfo()
Get evolved section info for an edge curve.
public func evolvedSectionInfo() -> EvolvedSectionInfo
- Returns:
EvolvedSectionInfowithnbPoles,nbKnots,degree, andisRational. - OCCT:
GeomFill_EvolvedSection - Example:
let info = edge.evolvedSectionInfo() print(info.degree, info.isRational)
EvolvedSectionInfo.nbPoles
Number of BSpline control poles in the evolved section curve.
EvolvedSectionInfo.nbKnots
Number of BSpline knots in the evolved section curve.
ProjLib_ComputeApprox
projectOntoSurface(_:tolerance:)
Project this edge’s 3D curve onto a face’s surface, returning an edge-on-surface.
public func projectOntoSurface(_ face: Shape, tolerance: Double = 1e-3) -> Shape?
- Parameters:
face, target face.tolerance, approximation tolerance. - Returns: Projected edge as shape, or
nilon failure. - OCCT:
ProjLib_ComputeApprox - Example:
if let proj = edge.projectOntoSurface(face) { }
projectOntoPolarSurface(_:tolerance:)
Project this edge’s 3D curve onto a polar surface (sphere, torus).
public func projectOntoPolarSurface(_ face: Shape, tolerance: Double = 1e-3) -> Shape?
- Parameters:
face, polar face.tolerance, approximation tolerance. - Returns: Projected edge as shape, or
nilon failure. - OCCT:
ProjLib_ComputeApproxOnPolarSurface - Example:
if let proj = edge.projectOntoPolarSurface(sphereFace) { }
BRepOffset_Offset
offsetFace(distance:)
Offset a face by a distance, creating a new offset face.
public func offsetFace(distance: Double) -> Shape?
- Parameters:
distance, signed offset amount; positive moves along the face normal. - Returns: Offset face, or
nilon failure. - OCCT:
BRepOffset_Offset - Example:
if let off = face.offsetFace(distance: 2.0) { }
Adaptor3d_IsoCurve
uIsoCurvePoints(u:count:)
Evaluate sample points along a U-iso curve on a face.
public func uIsoCurvePoints(u: Double, count: Int = 20) -> [SIMD3<Double>]
- Parameters:
u, U parameter value.count, number of sample points, a request honoured within1...Sampling.maximumSampleCount(10,000,000); outside that range the result is empty (#558). - Returns: Array of 3D points along the iso curve.
- OCCT:
Adaptor3d_IsoCurve, selected withGeomAbs_IsoU/GeomAbs_IsoV(iso kind 0 = U) - Note: The samples are spread evenly over the iso curve’s own parameter range, clamped to
-1e6...1e6when the surface is infinite in that direction (a plane, or a cylinder’s V), so on an unbounded face the points span that clamp rather than anything derived from the face’s own extent. When the shape is not a face, or its surface cannot be read, the bridge writes nothing and the array comes back ascountpoints at the origin rather than empty. - Example:
let pts = face.uIsoCurvePoints(u: 0.5, count: 50)
vIsoCurvePoints(v:count:)
Evaluate sample points along a V-iso curve on a face.
public func vIsoCurvePoints(v: Double, count: Int = 20) -> [SIMD3<Double>]
- Parameters:
v, V parameter value.count, number of sample points, a request honoured within1...Sampling.maximumSampleCount(10,000,000); outside that range the result is empty (#558). - Returns: Array of 3D points along the iso curve.
- OCCT:
Adaptor3d_IsoCurve, selected withGeomAbs_IsoU/GeomAbs_IsoV(iso kind 1 = V) - Note: The samples are spread evenly over the iso curve’s own parameter range, clamped to
-1e6...1e6when the surface is infinite in that direction (a plane, or a cylinder’s V), so on an unbounded face the points span that clamp rather than anything derived from the face’s own extent. When the shape is not a face, or its surface cannot be read, the bridge writes nothing and the array comes back ascountpoints at the origin rather than empty. - Example:
let pts = face.vIsoCurvePoints(v: 0.25)
uIsoCurveEdge(u:vMin:vMax:)
Extract a U-iso curve from a face as an edge.
public func uIsoCurveEdge(u: Double, vMin: Double, vMax: Double) -> Shape?
- Parameters:
u, U parameter.vMin/vMax, V parameter range for the edge. - Returns: Edge shape representing the iso curve, or
nilon failure. - OCCT:
Geom_Surface::UIso/VIsoturned into an edge byBRepBuilderAPI_MakeEdge(noAdaptor3d_IsoCurve, unlike the point samplers above) - Example:
if let e = face.uIsoCurveEdge(u: 0.5, vMin: 0, vMax: 1) { }
vIsoCurveEdge(v:uMin:uMax:)
Extract a V-iso curve from a face as an edge.
public func vIsoCurveEdge(v: Double, uMin: Double, uMax: Double) -> Shape?
- Parameters:
v, V parameter.uMin/uMax, U parameter range for the edge. - Returns: Edge shape representing the iso curve, or
nilon failure. - OCCT:
Geom_Surface::UIso/VIsoturned into an edge byBRepBuilderAPI_MakeEdge(noAdaptor3d_IsoCurve, unlike the point samplers above) - Example:
if let e = face.vIsoCurveEdge(v: 0.5, uMin: 0, uMax: 1) { }
ShapeAnalysis_TransferParametersProj
transferParameterToFace(_:face:)
Transfer a parameter from edge to face coordinate system via projection.
public func transferParameterToFace(_ param: Double, face: Shape) -> Double
- Parameters:
param, edge parameter.face, face to transfer into. - Returns: Corresponding parameter in the face’s coordinate system.
- OCCT:
ShapeAnalysis_TransferParametersProj(toFace = true) - Example:
let faceParam = edge.transferParameterToFace(0.5, face: face)
transferParameterFromFace(_:face:)
Transfer a parameter from face to edge coordinate system via projection.
public func transferParameterFromFace(_ param: Double, face: Shape) -> Double
- Parameters:
param, face parameter.face, face to transfer from. - Returns: Corresponding parameter in the edge’s coordinate system.
- OCCT:
ShapeAnalysis_TransferParametersProj(toFace = false) - Example:
let edgeParam = edge.transferParameterFromFace(0.5, face: face)
BOPAlgo_RemoveFeatures
removeFeatures(faces:) was defeature(faces:) under a second name: BRepAlgoAPI_Defeaturing, which defeature(faces:) drives, is an API wrapper over BOPAlgo_RemoveFeatures, and both spellings drove one algorithm object with identical defaults, measured byte-for-byte identical on every case including the refusals (see Scripts/repro/536-defeature-removefeatures-unify/). Deprecated as a forward to defeature(faces:) in #536, removeFeatures(faces:) was removed at v2.0.0 (#784); use defeature(faces:).
let faces = solid.subShapes(ofType: .face)
if let cleaned = solid.defeature(faces: [faces[2]]) { }
BOPAlgo_Section
section(with:)
Compute section (intersection curves/vertices) between this shape and tools.
public func section(with tools: [Shape]) -> Shape?
- Parameters:
tools, tool shapes to intersect with this shape. - Returns: Compound of intersection edges and vertices, or
nilon failure. - OCCT:
BOPAlgo_Section - Example:
if let sect = solid.section(with: [plane]) { }
Shape.section(shapes:)
Compute section between multiple shapes (static variant).
public static func section(shapes: [Shape]) -> Shape?
- Parameters:
shapes, at least 2 shapes; all are treated as equal arguments. - Returns: Compound of intersection edges and vertices, or
nilon failure (requires ≥ 2 shapes). - OCCT:
BOPAlgo_Section - Example:
if let sect = Shape.section(shapes: [box, sphere]) { }
ShapeBuild_Edge
copyEdge(sharePCurves:)
Copy an edge, optionally sharing its PCurves with the original.
public func copyEdge(sharePCurves: Bool = true) -> Shape?
- Parameters:
sharePCurves, iftrue, the copy shares PCurves with the original edge. - Returns: Copied edge as shape, or
nilon failure. - OCCT:
ShapeBuild_Edge::Copy - Example:
if let copy = edge.copyEdge() { }
copyEdgeReplacingVertices(startVertex:endVertex:)
Copy an edge, replacing its start and/or end vertices.
public func copyEdgeReplacingVertices(startVertex: Shape?, endVertex: Shape?) -> Shape?
- Parameters:
startVertex, new start vertex, ornilto keep original.endVertex, new end vertex, ornilto keep original. - Returns: Edge with replaced vertices, or
nilon failure. - OCCT:
ShapeBuild_Edge::CopyReplaceVertices - Example:
if let e = edge.copyEdgeReplacingVertices(startVertex: v1, endVertex: nil) { }
setEdgeRange3d(first:last:)
Set the 3D parameter range on this edge shape.
public func setEdgeRange3d(first: Double, last: Double)
- Parameters:
first, start parameter.last, end parameter. - OCCT:
ShapeBuild_Edge::SetRange3d - Example:
edge.setEdgeRange3d(first: 0, last: 1)
buildEdgeCurve3d()
Rebuild the 3D curve of an edge from its PCurves.
@discardableResult
public func buildEdgeCurve3d() -> Bool
- Returns:
trueif the curve was rebuilt successfully. - OCCT:
ShapeBuild_Edge::BuildCurve3d - Example:
edge.buildEdgeCurve3d()
removeEdgeCurve3d()
Remove the 3D curve from this edge.
public func removeEdgeCurve3d()
- OCCT:
ShapeBuild_Edge::RemoveCurve3d - Example:
edge.removeEdgeCurve3d()
copyEdgeRanges(from:)
Copy parameter ranges from another edge to this edge.
public func copyEdgeRanges(from source: Shape)
- Parameters:
source, edge from which to copy ranges. - OCCT:
ShapeBuild_Edge::CopyRanges - Example:
edge.copyEdgeRanges(from: sourceEdge)
copyEdgePCurves(from:)
Copy PCurves from another edge to this edge.
public func copyEdgePCurves(from source: Shape)
- Parameters:
source, edge from which to copy PCurves. - OCCT:
ShapeBuild_Edge::CopyPCurves - Example:
edge.copyEdgePCurves(from: sourceEdge)
removeEdgePCurve(onFace:)
Remove the PCurve from this edge for a given face.
public func removeEdgePCurve(onFace face: Shape)
- Parameters:
face, the face whose PCurve should be removed from this edge. - OCCT:
ShapeBuild_Edge::RemovePCurve - Example:
edge.removeEdgePCurve(onFace: face)
reassignEdgePCurve(from:to:)
Reassign a PCurve from one face to another.
@discardableResult
public func reassignEdgePCurve(from oldFace: Shape, to newFace: Shape) -> Bool
- Parameters:
oldFace, face that currently holds the PCurve.newFace, destination face. - Returns:
trueif reassignment succeeded. - OCCT:
ShapeBuild_Edge::ReassignPCurve - Example:
edge.reassignEdgePCurve(from: oldFace, to: newFace)
ShapeBuild_Vertex
combineVertex(with:tolFactor:)
Combine this vertex shape with another at their average position.
public func combineVertex(with other: Shape, tolFactor: Double = 1.0001) -> Shape?
- Parameters:
other, vertex to combine with.tolFactor, tolerance scale factor. - Returns: Combined vertex as shape, or
nilon failure. - OCCT:
ShapeBuild_Vertex::CombineVertex - Example:
if let v = v1.combineVertex(with: v2) { }
Shape.combineVertices(point1:tol1:point2:tol2:tolFactor:)
Create a vertex by combining two 3D points with tolerances.
public static func combineVertices(
point1: SIMD3<Double>, tol1: Double,
point2: SIMD3<Double>, tol2: Double,
tolFactor: Double = 1.0001
) -> Shape?
- Parameters:
point1/tol1, first point and its tolerance.point2/tol2, second point and its tolerance.tolFactor, scale factor applied to the combined tolerance. - Returns: Combined vertex, or
nilon failure. - OCCT:
ShapeBuild_Vertex::CombineVertex(from points) - Example:
if let v = Shape.combineVertices(point1: .zero, tol1: 1e-7, point2: SIMD3(0,0,0.001), tol2: 1e-7) { }
ShapeExtend_Explorer
ShapeFilterType
Shape type enum for filtering compounds.
public typealias ShapeFilterType = ShapeType
A typealias for the canonical ShapeType (see “Shape-Features”), this used to be an independent local mirror of the same TopAbs_ShapeEnum ordinals, with its own, differently-cased compsolid case (ShapeType spells it compSolid). ShapeExtend_Explorer uses the identical ordinal convention every other sub-shape-type API in this package does, so there was no reason for a second declaration once the casing was reconciled (#844).
sortedCompound(type:explore:)
Filter this compound, extracting only sub-shapes of the specified type.
public func sortedCompound(type: ShapeFilterType, explore: Bool = true) -> Shape?
- Parameters:
type, target shape type.explore, iftrue, recurse into sub-compounds. - Returns: Compound of matching sub-shapes, or
nilon failure. - OCCT:
ShapeExtend_Explorer::SortedCompound - Example:
if let faces = compound.sortedCompound(type: .face) { }
predominantShapeType(lookInsideCompounds:)
Get the predominant shape type in this compound.
public func predominantShapeType(lookInsideCompounds: Bool = true) -> ShapeFilterType
- Parameters:
lookInsideCompounds, iftrue, inspect sub-compounds. - Returns: The most-common
ShapeFilterTypefound, or.unknownif the underlying OCCT walk throws (PR #870 aggregate review, this used to decode as.vertex, a real, legitimate case, indistinguishable from an actual vertex-dominated shape). - OCCT:
ShapeExtend_Explorer::ShapeType - Example:
let t = compound.predominantShapeType()
ShapeUpgrade_FaceDivide
divideFace()
Divide a face using surface segmentation.
public func divideFace() -> Shape?
- Returns: Divided shape, or
nilon failure. - OCCT:
ShapeUpgrade_FaceDivide - Example:
if let divided = face.divideFace() { }
ShapeUpgrade_WireDivide
divideWire(onFace:)
Divide a wire on a face.
public func divideWire(onFace face: Shape) -> Shape?
- Parameters:
face, face the wire lies on. - Returns: Divided wire as shape, or
nilon failure. - OCCT:
ShapeUpgrade_WireDivide - Example:
if let w = wire.divideWire(onFace: face) { }
ShapeUpgrade_EdgeDivide
EdgeDivideResult
Result of an edge divide analysis.
public struct EdgeDivideResult: Sendable {
public let hasCurve2d: Bool
public let hasCurve3d: Bool
}
| Field | Meaning |
|---|---|
hasCurve2d | true if the edge carries a 2D (pcurve) representation on the analysed face. |
hasCurve3d | true if the edge carries a 3D curve representation. |
Shape.EdgeDivideResult.hasCurve2d
analyzeEdgeDivide(onFace:)
Analyze an edge for potential division on a face.
public func analyzeEdgeDivide(onFace face: Shape) -> EdgeDivideResult?
- Parameters:
face, face context for the edge. - Returns: Analysis result indicating 2D/3D curve presence, or
nilon failure. - OCCT:
ShapeUpgrade_EdgeDivide::Compute - Example:
if let r = edge.analyzeEdgeDivide(onFace: face) { print(r.hasCurve3d) }
ShapeUpgrade_ClosedEdgeDivide
canDivideClosedEdge(onFace:)
Check if a closed (seam) edge can be divided on a face.
public func canDivideClosedEdge(onFace face: Shape) -> Bool
- Parameters:
face, face context. - Returns:
trueif the edge is closed and divisible. - OCCT:
ShapeUpgrade_ClosedEdgeDivide::Compute - Example:
if edge.canDivideClosedEdge(onFace: face) { }
ShapeUpgrade_ConvertCurve3dToBezier
convertCurves3dToBezier(lineMode:circleMode:conicMode:)
Convert 3D curves in this shape to Bezier representation.
public func convertCurves3dToBezier(lineMode: Bool = true, circleMode: Bool = true,
conicMode: Bool = true) -> Shape?
- Parameters:
lineMode, convert line segments.circleMode, convert circles.conicMode, convert other conics. - Returns: Shape with Bezier curves, or
nilon failure. - OCCT:
ShapeUpgrade_ShapeConvertToBezierwith 3D-curve conversion enabled - Example:
if let bez = shape.convertCurves3dToBezier(lineMode: false) { }
ShapeUpgrade_ConvertSurfaceToBezierBasis
convertSurfacesToBezier(planeMode:revolutionMode:extrusionMode:bsplineMode:)
Convert surfaces in this shape to Bezier patches.
public func convertSurfacesToBezier(planeMode: Bool = true, revolutionMode: Bool = true,
extrusionMode: Bool = true, bsplineMode: Bool = true) -> Shape?
- Parameters:
planeMode, convert planes.revolutionMode, convert revolution surfaces.extrusionMode, convert extrusions.bsplineMode, convert BSpline surfaces. - Returns: Shape with Bezier surfaces, or
nilon failure. - OCCT:
ShapeUpgrade_ShapeConvertToBezierwith surface conversion enabled - Example:
if let bez = shape.convertSurfacesToBezier(bsplineMode: false) { }
2D Vector/Direction Utilities & LProp
Shape.vector2DAngle(a:b:)
Signed angle between two 2D vectors, in radians (range −π to π).
public static func vector2DAngle(a: SIMD2<Double>, b: SIMD2<Double>) -> Double
- OCCT:
gp_Vec2d::Angle - Example:
let angle = Shape.vector2DAngle(a: SIMD2(1, 0), b: SIMD2(0, 1)) // π/2
Shape.vector2DCross(a:b:)
Cross product of two 2D vectors (scalar Z component).
public static func vector2DCross(a: SIMD2<Double>, b: SIMD2<Double>) -> Double
- OCCT: Inline arithmetic
ax * by - ay * bxviaOCCTVector2DCross(nogp_Vec2dconstructed). - Example:
let z = Shape.vector2DCross(a: SIMD2(1, 0), b: SIMD2(0, 1)) // 1.0
Shape.vector2DDot(a:b:)
Dot product of two 2D vectors.
public static func vector2DDot(a: SIMD2<Double>, b: SIMD2<Double>) -> Double
- OCCT: Inline arithmetic
ax * bx + ay * byviaOCCTVector2DDot(nogp_Vec2dconstructed). - Example:
let d = Shape.vector2DDot(a: SIMD2(1, 0), b: SIMD2(0.5, 0.5))
Shape.vector2DMagnitude(_:)
Magnitude of a 2D vector.
public static func vector2DMagnitude(_ v: SIMD2<Double>) -> Double
- OCCT: inline arithmetic
sqrt(x * x + y * y)(nogp_Vec2dconstructed) - Example:
let m = Shape.vector2DMagnitude(SIMD2(3, 4)) // 5.0
Shape.vector2DNormalized(_:)
Return a normalized copy of a 2D vector.
public static func vector2DNormalized(_ v: SIMD2<Double>) -> SIMD2<Double>
- OCCT: inline arithmetic dividing each component by the magnitude (no
gp_Vec2dconstructed) - Example:
let n = Shape.vector2DNormalized(SIMD2(3, 4))
Shape.direction2DNormalized(_:)
Create a normalized 2D direction from components.
public static func direction2DNormalized(_ v: SIMD2<Double>) -> SIMD2<Double>
- OCCT:
gp_Dir2dconstructor (normalizes on construction) - Example:
let d = Shape.direction2DNormalized(SIMD2(1, 1))
Shape.direction2DAngle(a:b:)
Signed angle between two 2D directions, in radians.
public static func direction2DAngle(a: SIMD2<Double>, b: SIMD2<Double>) -> Double
- OCCT:
gp_Dir2d::Angle - Example:
let angle = Shape.direction2DAngle(a: SIMD2(1, 0), b: SIMD2(0, 1))
Shape.direction2DCross(a:b:)
Cross product of two 2D directions.
public static func direction2DCross(a: SIMD2<Double>, b: SIMD2<Double>) -> Double
- OCCT:
gp_Dir2d::Crossed - Example:
let z = Shape.direction2DCross(a: SIMD2(1, 0), b: SIMD2(0, 1))
CurvaturePointType
Type of a special curvature point found by LProp analysis.
public enum CurvaturePointType: Int32 {
case inflection = 0
case minimumCurvature = 1
case maximumCurvature = 2
}
| case | meaning |
|---|---|
.inflection | Parameter where curvature changes sign. |
.minimumCurvature | Parameter at a local minimum of curvature. |
.maximumCurvature | Parameter at a local maximum of curvature. |
(Per-case anchors below, for cross-reference; the table above has the actual meaning of each.)
maximumCurvature
CurvatureSpecialPoint
A special point on a curve at a given parameter.
public struct CurvatureSpecialPoint {
public let parameter: Double
public let type: CurvaturePointType
}
Shape.analyticCurvaturePoints(curveType:first:last:)
Compute the curvature extrema of an analytic curve type, as parameter/kind pairs.
Only curveType: 2 (ellipse) ever produces a point: a line has zero curvature, a circle constant curvature, and a parabola and a hyperbola monotonic curvature, so none of them has an extremum, and every other value returns an empty array. An ellipse reports the four axis vertices that fall inside first...last, classified the way LProp_CurAndInf classifies them, by radius of curvature rather than by curvature: the major-axis vertices at 0 and π are .minimumCurvature (minimum radius) and the minor-axis vertices at π/2 and 3π/2 are .maximumCurvature. CurvaturePointType.inflection is declared but never returned; an analytic conic has no inflection.
public static func analyticCurvaturePoints(curveType: Int32, first: Double,
last: Double) -> [CurvatureSpecialPoint]
- Parameters:
curveType, theGeomAbs_CurveTypeordinal: 0=Line, 1=Circle, 2=Ellipse, 3=Hyperbola, 4=Parabola.first/last, parameter domain. - Returns: Array of curvature extrema; empty for every
curveTypebut 2, and for an ellipse whose domain excludes all four vertices. - OCCT:
LProp_CurAndInf(the result container) andLProp_CIType(the kind enum). The extrema themselves are computed in the bridge rather than by an OCCT algorithm, since the closed form for a conic is four fixed parameters;OCCTLPropAnalyticCurInffills the container withAddExtCurand reads it back withParameter/Type. - Example:
let pts = Shape.analyticCurvaturePoints(curveType: 2, first: 0, last: .pi)
TopTrans Surface Transition
TopologicalState
OCCT TopAbs_State mapping.
public enum TopologicalState: Int32, Sendable {
case `in` = 0, out = 1, on = 2, unknown = 3
}
The point or curve lies strictly inside the boundary for `in` (TopAbs_IN, not independently documented below since `-escaped keyword case names aren’t headings this project’s own tooling resolves).
TopologicalState.out
The point or curve lies strictly outside the boundary (TopAbs_OUT).
case out = 1
TopologicalState.on
The point or curve lies exactly on the boundary element itself (TopAbs_ON).
case on = 2
TopologicalState.unknown
The transition analysis could not determine a state (TopAbs_UNKNOWN).
case unknown = 3
SurfaceTransitionResult
Result of a surface or curve transition analysis.
public struct SurfaceTransitionResult: Sendable {
public let stateBefore: TopologicalState
public let stateAfter: TopologicalState
}
SurfaceTransitionResult.stateBefore
The TopologicalState immediately before the curve crosses the surface or boundary element.
public let stateBefore: TopologicalState
SurfaceTransitionResult.stateAfter
The TopologicalState immediately after the curve crosses the surface or boundary element.
public let stateAfter: TopologicalState
Shape.surfaceTransition(tangent:normal:surfaceNormal:tolerance:surfaceOrientation:boundaryOrientation:)
Analyze topological state before and after a curve crosses a surface boundary.
public static func surfaceTransition(
tangent: SIMD3<Double>, normal: SIMD3<Double>,
surfaceNormal: SIMD3<Double>, tolerance: Double = 1e-6,
surfaceOrientation: Int = 0, boundaryOrientation: Int = 0
) -> SurfaceTransitionResult
- Parameters:
tangent, curve tangent at crossing.normal, boundary normal.surfaceNormal, normal of the crossed surface.tolerance, angular tolerance.surfaceOrientation/boundaryOrientation, 0=FORWARD, 1=REVERSED. - Returns: States before and after the surface crossing.
- OCCT:
TopTrans_SurfaceTransition - Example:
let r = Shape.surfaceTransition(tangent: t, normal: n, surfaceNormal: sn)
Shape.surfaceTransitionWithCurvature(...)
Extended surface transition analysis that accounts for surface curvature.
public static func surfaceTransitionWithCurvature(
tangent: SIMD3<Double>, normal: SIMD3<Double>,
maxDirection: SIMD3<Double>, minDirection: SIMD3<Double>,
maxCurvature: Double, minCurvature: Double,
surfaceNormal: SIMD3<Double>,
surfaceMaxDirection: SIMD3<Double>, surfaceMinDirection: SIMD3<Double>,
surfaceMaxCurvature: Double, surfaceMinCurvature: Double,
tolerance: Double = 1e-6,
surfaceOrientation: Int = 0, boundaryOrientation: Int = 0
) -> SurfaceTransitionResult
- Parameters: Principal curvature directions and magnitudes for both the boundary and the surface at the crossing point, plus tangent and normals.
- Returns: States before and after.
- OCCT:
TopTrans_SurfaceTransition(with curvature) - Example:
let r = Shape.surfaceTransitionWithCurvature( tangent: t, normal: n, maxDirection: md, minDirection: nd, maxCurvature: k1, minCurvature: k2, surfaceNormal: sn, surfaceMaxDirection: smd, surfaceMinDirection: snd, surfaceMaxCurvature: sk1, surfaceMinCurvature: sk2)
TopTrans Curve Transition
Shape.curveTransition(tangent:boundaryTangent:boundaryNormal:curvature:tolerance:surfaceOrientation:boundaryOrientation:)
Analyze topological state before and after a curve crosses a boundary element.
public static func curveTransition(
tangent: SIMD3<Double>,
boundaryTangent: SIMD3<Double>, boundaryNormal: SIMD3<Double>,
curvature: Double = 0.0, tolerance: Double = 1e-6,
surfaceOrientation: Int = 0, boundaryOrientation: Int = 0
) -> SurfaceTransitionResult
- Parameters:
tangent, curve tangent.boundaryTangent/boundaryNormal, boundary element geometry.curvature, boundary curvature (0 for straight boundary). - Returns:
SurfaceTransitionResultwith before/after states. - OCCT:
TopTrans_CurveTransition - Example:
let r = Shape.curveTransition(tangent: t, boundaryTangent: bt, boundaryNormal: bn)
Shape.curveTransitionWithCurvature(tangent:curveNormal:curveCurvature:boundaryTangent:boundaryNormal:surfaceCurvature:tolerance:surfaceOrientation:boundaryOrientation:)
Curve transition analysis accounting for boundary curve curvature.
public static func curveTransitionWithCurvature(
tangent: SIMD3<Double>,
curveNormal: SIMD3<Double>, curveCurvature: Double,
boundaryTangent: SIMD3<Double>, boundaryNormal: SIMD3<Double>,
surfaceCurvature: Double, tolerance: Double = 1e-6,
surfaceOrientation: Int = 0, boundaryOrientation: Int = 0
) -> SurfaceTransitionResult
- Returns:
SurfaceTransitionResultwith before/after states. - OCCT:
TopTrans_CurveTransition(with curvature) - Example:
let r = Shape.curveTransitionWithCurvature( tangent: t, curveNormal: cn, curveCurvature: kc, boundaryTangent: bt, boundaryNormal: bn, surfaceCurvature: ks)
GeomFill Trihedrons
frenetTrihedron(at:)
Evaluate a Frenet trihedron on an edge at a parameter.
public func frenetTrihedron(at param: Double) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)?
- Parameters:
param, curve parameter. - Returns: Tuple of tangent, normal, binormal, or
nilif the trihedron cannot be computed (e.g. inflection point). - OCCT:
GeomFill_Frenet - Example:
if let f = edge.frenetTrihedron(at: 0.5) { print(f.tangent, f.normal, f.binormal) }
constantBiNormalTrihedron(at:biNormal:)
Evaluate a constant-binormal trihedron on an edge at a parameter.
public func constantBiNormalTrihedron(at param: Double, biNormal: SIMD3<Double>) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)?
- Parameters:
param, curve parameter.biNormal, fixed binormal direction. - Returns: Trihedron tuple, or
nilon failure. - OCCT:
GeomFill_ConstantBiNormal - Example:
if let f = edge.constantBiNormalTrihedron(at: 0.5, biNormal: SIMD3(0, 0, 1)) { }
Shape.fixedTrihedron(tangent:normal:at:)
Evaluate a fixed (constant) trihedron at any parameter.
public static func fixedTrihedron(tangent: SIMD3<Double>, normal: SIMD3<Double>, at param: Double = 0) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)
- Parameters:
tangent/normal, fixed trihedron directions.param, parameter (unused geometrically; for API consistency). - Returns: Trihedron tuple (binormal = tangent × normal).
- OCCT:
GeomFill_Fixed - Example:
let f = Shape.fixedTrihedron(tangent: SIMD3(1,0,0), normal: SIMD3(0,1,0))
darbouxTrihedron(onFace:at:)
Evaluate a Darboux trihedron on an edge lying on a face.
public func darbouxTrihedron(onFace face: Shape, at param: Double) -> (tangent: SIMD3<Double>, normal: SIMD3<Double>, binormal: SIMD3<Double>)?
- Parameters:
face, the supporting face.param, curve parameter. - Returns: Darboux frame (tangent, surface normal, binormal), or
nilon failure. - OCCT:
GeomFill_Darboux - Example:
if let f = edge.darbouxTrihedron(onFace: face, at: 0.5) { }
Polygon Interference
PolygonIntersection
Result of 2D polygon interference computation.
public struct PolygonIntersection: Sendable {
public let points: [SIMD2<Double>]
}
points is capped at 100 entries, and the truncation is silent: both entry points below size a fixed 100-element buffer and pass its length to Intf_InterferencePolygon2d as the maximum. A polyline pair with more than 100 crossings loses the rest with no signal (#1399).
Shape.polygonInterference(poly1:poly2:)
Compute intersection points between two 2D polylines.
public static func polygonInterference(
poly1: [SIMD2<Double>], poly2: [SIMD2<Double>]
) -> PolygonIntersection
- Parameters:
poly1/poly2, ordered arrays of 2D vertices defining each polyline. - Returns:
PolygonIntersectionwith intersection points (may be empty). - OCCT:
Intf_InterferencePolygon2d - Example:
let result = Shape.polygonInterference(poly1: pts1, poly2: pts2)
Shape.polygonSelfInterference(polygon:)
Compute self-intersection points of a 2D polyline.
public static func polygonSelfInterference(
polygon: [SIMD2<Double>]
) -> PolygonIntersection
- Parameters:
polygon, ordered 2D vertices. - Returns: Self-intersection points.
- OCCT:
Intf_InterferencePolygon2d(self-interference mode) - Example:
let result = Shape.polygonSelfInterference(polygon: pts)
GccAna_Circ2d3Tan
Circle2DSolution
A circle solution from a GccAna tangency solver.
public struct Circle2DSolution: Sendable {
public let centerX: Double
public let centerY: Double
public let radius: Double
}
Circle2DSolution.centerX
X coordinate of the solution circle’s center.
public let centerX: Double
Circle2DSolution.centerY
Y coordinate of the solution circle’s center.
public let centerY: Double
Circle2DSolution.radius
Radius of the solution circle.
public let radius: Double
Shape.circleThrough3Points(p1:p2:p3:tolerance:)
Find circles through 3 points (circumscribed circle).
public static func circleThrough3Points(
p1: SIMD2<Double>, p2: SIMD2<Double>, p3: SIMD2<Double>,
tolerance: Double = 1e-6
) -> [Circle2DSolution]
- Returns: Array of circle solutions (typically 0 or 1).
- OCCT:
GccAna_Circ2d3Tan(3 points) - Example:
let sols = Shape.circleThrough3Points(p1: SIMD2(0,0), p2: SIMD2(1,0), p3: SIMD2(0,1))
Shape.circleTangent3Lines(l1Point:l1Dir:l2Point:l2Dir:l3Point:l3Dir:tolerance:)
Find circles tangent to 3 lines.
public static func circleTangent3Lines(
l1Point: SIMD2<Double>, l1Dir: SIMD2<Double>,
l2Point: SIMD2<Double>, l2Dir: SIMD2<Double>,
l3Point: SIMD2<Double>, l3Dir: SIMD2<Double>,
tolerance: Double = 1e-6
) -> [Circle2DSolution]
- Returns: Array of up to 8 tangent circles.
- OCCT:
GccAna_Circ2d3Tan(3 lines) - Example:
let sols = Shape.circleTangent3Lines( l1Point: .zero, l1Dir: SIMD2(1,0), l2Point: SIMD2(0,1), l2Dir: SIMD2(1,0), l3Point: .zero, l3Dir: SIMD2(0,1))
Shape.circleTangent3Circles(c1Center:c1Radius:c2Center:c2Radius:c3Center:c3Radius:tolerance:)
Find circles tangent to 3 circles (Apollonius problem).
public static func circleTangent3Circles(
c1Center: SIMD2<Double>, c1Radius: Double,
c2Center: SIMD2<Double>, c2Radius: Double,
c3Center: SIMD2<Double>, c3Radius: Double,
tolerance: Double = 1e-6
) -> [Circle2DSolution]
- Returns: Array of up to 8 solution circles.
- OCCT:
GccAna_Circ2d3Tan(3 circles) - Note: every radius must be positive (#553). A zero-radius argument is a point, and the solver does not answer the point question when it is given one: measured, it returns each solution twice, because tangency to a circle of radius zero satisfies the enclosing and the outside qualifier at once. Use
circleTangent2CirclesPoint,circleTangentCircle2PointsorcircleThrough3Pointsto name a point as a point. A non-positive radius returns an empty array. - Example:
let sols = Shape.circleTangent3Circles( c1Center: SIMD2(-2,0), c1Radius: 1, c2Center: SIMD2(2,0), c2Radius: 1, c3Center: SIMD2(0,2), c3Radius: 1)
Shape.circleTangent2CirclesPoint(c1Center:c1Radius:c2Center:c2Radius:point:tolerance:)
Find circles tangent to 2 circles and passing through 1 point.
public static func circleTangent2CirclesPoint(
c1Center: SIMD2<Double>, c1Radius: Double,
c2Center: SIMD2<Double>, c2Radius: Double,
point: SIMD2<Double>, tolerance: Double = 1e-6
) -> [Circle2DSolution]
- OCCT:
GccAna_Circ2d3Tan(2 circles + point) - Note: both radii must be positive (#553). With a zero radius the solution set comes back padded with repeats: measured, four solutions holding two distinct circles.
- Example:
let sols = Shape.circleTangent2CirclesPoint( c1Center: .zero, c1Radius: 1, c2Center: SIMD2(3,0), c2Radius: 1, point: SIMD2(1.5, 2))
Shape.circleTangentCircle2Points(circleCenter:circleRadius:p1:p2:tolerance:)
Find circles tangent to 1 circle and passing through 2 points.
public static func circleTangentCircle2Points(
circleCenter: SIMD2<Double>, circleRadius: Double,
p1: SIMD2<Double>, p2: SIMD2<Double>, tolerance: Double = 1e-6
) -> [Circle2DSolution]
- OCCT:
GccAna_Circ2d3Tan(circle + 2 points) - Note:
circleRadiusmust be positive (#553). This is the case where reading a zero-radius circle as a point fails outright: measured, the solver finds nothing at all, wherecircleThrough3Pointson the same three positions finds the circle through them. - Example:
let sols = Shape.circleTangentCircle2Points( circleCenter: .zero, circleRadius: 1, p1: SIMD2(3,0), p2: SIMD2(0,3))
Shape.circleTangent2LinesPoint(l1Point:l1Dir:l2Point:l2Dir:point:tolerance:)
Find circles tangent to 2 lines and passing through 1 point.
public static func circleTangent2LinesPoint(
l1Point: SIMD2<Double>, l1Dir: SIMD2<Double>,
l2Point: SIMD2<Double>, l2Dir: SIMD2<Double>,
point: SIMD2<Double>, tolerance: Double = 1e-6
) -> [Circle2DSolution]
- OCCT:
GccAna_Circ2d3Tan(2 lines + point) - Example:
let sols = Shape.circleTangent2LinesPoint( l1Point: .zero, l1Dir: SIMD2(1,0), l2Point: .zero, l2Dir: SIMD2(0,1), point: SIMD2(2,2))
IntTools
CommonPartType
Type of an edge-edge or edge-face intersection common part.
public enum CommonPartType: Int32, Sendable {
case vertex = 0
case edge = 1
}
CommonPart
A single intersection common part from IntTools.
public struct CommonPart: Sendable {
public let type: CommonPartType
public let param1Range: (first: Double, last: Double)
public let param2Range: (first: Double, last: Double)
public let point: SIMD3<Double>
}
| field | meaning |
|---|---|
type | .vertex or .edge: the kind of intersection found. |
param1Range | Parameter range (first, last) on the first edge; equal endpoints for a vertex intersection. |
param2Range | Parameter range (first, last) on the second edge; equal endpoints for a vertex intersection. Only edgeEdgeIntersection(with:) has a second edge, see below. |
point | Representative 3D point of the intersection. |
param2Range is always (0, 0) from edgeFaceIntersection(with:). A face is not an edge, and IntTools_EdgeFace reflects that: IntTools_EdgeFace.cxx never calls AppendRange2 or SetVertexParameter2, so IntTools_CommonPrt::Ranges2() comes back empty and VertexParameter2() comes back as the 0.0 its default constructor set (IntTools_CommonPrt.cxx:33). The bridge reads those and passes them on, so the pair reads as a measurement and is not one. Measured in Scripts/repro/1399-refman-coverage-unlaned/probe-transcript.txt (#1399). Read param1Range, the range on the edge, and point.
(Per-field anchors below, for cross-reference; the table above has the actual meaning of each.)
param2Range
edgeEdgeIntersection(with:)
Intersect two edges to find common vertices and edge overlaps.
public func edgeEdgeIntersection(with other: Shape) -> [CommonPart]?
- Parameters:
other, second edge. - Returns: Array of common parts, or
nilif intersection failed. - OCCT:
IntTools_EdgeEdge - Example:
if let parts = e1.edgeEdgeIntersection(with: e2) { for p in parts { print(p.type, p.point) } }
edgeFaceIntersection(with:)
Intersect an edge with a face to find common vertices and edge overlaps.
public func edgeFaceIntersection(with face: Shape) -> [CommonPart]?
- Parameters:
face, face to intersect with. - Returns: Array of common parts, or
nilon failure. - Warning: this currently returns an empty array for every input, including an edge that genuinely crosses the face.
OCCTIntToolsEdgeFacenever callsIntTools_EdgeFace::SetRange, andIntTools_Range’s default is(0, 0), so the search window is degenerate. #1631 has the measurement and the fix. - Note:
CommonPart.param2Rangeis(0, 0)on this path whatever the result, see theCommonPartentry above. - OCCT:
IntTools_EdgeFace - Example:
if let parts = edge.edgeFaceIntersection(with: face) { }
FaceFaceCurve
An intersection curve from a face-face intersection.
public struct FaceFaceCurve: Sendable {
public let start: SIMD3<Double>?
public let end: SIMD3<Double>?
}
FaceFaceCurve.start
Start point of the intersection curve, or nil if the curve is unbounded.
public let start: SIMD3<Double>?
FaceFaceCurve.end
End point of the intersection curve, or nil if the curve is unbounded.
public let end: SIMD3<Double>?
FaceFacePoint
An intersection point from a face-face intersection.
public struct FaceFacePoint: Sendable {
public let pointOnFace1: SIMD3<Double>
public let pointOnFace2: SIMD3<Double>
}
FaceFacePoint.pointOnFace1
The coincident point’s coordinates as evaluated on the first face.
public let pointOnFace1: SIMD3<Double>
FaceFacePoint.pointOnFace2
The coincident point’s coordinates as evaluated on the second face.
public let pointOnFace2: SIMD3<Double>
FaceFaceResult
Result of a face-face intersection.
public struct FaceFaceResult: Sendable {
public let curves: [FaceFaceCurve]
public let points: [FaceFacePoint]
public let isTangent: Bool
}
| Field | Meaning |
|---|---|
curves | Intersection curves between the two faces. |
isTangent | true if the two faces are tangent at the intersection rather than transversally crossing. |
Shape.FaceFaceResult.isTangent
faceFaceIntersection(with:tolerance:)
Intersect two faces to find intersection curves and points.
public func faceFaceIntersection(with other: Shape, tolerance: Double = 1e-7) -> FaceFaceResult?
- Parameters:
other, second face.tolerance, approximation tolerance. - Returns:
FaceFaceResult, ornilon failure. - OCCT:
IntTools_FaceFace - Example:
if let r = f1.faceFaceIntersection(with: f2) { print(r.curves.count, r.isTangent) }
classifyPoint2d(u:v:tolerance:)
Classify a UV point relative to a face boundary in parameter space.
public func classifyPoint2d(u: Double, v: Double, tolerance: Double = 1e-6) -> OCCTSwift.PointClassification
Answers the same “in/on/out of the face boundary” question as Face.classify(u:v:tolerance:) (see “Shape-Healing”) and Shape.classifyPoint2D(faceIndex:u:v:tolerance:) (see “Document-Math-Bounds”), both backed by BRepClass_FaceClassifier/BRepClass_FClassifier. This method’s default used to be 1e-7, an order of magnitude tighter than the other two’s 1e-6; aligned to 1e-6 (#840). isHole(tolerance:) below, this method’s own IntTools_FClass2d file-neighbor, keeps its 1e-7 default deliberately, it answers a different question.
- Parameters:
u/v, UV coordinates.tolerance, classification tolerance (default 1e-6). - Returns:
.inside,.onBoundary,.outside, or.unknown. - OCCT:
IntTools_FClass2d::Perform - Example:
let c = face.classifyPoint2d(u: 0.5, v: 0.5)
isHole(tolerance:)
Check if a face represents a hole (inner-wire orientation).
public func isHole(tolerance: Double = 1e-7) -> Bool
- Returns:
trueif the face is classified as a hole. - OCCT:
IntTools_FClass2d(IsHole query) - Example:
if face.isHole() { }
BOPAlgo Builder
buildFaces(from:)
Build faces from edges that lie on this face’s surface.
public func buildFaces(from edges: [Shape]) -> [Shape]?
- Parameters:
edges, edge shapes on this face’s surface. - Returns: Array of result face shapes, or
nilon failure. - OCCT:
BOPAlgo_BuilderFace - Example:
if let faces = face.buildFaces(from: edges) { }
Shape.buildSolids(from:)
Build solids from a closed set of faces.
public static func buildSolids(from faces: [Shape]) -> [Shape]?
- Parameters:
faces, face shapes forming closed volumes. - Returns: Array of result solid shapes, or
nilon failure. - OCCT:
BOPAlgo_BuilderSolid - Example:
if let solids = Shape.buildSolids(from: faces) { }
splitShell()
Split a shell into connected components.
public func splitShell() -> [Shape]?
- Returns: Array of shell shapes (one per connected component), or
nilon failure. - OCCT:
BOPAlgo_ShellSplitter - Example:
if let shells = shell.splitShell() { }
edgesToWires(tolerance:)
Connect a compound of edges into wires.
public func edgesToWires(tolerance: Double = 1e-7) -> Shape?
- Parameters:
tolerance, edge connection tolerance. - Returns: Compound of wires, or
nilon failure. - OCCT:
BOPAlgo_Tools::EdgesToWires - Example:
if let wires = edgeCompound.edgesToWires() { }
wiresToFaces(tolerance:)
Build planar faces from a compound of wires.
public func wiresToFaces(tolerance: Double = 1e-7) -> Shape?
- Parameters:
tolerance, face building tolerance. - Returns: Compound of faces, or
nilon failure. - OCCT:
BOPAlgo_Tools::WiresToFaces - Example:
if let faces = wireCompound.wiresToFaces() { }
BOPTools
Shape.normalOnEdge(edge:face:)
Get the normal to a face at an edge location.
public static func normalOnEdge(edge: Shape, face: Shape) -> SIMD3<Double>?
- Parameters:
edge, edge on the face.face, containing face. - Returns: Unit normal direction, or
nilon failure. - OCCT:
BOPTools_AlgoTools3D::GetNormalToFaceOnEdge - Example:
if let n = Shape.normalOnEdge(edge: e, face: f) { }
pointInFace()
Find a point strictly inside this face.
public func pointInFace() -> SIMD3<Double>?
- Returns: A 3D point in the interior of this face, or
nilon failure. - OCCT:
BOPTools_AlgoTools3D::PointInFace - Example:
if let pt = face.pointInFace() { }
isEmpty
Check if this shape has no sub-shapes.
public var isEmpty: Bool { get }
- OCCT:
BOPTools_AlgoTools3D::IsEmptyShape - Example:
if shape.isEmpty { }
isOpenShell
Check if this shell is open (not all edges shared by two faces).
public var isOpenShell: Bool { get }
- OCCT:
BOPTools_AlgoTools::IsOpenShell - Example:
if shell.isOpenShell { }
IntTools_BeanFaceIntersector
BeanFaceIntersection
Result of an edge-face coincidence check.
public struct BeanFaceIntersection: Sendable {
public let ranges: [(first: Double, last: Double)]
public let minSquareDistance: Double
}
| field | meaning |
|---|---|
ranges | Coincident (first, last) parameter ranges on the edge curve where it lies on the face. |
minSquareDistance | Minimum squared distance between the edge curve and the face surface. |
(Per-field anchors below, for cross-reference; the table above has the actual meaning of each.)
minSquareDistance
Shape.beanFaceIntersect(edge:face:)
Find coincident parameter ranges where an edge lies on a face surface.
public static func beanFaceIntersect(edge: Shape, face: Shape) -> BeanFaceIntersection?
- Parameters:
edge, edge curve to test.face, face surface to test against. - Returns: Ranges of coincidence and minimum squared distance, or
nilon failure. - OCCT:
IntTools_BeanFaceIntersector - Example:
if let r = Shape.beanFaceIntersect(edge: e, face: f) { print(r.ranges.count, r.minSquareDistance) }
BOPAlgo_WireSplitter
Shape.makeWire(from:)
Assemble edges into a connected wire using BOPAlgo_WireSplitter.
public static func makeWire(from edges: [Shape]) -> Shape?
- Parameters:
edges, array of edge shapes to connect. - Returns: Result wire as shape, or
nilon failure. - OCCT:
BOPAlgo_WireSplitter::MakeWire - Example:
if let wire = Shape.makeWire(from: [e1, e2, e3]) { }
BRepFeat_SplitShape
splitByEdge(_:onFace:)
Split this shape by adding an edge to a face.
public func splitByEdge(_ edge: Shape, onFace face: Shape) -> Shape?
- Parameters:
edge, edge to add as a split line.face, face the edge lies on. - Returns: Result shape with the split face, or
nilon failure. - OCCT:
BRepFeat_SplitShape - Example:
if let split = solid.splitByEdge(e, onFace: face) { }
splitByWire(_:onFace:)
Split this shape by adding a wire to a face.
public func splitByWire(_ wire: Shape, onFace face: Shape) -> Shape?
- Parameters:
wire, wire to split along.face, face the wire lies on. - Returns: Result shape with split face, or
nilon failure. - OCCT:
BRepFeat_SplitShape - Example:
if let split = solid.splitByWire(w, onFace: face) { }
SplitShapeResult
Result of a multi-pair split-shape operation.
public struct SplitShapeResult: Sendable {
public let shape: Shape
public let leftFaces: [Shape]
public let rightFaces: [Shape]
}
SplitShapeResult.shape
The resulting shape after all edge-on-face pairs have been split in.
public let shape: Shape
SplitShapeResult.leftFaces
The faces BRepFeat_SplitShape::Left() classified as lying on the left side of the splitting edges.
public let leftFaces: [Shape]
SplitShapeResult.rightFaces
The faces BRepFeat_SplitShape::Right() classified as lying on the right side of the splitting edges.
public let rightFaces: [Shape]
splitWithSides(edgesOnFaces:)
Split this shape with multiple edge-on-face pairs, returning left/right face classifications.
public func splitWithSides(edgesOnFaces: [(edge: Shape, face: Shape)]) -> SplitShapeResult?
- Parameters:
edgesOnFaces, array of(edge, face)pairs; each edge is added to the corresponding face. - Returns: Split result with the resulting shape and left/right face arrays, or
nilon failure. - OCCT:
BRepFeat_SplitShapewithLeft()/Right()queries - Example:
if let r = solid.splitWithSides(edgesOnFaces: [(edge: e, face: f)]) { print(r.leftFaces.count, r.rightFaces.count) }
BRepFeat_MakeCylindricalHole
OCCT’s dedicated feature-drilling operator. It wants a solid: every extent but .throughAll reports .invalidPlacement for a shell or a face.
This is a different contract from drilled(at:direction:radius:depth:), not a better one, #496 measured six requests where the two disagree. Reach for this family when the solid’s own faces should bound the hole, or when you need a diagnosis of why a drill is impossible; reach for drilled when the hole starts where you say it starts, when the input is not a solid, or when an over-long depth should simply drill through. Full measurements: Scripts/repro/496-drill-hole-contracts/.
radius must exceed Precision::Confusion (1e-7) for every spelling below. Under that, OCCT reports BRepFeat_NoError and hands back the undrilled input, so the bridge rejects it (#496).
CylindricalHoleExtent
How a feature-drilled hole is bounded. The five modes are not interchangeable.
public enum CylindricalHoleExtent: Sendable, Equatable {
case throughAll
case untilEnd
case thruNext
case blind(depth: Double)
case range(from: Double, to: Double)
}
| case | OCCT | bounded by |
|---|---|---|
.throughAll | Perform(R) | nothing, an infinite cylinder, both ways along the axis. The origin anchors the axis; it is not where the hole starts. The only extent that tolerates a non-solid input. |
.untilEnd | PerformUntilEnd(R) | the stock’s own first and last faces along the axis. The forward-bounded through hole most callers reach for .throughAll expecting. |
.thruNext | PerformThruNext(R) | the next face after the origin. |
.blind(depth:) | PerformBlind(R, depth) | depth, measured from the axis origin. The only extent that can report .holeTooLong: a depth that would leave the far side of the stock is refused rather than drilled through. |
.range(from:to:) | Perform(R, PFrom, PTo) | the entry/exit face pair the parameter window selects. |
.range is the subtle one: the window chooses a face pair, it does not trim the cut. A window lying strictly inside one body still drills all the way through that body; a window naming no face pair (the gap between two plates) is .invalidPlacement. Its use is picking which body to drill in a stack, a window over one plate drills that plate, one spanning several drills all of them.
On a stack, every extent that bounds the hole by the stock’s own faces drills every body the axis crosses: .untilEnd, a spanning .range, .throughAll and drilled(at:…) all agree. Until the kernel patch carried for #532 they did not, .untilEnd, .range and .blind(depth:) reported .noError while removing no material at all, because OCCT selected which piece of its drilling tool to keep from the cut result rather than from the split tool.
The three cases the table above covers are .thruNext, .untilEnd, .range(from:to:) and .blind(depth:); .blind bores to a fixed depth from the placement, and .range is the one whose two parameters are measured along the axis rather than from the face.
bridgeParameters (var bridgeParameters: (mode: Int32, p0: Double, p1: Double)) is internal, not public API: it is the (mode, p0, p1) triple the bridge call reads, one row per case above.
cylindricalHole(axisOrigin:axisDirection:radius:extent:)
Drill a cylindrical hole bounded by extent.
public func cylindricalHole(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>,
radius: Double, extent: CylindricalHoleExtent) -> Shape?
- Parameters:
axisOrigin, hole axis origin.axisDirection, hole axis direction, any non-zero vector.radius, hole radius, abovePrecision::Confusion.extent, where the hole stops. - Returns: Shape with hole, or
nilon failure. AskcylindricalHoleStatus(…extent:)when you need to know why;nilcollapses every reason into one. - OCCT:
BRepFeat_MakeCylindricalHole::Perform/PerformUntilEnd/PerformThruNext/PerformBlind, perextent - Example:
let plate = Shape.box(width: 50, height: 50, depth: 20)! let origin = SIMD3<Double>(0, 0, 15) // 5mm above the top face let axis = SIMD3<Double>(0, 0, -1) // Bounded by the plate's own entry and exit faces: let through = plate.cylindricalHole(axisOrigin: origin, axisDirection: axis, radius: 5, extent: .untilEnd) // A 6mm-deep blind hole, measured from the origin, so 1mm into the plate: let blind = plate.cylindricalHole(axisOrigin: origin, axisDirection: axis, radius: 5, extent: .blind(depth: 6))
cylindricalHoleStatus(axisOrigin:axisDirection:radius:extent:)
Ask what the matching drill would report, without building the result.
public func cylindricalHoleStatus(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>,
radius: Double,
extent: CylindricalHoleExtent) -> CylindricalHoleStatus
The extent is part of the question, because the answer depends on it: a radius wider than the whole solid is .noError for .throughAll and .invalidPlacement for .thruNext, and .holeTooLong exists only under .blind(depth:).
- Returns:
.noErrorif and only ifcylindricalHole(…extent:)would return a shape for the same request. - OCCT:
BRepFeat_MakeCylindricalHole::Statusafter the matchingPerform* - Example:
let origin = SIMD3<Double>(0, 0, 11), axis = SIMD3<Double>(0, 0, -1) if plate.cylindricalHoleStatus(axisOrigin: origin, axisDirection: axis, radius: 5, extent: .blind(depth: 100)) == .holeTooLong { // too deep for this stock, drill it through instead }
CylindricalHoleStatus
Status result for a cylindrical hole operation.
public enum CylindricalHoleStatus: Int32, Sendable {
case noError = 0
case invalidPlacement = 1
case holeTooLong = 2
case unknown = 3
}
.invalidPlacementalso covers a request with no axis direction, or a radius at or belowPrecision::Confusion..holeTooLongis reachable only through.blind(depth:).
CylindricalHoleStatus.noError
The request is drillable.
case noError = 0
CylindricalHoleStatus.invalidPlacement
The axis does not meet the shape in a way this extent can use, including a request with no axis direction, or a radius at or below Precision::Confusion.
case invalidPlacement = 1
CylindricalHoleStatus.holeTooLong
A .blind(depth:) depth that would leave the far side of the stock. Only that extent produces this status.
case holeTooLong = 2
CylindricalHoleStatus.unknown
OCCT raised something the bridge does not recognise.
case unknown = 3
cylindricalHole(axisOrigin:axisDirection:radius:)
Drill a through cylindrical hole in this shape. Convenience for extent: .throughAll.
public func cylindricalHole(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>, radius: Double) -> Shape?
- Parameters:
axisOrigin, hole axis origin.axisDirection, hole axis direction.radius, hole radius. - Returns: Shape with hole, or
nilon failure. - OCCT:
BRepFeat_MakeCylindricalHole::Perform, an infinite cylinder both ways along the axis. For a hole bounded by the stock’s own faces, useextent: .untilEnd. - Example:
if let holed = solid.cylindricalHole(axisOrigin: .zero, axisDirection: SIMD3(0,0,1), radius: 5) { }
cylindricalHoleBlind(axisOrigin:axisDirection:radius:depth:)
Drill a blind cylindrical hole to a specified depth. Convenience for extent: .blind(depth:).
public func cylindricalHoleBlind(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>, radius: Double, depth: Double) -> Shape?
- Parameters:
depth, hole depth, measured from the axis origin. - Returns: Shape with blind hole, or
nilon failure, including adepththat would leave the far side of the stock, which is refused rather than drilled through (.holeTooLong). - OCCT:
BRepFeat_MakeCylindricalHole::PerformBlind - Example:
if let holed = solid.cylindricalHoleBlind(axisOrigin: .zero, axisDirection: SIMD3(0,0,1), radius: 5, depth: 10) { }
cylindricalHoleThruNext(axisOrigin:axisDirection:radius:)
Drill a cylindrical hole through to the next face encountered. Convenience for extent: .thruNext.
public func cylindricalHoleThruNext(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>, radius: Double) -> Shape?
- Returns: Shape with hole stopping at the first inner face, or
nilon failure. - OCCT:
BRepFeat_MakeCylindricalHole::PerformThruNext - Example:
if let holed = solid.cylindricalHoleThruNext(axisOrigin: .zero, axisDirection: SIMD3(0,1,0), radius: 3) { }
cylindricalHoleStatus(axisOrigin:axisDirection:radius:)
Check whether a through-all cylindrical hole can be drilled, without modifying the shape.
public func cylindricalHoleStatus(axisOrigin: SIMD3<Double>, axisDirection: SIMD3<Double>, radius: Double) -> CylindricalHoleStatus
Answers for .throughAll only. Pass the extent you are actually about to drill to cylindricalHoleStatus(…extent:): this spelling reports .noError for requests that cylindricalHoleThruNext and cylindricalHoleBlind then refuse.
- Returns: A
CylindricalHoleStatusindicating through-all feasibility. - OCCT:
BRepFeat_MakeCylindricalHole(status query) - Example:
let s = solid.cylindricalHoleStatus(axisOrigin: .zero, axisDirection: SIMD3(0,0,1), radius: 5) if s == .noError { }
BRepFeat_Gluer
glue(_:facePairs:)
Glue another shape onto this shape by binding matching face pairs.
public func glue(_ gluedShape: Shape, facePairs: [(base: Shape, glued: Shape)]) -> Shape?
- Parameters:
gluedShape, shape to merge onto this one.facePairs, matching face pairs:basefrom this shape,gluedfromgluedShape. - Returns: Glued result shape, or
nilon failure. - OCCT:
BRepFeat_Gluer - Example:
if let r = base.glue(toAttach, facePairs: [(base: bf, glued: gf)]) { }
LocOpe_WiresOnShape + LocOpe_Spliter
LocOpeSplitResult
Result of a LocOpe_Spliter operation.
public struct LocOpeSplitResult: Sendable {
public let shape: Shape
public let directLeftFaces: [Shape]
}
LocOpeSplitResult.shape
The resulting shape after all wire-on-face pairs have been split in.
public let shape: Shape
LocOpeSplitResult.directLeftFaces
The faces LocOpe_Spliter::DirectLeft() classified as lying directly to the left of the splitting wires.
public let directLeftFaces: [Shape]
locOpeSplit(wiresOnFaces:)
Split this shape by projecting wires onto specific faces using LocOpe_Spliter.
public func locOpeSplit(wiresOnFaces: [(wire: Shape, face: Shape)]) -> LocOpeSplitResult?
- Parameters:
wiresOnFaces, pairs binding each wire to the face it lies on. - Returns: Split result with direct-left faces, or
nilon failure. - OCCT:
LocOpe_WiresOnShape+LocOpe_Spliter - Note: Each pair contributes only the first wire of its
wireshape. A pair whose shape holds several wires binds one of them and ignores the rest; give each wire its own pair. A pair whose shape holds no wire at all is skipped silently. (#443 audit) - Example:
if let r = solid.locOpeSplit(wiresOnFaces: [(wire: w, face: f)]) { print(r.directLeftFaces.count) }
locOpeSplitAuto(wires:)
Split this shape by automatically projecting wires onto faces.
public func locOpeSplitAuto(wires: [Shape]) -> Shape?
- Parameters:
wires, wires to project and split by; faces are determined automatically. - Returns: Result shape, or
nilon failure. - OCCT:
LocOpe_WiresOnShape::BindAll+LocOpe_Spliter - Example:
if let r = solid.locOpeSplitAuto(wires: [w]) { }
LocOpe_Gluer
locOpeGlue(_:facePairs:edgePairs:)
Glue another shape onto this shape using LocOpe_Gluer with optional edge binding.
public func locOpeGlue(_ gluedShape: Shape,
facePairs: [(base: Shape, glued: Shape)],
edgePairs: [(base: Shape, glued: Shape)] = []) -> Shape?
- Parameters:
gluedShape, shape to glue.facePairs, at least one required matching face pair.edgePairs, optional edge pairs for precise alignment. - Returns: Result shape, or
nilon failure (including emptyfacePairs). - OCCT:
LocOpe_Gluer - Example:
if let r = base.locOpeGlue(toGlue, facePairs: [(base: bf, glued: gf)]) { }
ChFi2d_Builder
All ChFi2d_Builder methods operate exclusively on planar faces, not solids. Extract the target face first if working from a solid.
addFillet2d(vertexIndex:radius:)
Add a 2D fillet at a vertex on a planar face.
public func addFillet2d(vertexIndex: Int, radius: Double) -> Shape?
- Parameters:
vertexIndex, 0-based vertex index.radius, fillet radius. - Returns: Result face with fillet, or
nilif the shape is not a planar face. - OCCT:
ChFi2d_Builder::AddFillet - Example:
let face = solid.subShapes(ofType: .face)[0] if let filleted = face.addFillet2d(vertexIndex: 0, radius: 1.0) { }
addChamfer2d(edge1Index:edge2Index:d1:d2:)
Add a 2D chamfer between two edges on a planar face.
public func addChamfer2d(edge1Index: Int, edge2Index: Int, d1: Double, d2: Double) -> Shape?
- Parameters:
edge1Index/edge2Index, 0-based edge indices.d1/d2, chamfer distances on each edge. - Returns: Result face with chamfer, or
nilon failure. - OCCT:
ChFi2d_Builder::AddChamfer - Example:
if let ch = face.addChamfer2d(edge1Index: 0, edge2Index: 1, d1: 1.0, d2: 1.0) { }
addChamfer2dAngle(edgeIndex:vertexIndex:distance:angle:)
Add a 2D chamfer defined by distance and angle on a planar face.
public func addChamfer2dAngle(edgeIndex: Int, vertexIndex: Int, distance: Double, angle: Double) -> Shape?
- Parameters:
edgeIndex, reference edge.vertexIndex, vertex to chamfer.distance, distance on the edge.angle, chamfer angle in radians. - Returns: Result face with chamfer, or
nilon failure. - OCCT:
ChFi2d_Builder::AddChamfer(distance + angle) - Example:
if let ch = face.addChamfer2dAngle(edgeIndex: 0, vertexIndex: 1, distance: 1.0, angle: .pi/4) { }
modifyFillet2d(originalFace:filletEdgeIndex:newRadius:)
Modify an existing fillet radius on a face.
public func modifyFillet2d(originalFace: Shape, filletEdgeIndex: Int, newRadius: Double) -> Shape?
- Parameters:
originalFace, face before the fillet was added.filletEdgeIndex, 0-based index of the fillet edge inself.newRadius, new fillet radius. - Returns: Result face with modified fillet, or
nilon failure. - OCCT:
ChFi2d_Builder::ModifyFillet - Example:
if let modified = filletedFace.modifyFillet2d(originalFace: original, filletEdgeIndex: 0, newRadius: 2.0) { }
removeFillet2d(originalFace:filletEdgeIndex:)
Remove a fillet from a face, restoring the original corner.
public func removeFillet2d(originalFace: Shape, filletEdgeIndex: Int) -> Shape?
- Parameters:
originalFace, face before the fillet.filletEdgeIndex, 0-based fillet edge index inself. - Returns: Face with fillet removed, or
nilon failure. - OCCT:
ChFi2d_Builder::RemoveFillet - Example:
if let r = filletedFace.removeFillet2d(originalFace: original, filletEdgeIndex: 0) { }
removeChamfer2d(originalFace:chamferEdgeIndex:)
Remove a chamfer from a face.
public func removeChamfer2d(originalFace: Shape, chamferEdgeIndex: Int) -> Shape?
- Parameters:
originalFace, face before the chamfer.chamferEdgeIndex, 0-based chamfer edge index inself. - Returns: Face with chamfer removed, or
nilon failure. - OCCT:
ChFi2d_Builder::RemoveChamfer - Example:
if let r = chamferedFace.removeChamfer2d(originalFace: original, chamferEdgeIndex: 0) { }
ChFi2d_ChamferAPI
Chamfer2DEdgeResult
Result of a standalone 2D chamfer between two edges.
public struct Chamfer2DEdgeResult: Sendable {
public let chamferEdge: Shape
public let modifiedEdge1: Shape
public let modifiedEdge2: Shape
}
Chamfer2DEdgeResult.chamferEdge
The new chamfer edge connecting the two trimmed originals.
public let chamferEdge: Shape
Chamfer2DEdgeResult.modifiedEdge1
edge1, trimmed back by d1 to meet the chamfer edge.
public let modifiedEdge1: Shape
Chamfer2DEdgeResult.modifiedEdge2
edge2, trimmed back by d2 to meet the chamfer edge.
public let modifiedEdge2: Shape
Shape.chamfer2dEdges(edge1:edge2:d1:d2:)
Create a chamfer between two linear edges using ChFi2d_ChamferAPI.
public static func chamfer2dEdges(edge1: Shape, edge2: Shape, d1: Double, d2: Double) -> Chamfer2DEdgeResult?
- Parameters:
edge1/edge2, linear edges sharing a vertex.d1/d2, chamfer distances on each edge. - Returns:
Chamfer2DEdgeResultwith chamfer edge and trimmed originals, ornilon failure. - OCCT:
ChFi2d_ChamferAPI - Example:
if let r = Shape.chamfer2dEdges(edge1: e1, edge2: e2, d1: 1.0, d2: 1.0) { let chamfer = r.chamferEdge }
ChFi2d_FilletAPI
Fillet2DEdgeResult
Result of a standalone 2D fillet between two edges.
public struct Fillet2DEdgeResult: Sendable {
public let filletEdge: Shape
public let modifiedEdge1: Shape
public let modifiedEdge2: Shape
public let solutionCount: Int
}
| Field | Meaning |
|---|---|
filletEdge | The new fillet arc edge. |
modifiedEdge1 | edge1, trimmed to meet the fillet arc. |
modifiedEdge2 | edge2, trimmed to meet the fillet arc. |
Shape.Fillet2DEdgeResult.modifiedEdge2
Shape.fillet2dEdges(edge1:edge2:planeOrigin:planeNormal:radius:nearPoint:)
Create a fillet between two edges in a plane using ChFi2d_FilletAPI.
public static func fillet2dEdges(edge1: Shape, edge2: Shape,
planeOrigin: SIMD3<Double> = .zero,
planeNormal: SIMD3<Double>,
radius: Double,
nearPoint: SIMD3<Double>) -> Fillet2DEdgeResult?
- Parameters:
edge1/edge2, edges to fillet.planeOrigin, a point on the plane containing the edges (defaults to the world origin; must match the edges’ actual plane for edges not passing through(0,0,0), #1459).planeNormal, normal of the plane containing the edges.radius, fillet radius.nearPoint, point near the desired fillet location, used to select among multiple solutions. - Returns:
Fillet2DEdgeResultwith the fillet arc, trimmed edges, and solution count, ornilon failure. - OCCT:
ChFi2d_FilletAPI(selects analytical or iterative algorithm automatically) - Example:
if let r = Shape.fillet2dEdges( edge1: e1, edge2: e2, planeOrigin: SIMD3(0, 0, 0), planeNormal: SIMD3(0, 0, 1), radius: 2.0, nearPoint: SIMD3(1, 1, 0)) { print(r.solutionCount) }
FilletSurf_Builder
FilletSurfaceInfo
Geometry information for one computed fillet surface.
public struct FilletSurfaceInfo: Sendable {
public let surface: Surface
public let supportFace1: Shape
public let supportFace2: Shape
public let tolerance: Double
public let firstParameter: Double
public let lastParameter: Double
public let startStatus: Int
public let endStatus: Int
}
| Field | Meaning |
|---|---|
supportFace1 | The first of the two original faces this fillet surface blends between. |
supportFace2 | The second of the two original faces this fillet surface blends between. |
tolerance | Geometric tolerance achieved for this fillet surface. |
firstParameter | The fillet’s parameter on the first edge of the whole request, not a per-surface value; see the note below. |
lastParameter | The fillet’s parameter on the last edge of the whole request; per request, not per surface, for the same reason. |
startStatus | Where the fillet’s start section sits relative to the edge it was built on: both extremities on the edge (0), one extremity on the edge (1), or neither (2); see the note below. |
endStatus | The same scale at the fillet’s end section. |
firstParameter and lastParameter come from FilletSurf_Builder::FirstParameter() and LastParameter(), which take no surface index. They are the fillet’s parameters on the first and last edge of the whole request, and this struct repeats the same pair into every element rather than measuring one per surface.
startStatus/endStatus come from FilletSurf_Builder::StartSectionStatus() and EndSectionStatus(), whose enum is FilletSurf_StatusType (0 = FilletSurf_TwoExtremityOnEdge, 1 = FilletSurf_OneExtremityOnEdge, 2 = FilletSurf_NoExtremityOnEdge). They are not on FilletSurfaceResult.status’s scale, and reading them as if they were is a silent misread rather than an error: that field carries FilletSurf_StatusDone (0 = ok, 1 = not ok, 2 = partial). The two enums are unrelated and share the ordinals 0...2. This table described both as the ok/not-ok/partial scale until #1399 measured the ordinals against the pinned FilletSurf_StatusType.hxx (Scripts/repro/1399-refman-coverage-unlaned/probe-transcript.txt).
Shape.FilletSurfaceInfo.endStatus
FilletSurfaceResult
Result of FilletSurf_Builder computation.
public struct FilletSurfaceResult: Sendable {
public let surfaces: [FilletSurfaceInfo]
public let status: Int // 0=ok, 1=notOk, 2=partial
}
| Field | Meaning |
|---|---|
surfaces | One FilletSurfaceInfo per requested edge that produced a fillet surface. |
status | Overall outcome of the whole computation: 0 = ok, 1 = not ok, 2 = partial. |
That is FilletSurf_Builder::IsDone()’s FilletSurf_StatusDone, and it is unrelated to FilletSurfaceInfo.startStatus/endStatus, which carry FilletSurf_StatusType on the same ordinals.
Shape.FilletSurfaceResult.surfaces
filletSurfaces(edges:radius:)
Compute fillet surface geometry on this shape without modifying its topology.
public func filletSurfaces(edges: [Shape], radius: Double) -> FilletSurfaceResult?
- Parameters:
edges, edges to fillet.radius, fillet radius. - Returns:
FilletSurfaceResultwith NURBS fillet surfaces and support faces, ornilon total failure.status == 1with an emptysurfacesarray also maps tonil. - OCCT:
FilletSurf_Builder - Note: Returns raw surface geometry only; does not produce a new solid. Use
Shape.filleted(edges:radius:)to produce a filleted solid. - Example:
if let r = solid.filletSurfaces(edges: [e1, e2], radius: 1.0) { for info in r.surfaces { print(info.surface, info.tolerance) } }