BRepGraph — Editor Geometry, Sampling & Durable Identity
This page covers the final sections of BRepGraph: geometric setters for the EditorView, assembly-building ProductOps, in-place RepOps swaps, MeshView cache inspection, UV-grid and edge-curve sampling, and the durable-identity UID/RefUID/ItemUID API. See the other BRepGraph — … pages for the core read API, write helpers, and I/O.
Topics
- EditorView Geometric Setters & PCurve API · EditorView ProductOps Assembly Building · EditorView RepOps Non-Guard Setters · MeshView Cache Entry Inspection · UV-Grid Sampling · Edge Curve Sampling · Durable Identity (UID / RefUID / ItemUID)
EditorView Geometric Setters & PCurve API
(v0.162.0) Low-level geometric mutation of coedge, edge, face, and reference-entry nodes — used when reconstructing or repairing a BRepGraph from external data.
setCoEdgeUVBox(_:u1:v1:u2:v2:)
Set the UV bounding box (UV1 at ParamFirst, UV2 at ParamLast) of a coedge definition.
public func setCoEdgeUVBox(_ coedgeIndex: Int, u1: Double, v1: Double, u2: Double, v2: Double)
- Parameters:
coedgeIndex— per-kind coedge index;u1/v1— UV at the first parameter;u2/v2— UV at the last parameter. - OCCT:
BRepGraph_CoEdgeDefUV-box field (viaOCCTBRepGraphSetCoEdgeUVBox). - Example:
graph.setCoEdgeUVBox(0, u1: 0.0, v1: 0.0, u2: 1.0, v2: 1.0)
setEdgeRegularity(_:face1:face2:continuity:)
Set the geometric regularity (C^k continuity) for an edge across a pair of faces.
@discardableResult
public func setEdgeRegularity(_ edgeIndex: Int, face1: Int, face2: Int, continuity: Int) -> Bool
Pass the same index for face1 and face2 to set the seam continuity across a closed-surface seam line. In OCCT 8.0.0 GA the continuity model lives on the (edge, face1, face2) triple in BRepGraph_LayerRegularity; the earlier per-coedge setters were removed.
- Parameters:
edgeIndex— per-kind edge index.face1,face2— adjacent face indices (equal for seam).continuity— ignored; see the note below.
- Returns: Always
falseon OCCT 8.0.0p1. - OCCT:
BRepGraph_LayerRegularity(viaOCCTBRepGraphSetEdgeRegularity).
This setter does not work on the pinned kernel.
BRepGraph_LayerRegularity— the only write path in the GA continuity model — does not compile in 8.0.0p1 and is absent fromlibOCCT, so the bridge function is a stub that reports failure without readingcontinuityat all. It had shipped that way silently since the GA upgrade: the one test covering it discarded the return value and asserted nothing (fixed in #490, tracked for resolution in #513). To read continuity, useShape.continuity(edge:face1:face2:)orShape.maxContinuity(edge:), which go through the shape-basedBRepLib/BRep_Toolpath and are unaffected.
- Example:
let ok = graph.setEdgeRegularity(2, face1: 0, face2: 1, continuity: 2) #expect(ok == false) // no write path in 8.0.0p1
setFaceTriangulationRep(_:triRepId:)
Set the active triangulation rep on a face, binding a fresh Triangulation to the persistent tier.
public func setFaceTriangulationRep(_ faceIndex: Int, triRepId: Int)
Also see appendCachedTriangulation for cache-tier writes.
- Parameters:
faceIndex— per-kind face index;triRepId— rep-store triangulation id. - OCCT:
BRepGraph_FaceDeftriangulation-rep field (viaOCCTBRepGraphSetFaceTriangulationRep).
coEdgeCreateCurve2DRep(_:)
Create a new Curve2DRep from a Curve2D and return its rep id.
public func coEdgeCreateCurve2DRep(_ curve2D: Curve2D) -> Int?
- Parameters:
curve2D— the 2D curve to wrap in a new rep entry. - Returns: Non-negative rep id on success, or
nilon failure. - OCCT:
BRepGraph_RepStorecurve-2D entry (viaOCCTBRepGraphCoEdgeCreateCurve2DRep). - Example:
if let repId = graph.coEdgeCreateCurve2DRep(myCurve2D) { graph.coEdgeSetPCurve(3, curve2D: myCurve2D) }
coEdgeSetPCurve(_:curve2D:)
Assign or clear the PCurve bound to an existing coedge.
public func coEdgeSetPCurve(_ coedgeIndex: Int, curve2D: Curve2D?)
- Parameters:
coedgeIndex— per-kind coedge index;curve2D— the curve to assign, ornilto clear the binding. - OCCT:
BRepGraph_CoEdgeDefcurve-2D field (viaOCCTBRepGraphCoEdgeSetPCurve).
coEdgeAddPCurve(edgeIndex:faceIndex:curve2D:first:last:orientation:)
Attach a PCurve to an edge for a given face context, creating a new CoEdge entry.
public func coEdgeAddPCurve(edgeIndex: Int, faceIndex: Int, curve2D: Curve2D,
first: Double, last: Double, orientation: Int = 0)
- Parameters:
edgeIndex— the edge to attach the PCurve to.faceIndex— the face context.curve2D— the parametric curve.first,last— parameter range on the curve.orientation— 0 = forward, 1 = reversed (default0).
- OCCT:
BRepGraphcoedge construction (viaOCCTBRepGraphCoEdgeAddPCurve). - Example:
graph.coEdgeAddPCurve(edgeIndex: 1, faceIndex: 0, curve2D: pcurve, first: 0.0, last: 1.0, orientation: 0)
setVertexRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a vertex reference entry.
public func setVertexRefLocalLocation(_ vertexRefIndex: Int, matrix: [Double])
matrix is a row-major 3×4 array (12 doubles) following the gp_Trsf::SetValues convention — rows are [r00 r01 r02 tx | r10 r11 r12 ty | r20 r21 r22 tz]. Use BRepGraph.identityLocationMatrix for a no-op placement.
- Parameters:
vertexRefIndex— per-kind vertex-ref index;matrix— 12-element row-major 3×4 transform. - OCCT:
TopLoc_Locationviagp_Trsf::SetValues(viaOCCTBRepGraphSetVertexRefLocalLocation). - Note: Precondition:
matrix.count == 12.
setCoEdgeRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a coedge reference entry.
public func setCoEdgeRefLocalLocation(_ coedgeRefIndex: Int, matrix: [Double])
- Parameters:
coedgeRefIndex— per-kind coedge-ref index;matrix— 12-element 3×4 row-major transform. - OCCT:
TopLoc_Location(viaOCCTBRepGraphSetCoEdgeRefLocalLocation).
setWireRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a wire reference entry.
public func setWireRefLocalLocation(_ wireRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetWireRefLocalLocation).
setFaceRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a face reference entry.
public func setFaceRefLocalLocation(_ faceRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetFaceRefLocalLocation).
setShellRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a shell reference entry.
public func setShellRefLocalLocation(_ shellRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetShellRefLocalLocation).
setSolidRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a solid reference entry.
public func setSolidRefLocalLocation(_ solidRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetSolidRefLocalLocation).
setOccurrenceRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of an occurrence reference entry.
public func setOccurrenceRefLocalLocation(_ occurrenceRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetOccurrenceRefLocalLocation).
setChildRefLocalLocation(_:matrix:)
Set the local TopLoc_Location of a child reference entry.
public func setChildRefLocalLocation(_ childRefIndex: Int, matrix: [Double])
- OCCT:
TopLoc_Location(viaOCCTBRepGraphSetChildRefLocalLocation).
identityLocationMatrix
Identity matrix (3×4) suitable for all set*LocalLocation calls.
public static var identityLocationMatrix: [Double] { get }
Returns [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0] — a row-major identity with zero translation.
- Example:
graph.setFaceRefLocalLocation(0, matrix: BRepGraph.identityLocationMatrix)
EditorView ProductOps Assembly Building
(v0.163.0) Methods for building and editing the product/assembly graph layer of BRepGraph.
linkProductToTopology(shapeRootKind:shapeRootIndex:placement:)
Wrap an existing topology root in a new Product.
public func linkProductToTopology(shapeRootKind: Int, shapeRootIndex: Int,
placement: [Double]? = nil) -> Int?
- Parameters:
shapeRootKind—BRepGraph_NodeId::Kindordinal of the topology root (e.g. 0 = Solid).shapeRootIndex— per-kind node index of the root.placement— optional 12-element 3×4 row-major placement matrix; passnilfor identity.
- Returns: New product id on success, or
nilon failure. - OCCT:
BRepGraphproduct-layer creation (viaOCCTBRepGraphLinkProductToTopology). - Note: Precondition:
placement.count == 12if non-nil. - Example:
if let pid = graph.linkProductToTopology(shapeRootKind: 0, shapeRootIndex: 0) { print("Product id:", pid) }
createEmptyProduct()
Create an empty product (assembly node with no direct topology).
public func createEmptyProduct() -> Int?
- Returns: New product id, or
nilon failure. - OCCT:
BRepGraphproduct-layer (viaOCCTBRepGraphCreateEmptyProduct). - Example:
guard let assemblyId = graph.createEmptyProduct() else { return }
linkProducts(parentProductIndex:referencedProductIndex:placement:parentOccurrenceIndex:)
Link two products via a fresh occurrence (assembly reference).
public func linkProducts(parentProductIndex: Int, referencedProductIndex: Int,
placement: [Double], parentOccurrenceIndex: Int? = nil)
-> (occurrenceIndex: Int, occurrenceRefIndex: Int)?
- Parameters:
parentProductIndex— product that will own the new occurrence.referencedProductIndex— product being instanced.placement— 12-element 3×4 row-major transform for the instance.parentOccurrenceIndex— passnilfor an unparented occurrence.
- Returns: Tuple of
(occurrenceIndex, occurrenceRefIndex), ornilon failure. - OCCT:
BRepGraphoccurrence construction (viaOCCTBRepGraphLinkProducts). - Note: Precondition:
placement.count == 12. - Example:
let matrix = BRepGraph.identityLocationMatrix if let result = graph.linkProducts(parentProductIndex: 0, referencedProductIndex: 1, placement: matrix) { print("Occurrence:", result.occurrenceIndex, "OccurrenceRef:", result.occurrenceRefIndex) }
productRemoveOccurrence(_:occurrenceRefIndex:)
Detach an occurrence ref from a product.
public func productRemoveOccurrence(_ productIndex: Int, occurrenceRefIndex: Int) -> Bool
- Parameters:
productIndex— the owning product;occurrenceRefIndex— the occurrence-ref to remove. - Returns:
trueif the active usage was removed. - OCCT:
BRepGraphproduct-layer (viaOCCTBRepGraphProductRemoveOccurrence).
productRemoveShapeRoot(_:)
Detach the scalar shape-root from a product.
public func productRemoveShapeRoot(_ productIndex: Int) -> Bool
- Returns:
trueif a root was detached. - OCCT:
BRepGraphproduct-layer (viaOCCTBRepGraphProductRemoveShapeRoot).
EditorView RepOps Non-Guard Setters
(v0.164.0) In-place swaps of the geometry object bound to an existing rep-store entry. These do not recreate the rep — they update the pointer in-place, allowing dependent coedges/edges/faces to pick up new geometry without structural graph changes.
repSetSurface(_:surface:)
Swap the surface bound to an existing surface rep id.
public func repSetSurface(_ surfaceRepId: Int, surface: Surface)
- Parameters:
surfaceRepId— rep-store surface rep id;surface— the replacementSurface. - OCCT:
BRepGraph_RepStoresurface entry (viaOCCTBRepGraphRepSetSurface).
repSetCurve3D(_:curve:)
Swap the 3D curve bound to an existing curve-3D rep id.
public func repSetCurve3D(_ curve3DRepId: Int, curve: Curve3D)
- OCCT:
BRepGraph_RepStorecurve-3D entry (viaOCCTBRepGraphRepSetCurve3D).
repSetCurve2D(_:curve:)
Swap the 2D curve bound to an existing curve-2D rep id.
public func repSetCurve2D(_ curve2DRepId: Int, curve: Curve2D)
- OCCT:
BRepGraph_RepStorecurve-2D entry (viaOCCTBRepGraphRepSetCurve2D).
repSetTriangulation(_:triangulation:)
Swap the triangulation bound to an existing triangulation rep id.
public func repSetTriangulation(_ triRepId: Int, triangulation: Triangulation)
- OCCT:
BRepGraph_RepStoretriangulation entry (viaOCCTBRepGraphRepSetTriangulation).
repSetPolygon3D(_:polygon:)
Swap the Polygon3D bound to an existing polygon-3D rep id.
public func repSetPolygon3D(_ polyRepId: Int, polygon: Polygon3D)
- OCCT:
BRepGraph_RepStorepolygon-3D entry (viaOCCTBRepGraphRepSetPolygon3D).
repSetPolygon2D(_:polygon:)
Swap the Polygon2D bound to an existing polygon-2D rep id.
public func repSetPolygon2D(_ polyRepId: Int, polygon: Polygon2D)
- OCCT:
BRepGraph_RepStorepolygon-2D entry (viaOCCTBRepGraphRepSetPolygon2D).
repSetPolygonOnTri(_:polygon:)
Swap the PolygonOnTriangulation bound to an existing polygon-on-triangulation rep id.
public func repSetPolygonOnTri(_ polyRepId: Int, polygon: PolygonOnTriangulation)
- OCCT:
BRepGraph_RepStorepolygon-on-tri entry (viaOCCTBRepGraphRepSetPolygonOnTri).
repSetPolygonOnTriTriangulationId(_:triRepId:)
Update the triangulation id referenced by an existing polygon-on-triangulation rep.
public func repSetPolygonOnTriTriangulationId(_ polyOnTriRepId: Int, triRepId: Int)
- Parameters:
polyOnTriRepId— the polygon-on-tri rep to update;triRepId— the new triangulation rep id. - OCCT:
BRepGraph_RepStorepolygon-on-tri triangulation-id field (viaOCCTBRepGraphRepSetPolygonOnTriTriangulationId). - Example:
// After replacing a triangulation, rebind the polygon-on-tri to the new rep: graph.repSetTriangulation(newTriRepId, triangulation: updatedTri) graph.repSetPolygonOnTriTriangulationId(polyOnTriRepId, triRepId: newTriRepId)
MeshView Cache Entry Inspection
(v0.164.0) Read-only accessors for the cached-mesh tier (algorithm-derived meshes). All return absent values (false, 0, or nil) when no cache entry exists for the entity.
cachedFaceMeshIsPresent(_:)
Whether a cached mesh entry exists for the given face.
public func cachedFaceMeshIsPresent(_ faceIndex: Int) -> Bool
- OCCT:
BRepGraph_MeshCacheface entry (viaOCCTBRepGraphCachedFaceMeshIsPresent).
cachedFaceMeshTriRepCount(_:)
Number of triangulation reps in the cached mesh entry for a face.
public func cachedFaceMeshTriRepCount(_ faceIndex: Int) -> Int
- OCCT:
OCCTBRepGraphCachedFaceMeshTriRepCount.
cachedFaceMeshActiveIndex(_:)
The active triangulation rep index within the cached mesh entry for a face.
public func cachedFaceMeshActiveIndex(_ faceIndex: Int) -> Int
- OCCT:
OCCTBRepGraphCachedFaceMeshActiveIndex.
cachedFaceMeshStoredOwnGen(_:)
The stored generation counter from when the cached face mesh was last committed.
public func cachedFaceMeshStoredOwnGen(_ faceIndex: Int) -> UInt32
This is the entry’s own field (FaceMeshEntry::MeshGeneration), maintained by OCCT’s mesh cache. It is not comparable to the graph’s generation counter, and this page previously said to compare them — it never worked (#295).
- OCCT:
OCCTBRepGraphCachedFaceMeshStoredOwnGen.
cachedFaceMeshTriRepId(_:repIndex:)
The triangulation rep id at a given rep-slot in the cached face mesh.
public func cachedFaceMeshTriRepId(_ faceIndex: Int, repIndex: Int) -> Int?
- Returns: Non-negative rep id, or
nilifrepIndexis out of range. - OCCT:
OCCTBRepGraphCachedFaceMeshTriRepId. - Example:
if graph.cachedFaceMeshIsPresent(0) { let count = graph.cachedFaceMeshTriRepCount(0) for i in 0..<count { if let repId = graph.cachedFaceMeshTriRepId(0, repIndex: i) { print("TriRep:", repId) } } }
cachedEdgeMeshIsPresent(_:)
Whether a cached mesh entry exists for the given edge.
public func cachedEdgeMeshIsPresent(_ edgeIndex: Int) -> Bool
- OCCT:
OCCTBRepGraphCachedEdgeMeshIsPresent.
cachedEdgeMeshPolygon3DRepId(_:)
The polygon-3D rep id in the cached edge mesh entry.
public func cachedEdgeMeshPolygon3DRepId(_ edgeIndex: Int) -> Int?
- Returns: Non-negative rep id, or
nilif no entry exists. - OCCT:
OCCTBRepGraphCachedEdgeMeshPolygon3DRepId.
cachedEdgeMeshStoredOwnGen(_:)
The stored generation counter for the cached edge mesh.
public func cachedEdgeMeshStoredOwnGen(_ edgeIndex: Int) -> UInt32
- OCCT:
OCCTBRepGraphCachedEdgeMeshStoredOwnGen.
cachedCoEdgeMeshIsPresent(_:)
Whether a cached mesh entry exists for the given coedge.
public func cachedCoEdgeMeshIsPresent(_ coedgeIndex: Int) -> Bool
- OCCT:
OCCTBRepGraphCachedCoEdgeMeshIsPresent.
cachedCoEdgeMeshPolygon2DRepId(_:)
The polygon-2D rep id in the cached coedge mesh entry.
public func cachedCoEdgeMeshPolygon2DRepId(_ coedgeIndex: Int) -> Int?
- Returns: Non-negative rep id, or
nilif no entry exists. - OCCT:
OCCTBRepGraphCachedCoEdgeMeshPolygon2DRepId.
cachedCoEdgeMeshPolygonOnTriRepCount(_:)
Number of polygon-on-triangulation reps in the cached coedge mesh entry.
public func cachedCoEdgeMeshPolygonOnTriRepCount(_ coedgeIndex: Int) -> Int
- OCCT:
OCCTBRepGraphCachedCoEdgeMeshPolygonOnTriRepCount.
cachedCoEdgeMeshPolygonOnTriRepId(_:repIndex:)
The polygon-on-triangulation rep id at a given rep-slot in the cached coedge mesh.
public func cachedCoEdgeMeshPolygonOnTriRepId(_ coedgeIndex: Int, repIndex: Int) -> Int?
- Returns: Non-negative rep id, or
nilifrepIndexis out of range. - OCCT:
OCCTBRepGraphCachedCoEdgeMeshPolygonOnTriRepId.
cachedCoEdgeMeshStoredOwnGen(_:)
The stored generation counter for the cached coedge mesh.
public func cachedCoEdgeMeshStoredOwnGen(_ coedgeIndex: Int) -> UInt32
- OCCT:
OCCTBRepGraphCachedCoEdgeMeshStoredOwnGen.
UV-Grid Sampling
(v0.136.0)
FaceGridSample
Result of sampling a face surface on a regular UV grid.
public struct FaceGridSample: Sendable {
/// Surface positions at grid points, U-major.
public let positions: [SIMD3<Double>]
/// Surface normals at grid points, U-major.
public let normals: [SIMD3<Double>]
/// Gaussian curvature at each grid point, U-major.
public let gaussianCurvatures: [Double]
/// Mean curvature at each grid point, U-major.
public let meanCurvatures: [Double]
/// Number of samples in U direction.
public let uSamples: Int
/// Number of samples in V direction.
public let vSamples: Int
/// Position, normal and curvatures at the given U/V grid index.
public func at(u: Int, v: Int) -> (position: SIMD3<Double>, normal: SIMD3<Double>,
gaussianCurvature: Double, meanCurvature: Double)
}
| Field | Meaning |
|---|---|
positions | Surface positions at grid points, U-major |
normals | Surface normals at grid points, U-major |
gaussianCurvatures | Gaussian curvature at each grid point, U-major |
meanCurvatures | Mean curvature at each grid point, U-major |
uSamples | Number of samples in the U direction |
vSamples | Number of samples in the V direction |
Read through at(u:v:) rather than spelling the index out. Until #617 the bridge wrote these buffers transposed (v * uSamples + u) while this page already documented the U-major index above, so a caller who followed the docs read the wrong point of the face; getting the stride wrong instead (u * uSamples + v) is silently in range on a 3×10 grid and out of bounds on a 10×3 one. at(u:v:) removes both failure modes by owning the index.
guard let sample = graph.sampleFaceUVGrid(faceIndex: 0, uSamples: 10, vSamples: 3)
else { return }
for u in 0..<sample.uSamples {
for v in 0..<sample.vSamples {
let s = sample.at(u: u, v: v)
print("(\(u), \(v)) -> \(s.position) kG=\(s.gaussianCurvature) kH=\(s.meanCurvature)")
}
}
BRepGraph.FaceGridSample.vSamples
Number of samples in the V direction.
All four arrays share one layout: U-major, u varying slowest and v fastest, so grid position (u, v) sits at index = u * vSamples + v for u ∈ [0, uSamples) and v ∈ [0, vSamples). This is the layout SurfaceGrid and SurfaceGridD1 use, and the one #486 declared for the whole API.
BRepGraph.FaceGridSample.at(u:v:)
Position, normal and curvatures at the given U/V grid index. Read through this rather than spelling the flat index out yourself. Until #617 the bridge wrote these buffers transposed (v * uSamples + u) while this page already documented the U-major index above, so a caller who followed the docs read the wrong point of the face; getting the stride wrong instead (u * uSamples + v) is silently in range on a 3×10 grid and out of bounds on a 10×3 one. at(u:v:) removes both failure modes by owning the index.
public func at(u: Int, v: Int) -> (position: SIMD3<Double>, normal: SIMD3<Double>,
gaussianCurvature: Double, meanCurvature: Double)
- Parameters:
u: U grid index,0..<uSamples;v: V grid index,0..<vSamples. - Returns: The position, normal, Gaussian curvature and mean curvature at that grid point.
- Example:
if let sample = graph.sampleFaceUVGrid(faceIndex: 0, uSamples: 3, vSamples: 10) { let corner = sample.at(u: 2, v: 9) print(corner.position, corner.meanCurvature) }
Walk the whole grid row by row (U outer, V inner) to visit every point in storage order:
guard let sample = graph.sampleFaceUVGrid(faceIndex: 0, uSamples: 10, vSamples: 3)
else { return }
for u in 0..<sample.uSamples {
for v in 0..<sample.vSamples {
let s = sample.at(u: u, v: v)
print("(\(u), \(v)) -> \(s.position) kG=\(s.gaussianCurvature) kH=\(s.meanCurvature)")
}
}
sampleFaceUVGrid(faceIndex:uSamples:vSamples:)
Sample a face surface on a regular UV grid, evaluating positions, normals, and principal curvatures.
public func sampleFaceUVGrid(faceIndex: Int, uSamples: Int, vSamples: Int) -> FaceGridSample?
- Parameters:
faceIndex— face definition index.uSamples— number of samples in U direction (must be ≥ 1).vSamples— number of samples in V direction (must be ≥ 1).
The bound is on the product:
uSamples * vSamplesmust not exceedSampling.maximumSampleCount(10,000,000), and each factor is checked on its own, since two negatives multiply to a plausible positive total (#558). This sampler fills four buffers per point (position, normal, Gaussian and mean curvature), so it reaches the ceiling’s memory cost sooner than the point-only samplers do. - Returns:
FaceGridSamplewithuSamples × vSamplesentries laid out U-major (u * vSamples + v, seeFaceGridSampleabove), ornilif the face has no surface, sampling fails, or the grid cannot be served. - OCCT:
GeomLProp_SLProps(position, normal, curvature evaluation) viaOCCTBRepGraphSampleFaceUVGrid. - Example:
if let grid = graph.sampleFaceUVGrid(faceIndex: 0, uSamples: 5, vSamples: 5) { for (i, pos) in grid.positions.enumerated() { let kG = grid.gaussianCurvatures[i] let kH = grid.meanCurvatures[i] print("(\(pos.x), \(pos.y), \(pos.z)) kG=\(kG) kH=\(kH)") } } - Example (indexed by grid position, not flat order):
if let grid = graph.sampleFaceUVGrid(faceIndex: 0, uSamples: 10, vSamples: 3) { // The far corner of a non-square grid: `at` resolves the U-major index for you. let corner = grid.at(u: grid.uSamples - 1, v: grid.vSamples - 1) print(corner.position, corner.normal, corner.meanCurvature) }
Edge Curve Sampling
(v0.136.0)
sampleEdgeCurve(edgeIndex:count:)
Sample evenly-spaced points along an edge curve.
public func sampleEdgeCurve(edgeIndex: Int, count: Int) -> [SIMD3<Double>]
- Parameters:
edgeIndex— edge definition index.count— number of points to sample, a request honoured within1...Sampling.maximumSampleCount(10,000,000); outside that range the result is empty (#558).
- Returns: Array of 3D points along the edge curve, in parameter order; empty if the edge has no curve or sampling fails.
- OCCT:
GeomAdaptor_Curve(viaOCCTBRepGraphSampleEdgeCurve). - Example:
let pts = graph.sampleEdgeCurve(edgeIndex: 0, count: 20) for p in pts { print(p.x, p.y, p.z) }
Durable Identity (UID / RefUID / ItemUID)
(OCCT 8.0.0p1) The UID system provides counter-based identifiers that remain stable across mutations of the one graph instance that minted them — compaction, node removal. Unlike (kind, index) pairs, counters never repeat within a kind and survive vector-index shifts. A counter of 0 is always the invalid sentinel.
Scope: one graph instance
A UID is meaningful only inside the graph that minted it. Every graph allocates counters from 1 independently, so the same (kind, counter) names some unrelated node in every other graph. Each UID therefore carries a graphID — the instanceID of the graph that minted it — and the resolvers reject a UID from anywhere else:
let boxGraph = BRepGraph(shape: box)!
let cylGraph = BRepGraph(shape: cylinder)!
let faceUID = boxGraph.uid(ofNodeKind: 2, index: 2)! // a face of the BOX
boxGraph.node(forUID: faceUID) // Optional((kind: 2, index: 2))
cylGraph.node(forUID: faceUID) // nil — not this graph's UID
cylGraph.contains(uid: faceUID) // false
The scope is the graph instance, not the shape: two graphs built from the same shape are two instances, and a UID from one does not resolve in the other. A rebuild is likewise a new instance.
Which operations carry identity across follows the kernel’s own rule — whether it transplants the UID counter space into the target:
| Operation | Identity | UIDs |
|---|---|---|
compact(), node removal, add(_:absorbing:…) | same instance, mutated in place | keep resolving |
copy(), translated() | inherited — BRepGraph_Copy/_Transform::Perform transplant the counter space, Generation and GraphGUID | keep resolving, naming the same nodes |
copyFace() | fresh — CopyNode lifts one face without the counter space | source UIDs return nil |
| a new graph over any shape (incl. a rebuild of the same one) | fresh | source UIDs return nil |
To carry a selection across a modelling operation rather than across mutations of one graph, absorb the operation’s history — see add(_:absorbing:inputRoots:operationName:). To carry one across a save/load, store (kind, index) with the shape and re-mint after rebuilding — see BRep Graph § UIDs and persistence.
Before v1.12.0 UIDs carried no provenance, so a UID from an unrelated graph resolved to a plausible but wrong node instead of returning
nil.copyFace()was affected the same way. (#295)
GraphUID
A durable node identifier: a (kind, counter) pair for a definition node, stamped with the graph that minted it.
public struct GraphUID: Sendable, Hashable, Codable {
public var kind: Int
public var counter: UInt32
public let graphID: UInt64
public var isValid: Bool { get }
}
graphID is the instanceID of the minting graph. 0 means unstamped — built by hand, or decoded from a payload written before v1.12.0 — and resolves in no graph. Mint UIDs with uid(ofNodeKind:index:) rather than constructing them.
kind is the raw BRepGraph_NodeId::Kind ordinal:
| Value | Node type |
|---|---|
| 0 | Solid |
| 1 | Shell |
| 2 | Face |
| 3 | Wire |
| 4 | Edge |
| 5 | Vertex |
| 6 | Compound |
| 7 | CompSolid |
| 8 | CoEdge |
| 10 | Product |
| 11 | Occurrence |
isValid returns true when counter > 0; a valid UID may still fail to resolve if the node has been removed from the graph.
GraphUID.graphID
The instanceID of the graph instance that minted this UID. 0 means unstamped, built by hand or decoded from a payload written before v1.12.0, and resolves in no graph. BRepGraph.node(forUID:) rejects a UID minted by a different graph instance.
GraphUID.counter
The per-kind counter component of the (kind, counter) pair. Never repeats within a kind, and stays stable when the node’s (kind, index) shifts, e.g. after compact(). 0 is the invalid sentinel; see isValid.
kind is the raw BRepGraph_NodeId::Kind ordinal:
| Value | Node type |
|---|---|
| 0 | Solid |
| 1 | Shell |
| 2 | Face |
| 3 | Wire |
| 4 | Edge |
| 5 | Vertex |
| 6 | Compound |
| 7 | CompSolid |
| 8 | CoEdge |
| 10 | Product |
| 11 | Occurrence |
isValid returns true when counter > 0; a valid UID may still fail to resolve if the node has been removed from the graph.
GraphRefUID
A durable reference-entry identifier: a (kind, counter) pair for a reference (ref) node. Scoped to one graph instance and stamped with graphID, exactly as GraphUID is.
public struct GraphRefUID: Sendable, Hashable, Codable {
public var kind: Int
public var counter: UInt32
public let graphID: UInt64
public var isValid: Bool { get }
}
kind is the raw BRepGraph_RefId::Kind ordinal:
| Value | Ref type |
|---|---|
| 0 | Shell |
| 1 | Face |
| 2 | Wire |
| 3 | Vertex |
| 4 | Solid |
| 5 | Child |
| 6 | Occurrence |
| Field | Meaning |
|---|---|
kind | Raw BRepGraph_RefId::Kind ordinal, see the table above |
counter | Per-kind sequence number minted when the reference was created; 0 means invalid |
graphID | The BRepGraph instance ID that minted this UID; 0 means unstamped, resolving in no graph |
BRepGraph.GraphRefUID.graphID
The minting graph’s own instanceID; 0 means unstamped, which resolves in no graph.
GraphItemUID
A durable generic item identifier covering both definition nodes (domain == 1) and reference entries (domain == 2). Scoped to one graph instance and stamped with graphID, exactly as GraphUID is.
public struct GraphItemUID: Sendable, Hashable, Codable {
public var domain: Int
public var kind: Int
public var counter: UInt32
public let graphID: UInt64
public var isValid: Bool { get }
}
domain values: 1 = node, 2 = reference. kind is the raw kind ordinal in that domain’s enum space.
GraphItemUID.graphID
uid(ofNodeKind:index:)
Return the durable GraphUID for a node.
public func uid(ofNodeKind kind: Int, index: Int) -> GraphUID?
- Parameters:
kind— rawBRepGraph_NodeId::Kindordinal;index— per-kind node index. - Returns:
GraphUIDwith a non-zero counter, ornilif the node is invalid, removed, or out of bounds. - OCCT:
BRepGraph_NodeIdUID query (viaOCCTBRepGraphNodeUID). - Example:
if let faceUID = graph.uid(ofNodeKind: 2, index: 0) { // Face at index 0 print("Face UID counter:", faceUID.counter) }
node(forUID:)
Resolve a GraphUID back to its (kind, index) in this graph.
public func node(forUID uid: GraphUID) -> (kind: Int, index: Int)?
- Parameters:
uid— aGraphUIDpreviously obtained from this graph’suid(ofNodeKind:index:). - Returns:
(kind, index)tuple if the UID resolves, ornilif this graph did not mint it or the node no longer exists. A UID minted by another graph returnsnileven when its counter is in range here — which it usually is, since counters restart per graph. - OCCT:
BRepGraph_NodeIdreverse lookup (viaOCCTBRepGraphNodeFromUID). - Example:
guard let faceUID = graph.uid(ofNodeKind: 2, index: 0) else { return } // ... graph mutations ... if let resolved = graph.node(forUID: faceUID) { print("Face now at index:", resolved.index) }
contains(uid:) — GraphUID
Return true if this graph minted the GraphUID and the node it names still exists here.
public func contains(uid: GraphUID) -> Bool
- OCCT:
OCCTBRepGraphHasNodeUID.
uid(ofRefKind:index:)
Return the durable GraphRefUID for a reference entry.
public func uid(ofRefKind kind: Int, index: Int) -> GraphRefUID?
- Parameters:
kind— rawBRepGraph_RefId::Kindordinal;index— per-kind reference index. - Returns:
GraphRefUID, ornilif invalid or removed. - OCCT:
BRepGraph_RefIdUID query (viaOCCTBRepGraphRefUID).
ref(forUID:)
Resolve a GraphRefUID back to its (kind, index).
public func ref(forUID uid: GraphRefUID) -> (kind: Int, index: Int)?
- Returns:
(kind, index)if the UID resolves, ornilif the reference no longer exists. - OCCT:
BRepGraph_RefIdreverse lookup (viaOCCTBRepGraphRefFromUID).
contains(uid:) — GraphRefUID
Return true if this graph minted the GraphRefUID and the reference it names still exists here.
public func contains(uid: GraphRefUID) -> Bool
- OCCT:
OCCTBRepGraphHasRefUID.
itemUID(ofNodeKind:index:)
Return the durable GraphItemUID for a node (domain 1).
public func itemUID(ofNodeKind kind: Int, index: Int) -> GraphItemUID?
- Returns:
GraphItemUIDwithdomain == 1, ornilif the node is invalid or removed. - OCCT:
BRepGraphitem-UID layer (viaOCCTBRepGraphItemUIDOfNode). - Example:
if let itemUID = graph.itemUID(ofNodeKind: 2, index: 0) { assert(itemUID.domain == 1) }
item(forUID:)
Resolve a GraphItemUID back to its (domain, kind, index).
public func item(forUID uid: GraphItemUID) -> (domain: Int, kind: Int, index: Int)?
- Returns:
(domain, kind, index)if the UID resolves, ornilif the item no longer exists. - OCCT:
BRepGraphitem-UID reverse lookup (viaOCCTBRepGraphItemFromUID).
instanceID
Identifies this graph instance for as long as it lives.
public var instanceID: UInt64 { get }
Unique among every graph this process builds, and — because the sequence starts at a random point — distinct from any other process’s ids with overwhelming probability. Every UID this graph mints carries it as graphID, which is how node(forUID:) tells one of its own nodes from a node of some other graph.
Identity here is the graph object, not the geometry: two graphs built from the same shape have different ids.
- OCCT: none — assigned by the bridge per
OCCTBRepGraph(viaOCCTBRepGraphInstanceID). - Example:
let graph = BRepGraph(shape: box)! let uid = graph.uid(ofNodeKind: 2, index: 0)! print(uid.graphID == graph.instanceID) // true — this graph minted it let rebuilt = BRepGraph(shape: box)! // same shape, new instance print(rebuilt.instanceID == graph.instanceID) // false print(rebuilt.node(forUID: uid)) // nil
generation (removed in v2.0.0)
Removed by #784, along with the OCCTBRepGraphGeneration bridge function behind it. Deprecated in v1.12.0.
Use instanceID to compare graph identity. Nothing else is needed: node(forUID:) already rejects a UID minted by another graph on its own.
It was always 1. OCCT advances the counter only from BRepGraph::Clear(), and since v1.12.2 (#303) OCCTSwift calls Clear() exactly once, when it builds a graph, and never rebuilds an existing one. So it landed at 1, stayed there, and read the same for every graph, which is why it could tell neither two graphs apart nor a stale cache.
Earlier revisions of this page suggested comparing a cached storedOwnGen against generation to detect a stale mesh. That recipe never worked: storedOwnGen is a per-entity mesh field (FaceMeshEntry::MeshGeneration), not this counter, so the two were never comparable (#295).