From ea3fc1f8bd2624c091fd48797b84c4a74bd8f7dc Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Sun, 14 Jun 2026 14:15:32 +0100 Subject: [PATCH] Modeling, BRepGraph - Identity copy path, lock-free cache reads, per-CoEdge queries (#1306) Identity copy path: - copyFullGraphIdentity with PrepareForLoad() + direct slot assignment - CopyDerivedRelationsFrom for O(K) relation vector copy - CopyRemovedFlagsFrom for bulk removed-flag copy - CopyShapeBindingsFrom for TShape/Original shape binding copy - PrepareForLoad skips Clear() when storage already empty (IsEmpty fast path) - appendRelationIdDirect for O(1) append in rebuild loop (duplicates structurally impossible) - ChangeCompoundRefsOfNodeInternal uses TryBound for single lookup - Counts() and ActiveCounts() accessors for Counts struct construction Lock-free cache reads: - EdgeEntry: packed atomic (GeomStatus+IsClosed+IsComputed) - CoEdgeSameRangeEntry: packed atomic (SameRange+SameParameter+Computed) - WireEntry: packed atomic (IsClosed+IsComputed) - ShellEntry: atomic with Invalid sentinel - All entries use memory_order_acquire/release pairs - ensureSize handles lazy array growth (no myPreSized) - Enums (GeomStatus, ClosureStatus) moved inside entry structs Per-CoEdge queries: - SameRange/SameParameter are per-CoEdge properties, bound to CoEdge OwnGen - Edge class no longer has SameParameter/SameRange/IsClosed coedge overloads - CoEdge class owns SameParameter/SameRange queries - Test files use local edgeSameParameter/edgeSameRange helpers Lock-free storage and registry: - BRepGraphInc_Storage: atomic dirty flags for UID reverse indexes - BRepGraph_LayerRegistry: atomic subscription masks for lock-free dispatch - Ensure/EnsureCache/EnsureLayer: double-checked locking with shared fast path Other optimizations: - Iterator Next() fast-path: check next element validity inline - NbFaces O(K) inline dedup with NCollection_LocalArray - GeomAdaptor_Curve/Surface/Geom2dAdaptor_Curve for cached geometry eval - Value() calls replaced with EvalD0() for clearer naming - TargetItem returns value instead of pointer (no null-pointer risk) - copyTopologyDefinitionsIdentity clears Curve3DRepId on GeomPolicy::Drop - ensureEdgeEntry concurrency: fast-path validation + selective field merge --- .../GTests/NCollection_LinearVector_Test.cxx | 4 - .../GTests/NCollection_LocalArray_Test.cxx | 4 - .../BRepGraph/BRepGraph_CacheDerivedState.cxx | 762 +++++++++------ .../BRepGraph/BRepGraph_CacheDerivedState.hxx | 372 ++++++-- .../TKBRep/BRepGraph/BRepGraph_CacheMesh.cxx | 6 +- .../BRepGraph/BRepGraph_CacheRegistry.cxx | 58 ++ .../BRepGraph/BRepGraph_CacheRegistry.hxx | 24 +- .../TKBRep/BRepGraph/BRepGraph_Copy.cxx | 875 +++++++----------- .../TKBRep/BRepGraph/BRepGraph_CopyRemap.cxx | 39 +- .../TKBRep/BRepGraph/BRepGraph_CopyRemap.hxx | 21 +- .../BRepGraph/BRepGraph_DefsIterator.hxx | 57 +- .../TKBRep/BRepGraph/BRepGraph_Layer.hxx | 12 +- .../BRepGraph/BRepGraph_LayerDeferred.cxx | 6 +- .../BRepGraph/BRepGraph_LayerHistory.cxx | 56 +- .../TKBRep/BRepGraph/BRepGraph_LayerLock.cxx | 12 +- .../BRepGraph/BRepGraph_LayerRegistry.cxx | 144 ++- .../BRepGraph/BRepGraph_LayerRegistry.hxx | 47 +- .../BRepGraph_LayerTopoSupplement.cxx | 6 +- .../BRepGraph/BRepGraph_RefsIterator.hxx | 32 +- .../TKBRep/BRepGraph/BRepGraph_ShapesView.cxx | 4 +- .../TKBRep/BRepGraph/BRepGraph_Tool.cxx | 171 +--- .../TKBRep/BRepGraph/BRepGraph_Tool.hxx | 91 +- .../TKBRep/BRepGraph/BRepGraph_TopoView.cxx | 60 +- .../BRepGraphInc_BoundaryBuilder.pxx | 8 +- .../BRepGraphInc/BRepGraphInc_Reconstruct.cxx | 106 ++- .../BRepGraphInc/BRepGraphInc_Reconstruct.hxx | 7 +- .../BRepGraphInc/BRepGraphInc_Storage.cxx | 311 ++++++- .../BRepGraphInc/BRepGraphInc_Storage.hxx | 22 +- .../TKBRep/GTests/BRepGraphInc_Test.cxx | 26 +- .../TKBRep/GTests/BRepGraph_Copy_Test.cxx | 30 +- .../TKBRep/GTests/BRepGraph_Geometry_Test.cxx | 36 +- 31 files changed, 2059 insertions(+), 1350 deletions(-) diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_LinearVector_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_LinearVector_Test.cxx index 323d3d2477..89b47cdf74 100644 --- a/src/FoundationClasses/TKernel/GTests/NCollection_LinearVector_Test.cxx +++ b/src/FoundationClasses/TKernel/GTests/NCollection_LinearVector_Test.cxx @@ -825,10 +825,6 @@ static_assert(HasToArray1>::value, static_assert(std::is_same_v&>().ToArray1()), NCollection_Array1>, "Mutable NCollection_LinearVector should expose mutable Array1 view"); -static_assert( - std::is_same_v&>().ToArray1()), - NCollection_Array1>, - "Const NCollection_LinearVector should expose Array1 view"); // Verify that ToArray1() returns an Array1 sharing the same memory buffer. TEST(NCollection_LinearVectorTest, ToArray1_SamePointer) diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx index f03e606882..3e6025c7f3 100644 --- a/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx +++ b/src/FoundationClasses/TKernel/GTests/NCollection_LocalArray_Test.cxx @@ -626,10 +626,6 @@ static_assert(HasToArray1>::value, static_assert(std::is_same_v&>().ToArray1()), NCollection_Array1>, "Mutable NCollection_LocalArray should expose mutable Array1 view"); -static_assert( - std::is_same_v&>().ToArray1()), - NCollection_Array1>, - "Const NCollection_LocalArray should expose Array1 view"); // Verify that ToArray1() returns an Array1 sharing the same memory buffer. TEST(NCollection_LocalArrayTest, ToArray1_SamePointer) diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.cxx index e7eee6bc04..3a4b1519d5 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.cxx @@ -22,12 +22,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include -#include + #include IMPLEMENT_STANDARD_RTTIEXT(BRepGraph_CacheDerivedState, BRepGraph_Cache) @@ -41,6 +44,15 @@ const Standard_GUID& theGUID() return aGUID; } +template +void ensureSize(NCollection_DynamicArray& theArray, uint32_t theIndex) +{ + if (static_cast(theIndex) >= theArray.Size()) + { + theArray.SetValue(static_cast(theIndex), T()); + } +} + template IdT remappedNode(const BRepGraph_CopyRemap& theCopy, const IdT theId) { @@ -48,12 +60,12 @@ IdT remappedNode(const BRepGraph_CopyRemap& theCopy, const IdT theId) { return IdT(); } - const BRepGraph_ItemId* aTarget = theCopy.TargetItem(BRepGraph_ItemId(theId)); - if (aTarget == nullptr || !aTarget->IsNode()) + const BRepGraph_ItemId aTarget = theCopy.TargetItem(BRepGraph_ItemId(theId)); + if (!aTarget.IsNode()) { return IdT(); } - return IdT::FromNodeId(aTarget->NodeId()); + return IdT::FromNodeId(aTarget.NodeId()); } //================================================================================================= @@ -130,90 +142,80 @@ bool coEdgeOrientedVertices(const BRepGraph& theGraph, //================================================================================================= -bool isEdgeSameRange(const BRepGraph& theGraph, - const BRepGraph_EdgeId theEdge, - const std::pair& theEdgeRange) +bool isCoEdgeSameRange(const BRepGraph& theGraph, + const BRepGraph_CoEdgeId theCoEdge, + const BRepGraph_EdgeId theEdge) { - const BRepGraphInc::EdgeRelations& anEdgeRel = theGraph.Topo().Edges().Relations(theEdge); - for (const BRepGraph_CoEdgeId& aCoEdgeId : anEdgeRel.CoEdgeIds) + if (!theCoEdge.IsValid(theGraph.Topo().CoEdges().Nb()) || theCoEdge.IsRemoved(theGraph)) { - if (!aCoEdgeId.IsValid(theGraph.Topo().CoEdges().Nb()) || aCoEdgeId.IsRemoved(theGraph)) - { - continue; - } - - const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(aCoEdgeId); - if (!aCoEdge.FaceId.IsValid(theGraph.Topo().Faces().Nb()) || aCoEdge.FaceId.IsRemoved(theGraph)) - { - continue; - } - - if (coEdgePCurve(theGraph, aCoEdgeId).IsNull()) - { - continue; - } - - const std::pair aPCurveRange = - BRepGraph_Tool::CoEdge::Range(theGraph, aCoEdgeId); - if (std::abs(aPCurveRange.first - theEdgeRange.first) > Precision::PConfusion() - || std::abs(aPCurveRange.second - theEdgeRange.second) > Precision::PConfusion()) - { - return false; - } + return true; } - return true; + + const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); + if (!aCoEdge.FaceId.IsValid(theGraph.Topo().Faces().Nb()) || aCoEdge.FaceId.IsRemoved(theGraph)) + { + return true; + } + + if (coEdgePCurve(theGraph, theCoEdge).IsNull()) + { + return true; + } + + const std::pair anEdgeRange = BRepGraph_Tool::Edge::Range(theGraph, theEdge); + const std::pair aPCurveRange = BRepGraph_Tool::CoEdge::Range(theGraph, theCoEdge); + return std::abs(aPCurveRange.first - anEdgeRange.first) <= Precision::PConfusion() + && std::abs(aPCurveRange.second - anEdgeRange.second) <= Precision::PConfusion(); } //================================================================================================= -bool isEdgeSameParameter(const BRepGraph& theGraph, - const BRepGraph_EdgeId theEdge, - const BRepGraphInc::EdgeDef& theEdgeDef, - const occ::handle& theCurve3D, - const std::pair& theEdgeRange) +bool isCoEdgeSameParameter(const BRepGraph& theGraph, + const BRepGraph_CoEdgeId theCoEdge, + const BRepGraphInc::EdgeDef& theEdgeDef, + const occ::handle& theCurve3D, + const std::pair& theEdgeRange) { + if (!theCoEdge.IsValid(theGraph.Topo().CoEdges().Nb()) || theCoEdge.IsRemoved(theGraph)) + { + return true; + } + + const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); + if (!aCoEdge.FaceId.IsValid(theGraph.Topo().Faces().Nb()) || aCoEdge.FaceId.IsRemoved(theGraph)) + { + return true; + } + + const occ::handle& aPCurve = coEdgePCurve(theGraph, theCoEdge); + if (aPCurve.IsNull()) + { + return true; + } + + const occ::handle aSurface = faceSurface(theGraph, aCoEdge.FaceId); + if (aSurface.IsNull()) + { + return true; + } + const double aTol = theEdgeDef.Tolerance + Precision::Confusion(); constexpr int THE_NB_SAMPLES = 5; - const BRepGraphInc::EdgeRelations& anEdgeRel = theGraph.Topo().Edges().Relations(theEdge); + GeomAdaptor_Curve aCurveAdaptor(theCurve3D, theEdgeRange.first, theEdgeRange.second); + Geom2dAdaptor_Curve aPCurveAdaptor(aPCurve); + GeomAdaptor_Surface aSurfAdaptor(aSurface); + for (int anIdx = 0; anIdx <= THE_NB_SAMPLES; ++anIdx) { const double aParam = theEdgeRange.first + (theEdgeRange.second - theEdgeRange.first) * anIdx / THE_NB_SAMPLES; - const gp_Pnt aPoint3D = theCurve3D->Value(aParam); - - for (const BRepGraph_CoEdgeId& aCoEdgeId : anEdgeRel.CoEdgeIds) + const gp_Pnt aPoint3D = aCurveAdaptor.EvalD0(aParam); + const gp_Pnt2d aUV = aPCurveAdaptor.EvalD0(aParam); + const gp_Pnt aSurfacePoint = aSurfAdaptor.EvalD0(aUV.X(), aUV.Y()); + if (aPoint3D.Distance(aSurfacePoint) > aTol) { - if (!aCoEdgeId.IsValid(theGraph.Topo().CoEdges().Nb()) || aCoEdgeId.IsRemoved(theGraph)) - { - continue; - } - - const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(aCoEdgeId); - if (!aCoEdge.FaceId.IsValid(theGraph.Topo().Faces().Nb()) - || aCoEdge.FaceId.IsRemoved(theGraph)) - { - continue; - } - - const occ::handle& aPCurve = coEdgePCurve(theGraph, aCoEdgeId); - if (aPCurve.IsNull()) - { - continue; - } - - const occ::handle aSurface = faceSurface(theGraph, aCoEdge.FaceId); - if (aSurface.IsNull()) - { - continue; - } - - const gp_Pnt2d aUV = aPCurve->Value(aParam); - const gp_Pnt aSurfacePoint = aSurface->Value(aUV.X(), aUV.Y()); - if (aPoint3D.Distance(aSurfacePoint) > aTol) - { - return false; - } + return false; } } return true; @@ -247,10 +249,23 @@ const TCollection_AsciiString& BRepGraph_CacheDerivedState::Name() const void BRepGraph_CacheDerivedState::Clear() noexcept { - std::unique_lock aLock(myMutex); - myEdgeEntries.Clear(); - myWireEntries.Clear(); - myShellEntries.Clear(); + std::lock_guard aLock(myMutex); + for (EdgeEntry& aEntry : myEdgeEntries) + { + aEntry.Reset(); + } + for (CoEdgeSameRangeEntry& aEntry : myCoEdgeSameRangeEntries) + { + aEntry.Reset(); + } + for (WireEntry& aEntry : myWireEntries) + { + aEntry.Reset(); + } + for (ShellEntry& aEntry : myShellEntries) + { + aEntry.Reset(); + } } //================================================================================================= @@ -260,132 +275,412 @@ void BRepGraph_CacheDerivedState::CopyFreshTo(const BRepGraph_CopyRemap& theCopy occ::handle aTargetCache = theCopy.TargetGraph().CacheRegistry().Ensure(); - std::shared_lock aSourceLock(myMutex); - std::unique_lock aTargetLock(aTargetCache->myMutex); + std::lock_guard aSourceLock(myMutex); + std::lock_guard aTargetLock(aTargetCache->myMutex); - for (NCollection_DataMap::Iterator anIt(myEdgeEntries); anIt.More(); - anIt.Next()) + for (const EdgeEntry& aSourceEntry : myEdgeEntries) { - const BRepGraph_EdgeId aSourceEdge = anIt.Key(); - const EdgeEntry& aSourceEntry = anIt.Value(); - if (!aSourceEntry.IsFreshOwn(*this, BRepGraph_NodeId(aSourceEdge))) + if (!aSourceEntry.IsFreshOwn(*this, aSourceEntry.Node())) { continue; } + const BRepGraph_EdgeId aSourceEdge = BRepGraph_EdgeId::FromNodeId(aSourceEntry.Node()); const BRepGraph_EdgeId aTargetEdge = remappedNode(theCopy, aSourceEdge); if (!aTargetEdge.IsValidIn(theCopy.TargetGraph().Topo().Edges())) { continue; } + ensureSize(aTargetCache->myEdgeEntries, aTargetEdge.Index); EdgeEntry aTargetEntry = aSourceEntry; if (aTargetEntry.BindOwnGen(*aTargetCache, BRepGraph_NodeId(aTargetEdge))) { - aTargetCache->myEdgeEntries.Bind(aTargetEdge, aTargetEntry); + aTargetCache->myEdgeEntries.ChangeValue(static_cast(aTargetEdge.Index)) = + aTargetEntry; } } - for (NCollection_DataMap::Iterator anIt(myWireEntries); anIt.More(); - anIt.Next()) + for (const CoEdgeSameRangeEntry& aSourceEntry : myCoEdgeSameRangeEntries) { - const BRepGraph_WireId aSourceWire = anIt.Key(); - const WireEntry& aSourceEntry = anIt.Value(); - if (!aSourceEntry.IsFreshOwn(*this, BRepGraph_NodeId(aSourceWire))) + if (!aSourceEntry.IsFreshOwn(*this, aSourceEntry.Node())) { continue; } + const BRepGraph_CoEdgeId aSourceCoEdge = BRepGraph_CoEdgeId::FromNodeId(aSourceEntry.Node()); + const BRepGraph_CoEdgeId aTargetCoEdge = remappedNode(theCopy, aSourceCoEdge); + if (!aTargetCoEdge.IsValidIn(theCopy.TargetGraph().Topo().CoEdges())) + { + continue; + } + ensureSize(aTargetCache->myCoEdgeSameRangeEntries, aTargetCoEdge.Index); + CoEdgeSameRangeEntry aTargetEntry = aSourceEntry; + if (aTargetEntry.BindOwnGen(*aTargetCache, BRepGraph_NodeId(aTargetCoEdge))) + { + aTargetCache->myCoEdgeSameRangeEntries.ChangeValue(static_cast(aTargetCoEdge.Index)) = + aTargetEntry; + } + } + + for (const WireEntry& aSourceEntry : myWireEntries) + { + if (!aSourceEntry.IsFreshOwn(*this, aSourceEntry.Node())) + { + continue; + } + const BRepGraph_WireId aSourceWire = BRepGraph_WireId::FromNodeId(aSourceEntry.Node()); const BRepGraph_WireId aTargetWire = remappedNode(theCopy, aSourceWire); if (!aTargetWire.IsValidIn(theCopy.TargetGraph().Topo().Wires())) { continue; } + ensureSize(aTargetCache->myWireEntries, aTargetWire.Index); WireEntry aTargetEntry = aSourceEntry; if (aTargetEntry.BindOwnGen(*aTargetCache, BRepGraph_NodeId(aTargetWire))) { - aTargetCache->myWireEntries.Bind(aTargetWire, aTargetEntry); + aTargetCache->myWireEntries.ChangeValue(static_cast(aTargetWire.Index)) = + aTargetEntry; } } - for (NCollection_DataMap::Iterator anIt(myShellEntries); - anIt.More(); - anIt.Next()) + for (const ShellEntry& aSourceEntry : myShellEntries) { - const BRepGraph_ShellId aSourceShell = anIt.Key(); - const ShellEntry& aSourceEntry = anIt.Value(); - if (!aSourceEntry.IsFreshOwn(*this, BRepGraph_NodeId(aSourceShell))) + if (!aSourceEntry.IsFreshOwn(*this, aSourceEntry.Node())) { continue; } + const BRepGraph_ShellId aSourceShell = BRepGraph_ShellId::FromNodeId(aSourceEntry.Node()); const BRepGraph_ShellId aTargetShell = remappedNode(theCopy, aSourceShell); if (!aTargetShell.IsValidIn(theCopy.TargetGraph().Topo().Shells())) { continue; } + ensureSize(aTargetCache->myShellEntries, aTargetShell.Index); ShellEntry aTargetEntry = aSourceEntry; if (aTargetEntry.BindOwnGen(*aTargetCache, BRepGraph_NodeId(aTargetShell))) { - aTargetCache->myShellEntries.Bind(aTargetShell, aTargetEntry); + aTargetCache->myShellEntries.ChangeValue(static_cast(aTargetShell.Index)) = + aTargetEntry; } } } //================================================================================================= -bool BRepGraph_CacheDerivedState::ComputeEdgeStatus(const BRepGraph& theGraph, +void BRepGraph_CacheDerivedState::computeStatusOnly(const BRepGraph& theGraph, BRepGraph_EdgeId theEdge, EdgeEntry& theEntry) { - theEntry.Status = EdgeGeometryStatus::Invalid; - theEntry.IsClosed = false; - theEntry.SameRange = false; - theEntry.SameParameter = false; + const BRepGraphInc::EdgeDef& aDef = theGraph.Topo().Edges().Definition(theEdge); + const BRepGraph_VertexId aStartV = resolveChildVertex(theGraph, aDef.StartVertexRefId); + const BRepGraph_VertexId aEndV = resolveChildVertex(theGraph, aDef.EndVertexRefId); + const bool aClosed = aStartV.IsValid() && aStartV == aEndV; + + const occ::handle& aCurve3D = edgeCurve3D(theGraph, theEdge); + EdgeEntry::GeomStatus aStatus; + if (!aCurve3D.IsNull()) + { + aStatus = EdgeEntry::GeomStatus::HasCurve3D; + } + else if (aClosed) + { + aStatus = EdgeEntry::GeomStatus::DegenerateOnSurface; + } + else if (aStartV.IsValid() && aEndV.IsValid()) + { + const BRepGraphInc::VertexDef& aStartDef = theGraph.Topo().Vertices().Definition(aStartV); + const BRepGraphInc::VertexDef& aEndDef = theGraph.Topo().Vertices().Definition(aEndV); + aStatus = aStartDef.Point.Distance(aEndDef.Point) <= aDef.Tolerance + ? EdgeEntry::GeomStatus::DegenerateOnSurface + : EdgeEntry::GeomStatus::MissingCurve3D; + } + else + { + aStatus = EdgeEntry::GeomStatus::MissingCurve3D; + } + + theEntry.Set(aStatus, aClosed); +} + +//================================================================================================= + +void BRepGraph_CacheDerivedState::computeSameRange(const BRepGraph& theGraph, + BRepGraph_CoEdgeId theCoEdge, + CoEdgeSameRangeEntry& theEntry) +{ + if (!theCoEdge.IsValid(theGraph.Topo().CoEdges().Nb()) || theCoEdge.IsRemoved(theGraph)) + { + theEntry.SetSameRange(true); + return; + } + + const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); + const BRepGraph_EdgeId anEdge = aCoEdge.ChildEdgeId; + + if (!anEdge.IsValid(theGraph.Topo().Edges().Nb()) || anEdge.IsRemoved(theGraph)) + { + theEntry.SetSameRange(true); + return; + } + + const occ::handle& aCurve3D = edgeCurve3D(theGraph, anEdge); + if (!aCurve3D.IsNull()) + { + theEntry.SetSameRange(isCoEdgeSameRange(theGraph, theCoEdge, anEdge)); + } + else + { + const BRepGraphInc::EdgeDef& aDef = theGraph.Topo().Edges().Definition(anEdge); + const BRepGraph_VertexId aStartV = resolveChildVertex(theGraph, aDef.StartVertexRefId); + const BRepGraph_VertexId aEndV = resolveChildVertex(theGraph, aDef.EndVertexRefId); + theEntry.SetSameRange(aStartV.IsValid() && aStartV == aEndV); + } +} + +//================================================================================================= + +void BRepGraph_CacheDerivedState::computeSameParameter(const BRepGraph& theGraph, + BRepGraph_CoEdgeId theCoEdge, + CoEdgeSameRangeEntry& theEntry) +{ + if ((theEntry.Computed() & CoEdgeSameRangeEntry::ComputedSameRange) == 0) + { + computeSameRange(theGraph, theCoEdge, theEntry); + } + + if (!theCoEdge.IsValid(theGraph.Topo().CoEdges().Nb()) || theCoEdge.IsRemoved(theGraph)) + { + theEntry.SetSameParameter(true); + return; + } + + const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); + const BRepGraph_EdgeId anEdge = aCoEdge.ChildEdgeId; + + if (!anEdge.IsValid(theGraph.Topo().Edges().Nb()) || anEdge.IsRemoved(theGraph)) + { + theEntry.SetSameParameter(true); + return; + } + + const BRepGraphInc::EdgeDef& aDef = theGraph.Topo().Edges().Definition(anEdge); + const occ::handle& aCurve3D = edgeCurve3D(theGraph, anEdge); + + if (!aCurve3D.IsNull()) + { + if (theEntry.SameRange()) + { + const std::pair aRange = BRepGraph_Tool::Edge::Range(theGraph, anEdge); + theEntry.SetSameParameter(isCoEdgeSameParameter(theGraph, theCoEdge, aDef, aCurve3D, aRange)); + } + else + { + theEntry.SetSameParameter(false); + } + } + else + { + const BRepGraph_VertexId aStartV = resolveChildVertex(theGraph, aDef.StartVertexRefId); + const BRepGraph_VertexId aEndV = resolveChildVertex(theGraph, aDef.EndVertexRefId); + theEntry.SetSameParameter(aStartV.IsValid() && aStartV == aEndV); + } +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::ensureEdgeEntry(BRepGraph_EdgeId theEdge, EdgeEntry& theEntry) +{ + // Lock-free read path: check packed flags without mutex. + if (static_cast(theEdge.Index) < myEdgeEntries.Size()) + { + const EdgeEntry& aCached = myEdgeEntries.Value(static_cast(theEdge.Index)); + if (aCached.IsFreshOwn(*this, theEdge) && aCached.IsComputed()) + { + theEntry = aCached; + return true; + } + } + + const BRepGraph& aGraph = Graph(); + if (!theEdge.IsValid(aGraph.Topo().Edges().Nb()) || theEdge.IsRemoved(aGraph)) + { + return false; + } + + EdgeEntry aEntry; + computeStatusOnly(aGraph, theEdge, aEntry); + + { + std::unique_lock aLock(myMutex); + ensureSize(myEdgeEntries, theEdge.Index); + EdgeEntry& aStored = myEdgeEntries.ChangeValue(static_cast(theEdge.Index)); + if (aStored.IsFreshOwn(*this, theEdge) && aStored.IsComputed()) + { + theEntry = aStored; + return true; + } + aStored = aEntry; + if (!aStored.BindOwnGen(*this, theEdge)) + { + aStored.Reset(); + return false; + } + theEntry = aStored; + } + + return true; +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::ensureCoEdgeSameRangeEntry(BRepGraph_CoEdgeId theCoEdge, + uint8_t theRequiredFlags, + CoEdgeSameRangeEntry& theEntry) +{ + // Lock-free read path: check packed flags without mutex. + if (static_cast(theCoEdge.Index) < myCoEdgeSameRangeEntries.Size()) + { + const CoEdgeSameRangeEntry& aCached = + myCoEdgeSameRangeEntries.Value(static_cast(theCoEdge.Index)); + if (aCached.IsFreshOwn(*this, theCoEdge)) + { + const uint8_t aComputed = aCached.Computed(); + if ((aComputed & theRequiredFlags) == theRequiredFlags) + { + theEntry = aCached; + return true; + } + } + } + + const BRepGraph& aGraph = Graph(); + if (!theCoEdge.IsValid(aGraph.Topo().CoEdges().Nb()) || theCoEdge.IsRemoved(aGraph)) + { + return false; + } + + CoEdgeSameRangeEntry aEntry; + if (static_cast(theCoEdge.Index) < myCoEdgeSameRangeEntries.Size()) + { + const CoEdgeSameRangeEntry& aCached = + myCoEdgeSameRangeEntries.Value(static_cast(theCoEdge.Index)); + if (aCached.IsFreshOwn(*this, theCoEdge)) + { + aEntry = aCached; + } + } + + if ((aEntry.Computed() & CoEdgeSameRangeEntry::ComputedSameRange) == 0 + && (theRequiredFlags & CoEdgeSameRangeEntry::ComputedSameRange)) + { + computeSameRange(aGraph, theCoEdge, aEntry); + } + if ((aEntry.Computed() & CoEdgeSameRangeEntry::ComputedSameParam) == 0 + && (theRequiredFlags & CoEdgeSameRangeEntry::ComputedSameParam)) + { + computeSameParameter(aGraph, theCoEdge, aEntry); + } + + { + std::unique_lock aLock(myMutex); + ensureSize(myCoEdgeSameRangeEntries, theCoEdge.Index); + CoEdgeSameRangeEntry& aStored = + myCoEdgeSameRangeEntries.ChangeValue(static_cast(theCoEdge.Index)); + if (aStored.IsFreshOwn(*this, theCoEdge)) + { + const uint8_t aMyPacked = aEntry.Packed.load(std::memory_order_relaxed); + const uint8_t aMyComputed = + aMyPacked + & (CoEdgeSameRangeEntry::ComputedSameRange | CoEdgeSameRangeEntry::ComputedSameParam); + const uint8_t aStoredPacked = aStored.Packed.load(std::memory_order_relaxed); + const uint8_t aNewBits = aMyComputed & ~aStoredPacked; + if (aNewBits != 0) + { + // Merge value bits (shifted by 2 from computed) and computed bits into a single store. + const uint8_t aMerged = (aStoredPacked & ~((aNewBits << 2) | aNewBits)) + | (aMyPacked & (aNewBits << 2)) | aNewBits; + aStored.Packed.store(aMerged, std::memory_order_release); + } + } + else + { + aStored = aEntry; + } + if (!aStored.BindOwnGen(*this, theCoEdge)) + { + aStored.Reset(); + return false; + } + theEntry = aStored; + } + + return true; +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::IsDegenerated(BRepGraph_EdgeId theEdge) +{ + EdgeEntry aEntry; + if (!ensureEdgeEntry(theEdge, aEntry)) + { + return false; + } + return aEntry.GetStatus() == EdgeEntry::GeomStatus::DegenerateOnSurface; +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::SameParameter(BRepGraph_CoEdgeId theCoEdge) +{ + CoEdgeSameRangeEntry aEntry; + if (!ensureCoEdgeSameRangeEntry(theCoEdge, CoEdgeSameRangeEntry::ComputedSameParam, aEntry)) + { + return false; + } + return aEntry.SameParameter(); +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::SameRange(BRepGraph_CoEdgeId theCoEdge) +{ + CoEdgeSameRangeEntry aEntry; + if (!ensureCoEdgeSameRangeEntry(theCoEdge, CoEdgeSameRangeEntry::ComputedSameRange, aEntry)) + { + return false; + } + return aEntry.SameRange(); +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::IsClosed(BRepGraph_EdgeId theEdge) +{ + EdgeEntry aEntry; + if (!ensureEdgeEntry(theEdge, aEntry)) + { + return false; + } + return aEntry.IsClosed(); +} + +//================================================================================================= + +bool BRepGraph_CacheDerivedState::ComputeEdgeProperties(const BRepGraph& theGraph, + BRepGraph_EdgeId theEdge, + bool& theIsDegenerated, + bool& theIsClosed) +{ if (!theEdge.IsValid(theGraph.Topo().Edges().Nb()) || theEdge.IsRemoved(theGraph)) { return false; } - const BRepGraphInc::EdgeDef& aDef = theGraph.Topo().Edges().Definition(theEdge); + EdgeEntry aStatusEntry; + computeStatusOnly(theGraph, theEdge, aStatusEntry); - const BRepGraph_VertexId aStartV = resolveChildVertex(theGraph, aDef.StartVertexRefId); - const BRepGraph_VertexId aEndV = resolveChildVertex(theGraph, aDef.EndVertexRefId); - theEntry.IsClosed = aStartV.IsValid() && aStartV == aEndV; - - const occ::handle& aCurve3D = edgeCurve3D(theGraph, theEdge); - const bool hasCurve3D = !aCurve3D.IsNull(); - theEntry.Status = - hasCurve3D ? EdgeGeometryStatus::HasCurve3D : EdgeGeometryStatus::MissingCurve3D; - - if (hasCurve3D) - { - const std::pair anEdgeRange = BRepGraph_Tool::Edge::Range(theGraph, theEdge); - theEntry.SameRange = isEdgeSameRange(theGraph, theEdge, anEdgeRange); - theEntry.SameParameter = - theEntry.SameRange && isEdgeSameParameter(theGraph, theEdge, aDef, aCurve3D, anEdgeRange); - return true; - } - - if (theEntry.IsClosed) - { - theEntry.Status = EdgeGeometryStatus::DegenerateOnSurface; - theEntry.SameRange = true; - theEntry.SameParameter = true; - return true; - } - - if (aStartV.IsValid() && aEndV.IsValid()) - { - const BRepGraphInc::VertexDef& aStartDef = theGraph.Topo().Vertices().Definition(aStartV); - const BRepGraphInc::VertexDef& aEndDef = theGraph.Topo().Vertices().Definition(aEndV); - - const double aDist = aStartDef.Point.Distance(aEndDef.Point); - if (aDist <= aDef.Tolerance) - { - theEntry.Status = EdgeGeometryStatus::DegenerateOnSurface; - theEntry.SameRange = true; - theEntry.SameParameter = true; - return true; - } - } + theIsDegenerated = aStatusEntry.GetStatus() == EdgeEntry::GeomStatus::DegenerateOnSurface; + theIsClosed = aStatusEntry.IsClosed(); return true; } @@ -433,22 +728,18 @@ bool BRepGraph_CacheDerivedState::ComputeWireIsClosed(const BRepGraph& theGraph, //================================================================================================= -bool BRepGraph_CacheDerivedState::ComputeShellStatus(const BRepGraph& theGraph, - BRepGraph_ShellId theShell, - ShellEntry& theEntry) +BRepGraph_CacheDerivedState::ShellEntry::ClosureStatus BRepGraph_CacheDerivedState:: + computeShellClosure(const BRepGraph& theGraph, BRepGraph_ShellId theShell) { - theEntry.Status = ShellClosureStatus::Invalid; - if (!theShell.IsValid(theGraph.Topo().Shells().Nb()) || theShell.IsRemoved(theGraph)) { - return false; + return ShellEntry::ClosureStatus::Invalid; } const BRepGraphInc::ShellRelations& aSR = theGraph.Topo().Shells().Relations(theShell); if (aSR.FaceRefIds.IsEmpty()) { - theEntry.Status = ShellClosureStatus::Empty; - return true; + return ShellEntry::ClosureStatus::Empty; } NCollection_FlatMap anActiveFaces; @@ -470,8 +761,7 @@ bool BRepGraph_CacheDerivedState::ComputeShellStatus(const BRepGraph& theGraph, if (anActiveFaces.IsEmpty()) { - theEntry.Status = ShellClosureStatus::Empty; - return true; + return ShellEntry::ClosureStatus::Empty; } NCollection_DataMap anEdgeUsage; @@ -515,9 +805,9 @@ bool BRepGraph_CacheDerivedState::ComputeShellStatus(const BRepGraph& theGraph, continue; } - EdgeEntry anEdgeEntry; - if (!ComputeEdgeStatus(theGraph, anEdgeId, anEdgeEntry) - || anEdgeEntry.Status == EdgeGeometryStatus::DegenerateOnSurface) + EdgeEntry aEdgeEntry; + computeStatusOnly(theGraph, anEdgeId, aEdgeEntry); + if (aEdgeEntry.GetStatus() == EdgeEntry::GeomStatus::DegenerateOnSurface) { continue; } @@ -537,8 +827,7 @@ bool BRepGraph_CacheDerivedState::ComputeShellStatus(const BRepGraph& theGraph, if (anEdgeUsage.IsEmpty()) { - theEntry.Status = ShellClosureStatus::Closed; - return true; + return ShellEntry::ClosureStatus::Closed; } bool hasOpen = false; @@ -560,151 +849,98 @@ bool BRepGraph_CacheDerivedState::ComputeShellStatus(const BRepGraph& theGraph, if (hasNonManifold) { - theEntry.Status = ShellClosureStatus::NonManifold; + return ShellEntry::ClosureStatus::NonManifold; } - else if (hasOpen) + if (hasOpen) { - theEntry.Status = ShellClosureStatus::Open; + return ShellEntry::ClosureStatus::Open; } - else - { - theEntry.Status = ShellClosureStatus::Closed; - } - - return true; -} - -//================================================================================================= - -bool BRepGraph_CacheDerivedState::GetEdgeStatus(BRepGraph_EdgeId theEdge, EdgeEntry& theEntry) -{ - EdgeEntry aComputed; - if (!ComputeEdgeStatus(Graph(), theEdge, aComputed)) - { - return false; - } - - std::unique_lock aLock(myMutex); - EdgeEntry* aStored = myEdgeEntries.ChangeSeek(theEdge); - if (aStored != nullptr) - { - *aStored = aComputed; - } - else - { - myEdgeEntries.Bind(theEdge, aComputed); - aStored = myEdgeEntries.ChangeSeek(theEdge); - } - if (!aStored->BindOwnGen(*this, theEdge)) - { - myEdgeEntries.UnBind(theEdge); - return false; - } - theEntry = *aStored; - return true; + return ShellEntry::ClosureStatus::Closed; } //================================================================================================= bool BRepGraph_CacheDerivedState::GetWireIsClosed(BRepGraph_WireId theWire, bool& theClosed) { + // Lock-free read path: check packed flags without mutex. + if (static_cast(theWire.Index) < myWireEntries.Size()) + { + const WireEntry& aCached = myWireEntries.Value(static_cast(theWire.Index)); + if (aCached.IsComputed() && aCached.IsFreshOwn(*this, theWire)) + { + theClosed = aCached.IsClosed(); + return true; + } + } + const bool aClosed = ComputeWireIsClosed(Graph(), theWire); - std::unique_lock aLock(myMutex); - WireEntry* aStored = myWireEntries.ChangeSeek(theWire); - if (aStored == nullptr) + std::lock_guard aLock(myMutex); + ensureSize(myWireEntries, theWire.Index); + WireEntry& aStored = myWireEntries.ChangeValue(static_cast(theWire.Index)); + if (!aStored.BindOwnGen(*this, theWire)) { - myWireEntries.Bind(theWire, WireEntry()); - aStored = myWireEntries.ChangeSeek(theWire); - } - aStored->IsClosed = aClosed; - if (!aStored->BindOwnGen(*this, theWire)) - { - myWireEntries.UnBind(theWire); + aStored.Reset(); return false; } + aStored.SetClosed(aClosed); theClosed = aClosed; return true; } //================================================================================================= -bool BRepGraph_CacheDerivedState::GetShellStatus(BRepGraph_ShellId theShell, ShellEntry& theEntry) +bool BRepGraph_CacheDerivedState::IsShellClosed(BRepGraph_ShellId theShell) { - ShellEntry aComputed; - if (!ComputeShellStatus(Graph(), theShell, aComputed)) + // Lock-free read path: check atomic Status without mutex. + if (static_cast(theShell.Index) < myShellEntries.Size()) { - return false; + const ShellEntry& aCached = myShellEntries.Value(static_cast(theShell.Index)); + const auto aStatus = aCached.Status.load(std::memory_order_acquire); + if (aStatus != ShellEntry::ClosureStatus::Invalid && aCached.IsFreshOwn(*this, theShell)) + { + return aStatus == ShellEntry::ClosureStatus::Closed; + } } - std::unique_lock aLock(myMutex); - ShellEntry* aStored = myShellEntries.ChangeSeek(theShell); - if (aStored != nullptr) + const ShellEntry::ClosureStatus aStatus = computeShellClosure(Graph(), theShell); + + std::lock_guard aLock(myMutex); + ensureSize(myShellEntries, theShell.Index); + ShellEntry& aStored = myShellEntries.ChangeValue(static_cast(theShell.Index)); + if (aStored.Status.load(std::memory_order_acquire) != ShellEntry::ClosureStatus::Invalid + && aStored.IsFreshOwn(*this, theShell)) { - *aStored = aComputed; + return aStored.Status.load(std::memory_order_acquire) == ShellEntry::ClosureStatus::Closed; } - else + if (!aStored.BindOwnGen(*this, theShell)) { - myShellEntries.Bind(theShell, aComputed); - aStored = myShellEntries.ChangeSeek(theShell); - } - if (!aStored->BindOwnGen(*this, theShell)) - { - myShellEntries.UnBind(theShell); + aStored.Reset(); return false; } - theEntry = *aStored; - return true; + aStored.Status.store(aStatus, std::memory_order_release); + return aStatus == ShellEntry::ClosureStatus::Closed; } //================================================================================================= -void BRepGraph_CacheDerivedState::SetEdgeStatus(BRepGraph_EdgeId theEdge, const EdgeEntry& theEntry) +bool BRepGraph_CacheDerivedState::ComputeShellIsClosed(const BRepGraph& theGraph, + BRepGraph_ShellId theShell) { - std::unique_lock aLock(myMutex); - EdgeEntry* aStored = myEdgeEntries.ChangeSeek(theEdge); - if (aStored != nullptr) - { - *aStored = theEntry; - } - else - { - myEdgeEntries.Bind(theEdge, theEntry); - aStored = myEdgeEntries.ChangeSeek(theEdge); - } - [[maybe_unused]] const bool isBound = aStored->BindOwnGen(*this, theEdge); + return computeShellClosure(theGraph, theShell) == ShellEntry::ClosureStatus::Closed; } //================================================================================================= void BRepGraph_CacheDerivedState::SetWireIsClosed(BRepGraph_WireId theWire, bool theClosed) { - std::unique_lock aLock(myMutex); - WireEntry* aStored = myWireEntries.ChangeSeek(theWire); - if (aStored == nullptr) + std::lock_guard aLock(myMutex); + ensureSize(myWireEntries, theWire.Index); + WireEntry& aStored = myWireEntries.ChangeValue(static_cast(theWire.Index)); + if (!aStored.BindOwnGen(*this, theWire)) { - myWireEntries.Bind(theWire, WireEntry()); - aStored = myWireEntries.ChangeSeek(theWire); + aStored.Reset(); + return; } - aStored->IsClosed = theClosed; - [[maybe_unused]] const bool isBound = aStored->BindOwnGen(*this, theWire); -} - -//================================================================================================= - -void BRepGraph_CacheDerivedState::SetShellStatus(BRepGraph_ShellId theShell, - const ShellEntry& theEntry) -{ - std::unique_lock aLock(myMutex); - ShellEntry* aStored = myShellEntries.ChangeSeek(theShell); - if (aStored != nullptr) - { - *aStored = theEntry; - } - else - { - myShellEntries.Bind(theShell, theEntry); - aStored = myShellEntries.ChangeSeek(theShell); - } - [[maybe_unused]] const bool isBound = aStored->BindOwnGen(*this, theShell); + aStored.SetClosed(theClosed); } diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.hxx index 98c4938a4a..10af419d70 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheDerivedState.hxx @@ -16,73 +16,23 @@ #include #include -#include +#include #include #include -#include +#include +#include class BRepGraphInc_Storage; //! @brief Cache for derived edge, wire, and shell properties. //! -//! Stores degeneracy, closure, SameRange, and SameParameter results derived from -//! current BRepGraph topology and geometry. Cache getters compute on read, -//! refresh the stored entries, and expose only fresh values to callers. +//! Each query is independent and caches only its own result. +//! Callers request specific values (IsDegenerated, SameParameter, etc.) +//! and the cache computes + stores only what is needed. class BRepGraph_CacheDerivedState : public BRepGraph_Cache { public: - //! @brief Geometry status of an edge. - //! - enum class EdgeGeometryStatus - { - HasCurve3D, //!< Edge has a valid 3D curve - DegenerateOnSurface, //!< Edge collapses to a point on a face surface - MissingCurve3D, //!< Edge has no 3D curve and no valid degenerate evidence - Invalid //!< Edge id is invalid or removed - }; - - //! @brief Shell closure status. - //! - enum class ShellClosureStatus - { - Empty, //!< Shell has no active faces - Open, //!< At least one non-degenerate boundary edge has exactly one use - Closed, //!< All non-degenerate boundary edges have exactly two uses - NonManifold, //!< At least one non-degenerate boundary edge has more than two uses - Invalid //!< Shell id is invalid or removed - }; - - //! @brief Cached derived-state entry for an edge. - //! - //! Inherits generation-based freshness tracking from NodeEntry and adds - //! edge-specific derived properties. - struct EdgeEntry : public NodeEntry - { - EdgeGeometryStatus Status = EdgeGeometryStatus::Invalid; //!< Edge geometry status - bool IsClosed = false; //!< True if start vertex == end vertex - bool SameRange = false; //!< True if all PCurve ranges equal 3D curve range - bool SameParameter = false; //!< True if PCurves evaluate to the 3D curve on surfaces - }; - - //! @brief Cached derived-state entry for a wire. - //! - //! Inherits generation-based freshness tracking from NodeEntry and adds - //! wire-specific derived properties. - struct WireEntry : public NodeEntry - { - bool IsClosed = false; //!< True if the wire forms a topological loop - }; - - //! @brief Cached derived-state entry for a shell. - //! - //! Inherits generation-based freshness tracking from NodeEntry and adds - //! shell-specific derived properties. - struct ShellEntry : public NodeEntry - { - ShellClosureStatus Status = ShellClosureStatus::Invalid; //!< Shell closure status - }; - //! Returns the unique cache service GUID. [[nodiscard]] Standard_EXPORT static const Standard_GUID& GetID(); @@ -98,11 +48,27 @@ public: //! Copy fresh, remappable derived-state entries into the target graph. Standard_EXPORT void CopyFreshTo(const BRepGraph_CopyRemap& theCopy) const override; - //! @brief Return edge status, computing and storing a fresh entry. - //! @param[in] theEdge edge definition identifier - //! @param[out] theEntry filled with a fresh derived entry - //! @return true if computation succeeded - [[nodiscard]] Standard_EXPORT bool GetEdgeStatus(BRepGraph_EdgeId theEdge, EdgeEntry& theEntry); + //! @brief Test if an edge is degenerate (no 3D curve and vertex collapse). + //! Computes and caches only Status - does NOT compute SameParameter/SameRange. + //! @param[in] theEdge edge definition identifier + //! @return true if the edge is degenerate + [[nodiscard]] Standard_EXPORT bool IsDegenerated(BRepGraph_EdgeId theEdge); + + //! @brief Test if a single coedge has SameParameter. + //! @param[in] theCoEdge coedge definition identifier + //! @return true if the coedge has SameParameter + [[nodiscard]] Standard_EXPORT bool SameParameter(BRepGraph_CoEdgeId theCoEdge); + + //! @brief Test if a single coedge has SameRange. + //! @param[in] theCoEdge coedge definition identifier + //! @return true if the coedge has SameRange + [[nodiscard]] Standard_EXPORT bool SameRange(BRepGraph_CoEdgeId theCoEdge); + + //! @brief Test if an edge is closed (start vertex == end vertex). + //! Computes and caches only IsClosed. + //! @param[in] theEdge edge definition identifier + //! @return true if the edge is closed + [[nodiscard]] Standard_EXPORT bool IsClosed(BRepGraph_EdgeId theEdge); //! @brief Return wire closure, computing and storing a fresh entry. //! @param[in] theWire wire definition identifier @@ -110,37 +76,34 @@ public: //! @return true if computation succeeded [[nodiscard]] Standard_EXPORT bool GetWireIsClosed(BRepGraph_WireId theWire, bool& theClosed); - //! @brief Return shell status, computing and storing a fresh entry. - //! @param[in] theShell shell definition identifier - //! @param[out] theEntry filled with a fresh derived entry - //! @return true if computation succeeded - [[nodiscard]] Standard_EXPORT bool GetShellStatus(BRepGraph_ShellId theShell, - ShellEntry& theEntry); - - //! @brief Store a pre-computed edge entry (warm-start from import or after computation). - //! @param[in] theEdge edge definition identifier - //! @param[in] theEntry pre-computed entry to store - Standard_EXPORT void SetEdgeStatus(BRepGraph_EdgeId theEdge, const EdgeEntry& theEntry); - //! @brief Store a pre-computed wire closure value. //! @param[in] theWire wire definition identifier //! @param[in] theClosed pre-computed closure value Standard_EXPORT void SetWireIsClosed(BRepGraph_WireId theWire, bool theClosed); - //! @brief Store a pre-computed shell entry (warm-start from import or after computation). + //! @brief Test if a shell is closed. //! @param[in] theShell shell definition identifier - //! @param[in] theEntry pre-computed entry to store - Standard_EXPORT void SetShellStatus(BRepGraph_ShellId theShell, const ShellEntry& theEntry); + //! @return true if the shell is closed + [[nodiscard]] Standard_EXPORT bool IsShellClosed(BRepGraph_ShellId theShell); - //! Compute edge derived state directly from a BRepGraph without caching. - //! Used by callers like Reconstruct that need one-shot computation. + //! Compute edge-own derived state (Status, IsClosed). + //! SameRange/SameParameter are per-CoEdge - use the per-CoEdge cache directly. //! @param[in] theGraph source graph //! @param[in] theEdge edge definition identifier - //! @param[out] theEntry filled with computed entry + //! @param[out] theIsDegenerated true if edge is degenerate + //! @param[out] theIsClosed true if edge is closed //! @return true if computation succeeded - [[nodiscard]] Standard_EXPORT static bool ComputeEdgeStatus(const BRepGraph& theGraph, - BRepGraph_EdgeId theEdge, - EdgeEntry& theEntry); + [[nodiscard]] Standard_EXPORT static bool ComputeEdgeProperties(const BRepGraph& theGraph, + BRepGraph_EdgeId theEdge, + bool& theIsDegenerated, + bool& theIsClosed); + + //! Compute shell closure directly from a BRepGraph without caching. + //! @param[in] theGraph source graph + //! @param[in] theShell shell definition identifier + //! @return true if the shell is closed + [[nodiscard]] Standard_EXPORT static bool ComputeShellIsClosed(const BRepGraph& theGraph, + BRepGraph_ShellId theShell); //! Compute wire closure directly from a BRepGraph without caching. //! @param[in] theGraph source graph @@ -149,23 +112,242 @@ public: [[nodiscard]] Standard_EXPORT static bool ComputeWireIsClosed(const BRepGraph& theGraph, BRepGraph_WireId theWire); - //! Compute shell closure status directly from a BRepGraph without caching. - //! @param[in] theGraph source graph - //! @param[in] theShell shell definition identifier - //! @param[out] theEntry filled with computed entry - //! @return true if computation succeeded - [[nodiscard]] Standard_EXPORT static bool ComputeShellStatus(const BRepGraph& theGraph, - BRepGraph_ShellId theShell, - ShellEntry& theEntry); - DEFINE_STANDARD_RTTIEXT(BRepGraph_CacheDerivedState, BRepGraph_Cache) private: - mutable std::shared_mutex myMutex; + //! Edge-own derived state: Status (HasCurve3D/Degenerate/Missing), IsClosed. + //! Depends only on Edge OwnGen (vertices, 3D curve). + //! Packed into a single atomic byte for lock-free reads. + struct EdgeEntry : public NodeEntry + { + enum class GeomStatus : uint8_t + { + HasCurve3D, + DegenerateOnSurface, + MissingCurve3D, + Invalid + }; - NCollection_DataMap myEdgeEntries; - NCollection_DataMap myWireEntries; - NCollection_DataMap myShellEntries; + enum Flags : uint8_t + { + FlagNone = 0, + StatusMask = 0x07, + FlagClosed = 1 << 3, + FlagComputed = 1 << 4, + }; + + std::atomic Packed{FlagNone}; + + EdgeEntry() = default; + + EdgeEntry(const EdgeEntry& theOther) + : NodeEntry(theOther), + Packed(theOther.Packed.load(std::memory_order_relaxed)) + { + } + + EdgeEntry& operator=(const EdgeEntry& theOther) + { + NodeEntry::operator=(theOther); + Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + + [[nodiscard]] GeomStatus GetStatus() const + { + return static_cast(Packed.load(std::memory_order_acquire) & StatusMask); + } + + [[nodiscard]] bool IsClosed() const + { + return (Packed.load(std::memory_order_acquire) & FlagClosed) != 0; + } + + [[nodiscard]] bool IsComputed() const + { + return (Packed.load(std::memory_order_acquire) & FlagComputed) != 0; + } + + void Set(GeomStatus theStatus, bool theClosed) + { + uint8_t aFlags = FlagComputed | static_cast(theStatus); + if (theClosed) + { + aFlags |= FlagClosed; + } + Packed.store(aFlags, std::memory_order_release); + } + }; + + //! Per-CoEdge entry for SameRange/SameParameter. + //! Bound to CoEdge OwnGen - invalidates automatically when PCurve changes. + //! Packed into a single atomic byte for lock-free reads. + struct CoEdgeSameRangeEntry : public NodeEntry + { + enum Flags : uint8_t + { + FlagNone = 0, + ComputedSameRange = 1 << 0, + ComputedSameParam = 1 << 1, + FlagSameRange = 1 << 2, + FlagSameParameter = 1 << 3, + }; + + std::atomic Packed{FlagNone}; + + CoEdgeSameRangeEntry() = default; + + CoEdgeSameRangeEntry(const CoEdgeSameRangeEntry& theOther) + : NodeEntry(theOther), + Packed(theOther.Packed.load(std::memory_order_relaxed)) + { + } + + CoEdgeSameRangeEntry& operator=(const CoEdgeSameRangeEntry& theOther) + { + NodeEntry::operator=(theOther); + Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + + [[nodiscard]] bool SameRange() const + { + return (Packed.load(std::memory_order_acquire) & FlagSameRange) != 0; + } + + [[nodiscard]] bool SameParameter() const + { + return (Packed.load(std::memory_order_acquire) & FlagSameParameter) != 0; + } + + [[nodiscard]] uint8_t Computed() const { return Packed.load(std::memory_order_acquire); } + + void SetSameRange(bool theVal) + { + uint8_t aFlags = ComputedSameRange; + if (theVal) + { + aFlags |= FlagSameRange; + } + Packed.fetch_or(aFlags, std::memory_order_release); + } + + void SetSameParameter(bool theVal) + { + uint8_t aFlags = ComputedSameParam; + if (theVal) + { + aFlags |= FlagSameParameter; + } + Packed.fetch_or(aFlags, std::memory_order_release); + } + }; + + struct WireEntry : public NodeEntry + { + enum Flags : uint8_t + { + FlagNone = 0, + FlagClosed = 1 << 0, + FlagComputed = 1 << 1, + }; + + std::atomic Packed{FlagNone}; + + WireEntry() = default; + + WireEntry(const WireEntry& theOther) + : NodeEntry(theOther), + Packed(theOther.Packed.load(std::memory_order_relaxed)) + { + } + + WireEntry& operator=(const WireEntry& theOther) + { + NodeEntry::operator=(theOther); + Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + + [[nodiscard]] bool IsClosed() const + { + return (Packed.load(std::memory_order_acquire) & FlagClosed) != 0; + } + + [[nodiscard]] bool IsComputed() const + { + return (Packed.load(std::memory_order_acquire) & FlagComputed) != 0; + } + + void SetClosed(bool theVal) + { + uint8_t aFlags = FlagComputed; + if (theVal) + { + aFlags |= FlagClosed; + } + Packed.store(aFlags, std::memory_order_release); + } + }; + + struct ShellEntry : public NodeEntry + { + enum class ClosureStatus : uint8_t + { + Empty, + Open, + Closed, + NonManifold, + Invalid + }; + + std::atomic Status{ClosureStatus::Invalid}; + + ShellEntry() = default; + + ShellEntry(const ShellEntry& theOther) + : NodeEntry(theOther), + Status(theOther.Status.load(std::memory_order_relaxed)) + { + } + + ShellEntry& operator=(const ShellEntry& theOther) + { + NodeEntry::operator=(theOther); + Status.store(theOther.Status.load(std::memory_order_relaxed), std::memory_order_relaxed); + return *this; + } + }; + + //! Ensure edge-own entry (Status, IsClosed) is fresh. Uses OwnGen only. + bool ensureEdgeEntry(BRepGraph_EdgeId theEdge, EdgeEntry& theEntry); + + //! Ensure per-CoEdge entry is fresh. Bound to CoEdge OwnGen. + bool ensureCoEdgeSameRangeEntry(BRepGraph_CoEdgeId theCoEdge, + uint8_t theRequiredFlags, + CoEdgeSameRangeEntry& theEntry); + + static void computeStatusOnly(const BRepGraph& theGraph, + BRepGraph_EdgeId theEdge, + EdgeEntry& theEntry); + + static void computeSameRange(const BRepGraph& theGraph, + BRepGraph_CoEdgeId theCoEdge, + CoEdgeSameRangeEntry& theEntry); + + static void computeSameParameter(const BRepGraph& theGraph, + BRepGraph_CoEdgeId theCoEdge, + CoEdgeSameRangeEntry& theEntry); + + static ShellEntry::ClosureStatus computeShellClosure(const BRepGraph& theGraph, + BRepGraph_ShellId theShell); + + mutable std::mutex myMutex; + + NCollection_DynamicArray myEdgeEntries; + NCollection_DynamicArray myCoEdgeSameRangeEntries; + NCollection_DynamicArray myWireEntries; + NCollection_DynamicArray myShellEntries; }; #endif // _BRepGraph_CacheDerivedState_HeaderFile diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheMesh.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheMesh.cxx index d507909912..b4b1af3450 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheMesh.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheMesh.cxx @@ -51,12 +51,12 @@ IdT remappedNode(const BRepGraph_CopyRemap& theCopy, const IdT theId) { return IdT(); } - const BRepGraph_ItemId* aTarget = theCopy.TargetItem(BRepGraph_ItemId(theId)); - if (aTarget == nullptr || !aTarget->IsNode()) + const BRepGraph_ItemId aTarget = theCopy.TargetItem(BRepGraph_ItemId(theId)); + if (!aTarget.IsNode()) { return IdT(); } - return IdT::FromNodeId(aTarget->NodeId()); + return IdT::FromNodeId(aTarget.NodeId()); } void appendPolygonsOnTri( diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.cxx index 5577b0733a..9b9965cbe6 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.cxx @@ -126,6 +126,36 @@ occ::handle BRepGraph_CacheRegistry::FindCache(const Standard_G //================================================================================================= +occ::handle BRepGraph_CacheRegistry::ensureCache( + const Standard_GUID& theGUID, + const std::function()>& theFactory) +{ + // Fast path: shared lock for read-only lookup. + { + std::shared_lock aLock(myMutex); + occ::handle aCache = findCacheLocked(theGUID); + if (!aCache.IsNull()) + { + return aCache; + } + } + + // Slow path: exclusive lock for creation. + { + std::unique_lock aLock(myMutex); + // Re-check after acquiring exclusive lock (another thread may have created it). + occ::handle aCache = findCacheLocked(theGUID); + if (aCache.IsNull()) + { + aCache = theFactory(); + registerCacheLocked(aCache); + } + return aCache; + } +} + +//================================================================================================= + bool BRepGraph_CacheRegistry::FindSlot(const Standard_GUID& theGUID, uint32_t& theSlot) const { std::shared_lock aLock(myMutex); @@ -228,6 +258,34 @@ void BRepGraph_CacheRegistry::CopyFreshCachesTo( //================================================================================================= +void BRepGraph_CacheRegistry::CopyFreshCachesTo(BRepGraph& theTargetGraph, + BRepGraph_CopyRemap::MappingKind theMappingKind, + BRepGraph_CopyRemap::Mode theMode) const +{ + BRepGraph* aSourceGraph = nullptr; + { + std::shared_lock aLock(myMutex); + aSourceGraph = myGraph; + } + if (aSourceGraph == nullptr) + { + return; + } + + const BRepGraph_CopyRemap aCopy(*aSourceGraph, theTargetGraph, theMappingKind, theMode); + for (uint32_t aSlot = 0;; ++aSlot) + { + occ::handle aCache = cacheAt(aSlot); + if (aCache.IsNull()) + { + return; + } + aCache->CopyFreshTo(aCopy); + } +} + +//================================================================================================= + occ::handle BRepGraph_CacheRegistry::findCacheLocked( const Standard_GUID& theGUID) const { diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.hxx index 8862455928..cae43aed83 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CacheRegistry.hxx @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -83,17 +84,12 @@ public: } //! Return an existing cache service or create and register a default one. + //! Template convenience wrapper: extracts GUID and calls ensureCache. template [[nodiscard]] occ::handle Ensure() { - std::unique_lock aLock(myMutex); - occ::handle aCache = occ::down_cast(findCacheLocked(T::GetID())); - if (aCache.IsNull()) - { - aCache = new T(); - registerCacheLocked(aCache); - } - return aCache; + return occ::down_cast( + ensureCache(T::GetID(), []() -> occ::handle { return new T(); })); } //! Return current graph-local slot for a GUID. @@ -133,6 +129,11 @@ public: const NCollection_FlatDataMap& theItemRemap, const BRepGraph_CopyRemap::Mode theMode) const; + //! Ask registered cache services to copy fresh data using identity mapping. + Standard_EXPORT void CopyFreshCachesTo(BRepGraph& theTargetGraph, + BRepGraph_CopyRemap::MappingKind theMappingKind, + BRepGraph_CopyRemap::Mode theMode) const; + //! Unregister all cache services. Standard_EXPORT void Clear() noexcept; @@ -149,6 +150,13 @@ private: [[nodiscard]] Standard_EXPORT occ::handle findCacheLocked( const Standard_GUID& theGUID) const; + //! Return an existing cache service or create and register a default one. + //! Uses double-checked locking: shared lock for fast path (cache exists), + //! exclusive lock only for creation (rare, first-call only). + [[nodiscard]] Standard_EXPORT occ::handle ensureCache( + const Standard_GUID& theGUID, + const std::function()>& theFactory); + [[nodiscard]] Standard_EXPORT occ::handle cacheAt(uint32_t theSlot) const; Standard_EXPORT uint32_t registerCacheLocked(const occ::handle& theCache); diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Copy.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Copy.cxx index ef6080618a..5ac8564457 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Copy.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Copy.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -299,146 +300,6 @@ size_t itemCapacityUpperBound(const BRepGraphInc_Storage& theStorage) //================================================================================================= -template -void bindIdentityRange(const uint32_t theSourceCount, - const uint32_t theTargetCount, - NCollection_FlatDataMap& theItemRemap) -{ - const uint32_t aCount = std::min(theSourceCount, theTargetCount); - for (uint32_t anIndex = 0; anIndex < aCount; ++anIndex) - { - const IdT anId(anIndex); - if (anId.IsValid()) - { - bindItemRemap(theItemRemap, anId, anId); - } - } -} - -//================================================================================================= - -void bindIdentityItems(const BRepGraphInc_Storage& theSource, - const BRepGraphInc_Storage& theTarget, - NCollection_FlatDataMap& theItemRemap) -{ - theItemRemap.Reserve(itemCapacityUpperBound(theSource)); - bindIdentityRange(theSource.NbVertices(), - theTarget.NbVertices(), - theItemRemap); - bindIdentityRange(theSource.NbEdges(), theTarget.NbEdges(), theItemRemap); - bindIdentityRange(theSource.NbCoEdges(), theTarget.NbCoEdges(), theItemRemap); - bindIdentityRange(theSource.NbWires(), theTarget.NbWires(), theItemRemap); - bindIdentityRange(theSource.NbFaces(), theTarget.NbFaces(), theItemRemap); - bindIdentityRange(theSource.NbShells(), theTarget.NbShells(), theItemRemap); - bindIdentityRange(theSource.NbSolids(), theTarget.NbSolids(), theItemRemap); - bindIdentityRange(theSource.NbCompounds(), - theTarget.NbCompounds(), - theItemRemap); - bindIdentityRange(theSource.NbCompSolids(), - theTarget.NbCompSolids(), - theItemRemap); - bindIdentityRange(theSource.NbProducts(), - theTarget.NbProducts(), - theItemRemap); - bindIdentityRange(theSource.NbOccurrences(), - theTarget.NbOccurrences(), - theItemRemap); - bindIdentityRange(theSource.NbShellRefs(), - theTarget.NbShellRefs(), - theItemRemap); - bindIdentityRange(theSource.NbFaceRefs(), - theTarget.NbFaceRefs(), - theItemRemap); - bindIdentityRange(theSource.NbWireRefs(), - theTarget.NbWireRefs(), - theItemRemap); - bindIdentityRange(theSource.NbVertexRefs(), - theTarget.NbVertexRefs(), - theItemRemap); - bindIdentityRange(theSource.NbSolidRefs(), - theTarget.NbSolidRefs(), - theItemRemap); - bindIdentityRange(theSource.NbChildRefs(), - theTarget.NbChildRefs(), - theItemRemap); - bindIdentityRange(theSource.NbOccurrenceRefs(), - theTarget.NbOccurrenceRefs(), - theItemRemap); -} - -//================================================================================================= - -void copyCurve2DReps(const BRepGraphInc_Storage& theSource, - BRepGraphInc_Storage& theTarget, - GeomPolicy theGeomPolicy) -{ - for (BRepGraph_CoEdgeCurve2DRepId aRepId(0); aRepId.IsValid(theSource.NbCoEdgeCurves2D()); - ++aRepId) - { - const BRepGraph_CoEdgeCurve2DRepId aNewRepId = theTarget.AppendCoEdgeCurve2DRep(); - Standard_ASSERT_RAISE(aNewRepId == aRepId, "BRepGraph_Copy: unexpected curve2d rep id"); - BRepGraphInc::CoEdgeCurve2DRep& aNewUse = theTarget.ChangeCoEdgeCurve2DRep(aNewRepId); - aNewUse = theSource.CoEdgeCurve2DRep(aRepId); - aNewUse.Curve = copyPCurve(aNewUse.Curve, theGeomPolicy); - theTarget.SetRemoved(aNewRepId, theSource.IsRemoved(aRepId)); - } -} - -//================================================================================================= - -void copyPersistentMeshReps(const BRepGraphInc_Storage& theSource, - BRepGraphInc_Storage& theTarget, - MeshPolicy theMeshPolicy) -{ - for (BRepGraph_FaceTriangulationRepId aRepId(0); aRepId.IsValid(theSource.NbFaceTriangulations()); - ++aRepId) - { - const BRepGraph_FaceTriangulationRepId aNewRepId = theTarget.AppendFaceTriangulationRep(); - Standard_ASSERT_RAISE(aNewRepId == aRepId, "BRepGraph_Copy: unexpected triangulation rep id"); - BRepGraphInc::FaceTriangulationRep& aNewRep = theTarget.ChangeFaceTriangulationRep(aNewRepId); - aNewRep = theSource.FaceTriangulationRep(aRepId); - aNewRep.Triangulation = copyMeshHandle(aNewRep.Triangulation, theMeshPolicy); - theTarget.SetRemoved(aNewRepId, theSource.IsRemoved(aRepId)); - } - - for (BRepGraph_EdgePolygon3DRepId aRepId(0); aRepId.IsValid(theSource.NbEdgePolygons3D()); - ++aRepId) - { - const BRepGraph_EdgePolygon3DRepId aNewRepId = theTarget.AppendEdgePolygon3DRep(); - Standard_ASSERT_RAISE(aNewRepId == aRepId, "BRepGraph_Copy: unexpected polygon3d rep id"); - BRepGraphInc::EdgePolygon3DRep& aNewRep = theTarget.ChangeEdgePolygon3DRep(aNewRepId); - aNewRep = theSource.EdgePolygon3DRep(aRepId); - aNewRep.Polygon = copyMeshHandle(aNewRep.Polygon, theMeshPolicy); - theTarget.SetRemoved(aNewRepId, theSource.IsRemoved(aRepId)); - } - - for (BRepGraph_CoEdgePolygon2DRepId aRepId(0); aRepId.IsValid(theSource.NbCoEdgePolygons2D()); - ++aRepId) - { - const BRepGraph_CoEdgePolygon2DRepId aNewRepId = theTarget.AppendCoEdgePolygon2DRep(); - Standard_ASSERT_RAISE(aNewRepId == aRepId, "BRepGraph_Copy: unexpected polygon2d rep id"); - BRepGraphInc::CoEdgePolygon2DRep& aNewRep = theTarget.ChangeCoEdgePolygon2DRep(aNewRepId); - aNewRep = theSource.CoEdgePolygon2DRep(aRepId); - aNewRep.Polygon = copyMeshHandle(aNewRep.Polygon, theMeshPolicy); - theTarget.SetRemoved(aNewRepId, theSource.IsRemoved(aRepId)); - } - - for (BRepGraph_CoEdgePolygonOnTriRepId aRepId(0); - aRepId.IsValid(theSource.NbCoEdgePolygonsOnTri()); - ++aRepId) - { - const BRepGraph_CoEdgePolygonOnTriRepId aNewRepId = theTarget.AppendCoEdgePolygonOnTriRep(); - Standard_ASSERT_RAISE(aNewRepId == aRepId, - "BRepGraph_Copy: unexpected polygon-on-triangulation rep id"); - BRepGraphInc::CoEdgePolygonOnTriRep& aNewRep = theTarget.ChangeCoEdgePolygonOnTriRep(aNewRepId); - aNewRep = theSource.CoEdgePolygonOnTriRep(aRepId); - aNewRep.Polygon = copyMeshHandle(aNewRep.Polygon, theMeshPolicy); - theTarget.SetRemoved(aNewRepId, theSource.IsRemoved(aRepId)); - } -} - -//================================================================================================= - void ensureTriangulationRep(GraphCopyContext& theCtx, const BRepGraph_FaceTriangulationRepId theSrcRepId, const BRepGraph_FaceId theDstFaceId) @@ -1065,6 +926,356 @@ BRepGraph_ProductId ensureProduct(GraphCopyContext& theCtx, BRepGraph_ProductId return aNewId; } +//================================================================================================= + +//! Build counts for identity copy, adjusting representation counts for drop policies. +static BRepGraphInc_Load::Counts countsForIdentityCopy(const BRepGraphInc_Storage& theSrc, + GeomPolicy theGeomPol, + MeshPolicy theMeshPol) +{ + BRepGraphInc_Load::Counts aCounts = theSrc.Counts(); + if (theGeomPol == GeomPolicy::Drop) + { + aCounts.NbFaceSurfaceReps = 0; + aCounts.NbEdgeCurve3DReps = 0; + aCounts.NbCoEdgeCurve2DReps = 0; + } + if (theMeshPol == MeshPolicy::Drop) + { + aCounts.NbFaceTriangulationReps = 0; + aCounts.NbEdgePolygon3DReps = 0; + aCounts.NbCoEdgePolygon2DReps = 0; + aCounts.NbCoEdgePolygonOnTriReps = 0; + } + return aCounts; +} + +//================================================================================================= + +//! Copy all topology definitions slot-for-slot from source to destination. +static void copyTopologyDefinitionsIdentity(const BRepGraphInc_Storage& theSrc, + BRepGraphInc_Storage& theDst, + GeomPolicy theGeomPol, + MeshPolicy theMeshPol) +{ + // Copy definition structs. + for (BRepGraph_VertexId anId(0); anId.IsValid(theSrc.NbVertices()); ++anId) + { + theDst.ChangeVertex(anId) = theSrc.Vertex(anId); + } + for (BRepGraph_EdgeId anId(0); anId.IsValid(theSrc.NbEdges()); ++anId) + { + theDst.ChangeEdge(anId) = theSrc.Edge(anId); + } + for (BRepGraph_CoEdgeId anId(0); anId.IsValid(theSrc.NbCoEdges()); ++anId) + { + theDst.ChangeCoEdge(anId) = theSrc.CoEdge(anId); + } + for (BRepGraph_WireId anId(0); anId.IsValid(theSrc.NbWires()); ++anId) + { + theDst.ChangeWire(anId) = theSrc.Wire(anId); + } + for (BRepGraph_FaceId anId(0); anId.IsValid(theSrc.NbFaces()); ++anId) + { + BRepGraphInc::FaceDef& aDstFace = theDst.ChangeFace(anId); + aDstFace = theSrc.Face(anId); + // Clear surface rep id if geometry is dropped. + if (theGeomPol == GeomPolicy::Drop) + { + aDstFace.SurfaceRepId = BRepGraph_FaceSurfaceRepId(); + } + if (theMeshPol == MeshPolicy::Drop) + { + aDstFace.TriangulationRepId = BRepGraph_FaceTriangulationRepId(); + } + } + for (BRepGraph_ShellId anId(0); anId.IsValid(theSrc.NbShells()); ++anId) + { + theDst.ChangeShell(anId) = theSrc.Shell(anId); + } + for (BRepGraph_SolidId anId(0); anId.IsValid(theSrc.NbSolids()); ++anId) + { + theDst.ChangeSolid(anId) = theSrc.Solid(anId); + } + for (BRepGraph_CompoundId anId(0); anId.IsValid(theSrc.NbCompounds()); ++anId) + { + theDst.ChangeCompound(anId) = theSrc.Compound(anId); + } + for (BRepGraph_CompSolidId anId(0); anId.IsValid(theSrc.NbCompSolids()); ++anId) + { + theDst.ChangeCompSolid(anId) = theSrc.CompSolid(anId); + } + for (BRepGraph_ProductId anId(0); anId.IsValid(theSrc.NbProducts()); ++anId) + { + theDst.ChangeProduct(anId) = theSrc.Product(anId); + } + for (BRepGraph_OccurrenceId anId(0); anId.IsValid(theSrc.NbOccurrences()); ++anId) + { + theDst.ChangeOccurrence(anId) = theSrc.Occurrence(anId); + } + + // Copy coedge rep ids with policy filtering. + if (theGeomPol == GeomPolicy::Drop || theMeshPol == MeshPolicy::Drop) + { + for (BRepGraph_CoEdgeId anId(0); anId.IsValid(theSrc.NbCoEdges()); ++anId) + { + BRepGraphInc::CoEdgeDef& aCoEdge = theDst.ChangeCoEdge(anId); + if (theGeomPol == GeomPolicy::Drop) + { + aCoEdge.Curve2DRepId = BRepGraph_CoEdgeCurve2DRepId(); + } + if (theMeshPol == MeshPolicy::Drop) + { + aCoEdge.Polygon2DRepId = BRepGraph_CoEdgePolygon2DRepId(); + aCoEdge.PolygonOnTriRepId = BRepGraph_CoEdgePolygonOnTriRepId(); + } + } + for (BRepGraph_EdgeId anId(0); anId.IsValid(theSrc.NbEdges()); ++anId) + { + if (theGeomPol == GeomPolicy::Drop) + { + theDst.ChangeEdge(anId).Curve3DRepId = BRepGraph_EdgeCurve3DRepId(); + } + if (theMeshPol == MeshPolicy::Drop) + { + theDst.ChangeEdge(anId).Polygon3DRepId = BRepGraph_EdgePolygon3DRepId(); + } + } + } +} + +//================================================================================================= + +//! Copy all reference stores slot-for-slot from source to destination. +static void copyReferencesIdentity(const BRepGraphInc_Storage& theSrc, BRepGraphInc_Storage& theDst) +{ + for (BRepGraph_ShellRefId anId(0); anId.IsValid(theSrc.NbShellRefs()); ++anId) + { + theDst.ChangeShellRef(anId) = theSrc.ShellRef(anId); + } + for (BRepGraph_FaceRefId anId(0); anId.IsValid(theSrc.NbFaceRefs()); ++anId) + { + theDst.ChangeFaceRef(anId) = theSrc.FaceRef(anId); + } + for (BRepGraph_WireRefId anId(0); anId.IsValid(theSrc.NbWireRefs()); ++anId) + { + theDst.ChangeWireRef(anId) = theSrc.WireRef(anId); + } + for (BRepGraph_VertexRefId anId(0); anId.IsValid(theSrc.NbVertexRefs()); ++anId) + { + theDst.ChangeVertexRef(anId) = theSrc.VertexRef(anId); + } + for (BRepGraph_SolidRefId anId(0); anId.IsValid(theSrc.NbSolidRefs()); ++anId) + { + theDst.ChangeSolidRef(anId) = theSrc.SolidRef(anId); + } + for (BRepGraph_ChildRefId anId(0); anId.IsValid(theSrc.NbChildRefs()); ++anId) + { + theDst.ChangeChildRef(anId) = theSrc.ChildRef(anId); + } + for (BRepGraph_OccurrenceRefId anId(0); anId.IsValid(theSrc.NbOccurrenceRefs()); ++anId) + { + theDst.ChangeOccurrenceRef(anId) = theSrc.OccurrenceRef(anId); + } +} + +//================================================================================================= + +//! Copy persistent representation stores with geometry/mesh policy. +static void copyRepresentationsIdentity(const BRepGraphInc_Storage& theSrc, + BRepGraphInc_Storage& theDst, + GeomPolicy theGeomPol, + MeshPolicy theMeshPol) +{ + if (theGeomPol != GeomPolicy::Drop) + { + // Face surfaces. + for (BRepGraph_FaceSurfaceRepId anId(0); anId.IsValid(theSrc.NbFaceSurfaces()); ++anId) + { + BRepGraphInc::FaceSurfaceRep& aDst = theDst.ChangeFaceSurfaceRep(anId); + aDst = theSrc.FaceSurfaceRep(anId); + if (theGeomPol == GeomPolicy::Copy && !aDst.Surface.IsNull()) + { + aDst.Surface = occ::down_cast(aDst.Surface->Copy()); + } + } + + // Edge 3D curves. + for (BRepGraph_EdgeCurve3DRepId anId(0); anId.IsValid(theSrc.NbEdgeCurves3D()); ++anId) + { + BRepGraphInc::EdgeCurve3DRep& aDst = theDst.ChangeEdgeCurve3DRep(anId); + aDst = theSrc.EdgeCurve3DRep(anId); + if (theGeomPol == GeomPolicy::Copy && !aDst.Curve.IsNull()) + { + aDst.Curve = occ::down_cast(aDst.Curve->Copy()); + } + } + + // Coedge 2D curves. + for (BRepGraph_CoEdgeCurve2DRepId anId(0); anId.IsValid(theSrc.NbCoEdgeCurves2D()); ++anId) + { + BRepGraphInc::CoEdgeCurve2DRep& aDst = theDst.ChangeCoEdgeCurve2DRep(anId); + aDst = theSrc.CoEdgeCurve2DRep(anId); + if (theGeomPol == GeomPolicy::Copy && !aDst.Curve.IsNull()) + { + aDst.Curve = occ::down_cast(aDst.Curve->Copy()); + } + } + } + + if (theMeshPol != MeshPolicy::Drop) + { + // Face triangulations. + for (BRepGraph_FaceTriangulationRepId anId(0); anId.IsValid(theSrc.NbFaceTriangulations()); + ++anId) + { + BRepGraphInc::FaceTriangulationRep& aDst = theDst.ChangeFaceTriangulationRep(anId); + aDst = theSrc.FaceTriangulationRep(anId); + if (theMeshPol == MeshPolicy::Copy && !aDst.Triangulation.IsNull()) + { + aDst.Triangulation = aDst.Triangulation->Copy(); + } + } + + // Edge 3D polygons. + for (BRepGraph_EdgePolygon3DRepId anId(0); anId.IsValid(theSrc.NbEdgePolygons3D()); ++anId) + { + BRepGraphInc::EdgePolygon3DRep& aDst = theDst.ChangeEdgePolygon3DRep(anId); + aDst = theSrc.EdgePolygon3DRep(anId); + if (theMeshPol == MeshPolicy::Copy && !aDst.Polygon.IsNull()) + { + aDst.Polygon = aDst.Polygon->Copy(); + } + } + + // Coedge 2D polygons. + for (BRepGraph_CoEdgePolygon2DRepId anId(0); anId.IsValid(theSrc.NbCoEdgePolygons2D()); ++anId) + { + BRepGraphInc::CoEdgePolygon2DRep& aDst = theDst.ChangeCoEdgePolygon2DRep(anId); + aDst = theSrc.CoEdgePolygon2DRep(anId); + if (theMeshPol == MeshPolicy::Copy && !aDst.Polygon.IsNull()) + { + aDst.Polygon = aDst.Polygon->Copy(); + } + } + + // Coedge polygon-on-triangulation. + for (BRepGraph_CoEdgePolygonOnTriRepId anId(0); anId.IsValid(theSrc.NbCoEdgePolygonsOnTri()); + ++anId) + { + BRepGraphInc::CoEdgePolygonOnTriRep& aDst = theDst.ChangeCoEdgePolygonOnTriRep(anId); + aDst = theSrc.CoEdgePolygonOnTriRep(anId); + if (theMeshPol == MeshPolicy::Copy && !aDst.Polygon.IsNull()) + { + aDst.Polygon = aDst.Polygon->Copy(); + } + } + } +} + +//================================================================================================= + +//! Copy root product ids from source to destination. +static void copyRootProductsIdentity(const BRepGraphInc_Storage& theSrc, + BRepGraphInc_Storage& theDst) +{ + theDst.ChangeRootProductIds().Clear(); + for (const BRepGraph_ProductId& aRootId : theSrc.RootProductIds()) + { + theDst.ChangeRootProductIds().Append(aRootId); + } +} + +//================================================================================================= + +//! Copy UID counters, generation, and graph GUID from source to destination. +static void copyUIDAndGraphStateIdentity(const BRepGraphInc_Storage& theSrc, + BRepGraphInc_Storage& theDst) +{ + constexpr BRepGraph_NodeId::Kind aNodeKinds[] = {BRepGraph_NodeId::Kind::Vertex, + BRepGraph_NodeId::Kind::Edge, + BRepGraph_NodeId::Kind::CoEdge, + BRepGraph_NodeId::Kind::Wire, + BRepGraph_NodeId::Kind::Face, + BRepGraph_NodeId::Kind::Shell, + BRepGraph_NodeId::Kind::Solid, + BRepGraph_NodeId::Kind::Compound, + BRepGraph_NodeId::Kind::CompSolid, + BRepGraph_NodeId::Kind::Product, + BRepGraph_NodeId::Kind::Occurrence}; + for (const auto aKind : aNodeKinds) + { + theDst.SetNextNodeUIDCounter(aKind, theSrc.NextNodeUIDCounter(aKind)); + } + + constexpr BRepGraph_RefId::Kind aRefKinds[] = {BRepGraph_RefId::Kind::Shell, + BRepGraph_RefId::Kind::Face, + BRepGraph_RefId::Kind::Wire, + BRepGraph_RefId::Kind::Vertex, + BRepGraph_RefId::Kind::Solid, + BRepGraph_RefId::Kind::Child, + BRepGraph_RefId::Kind::Occurrence}; + for (const auto aKind : aRefKinds) + { + theDst.SetNextRefUIDCounter(aKind, theSrc.NextRefUIDCounter(aKind)); + } + + theDst.SetGeneration(theSrc.Generation()); + theDst.SetGraphGUID(theSrc.GraphGUID()); +} + +//================================================================================================= + +//! Copy removed flags and active counts from source to destination. +static void copyFlagsAndActiveCountsIdentity(const BRepGraphInc_Storage& theSrc, + BRepGraphInc_Storage& theDst) +{ + // Bulk-copy all removed flags in a single pass per kind (vs per-slot loops). + theDst.CopyRemovedFlagsFrom(theSrc); + + // Recount active counts now that removed flags are correct. + theDst.RecountActiveCounts(); +} + +//================================================================================================= + +//! Fast identity copy: source and target ids match. +//! Used for Perform(source, emptyTarget, ...) to avoid editor API overhead. +static bool copyFullGraphIdentity(const BRepGraphInc_Storage& aSrc, + BRepGraphInc_Storage& aDst, + const BRepGraph& theSourceGraph, + BRepGraph& theTargetGraph, + GeomPolicy theGeomPolicy, + MeshPolicy theMeshPolicy, + BRepGraph_Copy::CachePolicy theCachePolicy) +{ + const BRepGraphInc_Load::Counts aCounts = + countsForIdentityCopy(aSrc, theGeomPolicy, theMeshPolicy); + aDst.PrepareForLoad(aCounts); + + copyTopologyDefinitionsIdentity(aSrc, aDst, theGeomPolicy, theMeshPolicy); + copyReferencesIdentity(aSrc, aDst); + copyRepresentationsIdentity(aSrc, aDst, theGeomPolicy, theMeshPolicy); + copyRootProductsIdentity(aSrc, aDst); + copyUIDAndGraphStateIdentity(aSrc, aDst); + copyFlagsAndActiveCountsIdentity(aSrc, aDst); + + aDst.CopyDerivedRelationsFrom(aSrc); + aDst.MarkUIDReverseIndexesDirty(); + aDst.CopyShapeBindingsFrom(aSrc); + + theSourceGraph.LayerRegistry().CopyLayersTo(theTargetGraph, + BRepGraph_CopyRemap::MappingKind::Identity, + BRepGraph_CopyRemap::Mode::Copy); + if (theCachePolicy == BRepGraph_Copy::CachePolicy::CopyFresh) + { + theSourceGraph.CacheRegistry().CopyFreshCachesTo(theTargetGraph, + BRepGraph_CopyRemap::MappingKind::Identity, + BRepGraph_CopyRemap::Mode::Copy); + } + return true; +} + } // namespace //================================================================================================= @@ -1180,382 +1391,14 @@ bool BRepGraph_Copy::Perform(const BRepGraph& theSourceGraph, return true; } - // Empty target: identity-mapped fast path (old index == new index). - - const bool doCopyMesh = theMeshPolicy != MeshPolicy::Drop; - const BRepGraph::RefsView& aRefs = theSourceGraph.Refs(); - - // Bottom-up graph rebuild via EditorView. - // Since this is a full copy into an empty target, old index == new index (identity mapping). - copyCurve2DReps(theSourceGraph.incStorage(), theTargetGraph.incStorage(), theGeomPolicy); - if (doCopyMesh) - { - copyPersistentMeshReps(theSourceGraph.incStorage(), theTargetGraph.incStorage(), theMeshPolicy); - } - - // Vertices. - for (BRepGraph_FullVertexIterator aVertexIt(theSourceGraph); aVertexIt.More(); aVertexIt.Next()) - { - const BRepGraph_VertexId aVertexId = aVertexIt.CurrentId(); - const BRepGraphInc::VertexDef& aVtx = theSourceGraph.Topo().Vertices().Definition(aVertexId); - const BRepGraph_VertexId aNewVertexId = - theTargetGraph.Editor().Vertices().Add(aVtx.Point, aVtx.Tolerance); - Standard_ASSERT_RAISE(aNewVertexId == aVertexId, "BRepGraph_Copy: unexpected vertex id"); - theTargetGraph.incStorage().SetRemoved(aNewVertexId, - theSourceGraph.incStorage().IsRemoved(aVertexId)); - } - - // Edges. - for (BRepGraph_FullEdgeIterator anEdgeIt(theSourceGraph); anEdgeIt.More(); anEdgeIt.Next()) - { - const BRepGraph_EdgeId anEdgeId = anEdgeIt.CurrentId(); - const BRepGraphInc::EdgeDef& anEdge = theSourceGraph.Topo().Edges().Definition(anEdgeId); - - const occ::handle& anEdgeSrcCurve = - BRepGraph_Tool::Edge::Curve(theSourceGraph, anEdgeId); - occ::handle aCurve = copyCurve(anEdgeSrcCurve, theGeomPolicy); - - const BRepGraph_VertexRefId aStartRefId = - BRepGraph_Tool::Edge::StartVertexId(theSourceGraph, anEdgeId); - const BRepGraph_VertexRefId anEndRefId = - BRepGraph_Tool::Edge::EndVertexId(theSourceGraph, anEdgeId); - const BRepGraph_VertexId aStartVtxId = - aStartRefId.IsValid() ? theSourceGraph.Refs().Vertices().Entry(aStartRefId).ChildVertexId - : BRepGraph_VertexId(); - const BRepGraph_VertexId anEndVtxId = - anEndRefId.IsValid() ? theSourceGraph.Refs().Vertices().Entry(anEndRefId).ChildVertexId - : BRepGraph_VertexId(); - - const auto [aEdgePF, aEdgePL] = BRepGraph_Tool::Edge::Range(theSourceGraph, anEdgeId); - - const BRepGraph_EdgeId aNewEdgeId = theTargetGraph.Editor().Edges().Add(aStartVtxId, - anEndVtxId, - aCurve, - aEdgePF, - aEdgePL, - anEdge.Tolerance); - Standard_ASSERT_RAISE(aNewEdgeId == anEdgeId, "BRepGraph_Copy: unexpected edge id"); - theTargetGraph.incStorage().SetRemoved(aNewEdgeId, - theSourceGraph.incStorage().IsRemoved(anEdgeId)); - const BRepGraphInc::EdgeDef& aNewEdge = theTargetGraph.incStorage().Edge(aNewEdgeId); - setRemovedLike(theSourceGraph.incStorage(), - theTargetGraph.incStorage(), - anEdge.StartVertexRefId, - aNewEdge.StartVertexRefId); - setRemovedLike(theSourceGraph.incStorage(), - theTargetGraph.incStorage(), - anEdge.EndVertexRefId, - aNewEdge.EndVertexRefId); - theTargetGraph.incStorage().ChangeEdge(anEdgeId).Polygon3DRepId = anEdge.Polygon3DRepId; - } - - // Wires. - for (BRepGraph_FullWireIterator aWireIt(theSourceGraph); aWireIt.More(); aWireIt.Next()) - { - const BRepGraph_WireId aWireId = aWireIt.CurrentId(); - NCollection_LinearVector aCoEdgeIds; - for (BRepGraph_CoEdgesOfWire aCEIt(theSourceGraph, aWireId); aCEIt.More(); aCEIt.Next()) - { - const BRepGraphInc::CoEdgeDef& aCoEdge = - theSourceGraph.Topo().CoEdges().Definition(aCEIt.CurrentId()); - aCoEdgeIds.Append( - theTargetGraph.Editor().CoEdges().Add(aCoEdge.ChildEdgeId, aCoEdge.Orientation)); - } - const BRepGraph_WireId aNewWireId = theTargetGraph.Editor().Wires().Add(aCoEdgeIds.ToArray1()); - Standard_ASSERT_RAISE(aNewWireId == aWireId, "BRepGraph_Copy: unexpected wire id"); - theTargetGraph.incStorage().SetRemoved(aNewWireId, - theSourceGraph.incStorage().IsRemoved(aWireId)); - } - - // Faces. - for (BRepGraph_FullFaceIterator aFaceIt(theSourceGraph); aFaceIt.More(); aFaceIt.Next()) - { - const BRepGraph_FaceId aFaceId = aFaceIt.CurrentId(); - const BRepGraphInc::FaceDef& aFace = theSourceGraph.Topo().Faces().Definition(aFaceId); - - const occ::handle& aFaceSrcSurf = - BRepGraph_Tool::Face::Surface(theSourceGraph, aFaceId); - occ::handle aSurf = copySurface(aFaceSrcSurf, theGeomPolicy); - - BRepGraph_WireId aFirstWire; - NCollection_LinearVector aNextWires; - - for (BRepGraph_RefsWireOfFace aWRIt(theSourceGraph, aFaceId); aWRIt.More(); aWRIt.Next()) - { - const BRepGraphInc::WireRef& aWR = aRefs.Wires().Entry(aWRIt.CurrentId()); - if (!aFirstWire.IsValid()) - { - aFirstWire = aWR.ChildWireId; - } - else - { - aNextWires.Append(aWR.ChildWireId); - } - } - - const BRepGraph_FaceId aNewFaceId = theTargetGraph.Editor().Faces().Add(aSurf, - aFirstWire, - aNextWires.ToArray1(), - aFace.Tolerance); - Standard_ASSERT_RAISE(aNewFaceId == aFaceId, "BRepGraph_Copy: unexpected face id"); - theTargetGraph.incStorage().SetRemoved(aNewFaceId, - theSourceGraph.incStorage().IsRemoved(aFaceId)); - const BRepGraphInc::FaceRelations& aSrcRel = theSourceGraph.incStorage().FaceRelations(aFaceId); - const BRepGraphInc::FaceRelations& aDstRel = - theTargetGraph.incStorage().FaceRelations(aNewFaceId); - const size_t aNbWireRefs = std::min(aSrcRel.WireRefIds.Size(), aDstRel.WireRefIds.Size()); - for (size_t anIdx = 0; anIdx < aNbWireRefs; ++anIdx) - { - theTargetGraph.incStorage().SetRemoved( - aDstRel.WireRefIds.Value(anIdx), - theSourceGraph.incStorage().IsRemoved(aSrcRel.WireRefIds.Value(anIdx))); - } - theTargetGraph.incStorage().ChangeFace(aFaceId).TriangulationRepId = aFace.TriangulationRepId; - } - - Standard_ASSERT_RAISE(theTargetGraph.incStorage().NbCoEdges() - <= theSourceGraph.incStorage().NbCoEdges(), - "BRepGraph_Copy: unexpected coedge count after wire copy"); - while (theTargetGraph.incStorage().NbCoEdges() < theSourceGraph.incStorage().NbCoEdges()) - { - const BRepGraph_CoEdgeId aNewId = theTargetGraph.incStorage().AppendCoEdge(); - Standard_ASSERT_RAISE(aNewId.Index + 1u == theTargetGraph.incStorage().NbCoEdges(), - "BRepGraph_Copy: unexpected coedge append id"); - } - for (BRepGraph_CoEdgeId aCoEdgeId(0); aCoEdgeId.IsValid(theSourceGraph.incStorage().NbCoEdges()); - ++aCoEdgeId) - { - theTargetGraph.incStorage().ChangeCoEdge(aCoEdgeId) = - theSourceGraph.incStorage().CoEdge(aCoEdgeId); - theTargetGraph.incStorage().SetRemoved(aCoEdgeId, - theSourceGraph.incStorage().IsRemoved(aCoEdgeId)); - } - - // Shells. - for (BRepGraph_FullShellIterator aShellIt(theSourceGraph); aShellIt.More(); aShellIt.Next()) - { - const BRepGraph_ShellId aShellId = aShellIt.CurrentId(); - BRepGraph_ShellId aNewShellId = theTargetGraph.Editor().Shells().Add(); - Standard_ASSERT_RAISE(aNewShellId == aShellId, "BRepGraph_Copy: unexpected shell id"); - theTargetGraph.incStorage().SetRemoved(aNewShellId, - theSourceGraph.incStorage().IsRemoved(aShellId)); - - for (BRepGraph_RefsFaceOfShell aFRIt(theSourceGraph, aShellId); aFRIt.More(); aFRIt.Next()) - { - const BRepGraphInc::FaceRef& aFR = aRefs.Faces().Entry(aFRIt.CurrentId()); - const BRepGraph_FaceRefId aNewRef = - theTargetGraph.Editor().Shells().Append(aNewShellId, aFR.ChildFaceId, aFR.Orientation); - theTargetGraph.incStorage().SetRemoved( - aNewRef, - theSourceGraph.incStorage().IsRemoved(aFRIt.CurrentId())); - } - } - - // Solids. - for (BRepGraph_FullSolidIterator aSolidIt(theSourceGraph); aSolidIt.More(); aSolidIt.Next()) - { - const BRepGraph_SolidId aSolidId = aSolidIt.CurrentId(); - BRepGraph_SolidId aNewSolidId = theTargetGraph.Editor().Solids().Add(); - Standard_ASSERT_RAISE(aNewSolidId == aSolidId, "BRepGraph_Copy: unexpected solid id"); - theTargetGraph.incStorage().SetRemoved(aNewSolidId, - theSourceGraph.incStorage().IsRemoved(aSolidId)); - - for (BRepGraph_RefsShellOfSolid aSRIt(theSourceGraph, aSolidId); aSRIt.More(); aSRIt.Next()) - { - const BRepGraphInc::ShellRef& aSR = aRefs.Shells().Entry(aSRIt.CurrentId()); - const BRepGraph_ShellRefId aNewRef = - theTargetGraph.Editor().Solids().Append(aNewSolidId, aSR.ChildShellId, aSR.Orientation); - theTargetGraph.incStorage().SetRemoved( - aNewRef, - theSourceGraph.incStorage().IsRemoved(aSRIt.CurrentId())); - } - } - - // Compounds. - for (BRepGraph_FullCompoundIterator aCompoundIt(theSourceGraph); aCompoundIt.More(); - aCompoundIt.Next()) - { - const BRepGraph_CompoundId aCompoundId = aCompoundIt.CurrentId(); - NCollection_LinearVector aChildNodeIds; - for (BRepGraph_RefsChildOfCompound aCRIt(theSourceGraph, aCompoundId); aCRIt.More(); - aCRIt.Next()) - { - aChildNodeIds.Append(aRefs.Children().Entry(aCRIt.CurrentId()).ChildNodeId); - } - const BRepGraph_CompoundId aNewCompoundId = - theTargetGraph.Editor().Compounds().Add(aChildNodeIds.ToArray1()); - Standard_ASSERT_RAISE(aNewCompoundId == aCompoundId, "BRepGraph_Copy: unexpected compound id"); - theTargetGraph.incStorage().SetRemoved(aNewCompoundId, - theSourceGraph.incStorage().IsRemoved(aCompoundId)); - const BRepGraphInc::CompoundRelations& aSrcRel = - theSourceGraph.incStorage().CompoundRelations(aCompoundId); - const BRepGraphInc::CompoundRelations& aDstRel = - theTargetGraph.incStorage().CompoundRelations(aNewCompoundId); - const size_t aNbChildRefs = std::min(aSrcRel.ChildRefIds.Size(), aDstRel.ChildRefIds.Size()); - for (size_t anIdx = 0; anIdx < aNbChildRefs; ++anIdx) - { - theTargetGraph.incStorage().SetRemoved( - aDstRel.ChildRefIds.Value(anIdx), - theSourceGraph.incStorage().IsRemoved(aSrcRel.ChildRefIds.Value(anIdx))); - } - } - - // CompSolids. - for (BRepGraph_FullCompSolidIterator aCompSolidIt(theSourceGraph); aCompSolidIt.More(); - aCompSolidIt.Next()) - { - const BRepGraph_CompSolidId aCompSolidId = aCompSolidIt.CurrentId(); - NCollection_LinearVector aSolidNodeIds; - for (BRepGraph_RefsSolidOfCompSolid aSRIt(theSourceGraph, aCompSolidId); aSRIt.More(); - aSRIt.Next()) - { - aSolidNodeIds.Append(aRefs.Solids().Entry(aSRIt.CurrentId()).ChildSolidId); - } - const BRepGraph_CompSolidId aNewCompSolidId = - theTargetGraph.Editor().CompSolids().Add(aSolidNodeIds.ToArray1()); - Standard_ASSERT_RAISE(aNewCompSolidId == aCompSolidId, - "BRepGraph_Copy: unexpected compsolid id"); - theTargetGraph.incStorage().SetRemoved(aNewCompSolidId, - theSourceGraph.incStorage().IsRemoved(aCompSolidId)); - const BRepGraphInc::CompSolidRelations& aSrcRel = - theSourceGraph.incStorage().CompSolidRelations(aCompSolidId); - const BRepGraphInc::CompSolidRelations& aDstRel = - theTargetGraph.incStorage().CompSolidRelations(aNewCompSolidId); - const size_t aNbSolidRefs = std::min(aSrcRel.SolidRefIds.Size(), aDstRel.SolidRefIds.Size()); - for (size_t anIdx = 0; anIdx < aNbSolidRefs; ++anIdx) - { - theTargetGraph.incStorage().SetRemoved( - aDstRel.SolidRefIds.Value(anIdx), - theSourceGraph.incStorage().IsRemoved(aSrcRel.SolidRefIds.Value(anIdx))); - } - } - - // Products. - for (BRepGraph_FullProductIterator aProductIt(theSourceGraph); aProductIt.More(); - aProductIt.Next()) - { - const BRepGraph_ProductId aProductId = aProductIt.CurrentId(); - const BRepGraph_ProductId aNewId = theTargetGraph.incStorage().AppendProduct(); - Standard_ASSERT_RAISE(aNewId == aProductId, "BRepGraph_Copy: unexpected product id"); - theTargetGraph.incStorage().SetRemoved(aNewId, - theSourceGraph.incStorage().IsRemoved(aProductId)); - } - - // Occurrences. - for (BRepGraph_FullOccurrenceIterator anOccurrenceIt(theSourceGraph); anOccurrenceIt.More(); - anOccurrenceIt.Next()) - { - const BRepGraph_OccurrenceId anOccurrenceId = anOccurrenceIt.CurrentId(); - const BRepGraphInc::OccurrenceDef& aSrcOcc = - theSourceGraph.incStorage().Occurrence(anOccurrenceId); - const BRepGraph_OccurrenceId aNewId = theTargetGraph.incStorage().AppendOccurrence(); - Standard_ASSERT_RAISE(aNewId == anOccurrenceId, "BRepGraph_Copy: unexpected occurrence id"); - theTargetGraph.incStorage().ChangeOccurrence(aNewId).ChildNodeId = aSrcOcc.ChildNodeId; - theTargetGraph.incStorage().SetRemoved(aNewId, - theSourceGraph.incStorage().IsRemoved(anOccurrenceId)); - } - - // OccurrenceRefs (carry LocalLocation). - for (BRepGraph_FullOccurrenceRefIterator aRefIt(theSourceGraph); aRefIt.More(); aRefIt.Next()) - { - const BRepGraph_OccurrenceRefId aRefId = aRefIt.CurrentId(); - const BRepGraphInc::OccurrenceRef& aSrcRef = theSourceGraph.incStorage().OccurrenceRef(aRefId); - const BRepGraph_OccurrenceRefId aNewId = theTargetGraph.incStorage().AppendOccurrenceRef(); - BRepGraphInc::OccurrenceRef& aNewRef = theTargetGraph.incStorage().ChangeOccurrenceRef(aNewId); - theTargetGraph.incStorage().SetRemoved(aNewId, theSourceGraph.incStorage().IsRemoved(aRefId)); - aNewRef.ParentProductId = aSrcRef.ParentProductId; - aNewRef.ChildOccurrenceId = aSrcRef.ChildOccurrenceId; - aNewRef.LocalLocation = aSrcRef.LocalLocation; - } - for (BRepGraph_FullProductIterator aProductIt(theSourceGraph); aProductIt.More(); - aProductIt.Next()) - { - const BRepGraph_ProductId aProductId = aProductIt.CurrentId(); - theTargetGraph.incStorage().SetProductOccurrenceRefs( - aProductId, - theSourceGraph.incStorage().ProductRelations(aProductId).OccurrenceRefIds.ToArray1()); - } - - // Copy per-kind next counters from source to target storage so that future - // allocations continue from the correct values. - constexpr BRepGraph_NodeId::Kind aNodeKinds[] = {BRepGraph_NodeId::Kind::Solid, - BRepGraph_NodeId::Kind::Shell, - BRepGraph_NodeId::Kind::Face, - BRepGraph_NodeId::Kind::Wire, - BRepGraph_NodeId::Kind::Edge, - BRepGraph_NodeId::Kind::Vertex, - BRepGraph_NodeId::Kind::Compound, - BRepGraph_NodeId::Kind::CompSolid, - BRepGraph_NodeId::Kind::CoEdge, - BRepGraph_NodeId::Kind::Product, - BRepGraph_NodeId::Kind::Occurrence}; - for (const auto aNodeKind : aNodeKinds) - { - theTargetGraph.incStorage().SetNextNodeUIDCounter( - aNodeKind, - theSourceGraph.incStorage().NextNodeUIDCounter(aNodeKind)); - } - constexpr BRepGraph_RefId::Kind aRefKinds[] = {BRepGraph_RefId::Kind::Shell, - BRepGraph_RefId::Kind::Face, - BRepGraph_RefId::Kind::Wire, - BRepGraph_RefId::Kind::Vertex, - BRepGraph_RefId::Kind::Solid, - BRepGraph_RefId::Kind::Child, - BRepGraph_RefId::Kind::Occurrence}; - for (const auto aRefKind : aRefKinds) - { - theTargetGraph.incStorage().SetNextRefUIDCounter( - aRefKind, - theSourceGraph.incStorage().NextRefUIDCounter(aRefKind)); - } - - theTargetGraph.incStorage().SetGeneration(theSourceGraph.incStorage().Generation()); - theTargetGraph.incStorage().SetGraphGUID(theSourceGraph.incStorage().GraphGUID()); - theTargetGraph.incStorage().RebuildDerivedRelationsPreservingActiveCounts(); - - // Build root product set: products not referenced as ChildNodeId by any occurrence. - { - NCollection_FlatMap aReferencedProducts; - for (BRepGraph_FullOccurrenceIterator anOccIt(theTargetGraph); anOccIt.More(); anOccIt.Next()) - { - const BRepGraph_OccurrenceId anOccId = anOccIt.CurrentId(); - const BRepGraphInc::OccurrenceDef& anOcc = theTargetGraph.incStorage().Occurrence(anOccId); - if (!theTargetGraph.incStorage().IsRemoved(anOccId) - && anOcc.ChildNodeId.NodeKind == BRepGraph_NodeId::Kind::Product) - { - const BRepGraph_ProductId aChildProductId = - BRepGraph_ProductId::FromNodeId(anOcc.ChildNodeId); - if (aChildProductId.IsValidIn(theTargetGraph.Topo().Products())) - { - aReferencedProducts.Add(aChildProductId); - } - } - } - for (BRepGraph_FullProductIterator aProdIt(theTargetGraph); aProdIt.More(); aProdIt.Next()) - { - const BRepGraph_ProductId aProdId = aProdIt.CurrentId(); - if (!theTargetGraph.incStorage().IsRemoved(aProdId) && !aReferencedProducts.Contains(aProdId)) - { - theTargetGraph.incStorage().ChangeRootProductIds().Append(aProdId); - } - } - } - - theTargetGraph.incStorage().MarkUIDReverseIndexesDirty(); - - NCollection_FlatDataMap anItemRemap; - bindIdentityItems(theSourceGraph.incStorage(), theTargetGraph.incStorage(), anItemRemap); - theSourceGraph.LayerRegistry().CopyLayersTo(theTargetGraph, - anItemRemap, - BRepGraph_CopyRemap::Mode::Copy); - if (theCachePolicy == CachePolicy::CopyFresh) - { - theSourceGraph.CacheRegistry().CopyFreshCachesTo(theTargetGraph, - anItemRemap, - BRepGraph_CopyRemap::Mode::Copy); - } - - return true; + // Empty target: fast identity copy using PrepareForLoad() instead of editor APIs. + return copyFullGraphIdentity(theSourceGraph.incStorage(), + theTargetGraph.incStorage(), + theSourceGraph, + theTargetGraph, + theGeomPolicy, + theMeshPolicy, + theCachePolicy); } //================================================================================================= diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.cxx index 1288d057b9..edf23f82da 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.cxx @@ -25,15 +25,42 @@ BRepGraph_CopyRemap::BRepGraph_CopyRemap(const BRepGraph& theSourceGraph, : mySourceGraph(&theSourceGraph), myTargetGraph(&theTargetGraph), myItemRemap(&theItemRemap), - myMode(theMode) + myMode(theMode), + myMappingKind(MappingKind::Explicit) { } //================================================================================================= -const BRepGraph_ItemId* BRepGraph_CopyRemap::TargetItem(const BRepGraph_ItemId theSourceItem) const +BRepGraph_CopyRemap::BRepGraph_CopyRemap(const BRepGraph& theSourceGraph, + BRepGraph& theTargetGraph, + const BRepGraph_CopyRemap::MappingKind theMappingKind, + const BRepGraph_CopyRemap::Mode theMode) noexcept + : mySourceGraph(&theSourceGraph), + myTargetGraph(&theTargetGraph), + myItemRemap(nullptr), + myMode(theMode), + myMappingKind(theMappingKind) { - return theSourceItem.IsValid() ? myItemRemap->Seek(theSourceItem) : nullptr; +} + +//================================================================================================= + +BRepGraph_ItemId BRepGraph_CopyRemap::TargetItem(const BRepGraph_ItemId theSourceItem) const +{ + if (!theSourceItem.IsValid()) + { + return BRepGraph_ItemId(); + } + + if (myMappingKind == MappingKind::Identity) + { + // In identity mode, the source item id IS the target item id. + return theSourceItem; + } + + const BRepGraph_ItemId* aFound = myItemRemap->Seek(theSourceItem); + return aFound != nullptr ? *aFound : BRepGraph_ItemId(); } //================================================================================================= @@ -41,16 +68,14 @@ const BRepGraph_ItemId* BRepGraph_CopyRemap::TargetItem(const BRepGraph_ItemId t BRepGraph_ItemId BRepGraph_CopyRemap::TargetItemOrInvalid( const BRepGraph_ItemId theSourceItem) const { - const BRepGraph_ItemId* aTarget = TargetItem(theSourceItem); - return aTarget != nullptr ? *aTarget : BRepGraph_ItemId(); + return TargetItem(theSourceItem); } //================================================================================================= bool BRepGraph_CopyRemap::HasTargetItem(const BRepGraph_ItemId theSourceItem) const { - const BRepGraph_ItemId* aTarget = TargetItem(theSourceItem); - return aTarget != nullptr && aTarget->IsValid(); + return TargetItem(theSourceItem).IsValid(); } //================================================================================================= diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.hxx index 4a0a68e9c6..e9dfc0f8e7 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_CopyRemap.hxx @@ -40,6 +40,13 @@ public: Compact = 1 //!< In-place compaction: layers migrate into the same (rebuilt) graph. }; + //! Distinguishes explicit item map vs. identity mapping. + enum class MappingKind : std::uint8_t + { + Explicit = 0, //!< Use theItemRemap for source->target resolution. + Identity = 1 //!< Source and target ids are identical (full identity copy). + }; + using ItemMap = NCollection_FlatDataMap; BRepGraph_CopyRemap(const BRepGraph& theSourceGraph, @@ -47,6 +54,13 @@ public: const ItemMap& theItemRemap, const Mode theMode) noexcept; + //! Identity-mapping constructor for full identity copy into an empty target. + //! Source item ids are returned directly as target item ids after validation. + BRepGraph_CopyRemap(const BRepGraph& theSourceGraph, + BRepGraph& theTargetGraph, + MappingKind theMappingKind, + Mode theMode) noexcept; + //! Migration mode of this context. [[nodiscard]] Mode CopyMode() const noexcept { return myMode; } @@ -65,9 +79,9 @@ public: //! Source item id -> target item id map for copied definitions, refs, and reps. [[nodiscard]] const ItemMap& Items() const noexcept { return *myItemRemap; } - //! Return the target item for a source item, or null if the source item was not copied. - [[nodiscard]] Standard_EXPORT const BRepGraph_ItemId* TargetItem( - const BRepGraph_ItemId theSourceItem) const; + //! Return the target item for a source item, or an invalid item if not copied. + [[nodiscard]] Standard_EXPORT BRepGraph_ItemId + TargetItem(const BRepGraph_ItemId theSourceItem) const; //! Return the target item for a source item, or an invalid item id. [[nodiscard]] Standard_EXPORT BRepGraph_ItemId @@ -93,6 +107,7 @@ private: BRepGraph* myTargetGraph = nullptr; const ItemMap* myItemRemap = nullptr; Mode myMode = Mode::Copy; + MappingKind myMappingKind = MappingKind::Explicit; }; #endif // _BRepGraph_CopyRemap_HeaderFile diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_DefsIterator.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_DefsIterator.hxx index 91971ad85d..3ac79067dc 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_DefsIterator.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_DefsIterator.hxx @@ -368,24 +368,52 @@ public: void Next() { ++myIndex; + // Fast-path: check if the very next element is already valid. + if (myRefIds != nullptr && myIndex < myLength) + { + const RefId aRefId = myRefIds->Value(static_cast(myIndex)); + if (aRefId.IsValid(myNbRefs) && !aRefId.IsRemoved(myGraph)) + { + if constexpr (TraitsT::THE_IS_DIRECT) + { + myCurrentChild = ChildId(aRefId); + return; + } + else + { + const typename TraitsT::RefEntry& aRef = TraitsT::Ref(myGraph, aRefId); + const ChildId aChildId = TraitsT::ChildIdOf(myGraph, aRef); + if constexpr (std::is_same_v) + { + if (myGraph.Topo().Gen().IsActive(aChildId)) + { + myCurrentChild = aChildId; + return; + } + } + else if (aChildId.IsValid(myNbChildren) && !aChildId.IsRemoved(myGraph)) + { + myCurrentChild = aChildId; + return; + } + } + } + } + // Slow-path: full scan for next valid element. skipRemoved(); } [[nodiscard]] ChildId CurrentId() const { - const RefId aRefId = myRefIds->Value(static_cast(myIndex)); - const typename TraitsT::RefEntry& aRef = TraitsT::Ref(myGraph, aRefId); - if constexpr (TraitsT::THE_IS_DIRECT) - { - return aRefId; - } - else - { - return TraitsT::ChildIdOf(myGraph, aRef); - } + Standard_ASSERT_VOID(More(), "DefsOfParent::CurrentId() called on exhausted iterator"); + return myCurrentChild; } - [[nodiscard]] const ChildDef& Current() const { return TraitsT::Child(myGraph, CurrentId()); } + [[nodiscard]] const ChildDef& Current() const + { + Standard_ASSERT_VOID(More(), "DefsOfParent::Current() called on exhausted iterator"); + return TraitsT::Child(myGraph, CurrentId()); + } //! Returns the reference/coedge entry that carries the current child relation. [[nodiscard]] RefId CurrentRefId() const @@ -428,11 +456,13 @@ private: { if (myGraph.Topo().Gen().IsActive(aChildId)) { + myCurrentChild = aChildId; return; } } else if (aChildId.IsValid(myNbChildren) && !aChildId.IsRemoved(myGraph)) { + myCurrentChild = aChildId; return; } } @@ -441,7 +471,8 @@ private: } const BRepGraph& myGraph; - const NCollection_LinearVector* myRefIds = nullptr; + const NCollection_LinearVector* myRefIds = nullptr; + ChildId myCurrentChild{}; uint32_t myIndex = 0; uint32_t myLength = 0; uint32_t myNbRefs = 0; @@ -482,11 +513,13 @@ public: [[nodiscard]] ChildId CurrentId() const { + Standard_ASSERT_VOID(More(), "DefsVertexOfEdge::CurrentId() called on exhausted iterator"); return myGraph.Refs().Vertices().Entry(currentRefId()).ChildVertexId; } [[nodiscard]] const ChildDef& Current() const { + Standard_ASSERT_VOID(More(), "DefsVertexOfEdge::Current() called on exhausted iterator"); return myGraph.Topo().Vertices().Definition(CurrentId()); } diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Layer.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Layer.hxx index 6b6938aceb..73520ec070 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Layer.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Layer.hxx @@ -209,12 +209,12 @@ protected: { return BRepGraph_NodeId::Typed(); } - const BRepGraph_ItemId* aMapped = theCopy.TargetItem(BRepGraph_ItemId(theId)); - if (aMapped == nullptr || !aMapped->IsNode()) + const BRepGraph_ItemId aMapped = theCopy.TargetItem(BRepGraph_ItemId(theId)); + if (!aMapped.IsNode()) { return BRepGraph_NodeId::Typed(); } - return BRepGraph_NodeId::Typed::FromNodeId(aMapped->NodeId()); + return BRepGraph_NodeId::Typed::FromNodeId(aMapped.NodeId()); } template @@ -226,12 +226,12 @@ protected: { return BRepGraph_RefId::Typed(); } - const BRepGraph_ItemId* aMapped = theCopy.TargetItem(BRepGraph_ItemId(theId)); - if (aMapped == nullptr || !aMapped->IsReference()) + const BRepGraph_ItemId aMapped = theCopy.TargetItem(BRepGraph_ItemId(theId)); + if (!aMapped.IsReference()) { return BRepGraph_RefId::Typed(); } - return BRepGraph_RefId::Typed::FromRefId(aMapped->RefId()); + return BRepGraph_RefId::Typed::FromRefId(aMapped.RefId()); } //! Called after the layer is attached to a graph registry. diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerDeferred.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerDeferred.cxx index c3caf48d70..9bcfd20817 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerDeferred.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerDeferred.cxx @@ -430,8 +430,8 @@ void BRepGraph_LayerDeferred::CopyTo(const BRepGraph_CopyRemap& theCopy) const for (NCollection_DataMap::Iterator anIt(myEntries); anIt.More(); anIt.Next()) { - const BRepGraph_ItemId* aTargetItem = theCopy.TargetItem(anIt.Key()); - if (aTargetItem == nullptr || !aTargetItem->IsValid()) + const BRepGraph_ItemId aTargetItem = theCopy.TargetItem(anIt.Key()); + if (!aTargetItem.IsValid()) { continue; } @@ -443,7 +443,7 @@ void BRepGraph_LayerDeferred::CopyTo(const BRepGraph_CopyRemap& theCopy) const { aRepresentations[aRepresentationIdx] = anEntry.Representations.Value(aRepresentationIdx); } - aTarget->RegisterDeferredRepresentationsDirect(*aTargetItem, + aTarget->RegisterDeferredRepresentationsDirect(aTargetItem, anEntry.Provider, anEntry.SourceKey, aRepresentations, diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerHistory.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerHistory.cxx index 233f8e55aa..bcc99de5c8 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerHistory.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerHistory.cxx @@ -452,8 +452,8 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const anIt.More(); anIt.Next()) { - const BRepGraph_ItemId* aNewOriginalItem = theCopy.TargetItem(BRepGraph_ItemId(anIt.Key())); - if (aNewOriginalItem == nullptr || !aNewOriginalItem->IsNode()) + const BRepGraph_ItemId aNewOriginalItem = theCopy.TargetItem(BRepGraph_ItemId(anIt.Key())); + if (!aNewOriginalItem.IsNode()) { continue; } @@ -461,13 +461,13 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const NCollection_LinearVector aNewImages(THE_HISTORY_FILTERED_BLOCK_SIZE); for (const BRepGraph_NodeId& anOldImage : anIt.Value()) { - const BRepGraph_ItemId* aNewImageItem = theCopy.TargetItem(BRepGraph_ItemId(anOldImage)); - if (aNewImageItem != nullptr && aNewImageItem->IsNode()) + const BRepGraph_ItemId aNewImageItem = theCopy.TargetItem(BRepGraph_ItemId(anOldImage)); + if (aNewImageItem.IsNode()) { - appendUniqueNode(aNewImages, aNewImageItem->NodeId()); + appendUniqueNode(aNewImages, aNewImageItem.NodeId()); } } - aNewRecord.Mapping.Bind(aNewOriginalItem->NodeId(), std::move(aNewImages)); + aNewRecord.Mapping.Bind(aNewOriginalItem.NodeId(), std::move(aNewImages)); } if (!aNewRecord.Mapping.IsEmpty() || !aNewRecord.UidMapping.IsEmpty() @@ -497,8 +497,8 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const const BRepGraph_ItemId theSourceOriginal, const BRepGraph_ItemUID& theDurableOriginalUID, const NCollection_LinearVector& theSourceImages) { - const BRepGraph_ItemId* aTargetOriginal = theCopy.TargetItem(theSourceOriginal); - if (aTargetOriginal == nullptr || !aTargetOriginal->IsValid()) + const BRepGraph_ItemId aTargetOriginal = theCopy.TargetItem(theSourceOriginal); + if (!aTargetOriginal.IsValid()) { if (theKind == BRepGraph_LayerHistory::Kind::Deleted) { @@ -523,24 +523,24 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const NCollection_LinearVector aTargetImageUIDs(THE_HISTORY_FILTERED_BLOCK_SIZE); NCollection_LinearVector aTargetImageNodes(THE_HISTORY_FILTERED_BLOCK_SIZE); - bool areAllItemsNodes = aTargetOriginal->IsNode(); + bool areAllItemsNodes = aTargetOriginal.IsNode(); for (const BRepGraph_ItemId& aSourceImage : theSourceImages) { - const BRepGraph_ItemId* aTargetImage = theCopy.TargetItem(aSourceImage); - if (aTargetImage == nullptr || !aTargetImage->IsValid()) + const BRepGraph_ItemId aTargetImage = theCopy.TargetItem(aSourceImage); + if (!aTargetImage.IsValid()) { continue; } - const BRepGraph_ItemUID aTargetUID = theCopy.TargetUID(*aTargetImage); + const BRepGraph_ItemUID aTargetUID = theCopy.TargetUID(aTargetImage); if (aTargetUID.IsValid()) { appendUniqueItemUid(aTargetImageUIDs, aTargetUID); } - if (areAllItemsNodes && aTargetImage->IsNode()) + if (areAllItemsNodes && aTargetImage.IsNode()) { - appendUniqueNode(aTargetImageNodes, aTargetImage->NodeId()); + appendUniqueNode(aTargetImageNodes, aTargetImage.NodeId()); } else { @@ -550,10 +550,10 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const if (theKind == BRepGraph_LayerHistory::Kind::Deleted) { - if (aTargetOriginal->IsNode()) + if (aTargetOriginal.IsNode()) { NCollection_LinearVector aDeleted(THE_HISTORY_REPLACEMENT_BLOCK_SIZE); - aDeleted.Append(aTargetOriginal->NodeId()); + aDeleted.Append(aTargetOriginal.NodeId()); aTarget->RecordDeleted(theOperationName, aDeleted.ToArray1()); } if (theDurableOriginalUID.IsValid()) @@ -573,13 +573,13 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const if (areAllItemsNodes) { aTarget->Record(theOperationName, - aTargetOriginal->NodeId(), + aTargetOriginal.NodeId(), aTargetImageNodes.ToArray1(), theKind); return; } - const BRepGraph_ItemUID aTargetOriginalUID = theCopy.TargetUID(*aTargetOriginal); + const BRepGraph_ItemUID aTargetOriginalUID = theCopy.TargetUID(aTargetOriginal); if (aTargetOriginalUID.IsValid()) { aTarget->RecordItemUid(theOperationName, @@ -605,11 +605,11 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const anIt.More(); anIt.Next()) { - BRepGraph_NodeId aTargetNode; - const BRepGraph_ItemId* aTargetOriginal = theCopy.TargetItem(BRepGraph_ItemId(anIt.Key())); - if (aTargetOriginal != nullptr && aTargetOriginal->IsNode()) + BRepGraph_NodeId aTargetNode; + const BRepGraph_ItemId aTargetOriginal = theCopy.TargetItem(BRepGraph_ItemId(anIt.Key())); + if (aTargetOriginal.IsNode()) { - aTargetNode = aTargetOriginal->NodeId(); + aTargetNode = aTargetOriginal.NodeId(); } else if (theCopy.TargetGraphConst().Topo().Gen().TopoEntity(anIt.Key()) != nullptr) { @@ -623,10 +623,10 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const NCollection_LinearVector aTargetImages(THE_HISTORY_FILTERED_BLOCK_SIZE); for (const BRepGraph_NodeId& aNode : anIt.Value()) { - const BRepGraph_ItemId* aTargetImage = theCopy.TargetItem(BRepGraph_ItemId(aNode)); - if (aTargetImage != nullptr && aTargetImage->IsNode()) + const BRepGraph_ItemId aTargetImage = theCopy.TargetItem(BRepGraph_ItemId(aNode)); + if (aTargetImage.IsNode()) { - appendUniqueNode(aTargetImages, aTargetImage->NodeId()); + appendUniqueNode(aTargetImages, aTargetImage.NodeId()); } } aNewRecord.Mapping.Bind(aTargetNode, std::move(aTargetImages)); @@ -702,11 +702,11 @@ void BRepGraph_LayerHistory::CopyTo(const BRepGraph_CopyRemap& theCopy) const if (aSourceImage.IsValid()) { aSourceImages.Append(aSourceImage); - const BRepGraph_ItemId* aTargetImage = theCopy.TargetItem(aSourceImage); - if (aTargetImage != nullptr && aTargetImage->IsNode()) + const BRepGraph_ItemId aTargetImage = theCopy.TargetItem(aSourceImage); + if (aTargetImage.IsNode()) { const BRepGraph_UID aTargetUID = - theCopy.TargetGraphConst().UIDs().Of(aTargetImage->NodeId()); + theCopy.TargetGraphConst().UIDs().Of(aTargetImage.NodeId()); if (aTargetUID.IsValid()) { appendUniqueUid(aTargetImageUIDs, aTargetUID); diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerLock.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerLock.cxx index 736965efeb..2e308f26cb 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerLock.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerLock.cxx @@ -456,23 +456,23 @@ void BRepGraph_LayerLock::CopyTo(const BRepGraph_CopyRemap& theCopy) const // Copy node root entries. for (OwnerMap::Iterator anIt(myNodeOwners); anIt.More(); anIt.Next()) { - const BRepGraph_ItemId* aTargetItem = theCopy.TargetItem(anIt.Key()); - if (aTargetItem == nullptr || !aTargetItem->IsValid()) + const BRepGraph_ItemId aTargetItem = theCopy.TargetItem(anIt.Key()); + if (!aTargetItem.IsValid()) { continue; } - hasCopied = aTarget->SetOwner(*aTargetItem, anIt.Value(), false) || hasCopied; + hasCopied = aTarget->SetOwner(aTargetItem, anIt.Value(), false) || hasCopied; } // Copy ref root entries. for (OwnerMap::Iterator anIt(myRefOwners); anIt.More(); anIt.Next()) { - const BRepGraph_ItemId* aTargetItem = theCopy.TargetItem(anIt.Key()); - if (aTargetItem == nullptr || !aTargetItem->IsValid()) + const BRepGraph_ItemId aTargetItem = theCopy.TargetItem(anIt.Key()); + if (!aTargetItem.IsValid()) { continue; } - hasCopied = aTarget->SetOwner(*aTargetItem, anIt.Value(), false) || hasCopied; + hasCopied = aTarget->SetOwner(aTargetItem, anIt.Value(), false) || hasCopied; } if (hasCopied) diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.cxx index 4b711f351f..648dac1f4c 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.cxx @@ -30,14 +30,16 @@ BRepGraph_LayerRegistry::BRepGraph_LayerRegistry() = default; BRepGraph_LayerRegistry::BRepGraph_LayerRegistry(BRepGraph_LayerRegistry&& theOther) noexcept { std::unique_lock aLock(theOther.myMutex); - myLayers = std::move(theOther.myLayers); - myGuidToSlot = std::move(theOther.myGuidToSlot); - mySubscribedKindsMask = theOther.mySubscribedKindsMask; - mySubscribedRefKindsMask = theOther.mySubscribedRefKindsMask; - myGraph = theOther.myGraph; - theOther.mySubscribedKindsMask = 0; - theOther.mySubscribedRefKindsMask = 0; - theOther.myGraph = nullptr; + myLayers = std::move(theOther.myLayers); + myGuidToSlot = std::move(theOther.myGuidToSlot); + mySubscribedKindsMask.store(theOther.mySubscribedKindsMask.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mySubscribedRefKindsMask.store(theOther.mySubscribedRefKindsMask.load(std::memory_order_relaxed), + std::memory_order_relaxed); + myGraph = theOther.myGraph; + theOther.mySubscribedKindsMask.store(0, std::memory_order_relaxed); + theOther.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed); + theOther.myGraph = nullptr; } //================================================================================================= @@ -52,14 +54,17 @@ BRepGraph_LayerRegistry& BRepGraph_LayerRegistry::operator=( std::lock(aThisLock, anOtherLock); detachAllLocked(); - myLayers = std::move(theOther.myLayers); - myGuidToSlot = std::move(theOther.myGuidToSlot); - mySubscribedKindsMask = theOther.mySubscribedKindsMask; - mySubscribedRefKindsMask = theOther.mySubscribedRefKindsMask; - myGraph = theOther.myGraph; - theOther.mySubscribedKindsMask = 0; - theOther.mySubscribedRefKindsMask = 0; - theOther.myGraph = nullptr; + myLayers = std::move(theOther.myLayers); + myGuidToSlot = std::move(theOther.myGuidToSlot); + mySubscribedKindsMask.store(theOther.mySubscribedKindsMask.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mySubscribedRefKindsMask.store( + theOther.mySubscribedRefKindsMask.load(std::memory_order_relaxed), + std::memory_order_relaxed); + myGraph = theOther.myGraph; + theOther.mySubscribedKindsMask.store(0, std::memory_order_relaxed); + theOther.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed); + theOther.myGraph = nullptr; } return *this; } @@ -100,8 +105,12 @@ uint32_t BRepGraph_LayerRegistry::registerLayerLocked(const occ::handleattachGraph(myGraph); myLayers.Append(theLayer); myGuidToSlot.Bind(aGUID, aNewSlot); - mySubscribedKindsMask |= theLayer->SubscribedKinds(); - mySubscribedRefKindsMask |= theLayer->SubscribedRefKinds(); + mySubscribedKindsMask.store(mySubscribedKindsMask.load(std::memory_order_relaxed) + | theLayer->SubscribedKinds(), + std::memory_order_relaxed); + mySubscribedRefKindsMask.store(mySubscribedRefKindsMask.load(std::memory_order_relaxed) + | theLayer->SubscribedRefKinds(), + std::memory_order_relaxed); return aNewSlot; } @@ -179,6 +188,35 @@ occ::handle BRepGraph_LayerRegistry::findLayerLocked( //================================================================================================= +occ::handle BRepGraph_LayerRegistry::ensureLayer( + const Standard_GUID& theGUID, + const std::function()>& theFactory) +{ + // Fast path: shared lock for read-only lookup. + { + std::shared_lock aLock(myMutex); + occ::handle aLayer = findLayerLocked(theGUID); + if (!aLayer.IsNull()) + { + return aLayer; + } + } + + // Slow path: exclusive lock for creation. + { + std::unique_lock aLock(myMutex); + occ::handle aLayer = findLayerLocked(theGUID); + if (aLayer.IsNull()) + { + aLayer = theFactory(); + registerLayerLocked(aLayer); + } + return aLayer; + } +} + +//================================================================================================= + bool BRepGraph_LayerRegistry::FindSlot(const Standard_GUID& theGUID, uint32_t& theSlot) const { std::shared_lock aLock(myMutex); @@ -270,12 +308,10 @@ void BRepGraph_LayerRegistry::DispatchOnNodeReplaced(const BRepGraph_NodeId theO void BRepGraph_LayerRegistry::DispatchNodeModified(const BRepGraph_NodeId theNode) noexcept { + // Lock-free early exit: check subscription mask without mutex. + if (mySubscribedKindsMask.load(std::memory_order_acquire) == 0) { - std::shared_lock aLock(myMutex); - if (mySubscribedKindsMask == 0) - { - return; - } + return; } const int aKindBit = BRepGraph_Layer::KindBit(theNode.NodeKind); @@ -321,12 +357,10 @@ void BRepGraph_LayerRegistry::DispatchNodesModified( const NCollection_Array1& theModifiedNodes, const int theModifiedKindsMask) noexcept { + // Lock-free early exit: check subscription mask without mutex. + if (mySubscribedKindsMask.load(std::memory_order_acquire) == 0 || theModifiedKindsMask == 0) { - std::shared_lock aLock(myMutex); - if (mySubscribedKindsMask == 0 || theModifiedKindsMask == 0) - { - return; - } + return; } for (uint32_t aSlot = 0;; ++aSlot) @@ -369,8 +403,8 @@ void BRepGraph_LayerRegistry::CopyLayersTo( aSelf.detachAllLocked(); aSelf.myLayers.Clear(); aSelf.myGuidToSlot.Clear(); - aSelf.mySubscribedKindsMask = 0; - aSelf.mySubscribedRefKindsMask = 0; + aSelf.mySubscribedKindsMask.store(0, std::memory_order_relaxed); + aSelf.mySubscribedRefKindsMask.store(0, std::memory_order_relaxed); aLock.unlock(); // Call CopyTo on each old (now detached) layer. @@ -404,6 +438,30 @@ void BRepGraph_LayerRegistry::CopyLayersTo( //================================================================================================= +void BRepGraph_LayerRegistry::CopyLayersTo(BRepGraph& theTargetGraph, + BRepGraph_CopyRemap::MappingKind theMappingKind, + BRepGraph_CopyRemap::Mode theMode) const +{ + BRepGraph* aSourceGraph = nullptr; + { + std::shared_lock aLock(myMutex); + aSourceGraph = myGraph; + } + + const BRepGraph_CopyRemap aCopy(*aSourceGraph, theTargetGraph, theMappingKind, theMode); + for (uint32_t aSlot = 0;; ++aSlot) + { + occ::handle aLayer = layerAt(aSlot); + if (aLayer.IsNull()) + { + return; + } + aLayer->CopyTo(aCopy); + } +} + +//================================================================================================= + void BRepGraph_LayerRegistry::ClearAll() noexcept { for (uint32_t aSlot = 0;; ++aSlot) @@ -451,12 +509,10 @@ void BRepGraph_LayerRegistry::DispatchOnRefRemoved(const BRepGraph_RefId theRef) void BRepGraph_LayerRegistry::DispatchRefModified(const BRepGraph_RefId theRef) noexcept { + // Lock-free early exit: check subscription mask without mutex. + if (mySubscribedRefKindsMask.load(std::memory_order_acquire) == 0) { - std::shared_lock aLock(myMutex); - if (mySubscribedRefKindsMask == 0) - { - return; - } + return; } const int aRefKindBit = BRepGraph_Layer::RefKindBit(theRef.RefKind); @@ -480,12 +536,10 @@ void BRepGraph_LayerRegistry::DispatchRefsModified( const NCollection_Array1& theModifiedRefs, const int theModifiedRefKindsMask) noexcept { + // Lock-free early exit: check subscription mask without mutex. + if (mySubscribedRefKindsMask.load(std::memory_order_acquire) == 0 || theModifiedRefKindsMask == 0) { - std::shared_lock aLock(myMutex); - if (mySubscribedRefKindsMask == 0 || theModifiedRefKindsMask == 0) - { - return; - } + return; } for (uint32_t aSlot = 0;; ++aSlot) @@ -519,11 +573,13 @@ void BRepGraph_LayerRegistry::detachAllLocked() noexcept void BRepGraph_LayerRegistry::recomputeSubscribedKindsMask() { - mySubscribedKindsMask = 0; - mySubscribedRefKindsMask = 0; + uint32_t aKindsMask = 0; + uint32_t aRefKindsMask = 0; for (const occ::handle& aLayer : myLayers) { - mySubscribedKindsMask |= aLayer->SubscribedKinds(); - mySubscribedRefKindsMask |= aLayer->SubscribedRefKinds(); + aKindsMask |= aLayer->SubscribedKinds(); + aRefKindsMask |= aLayer->SubscribedRefKinds(); } + mySubscribedKindsMask.store(aKindsMask, std::memory_order_relaxed); + mySubscribedRefKindsMask.store(aRefKindsMask, std::memory_order_relaxed); } diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.hxx index fb86a382f9..030d5f805c 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerRegistry.hxx @@ -23,8 +23,10 @@ #include #include +#include #include #include +#include //! @brief Dense GUID-keyed runtime registry of graph layers. //! @@ -69,17 +71,12 @@ public: } //! Return an existing layer or create and register a default one. + //! Template convenience wrapper: extracts GUID and calls ensureLayer. template [[nodiscard]] occ::handle Ensure() { - std::unique_lock aLock(myMutex); - occ::handle aLayer = occ::down_cast(findLayerLocked(T::GetID())); - if (aLayer.IsNull()) - { - aLayer = new T(); - registerLayerLocked(aLayer); - } - return aLayer; + return occ::down_cast( + ensureLayer(T::GetID(), []() -> occ::handle { return new T(); })); } //! Return current slot for a GUID. @@ -99,15 +96,13 @@ public: //! True if any registered layer subscribes to node modification events. [[nodiscard]] bool HasModificationSubscribers() const { - std::shared_lock aLock(myMutex); - return mySubscribedKindsMask != 0; + return mySubscribedKindsMask.load(std::memory_order_acquire) != 0; } //! Bitwise OR of all registered layer node subscription masks. [[nodiscard]] int SubscribedKindsMask() const { - std::shared_lock aLock(myMutex); - return mySubscribedKindsMask; + return static_cast(mySubscribedKindsMask.load(std::memory_order_acquire)); } //! Dispatch OnNodeRemoved to all registered layers. @@ -141,18 +136,25 @@ public: const NCollection_FlatDataMap& theItemRemap, const BRepGraph_CopyRemap::Mode theMode) const; + //! Ask every registered source layer to copy itself using identity mapping. + //! Source item ids are the same as target item ids (full identity copy). + //! @param[in] theTargetGraph target graph to receive layer data + //! @param[in] theMappingKind identity or explicit mapping + //! @param[in] theMode Copy or Compact semantics + Standard_EXPORT void CopyLayersTo(BRepGraph& theTargetGraph, + BRepGraph_CopyRemap::MappingKind theMappingKind, + BRepGraph_CopyRemap::Mode theMode) const; + //! True if any registered layer subscribes to reference modification events. [[nodiscard]] bool HasRefModificationSubscribers() const { - std::shared_lock aLock(myMutex); - return mySubscribedRefKindsMask != 0; + return mySubscribedRefKindsMask.load(std::memory_order_acquire) != 0; } //! Bitwise OR of all registered layer reference subscription masks. [[nodiscard]] int SubscribedRefKindsMask() const { - std::shared_lock aLock(myMutex); - return mySubscribedRefKindsMask; + return static_cast(mySubscribedRefKindsMask.load(std::memory_order_acquire)); } //! Dispatch OnRefRemoved to all registered layers (unconditional - not filtered). @@ -185,6 +187,13 @@ private: [[nodiscard]] Standard_EXPORT occ::handle findLayerLocked( const Standard_GUID& theGUID) const; + //! Return an existing layer or create and register a default one. + //! Uses double-checked locking: shared lock for fast path (layer exists), + //! exclusive lock only for creation (rare, first-call only). + [[nodiscard]] Standard_EXPORT occ::handle ensureLayer( + const Standard_GUID& theGUID, + const std::function()>& theFactory); + [[nodiscard]] Standard_EXPORT occ::handle layerAt(uint32_t theSlot) const; Standard_EXPORT uint32_t registerLayerLocked(const occ::handle& theLayer); @@ -195,9 +204,9 @@ private: private: NCollection_LinearVector> myLayers; NCollection_DataMap myGuidToSlot; - uint32_t mySubscribedKindsMask = 0; - uint32_t mySubscribedRefKindsMask = 0; - BRepGraph* myGraph = nullptr; + std::atomic mySubscribedKindsMask{0}; + std::atomic mySubscribedRefKindsMask{0}; + BRepGraph* myGraph = nullptr; mutable std::shared_mutex myMutex; }; diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerTopoSupplement.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerTopoSupplement.cxx index c8232c6698..44e59b085d 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerTopoSupplement.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_LayerTopoSupplement.cxx @@ -327,13 +327,13 @@ void BRepGraph_LayerTopoSupplement::CopyTo(const BRepGraph_CopyRemap& theCopy) c } for (const Entry& anEntry : aSourceEntries) { - const BRepGraph_ItemId* aTargetItem = theCopy.TargetItem(BRepGraph_ItemId(anEntry.BaseOwner)); - if (aTargetItem == nullptr || !aTargetItem->IsNode()) + const BRepGraph_ItemId aTargetItem = theCopy.TargetItem(BRepGraph_ItemId(anEntry.BaseOwner)); + if (!aTargetItem.IsNode()) { continue; } - const BRepGraph_NodeId aTargetOwner = aTargetItem->NodeId(); + const BRepGraph_NodeId aTargetOwner = aTargetItem.NodeId(); if (!aTargetOwner.IsValid()) { continue; diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_RefsIterator.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_RefsIterator.hxx index 62de003ee0..5ad6806311 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_RefsIterator.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_RefsIterator.hxx @@ -431,10 +431,40 @@ public: void Next() { ++myIndex; + // Fast-path: check if the very next element is already valid. + if (myRefIds != nullptr && myIndex < myLength) + { + const RefId aRefId = myRefIds->Value(static_cast(myIndex)); + if (aRefId.IsValid(myNbRefs) && !aRefId.IsRemoved(myGraph)) + { + if constexpr (TraitsT::THE_IS_DIRECT) + { + return; + } + else + { + const typename TraitsT::RefEntry& aRef = TraitsT::Ref(myGraph, aRefId); + const auto aChildId = TraitsT::ChildIdOf(myGraph, aRef); + if constexpr (std::is_same_v) + { + if (myGraph.Topo().Gen().IsActive(aChildId)) + return; + } + else if (aChildId.IsValid(myNbChildren) && !aChildId.IsRemoved(myGraph)) + { + return; + } + } + } + } skipRemoved(); } - [[nodiscard]] RefId CurrentId() const { return myRefIds->Value(static_cast(myIndex)); } + [[nodiscard]] RefId CurrentId() const + { + Standard_ASSERT_VOID(More(), "RefsOfParent::CurrentId() called on exhausted iterator"); + return myRefIds->Value(static_cast(myIndex)); + } [[nodiscard]] uint32_t Index() const { return myIndex; } diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_ShapesView.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_ShapesView.cxx index e235b6365f..4cd4e298f2 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_ShapesView.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_ShapesView.cxx @@ -40,7 +40,7 @@ namespace { struct BRepGraph_ReconstructionContext { - const BRepGraph* Graph = nullptr; + BRepGraph* Graph = nullptr; const BRepGraphInc_Storage* Storage = nullptr; BRepGraphInc_Reconstruct::Cache Cache; NCollection_FlatMap ActiveProducts; @@ -677,7 +677,7 @@ static TopoDS_Shape reconstructShape(BRepGraph_ReconstructionContext& theContext } static BRepGraph_ReconstructionContext makeReconstructionContext( - const BRepGraph& theGraph, + BRepGraph& theGraph, const BRepGraphInc_Storage& theStorage) { BRepGraph_ReconstructionContext aContext; diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.cxx index 387446834b..08d8f8ae64 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.cxx @@ -80,13 +80,6 @@ bool wireUVBounds(const BRepGraph& theGraph, return true; } -BRepGraph_EdgeId edgeOf(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - return theCoEdge.IsValid() && !theCoEdge.IsRemoved(theGraph) - ? theGraph.Topo().CoEdges().Definition(theCoEdge).ChildEdgeId - : BRepGraph_EdgeId(); -} - BRepGraph_FaceId faceOf(const BRepGraph& theGraph, const BRepGraph_FaceRefId theFaceRef) { if (!theFaceRef.IsValid() || theGraph.Refs().Gen().IsRemoved(theFaceRef)) @@ -274,76 +267,30 @@ double BRepGraph_Tool::Edge::Tolerance(const BRepGraph& theGraph, const BRepGrap bool BRepGraph_Tool::Edge::Degenerated(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) { - BRepGraph_CacheDerivedState::EdgeEntry anEntry; - return derivedStateCache(theGraph)->GetEdgeStatus(theEdge, anEntry) - && anEntry.Status == BRepGraph_CacheDerivedState::EdgeGeometryStatus::DegenerateOnSurface; + return derivedStateCache(theGraph)->IsDegenerated(theEdge); } //================================================================================================= -double BRepGraph_Tool::Edge::Tolerance(const BRepGraph& theGraph, +bool BRepGraph_Tool::CoEdge::SameParameter(const BRepGraph& theGraph, + const BRepGraph_CoEdgeId theCoEdge) +{ + return derivedStateCache(theGraph)->SameParameter(theCoEdge); +} + +//================================================================================================= + +bool BRepGraph_Tool::CoEdge::SameRange(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) { - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() ? Tolerance(theGraph, anEdge) : 0.0; -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::Degenerated(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && Degenerated(theGraph, anEdge); -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::SameParameter(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) -{ - BRepGraph_CacheDerivedState::EdgeEntry anEntry; - return derivedStateCache(theGraph)->GetEdgeStatus(theEdge, anEntry) && anEntry.SameParameter; -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::SameParameter(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && SameParameter(theGraph, anEdge); -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::SameRange(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) -{ - BRepGraph_CacheDerivedState::EdgeEntry anEntry; - return derivedStateCache(theGraph)->GetEdgeStatus(theEdge, anEntry) && anEntry.SameRange; -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::SameRange(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && SameRange(theGraph, anEdge); + return derivedStateCache(theGraph)->SameRange(theCoEdge); } //================================================================================================= bool BRepGraph_Tool::Edge::IsClosed(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) { - BRepGraph_CacheDerivedState::EdgeEntry anEntry; - return derivedStateCache(theGraph)->GetEdgeStatus(theEdge, anEntry) && anEntry.IsClosed; -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::IsClosed(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && IsClosed(theGraph, anEdge); + return derivedStateCache(theGraph)->IsClosed(theEdge); } //================================================================================================= @@ -366,15 +313,6 @@ std::pair BRepGraph_Tool::Edge::Range(const BRepGraph& the //================================================================================================= -std::pair BRepGraph_Tool::Edge::Range(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() ? Range(theGraph, anEdge) : std::pair{0.0, 0.0}; -} - -//================================================================================================= - bool BRepGraph_Tool::Edge::HasCurve(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) { const occ::handle aCurve = theGraph.Topo().Edges().Curve3D(theEdge); @@ -399,42 +337,6 @@ BRepGraph_VertexRefId BRepGraph_Tool::Edge::EndVertexId(const BRepGraph& t //================================================================================================= -BRepGraph_VertexRefId BRepGraph_Tool::Edge::StartVertexId(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - if (!theCoEdge.IsValid() || theCoEdge.IsRemoved(theGraph)) - { - return BRepGraph_VertexRefId(); - } - const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); - return aCoEdge.Orientation == TopAbs_REVERSED ? EndVertexId(theGraph, aCoEdge.ChildEdgeId) - : StartVertexId(theGraph, aCoEdge.ChildEdgeId); -} - -//================================================================================================= - -BRepGraph_VertexRefId BRepGraph_Tool::Edge::EndVertexId(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - if (!theCoEdge.IsValid() || theCoEdge.IsRemoved(theGraph)) - { - return BRepGraph_VertexRefId(); - } - const BRepGraphInc::CoEdgeDef& aCoEdge = theGraph.Topo().CoEdges().Definition(theCoEdge); - return aCoEdge.Orientation == TopAbs_REVERSED ? StartVertexId(theGraph, aCoEdge.ChildEdgeId) - : EndVertexId(theGraph, aCoEdge.ChildEdgeId); -} - -//================================================================================================= - -bool BRepGraph_Tool::Edge::HasCurve(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && HasCurve(theGraph, anEdge); -} - -//================================================================================================= - GeomAdaptor_TransformedCurve BRepGraph_Tool::Edge::CurveAdaptor( const BRepGraph& theGraph, const BRepGraphInc::CoEdgeInstance& theRef) @@ -531,24 +433,6 @@ const occ::handle& BRepGraph_Tool::Edge::Curve(const BRepGraph& //================================================================================================= -const occ::handle& BRepGraph_Tool::Edge::Curve(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() ? Curve(theGraph, anEdge) : THE_NULL_CURVE; -} - -//================================================================================================= - -GeomAdaptor_TransformedCurve BRepGraph_Tool::Edge::CurveAdaptor(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() ? CurveAdaptor(theGraph, anEdge) : GeomAdaptor_TransformedCurve(); -} - -//================================================================================================= - occ::handle BRepGraph_Tool::Edge::Curve(const BRepGraph& theGraph, const BRepGraphInc::CoEdgeInstance& theRef) { @@ -671,15 +555,6 @@ uint32_t BRepGraph_Tool::Edge::NbFaces(const BRepGraph& theGraph, const BRepGrap //================================================================================================= -uint32_t BRepGraph_Tool::Edge::NbFaces(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() ? NbFaces(theGraph, anEdge) : 0; -} - -//================================================================================================= - bool BRepGraph_Tool::Edge::IsManifold(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) { return NbFaces(theGraph, theEdge) == 2; @@ -687,14 +562,6 @@ bool BRepGraph_Tool::Edge::IsManifold(const BRepGraph& theGraph, const BRepGraph //================================================================================================= -bool BRepGraph_Tool::Edge::IsManifold(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && IsManifold(theGraph, anEdge); -} - -//================================================================================================= - bool BRepGraph_Tool::Edge::IsBoundary(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge) { return NbFaces(theGraph, theEdge) == 1; @@ -702,14 +569,6 @@ bool BRepGraph_Tool::Edge::IsBoundary(const BRepGraph& theGraph, const BRepGraph //================================================================================================= -bool BRepGraph_Tool::Edge::IsBoundary(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) -{ - const BRepGraph_EdgeId anEdge = edgeOf(theGraph, theCoEdge); - return anEdge.IsValid() && IsBoundary(theGraph, anEdge); -} - -//================================================================================================= - TopAbs_Orientation BRepGraph_Tool::CoEdge::Orientation(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge) { @@ -905,7 +764,7 @@ std::pair BRepGraph_Tool::CoEdge::UVPoints(const BRepGraph& { return {gp_Pnt2d(), gp_Pnt2d()}; } - return {aCurve->Value(aPCUse.ParamFirst), aCurve->Value(aPCUse.ParamLast)}; + return {aCurve->EvalD0(aPCUse.ParamFirst), aCurve->EvalD0(aPCUse.ParamLast)}; } //================================================================================================= @@ -1448,9 +1307,7 @@ BRepGraph_Tool::ShellUsage BRepGraph_Tool::Shell::Usage(const BRepGraph& bool BRepGraph_Tool::Shell::IsClosed(const BRepGraph& theGraph, const BRepGraph_ShellId theShell) { - BRepGraph_CacheDerivedState::ShellEntry anEntry; - return derivedStateCache(theGraph)->GetShellStatus(theShell, anEntry) - && anEntry.Status == BRepGraph_CacheDerivedState::ShellClosureStatus::Closed; + return derivedStateCache(theGraph)->IsShellClosed(theShell); } //================================================================================================= diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.hxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.hxx index c508ce148d..08899b6b30 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.hxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_Tool.hxx @@ -126,10 +126,6 @@ public: [[nodiscard]] Standard_EXPORT static double Tolerance(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the tolerance of the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static double Tolerance(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge is degenerate, derived from current geometry. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -137,34 +133,6 @@ public: [[nodiscard]] Standard_EXPORT static bool Degenerated(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns true if the edge referenced by the coedge is degenerate. - [[nodiscard]] Standard_EXPORT static bool Degenerated(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - - //! Returns true if all PCurves are reparametrized to the same range as the 3D curve. - //! This is a derived geometry check, not a stored flag. - //! @param[in] theGraph source graph - //! @param[in] theEdge typed edge definition identifier - //! @return true if same parameter - [[nodiscard]] Standard_EXPORT static bool SameParameter(const BRepGraph& theGraph, - const BRepGraph_EdgeId theEdge); - - //! Returns SameParameter for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static bool SameParameter(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - - //! Returns true if PCurve parameter range equals the 3D curve range. - //! This is a derived check, not a stored flag. - //! @param[in] theGraph source graph - //! @param[in] theEdge typed edge definition identifier - //! @return true if same range - [[nodiscard]] Standard_EXPORT static bool SameRange(const BRepGraph& theGraph, - const BRepGraph_EdgeId theEdge); - - //! Returns SameRange for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static bool SameRange(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge forms a topological loop, derived from vertex topology. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -172,10 +140,6 @@ public: [[nodiscard]] Standard_EXPORT static bool IsClosed(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the closed flag for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static bool IsClosed(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the 3D curve parameter range as (first, last). //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -184,11 +148,6 @@ public: const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the 3D curve parameter range for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static std::pair Range( - const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the start vertex reference id directly. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -197,11 +156,6 @@ public: const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the coedge start vertex reference id, respecting coedge orientation. - [[nodiscard]] Standard_EXPORT static BRepGraph_VertexRefId StartVertexId( - const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the end vertex reference id directly. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -210,11 +164,6 @@ public: const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the coedge end vertex reference id, respecting coedge orientation. - [[nodiscard]] Standard_EXPORT static BRepGraph_VertexRefId EndVertexId( - const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge has a 3D curve representation. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -222,10 +171,6 @@ public: [[nodiscard]] Standard_EXPORT static bool HasCurve(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns true if the edge referenced by the coedge has a 3D curve. - [[nodiscard]] Standard_EXPORT static bool HasCurve(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the raw 3D curve handle (definition frame, no copy). //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -234,11 +179,6 @@ public: const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the raw 3D curve handle for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static const occ::handle& Curve( - const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the transformed 3D curve handle via CoEdgeUsage (applies Location, may copy). //! @param[in] theGraph source graph //! @param[in] theRef coedge incidence reference carrying Location @@ -254,11 +194,6 @@ public: const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the 3D curve adaptor for the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static GeomAdaptor_TransformedCurve CurveAdaptor( - const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns the 3D curve adaptor via CoEdgeUsage (applies edge-in-wire Location in Trsf). //! Falls back to CurveOnSurface when no 3D curve exists. //! @param[in] theGraph source graph @@ -333,10 +268,6 @@ public: [[nodiscard]] Standard_EXPORT static uint32_t NbFaces(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns the number of faces referencing the edge referenced by the coedge. - [[nodiscard]] Standard_EXPORT static uint32_t NbFaces(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge is shared by exactly two faces (manifold). //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -344,10 +275,6 @@ public: [[nodiscard]] Standard_EXPORT static bool IsManifold(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns true if the edge referenced by the coedge is manifold. - [[nodiscard]] Standard_EXPORT static bool IsManifold(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge belongs to exactly one face (boundary / free edge). //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -355,10 +282,6 @@ public: [[nodiscard]] Standard_EXPORT static bool IsBoundary(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge); - //! Returns true if the edge referenced by the coedge is boundary. - [[nodiscard]] Standard_EXPORT static bool IsBoundary(const BRepGraph& theGraph, - const BRepGraph_CoEdgeId theCoEdge); - //! Returns true if the edge is a seam on the given face. //! @param[in] theGraph source graph //! @param[in] theEdge typed edge definition identifier @@ -434,6 +357,20 @@ public: [[nodiscard]] Standard_EXPORT static bool HasPCurve(const BRepGraph& theGraph, const BRepGraph_CoEdgeId theCoEdge); + //! Returns true if the coedge's PCurve parameter matches the 3D curve. + //! @param[in] theGraph source graph + //! @param[in] theCoEdge typed coedge definition identifier + //! @return true if same parameter + [[nodiscard]] Standard_EXPORT static bool SameParameter(const BRepGraph& theGraph, + const BRepGraph_CoEdgeId theCoEdge); + + //! Returns true if the coedge's PCurve range equals the 3D curve range. + //! @param[in] theGraph source graph + //! @param[in] theCoEdge typed coedge definition identifier + //! @return true if same range + [[nodiscard]] Standard_EXPORT static bool SameRange(const BRepGraph& theGraph, + const BRepGraph_CoEdgeId theCoEdge); + //! Returns the raw PCurve handle by coedge identifier (no Location - UV space). //! @param[in] theGraph source graph //! @param[in] theCoEdge typed coedge definition identifier diff --git a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_TopoView.cxx b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_TopoView.cxx index 3dde93bfc5..f00e1ee2ee 100644 --- a/src/ModelingData/TKBRep/BRepGraph/BRepGraph_TopoView.cxx +++ b/src/ModelingData/TKBRep/BRepGraph/BRepGraph_TopoView.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -148,12 +149,63 @@ const BRepGraphInc::EdgeRelations& BRepGraph::TopoView::EdgeOps::Relations( uint32_t BRepGraph::TopoView::EdgeOps::NbFaces(const BRepGraph_EdgeId theEdge) const { - uint32_t aCount = 0; - for (BRepGraph_FacesOfEdge aFaceIt(*myGraph, theEdge); aFaceIt.More(); aFaceIt.Next()) + const BRepGraphInc_Storage& aStorage = myGraph->myData->myIncStorage; + if (!theEdge.IsValid(aStorage.NbEdges()) || aStorage.IsRemoved(theEdge) + || aStorage.NbActiveFaces() == 0) { - ++aCount; + return 0; } - return aCount; + + const NCollection_LinearVector& aCoEdges = + aStorage.EdgeRelations(theEdge).CoEdgeIds; + const size_t aNbCoEdges = aCoEdges.Size(); + if (aNbCoEdges == 0) + { + return 0; + } + + // Inline buffer covers edges with up to 32 coedges without heap allocation. + // Seam edges (2 coedges, 1 face) and typical manifold edges (2 coedges, 2 faces) + // are the overwhelmingly common cases. + NCollection_LocalArray aSeenBuf(32); + uint32_t aNbSeen = 0; + + for (size_t aIdx = 0; aIdx < aNbCoEdges; ++aIdx) + { + const BRepGraph_CoEdgeId aCoEdgeId = aCoEdges.Value(aIdx); + if (!aCoEdgeId.IsValid(aStorage.NbCoEdges()) || aStorage.IsRemoved(aCoEdgeId)) + { + continue; + } + + const BRepGraph_FaceId aFace = aStorage.CoEdge(aCoEdgeId).FaceId; + if (!aFace.IsValid(aStorage.NbFaces()) || aStorage.IsRemoved(aFace)) + { + continue; + } + + // Linear scan over the small seen set (typically 1-2 entries). + bool aFound = false; + for (uint32_t aJ = 0; aJ < aNbSeen; ++aJ) + { + if (aSeenBuf[aJ] == aFace) + { + aFound = true; + break; + } + } + if (aFound) + { + continue; + } + if (aNbSeen >= aSeenBuf.Size()) + { + aSeenBuf.Reallocate(static_cast(aSeenBuf.Size() * 1.5)); + } + aSeenBuf[aNbSeen++] = aFace; + } + + return aNbSeen; } //================================================================================================= diff --git a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_BoundaryBuilder.pxx b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_BoundaryBuilder.pxx index 81a21261dc..3517368a82 100644 --- a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_BoundaryBuilder.pxx +++ b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_BoundaryBuilder.pxx @@ -172,10 +172,10 @@ inline bool BuildSurfaceBoundary(SurfaceBoundary& theBoundary, const bool isUClosed = isFullPeriod(theSurface, true, theUMin, theUMax, aPeriodTol); const bool isVClosed = isFullPeriod(theSurface, false, theVMin, theVMax, aPeriodTol); - size_t aV00 = addSurfaceVertex(theBoundary, theSurface->Value(theUMin, theVMin), aTol); - size_t aV10 = addSurfaceVertex(theBoundary, theSurface->Value(theUMax, theVMin), aTol); - size_t aV11 = addSurfaceVertex(theBoundary, theSurface->Value(theUMax, theVMax), aTol); - size_t aV01 = addSurfaceVertex(theBoundary, theSurface->Value(theUMin, theVMax), aTol); + size_t aV00 = addSurfaceVertex(theBoundary, theSurface->EvalD0(theUMin, theVMin), aTol); + size_t aV10 = addSurfaceVertex(theBoundary, theSurface->EvalD0(theUMax, theVMin), aTol); + size_t aV11 = addSurfaceVertex(theBoundary, theSurface->EvalD0(theUMax, theVMax), aTol); + size_t aV01 = addSurfaceVertex(theBoundary, theSurface->EvalD0(theUMin, theVMax), aTol); if (isUClosed) { diff --git a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.cxx b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.cxx index 18c4f17265..6495af5afa 100644 --- a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.cxx +++ b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -128,8 +129,7 @@ void BRepGraphInc_Reconstruct::Cache::Bind(const BRepGraph_NodeId theNode, //================================================================================================= -TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, - const BRepGraph_NodeId theNode) +TopoDS_Shape BRepGraphInc_Reconstruct::Node(BRepGraph& theGraph, const BRepGraph_NodeId theNode) { Cache aCache; return Node(theGraph, theNode, aCache); @@ -137,7 +137,7 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, //================================================================================================= -TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, +TopoDS_Shape BRepGraphInc_Reconstruct::Node(BRepGraph& theGraph, const BRepGraph_NodeId theNode, Cache& theCache) { @@ -176,14 +176,15 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, const BRepGraphInc::EdgeDef& anEdge = aStorage.Edge(BRepGraph_EdgeId(theNode)); TopoDS_Edge aNewEdge; - BRepGraph_CacheDerivedState::EdgeEntry anEdgeEntry; - [[maybe_unused]] const bool isEdgeStateComputed = - BRepGraph_CacheDerivedState::ComputeEdgeStatus(theGraph, - BRepGraph_EdgeId(theNode), - anEdgeEntry); + bool anIsDegenerated = false; + bool anIsClosed = false; + [[maybe_unused]] const bool isEdgeStateComputed = + BRepGraph_CacheDerivedState::ComputeEdgeProperties(theGraph, + BRepGraph_EdgeId(theNode), + anIsDegenerated, + anIsClosed); - if (anEdgeEntry.Status - == BRepGraph_CacheDerivedState::EdgeGeometryStatus::DegenerateOnSurface) + if (anIsDegenerated) { aBB.MakeEdge(aNewEdge); aBB.Degenerated(aNewEdge, true); @@ -219,8 +220,30 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, aParamLast = aUse.ParamLast; } aBB.Range(aNewEdge, aParamFirst, aParamLast); - aBB.SameParameter(aNewEdge, anEdgeEntry.SameParameter); - aBB.SameRange(aNewEdge, anEdgeEntry.SameRange); + + // SameRange/SameParameter are per-CoEdge properties. + // Set edge-level flags: true only if ALL coedges agree. + auto aCache = theGraph.CacheRegistry().Ensure(); + bool aSameRange = true; + bool aSameParameter = true; + const BRepGraphInc::EdgeRelations& anEdgeRel = + aStorage.EdgeRelations(BRepGraph_EdgeId(theNode)); + for (const BRepGraph_CoEdgeId& aCoEdgeId : anEdgeRel.CoEdgeIds) + { + if (aCoEdgeId.IsValid(aStorage.NbCoEdges()) && !aStorage.IsRemoved(aCoEdgeId)) + { + if (!aCache->SameRange(aCoEdgeId)) + { + aSameRange = false; + } + if (!aCache->SameParameter(aCoEdgeId)) + { + aSameParameter = false; + } + } + } + aBB.SameParameter(aNewEdge, aSameParameter); + aBB.SameRange(aNewEdge, aSameRange); if (anEdge.StartVertexRefId.IsValid()) { @@ -254,7 +277,7 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, aBB.UpdateEdge(aNewEdge, aPolygon3D, TopLoc_Location()); } } - if (anEdgeEntry.IsClosed) + if (anIsClosed) { aNewEdge.Closed(true); } @@ -326,11 +349,7 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, aBB.Add(aNewShell, aFace); } } - BRepGraph_CacheDerivedState::ShellEntry aShellEntry; - if (BRepGraph_CacheDerivedState::ComputeShellStatus(theGraph, - BRepGraph_ShellId(theNode), - aShellEntry) - && aShellEntry.Status == BRepGraph_CacheDerivedState::ShellClosureStatus::Closed) + if (BRepGraph_CacheDerivedState::ComputeShellIsClosed(theGraph, BRepGraph_ShellId(theNode))) { aNewShell.Closed(true); } @@ -441,7 +460,7 @@ TopoDS_Shape BRepGraphInc_Reconstruct::Node(const BRepGraph& theGraph, //================================================================================================= -TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theGraph, +TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(BRepGraph& theGraph, const BRepGraph_FaceId theFaceId, Cache& theCache) { @@ -516,11 +535,15 @@ TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theG const BRepGraphInc::EdgeDef& anEdge = aStorage.Edge(theEdgeId); TopoDS_Edge aNewEdge; - BRepGraph_CacheDerivedState::EdgeEntry anEdgeEntry; - [[maybe_unused]] const bool isEdgeStateComputed = - BRepGraph_CacheDerivedState::ComputeEdgeStatus(theGraph, theEdgeId, anEdgeEntry); + bool anIsDegenerated = false; + bool anIsClosed = false; + [[maybe_unused]] const bool isEdgeStateComputed = + BRepGraph_CacheDerivedState::ComputeEdgeProperties(theGraph, + theEdgeId, + anIsDegenerated, + anIsClosed); - if (anEdgeEntry.Status == BRepGraph_CacheDerivedState::EdgeGeometryStatus::DegenerateOnSurface) + if (anIsDegenerated) { aBB.MakeEdge(aNewEdge); aBB.Degenerated(aNewEdge, true); @@ -544,8 +567,31 @@ TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theG { aBB.MakeEdge(aNewEdge); } - aBB.SameParameter(aNewEdge, anEdgeEntry.SameParameter); - aBB.SameRange(aNewEdge, anEdgeEntry.SameRange); + + // SameRange/SameParameter are per-CoEdge properties. + // Set edge-level flags: true only if ALL coedges agree. + { + auto aCache = theGraph.CacheRegistry().Ensure(); + bool aSameRange = true; + bool aSameParameter = true; + const BRepGraphInc::EdgeRelations& anEdgeRel = aStorage.EdgeRelations(theEdgeId); + for (const BRepGraph_CoEdgeId& aCoEdgeId : anEdgeRel.CoEdgeIds) + { + if (aCoEdgeId.IsValid(aStorage.NbCoEdges()) && !aStorage.IsRemoved(aCoEdgeId)) + { + if (!aCache->SameRange(aCoEdgeId)) + { + aSameRange = false; + } + if (!aCache->SameParameter(aCoEdgeId)) + { + aSameParameter = false; + } + } + } + aBB.SameParameter(aNewEdge, aSameParameter); + aBB.SameRange(aNewEdge, aSameRange); + } // Vertices (also cached). const auto aGetOrBuildVertex = [&](const BRepGraph_VertexId theVtxId) -> TopoDS_Shape { @@ -600,7 +646,7 @@ TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theG } } - if (anEdgeEntry.IsClosed) + if (anIsClosed) { aNewEdge.Closed(true); } @@ -740,8 +786,8 @@ TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theG if (!aPC1.IsNull() && !aPC2.IsNull()) { - gp_Pnt2d aUV1 = aPC1->Value(aPCFirst); - gp_Pnt2d aUV2 = aPC1->Value(aPCLast); + gp_Pnt2d aUV1 = aPC1->EvalD0(aPCFirst); + gp_Pnt2d aUV2 = aPC1->EvalD0(aPCLast); aBB.UpdateEdge(anEdge, aPC1, aPC2, @@ -754,8 +800,8 @@ TopoDS_Shape BRepGraphInc_Reconstruct::FaceWithCache(const BRepGraph& theG } else if (!aPC1.IsNull()) { - gp_Pnt2d aUV1 = aPC1->Value(aPCFirst); - gp_Pnt2d aUV2 = aPC1->Value(aPCLast); + gp_Pnt2d aUV1 = aPC1->EvalD0(aPCFirst); + gp_Pnt2d aUV2 = aPC1->EvalD0(aPCLast); aBB.UpdateEdge(anEdge, aPC1, aFaceSurface, diff --git a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.hxx b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.hxx index 7ab3d22189..b6b4048924 100644 --- a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.hxx +++ b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Reconstruct.hxx @@ -77,8 +77,7 @@ public: //! @param[in] theGraph graph owning the storage and caches //! @param[in] theNode entity node id //! @return reconstructed shape - static Standard_EXPORT TopoDS_Shape Node(const BRepGraph& theGraph, - const BRepGraph_NodeId theNode); + static Standard_EXPORT TopoDS_Shape Node(BRepGraph& theGraph, const BRepGraph_NodeId theNode); //! Reconstruct a TopoDS_Shape with a shared cache for sub-shape reuse. //! Vertices and edges already in theCache are returned directly. @@ -86,7 +85,7 @@ public: //! @param[in] theNode entity node id //! @param[in,out] theCache shared cache for vertex/edge/face shapes //! @return reconstructed shape - static Standard_EXPORT TopoDS_Shape Node(const BRepGraph& theGraph, + static Standard_EXPORT TopoDS_Shape Node(BRepGraph& theGraph, const BRepGraph_NodeId theNode, Cache& theCache); @@ -95,7 +94,7 @@ public: //! @param[in] theFaceId face entity id //! @param[in,out] theCache shared cache for edge and vertex shapes //! @return reconstructed face shape - static Standard_EXPORT TopoDS_Shape FaceWithCache(const BRepGraph& theGraph, + static Standard_EXPORT TopoDS_Shape FaceWithCache(BRepGraph& theGraph, const BRepGraph_FaceId theFaceId, Cache& theCache); diff --git a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.cxx b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.cxx index 858e426592..605bf5623e 100644 --- a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.cxx +++ b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.cxx @@ -93,6 +93,14 @@ void appendUniqueRelationId(NCollection_LinearVector& theIds, const IdT the } } +// Unchecked append for rebuild paths where duplicates are structurally impossible +// (each source ref is processed exactly once after vectors are cleared). +template +void appendRelationIdDirect(NCollection_LinearVector& theIds, const IdT theId) +{ + theIds.Append(theId); +} + template bool eraseRelationId(NCollection_LinearVector& theIds, const IdT theId) { @@ -995,11 +1003,7 @@ void BRepGraphInc_Storage::SetHasOccurrenceParent(const BRepGraph_NodeId theNode NCollection_LinearVector& BRepGraphInc_Storage:: ChangeCompoundRefsOfNodeInternal(const BRepGraph_NodeId theNode) { - if (!myNodeToCompounds.IsBound(theNode)) - { - myNodeToCompounds.Bind(theNode, NCollection_LinearVector()); - } - return *myNodeToCompounds.ChangeSeek(theNode); + return myNodeToCompounds.TryBound(theNode, NCollection_LinearVector()); } //================================================================================================= @@ -1007,11 +1011,8 @@ NCollection_LinearVector& BRepGraphInc_Storage:: NCollection_LinearVector& BRepGraphInc_Storage:: ChangeOccurrenceRefsOfNodeInternal(const BRepGraph_NodeId theNode) { - if (!myNodeToOccurrences.IsBound(theNode)) - { - myNodeToOccurrences.Bind(theNode, NCollection_LinearVector()); - } - return *myNodeToOccurrences.ChangeSeek(theNode); + return myNodeToOccurrences.TryBound(theNode, + NCollection_LinearVector()); } //================================================================================================= @@ -1030,6 +1031,31 @@ void BRepGraphInc_Storage::RebuildDerivedRelationsPreservingActiveCounts() //================================================================================================= +void BRepGraphInc_Storage::CopyRemovedFlagsFrom(const BRepGraphInc_Storage& theSource) +{ + myVertices.RemovedFlags = theSource.myVertices.RemovedFlags; + myEdges.RemovedFlags = theSource.myEdges.RemovedFlags; + myCoEdges.RemovedFlags = theSource.myCoEdges.RemovedFlags; + myWires.RemovedFlags = theSource.myWires.RemovedFlags; + myFaces.RemovedFlags = theSource.myFaces.RemovedFlags; + myShells.RemovedFlags = theSource.myShells.RemovedFlags; + mySolids.RemovedFlags = theSource.mySolids.RemovedFlags; + myCompounds.RemovedFlags = theSource.myCompounds.RemovedFlags; + myCompSolids.RemovedFlags = theSource.myCompSolids.RemovedFlags; + myProducts.RemovedFlags = theSource.myProducts.RemovedFlags; + myOccurrences.RemovedFlags = theSource.myOccurrences.RemovedFlags; + + myShellRefs.RemovedFlags = theSource.myShellRefs.RemovedFlags; + myFaceRefs.RemovedFlags = theSource.myFaceRefs.RemovedFlags; + myWireRefs.RemovedFlags = theSource.myWireRefs.RemovedFlags; + myVertexRefs.RemovedFlags = theSource.myVertexRefs.RemovedFlags; + mySolidRefs.RemovedFlags = theSource.mySolidRefs.RemovedFlags; + myChildRefs.RemovedFlags = theSource.myChildRefs.RemovedFlags; + myOccurrenceRefs.RemovedFlags = theSource.myOccurrenceRefs.RemovedFlags; +} + +//================================================================================================= + void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecountActiveCounts) { prepareRelationTable(myVertexRelations, NbVertices()); @@ -1176,7 +1202,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount const BRepGraph_VertexId aVertexId = VertexRef(aStartRefId).ChildVertexId; if (aVertexId.IsValid(NbVertices()) && !IsRemoved(aVertexId)) { - appendUniqueRelationId(ChangeVertexRelationsInternal(aVertexId).EdgeIds, anEdgeId); + appendRelationIdDirect(ChangeVertexRelationsInternal(aVertexId).EdgeIds, anEdgeId); } } @@ -1186,7 +1212,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount const BRepGraph_VertexId aVertexId = VertexRef(anEndRefId).ChildVertexId; if (aVertexId.IsValid(NbVertices()) && !IsRemoved(aVertexId)) { - appendUniqueRelationId(ChangeVertexRelationsInternal(aVertexId).EdgeIds, anEdgeId); + appendRelationIdDirect(ChangeVertexRelationsInternal(aVertexId).EdgeIds, anEdgeId); } } } @@ -1201,7 +1227,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount if (aCoEdge.ChildEdgeId.IsValid(NbEdges()) && !IsRemoved(aCoEdge.ChildEdgeId)) { BRepGraphInc::EdgeRelations& anEdgeRel = ChangeEdgeRelationsInternal(aCoEdge.ChildEdgeId); - appendUniqueRelationId(anEdgeRel.CoEdgeIds, aCoEdgeId); + appendRelationIdDirect(anEdgeRel.CoEdgeIds, aCoEdgeId); } } @@ -1223,7 +1249,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount { continue; } - appendUniqueRelationId(ChangeWireRelationsInternal(aWireId).ParentWireRefIds, aWireRefId); + appendRelationIdDirect(ChangeWireRelationsInternal(aWireId).ParentWireRefIds, aWireRefId); } } @@ -1245,7 +1271,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount { continue; } - appendUniqueRelationId(ChangeFaceRelationsInternal(aFaceId).ParentFaceRefIds, aFaceRefId); + appendRelationIdDirect(ChangeFaceRelationsInternal(aFaceId).ParentFaceRefIds, aFaceRefId); } } @@ -1267,7 +1293,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount { continue; } - appendUniqueRelationId(ChangeShellRelationsInternal(aShellId).ParentShellRefIds, aShellRefId); + appendRelationIdDirect(ChangeShellRelationsInternal(aShellId).ParentShellRefIds, aShellRefId); } } @@ -1287,7 +1313,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount const BRepGraph_NodeId aChildNode = ChildRef(aChildRefId).ChildNodeId; if (aChildNode.IsValid() && !isNodeRemoved(*this, aChildNode)) { - appendUniqueRelationId(ChangeCompoundRefsOfNodeInternal(aChildNode), aChildRefId); + appendRelationIdDirect(ChangeCompoundRefsOfNodeInternal(aChildNode), aChildRefId); } } } @@ -1310,7 +1336,7 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount { continue; } - appendUniqueRelationId(ChangeSolidRelationsInternal(aSolidId).ParentSolidRefIds, aSolidRefId); + appendRelationIdDirect(ChangeSolidRelationsInternal(aSolidId).ParentSolidRefIds, aSolidRefId); } } @@ -1333,13 +1359,13 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount { continue; } - appendUniqueRelationId( + appendRelationIdDirect( ChangeOccurrenceRelationsInternal(anOccurrenceId).ParentOccurrenceRefIds, anOccurrenceRefId); const BRepGraph_NodeId aChildNode = Occurrence(anOccurrenceId).ChildNodeId; if (aChildNode.IsValid() && !isNodeRemoved(*this, aChildNode)) { - appendUniqueRelationId(ChangeOccurrenceRefsOfNodeInternal(aChildNode), anOccurrenceRefId); + appendRelationIdDirect(ChangeOccurrenceRefsOfNodeInternal(aChildNode), anOccurrenceRefId); } } } @@ -1376,6 +1402,137 @@ void BRepGraphInc_Storage::rebuildDerivedRelationsInternal(const bool theRecount //================================================================================================= +void BRepGraphInc_Storage::CopyDerivedRelationsFrom(const BRepGraphInc_Storage& theSource) +{ + prepareRelationTable(myVertexRelations, NbVertices()); + prepareRelationTable(myEdgeRelations, NbEdges()); + prepareRelationTable(myWireRelations, NbWires()); + prepareRelationTable(myFaceRelations, NbFaces()); + prepareRelationTable(myShellRelations, NbShells()); + prepareRelationTable(mySolidRelations, NbSolids()); + prepareRelationTable(myCompoundRelations, NbCompounds()); + prepareRelationTable(myCompSolidRelations, NbCompSolids()); + prepareRelationTable(myProductRelations, NbProducts()); + prepareRelationTable(myOccurrenceRelations, NbOccurrences()); + + for (BRepGraph_VertexId aV(0); aV.IsValid(NbVertices()); ++aV) + { + if (aV.IsValid(theSource.NbVertices())) + ChangeVertexRelationsInternal(aV).EdgeIds = theSource.VertexRelations(aV).EdgeIds; + } + for (BRepGraph_EdgeId anE(0); anE.IsValid(NbEdges()); ++anE) + { + if (anE.IsValid(theSource.NbEdges())) + ChangeEdgeRelationsInternal(anE).CoEdgeIds = theSource.EdgeRelations(anE).CoEdgeIds; + } + for (BRepGraph_WireId aW(0); aW.IsValid(NbWires()); ++aW) + { + if (aW.IsValid(theSource.NbWires())) + { + ChangeWireRelationsInternal(aW).CoEdgeIds = theSource.WireRelations(aW).CoEdgeIds; + ChangeWireRelationsInternal(aW).ParentWireRefIds = + theSource.WireRelations(aW).ParentWireRefIds; + } + } + for (BRepGraph_FaceId aF(0); aF.IsValid(NbFaces()); ++aF) + { + if (aF.IsValid(theSource.NbFaces())) + { + ChangeFaceRelationsInternal(aF).WireRefIds = theSource.FaceRelations(aF).WireRefIds; + ChangeFaceRelationsInternal(aF).ParentFaceRefIds = + theSource.FaceRelations(aF).ParentFaceRefIds; + } + } + for (BRepGraph_ShellId aS(0); aS.IsValid(NbShells()); ++aS) + { + if (aS.IsValid(theSource.NbShells())) + { + ChangeShellRelationsInternal(aS).FaceRefIds = theSource.ShellRelations(aS).FaceRefIds; + ChangeShellRelationsInternal(aS).ParentShellRefIds = + theSource.ShellRelations(aS).ParentShellRefIds; + } + } + for (BRepGraph_SolidId aS(0); aS.IsValid(NbSolids()); ++aS) + { + if (aS.IsValid(theSource.NbSolids())) + { + ChangeSolidRelationsInternal(aS).ShellRefIds = theSource.SolidRelations(aS).ShellRefIds; + ChangeSolidRelationsInternal(aS).ParentSolidRefIds = + theSource.SolidRelations(aS).ParentSolidRefIds; + } + } + for (BRepGraph_CompSolidId aCS(0); aCS.IsValid(NbCompSolids()); ++aCS) + { + if (aCS.IsValid(theSource.NbCompSolids())) + ChangeCompSolidRelationsInternal(aCS).SolidRefIds = + theSource.CompSolidRelations(aCS).SolidRefIds; + } + for (BRepGraph_CompoundId aC(0); aC.IsValid(NbCompounds()); ++aC) + { + if (aC.IsValid(theSource.NbCompounds())) + ChangeCompoundRelationsInternal(aC).ChildRefIds = theSource.CompoundRelations(aC).ChildRefIds; + } + for (BRepGraph_ProductId aP(0); aP.IsValid(NbProducts()); ++aP) + { + if (aP.IsValid(theSource.NbProducts())) + ChangeProductRelationsInternal(aP).OccurrenceRefIds = + theSource.ProductRelations(aP).OccurrenceRefIds; + } + for (BRepGraph_OccurrenceId anO(0); anO.IsValid(NbOccurrences()); ++anO) + { + if (anO.IsValid(theSource.NbOccurrences())) + ChangeOccurrenceRelationsInternal(anO).ParentOccurrenceRefIds = + theSource.OccurrenceRelations(anO).ParentOccurrenceRefIds; + } + + // Copy sparse reverse maps (node -> compound/occurrence child refs). + myNodeToCompounds.Clear(); + for (NCollection_DataMap>::Iterator + anIt(theSource.myNodeToCompounds); + anIt.More(); + anIt.Next()) + { + myNodeToCompounds.Bind(anIt.Key(), anIt.Value()); + } + myNodeToOccurrences.Clear(); + for (NCollection_DataMap>::Iterator + anIt(theSource.myNodeToOccurrences); + anIt.More(); + anIt.Next()) + { + myNodeToOccurrences.Bind(anIt.Key(), anIt.Value()); + } + + // Copy compound/occurrence parent bit-planes for all node kinds. + // These are indexed by the same type IDs in source and destination (identity copy). + myVertices.HasCompoundParentFlags = theSource.myVertices.HasCompoundParentFlags; + myVertices.HasOccurrenceParentFlags = theSource.myVertices.HasOccurrenceParentFlags; + myEdges.HasCompoundParentFlags = theSource.myEdges.HasCompoundParentFlags; + myEdges.HasOccurrenceParentFlags = theSource.myEdges.HasOccurrenceParentFlags; + myCoEdges.HasCompoundParentFlags = theSource.myCoEdges.HasCompoundParentFlags; + myCoEdges.HasOccurrenceParentFlags = theSource.myCoEdges.HasOccurrenceParentFlags; + myWires.HasCompoundParentFlags = theSource.myWires.HasCompoundParentFlags; + myWires.HasOccurrenceParentFlags = theSource.myWires.HasOccurrenceParentFlags; + myFaces.HasCompoundParentFlags = theSource.myFaces.HasCompoundParentFlags; + myFaces.HasOccurrenceParentFlags = theSource.myFaces.HasOccurrenceParentFlags; + myShells.HasCompoundParentFlags = theSource.myShells.HasCompoundParentFlags; + myShells.HasOccurrenceParentFlags = theSource.myShells.HasOccurrenceParentFlags; + mySolids.HasCompoundParentFlags = theSource.mySolids.HasCompoundParentFlags; + mySolids.HasOccurrenceParentFlags = theSource.mySolids.HasOccurrenceParentFlags; + myCompounds.HasCompoundParentFlags = theSource.myCompounds.HasCompoundParentFlags; + myCompounds.HasOccurrenceParentFlags = theSource.myCompounds.HasOccurrenceParentFlags; + myCompSolids.HasCompoundParentFlags = theSource.myCompSolids.HasCompoundParentFlags; + myCompSolids.HasOccurrenceParentFlags = theSource.myCompSolids.HasOccurrenceParentFlags; + myProducts.HasCompoundParentFlags = theSource.myProducts.HasCompoundParentFlags; + myProducts.HasOccurrenceParentFlags = theSource.myProducts.HasOccurrenceParentFlags; + myOccurrences.HasCompoundParentFlags = theSource.myOccurrences.HasCompoundParentFlags; + myOccurrences.HasOccurrenceParentFlags = theSource.myOccurrences.HasOccurrenceParentFlags; +} + +//================================================================================================= + bool BRepGraphInc_Storage::ValidateRelations() const { for (BRepGraph_CoEdgeId aCoEdgeId(0); aCoEdgeId.IsValid(NbCoEdges()); ++aCoEdgeId) @@ -2587,12 +2744,12 @@ void BRepGraphInc_Storage::ClearUIDIndexes() { std::unique_lock aLock(myUIDToNodeIdMutex); myUIDToNodeId.Clear(); - myUIDToNodeIdDirty = false; + myUIDToNodeIdDirty.store(false, std::memory_order_relaxed); } { std::unique_lock aLock(myRefUIDToRefIdMutex); myRefUIDToRefId.Clear(); - myRefUIDToRefIdDirty = false; + myRefUIDToRefIdDirty.store(false, std::memory_order_relaxed); } } @@ -2613,6 +2770,20 @@ void BRepGraphInc_Storage::ClearCurrentShapes() //================================================================================================= +void BRepGraphInc_Storage::CopyShapeBindingsFrom(const BRepGraphInc_Storage& theSource) +{ + theSource.ForEachTShapeBinding( + [this](const TopoDS_TShape* aTShape, const BRepGraph_NodeId aNodeId) { + myTShapeToNodeId.Bind(aTShape, aNodeId); + }); + theSource.ForEachOriginalBinding( + [this](const BRepGraph_NodeId aNodeId, const TopoDS_Shape& aShape) { + myOriginalShapes.Bind(aNodeId, aShape); + }); +} + +//================================================================================================= + void BRepGraphInc_Storage::UnbindCurrentShape(const BRepGraph_NodeId theNode) { std::unique_lock aLock(myCurrentShapesMutex); @@ -2741,7 +2912,11 @@ void BRepGraphInc_Storage::Clear() void BRepGraphInc_Storage::PrepareForLoad(const BRepGraphInc_Load::Counts& theCounts) { - Clear(); + // Skip full Clear() when storage is already empty - avoids allocator reset + reallocation. + if (!IsEmpty()) + { + Clear(); + } prepareDefStore(myVertices, theCounts.NbVertices, myAllocator); prepareDefStore(myEdges, theCounts.NbEdges, myAllocator); @@ -2785,6 +2960,72 @@ void BRepGraphInc_Storage::PrepareForLoad(const BRepGraphInc_Load::Counts& theCo //================================================================================================= +BRepGraphInc_Load::Counts BRepGraphInc_Storage::Counts() const +{ + BRepGraphInc_Load::Counts aCounts; + aCounts.NbVertices = NbVertices(); + aCounts.NbEdges = NbEdges(); + aCounts.NbCoEdges = NbCoEdges(); + aCounts.NbWires = NbWires(); + aCounts.NbFaces = NbFaces(); + aCounts.NbShells = NbShells(); + aCounts.NbSolids = NbSolids(); + aCounts.NbCompounds = NbCompounds(); + aCounts.NbCompSolids = NbCompSolids(); + aCounts.NbProducts = NbProducts(); + aCounts.NbOccurrences = NbOccurrences(); + aCounts.NbShellRefs = NbShellRefs(); + aCounts.NbFaceRefs = NbFaceRefs(); + aCounts.NbWireRefs = NbWireRefs(); + aCounts.NbVertexRefs = NbVertexRefs(); + aCounts.NbSolidRefs = NbSolidRefs(); + aCounts.NbChildRefs = NbChildRefs(); + aCounts.NbOccurrenceRefs = NbOccurrenceRefs(); + aCounts.NbFaceSurfaceReps = NbFaceSurfaces(); + aCounts.NbEdgeCurve3DReps = NbEdgeCurves3D(); + aCounts.NbCoEdgeCurve2DReps = NbCoEdgeCurves2D(); + aCounts.NbFaceTriangulationReps = NbFaceTriangulations(); + aCounts.NbEdgePolygon3DReps = NbEdgePolygons3D(); + aCounts.NbCoEdgePolygon2DReps = NbCoEdgePolygons2D(); + aCounts.NbCoEdgePolygonOnTriReps = NbCoEdgePolygonsOnTri(); + return aCounts; +} + +//================================================================================================= + +BRepGraphInc_Load::Counts BRepGraphInc_Storage::ActiveCounts() const +{ + BRepGraphInc_Load::Counts aCounts; + aCounts.NbVertices = NbActiveVertices(); + aCounts.NbEdges = NbActiveEdges(); + aCounts.NbCoEdges = NbActiveCoEdges(); + aCounts.NbWires = NbActiveWires(); + aCounts.NbFaces = NbActiveFaces(); + aCounts.NbShells = NbActiveShells(); + aCounts.NbSolids = NbActiveSolids(); + aCounts.NbCompounds = NbActiveCompounds(); + aCounts.NbCompSolids = NbActiveCompSolids(); + aCounts.NbProducts = NbActiveProducts(); + aCounts.NbOccurrences = NbActiveOccurrences(); + aCounts.NbShellRefs = NbActiveShellRefs(); + aCounts.NbFaceRefs = NbActiveFaceRefs(); + aCounts.NbWireRefs = NbActiveWireRefs(); + aCounts.NbVertexRefs = NbActiveVertexRefs(); + aCounts.NbSolidRefs = NbActiveSolidRefs(); + aCounts.NbChildRefs = NbActiveChildRefs(); + aCounts.NbOccurrenceRefs = NbActiveOccurrenceRefs(); + aCounts.NbFaceSurfaceReps = NbActiveFaceSurfaces(); + aCounts.NbEdgeCurve3DReps = NbActiveEdgeCurves3D(); + aCounts.NbCoEdgeCurve2DReps = NbActiveCoEdgeCurves2D(); + aCounts.NbFaceTriangulationReps = NbActiveFaceTriangulations(); + aCounts.NbEdgePolygon3DReps = NbActiveEdgePolygons3D(); + aCounts.NbCoEdgePolygon2DReps = NbActiveCoEdgePolygons2D(); + aCounts.NbCoEdgePolygonOnTriReps = NbActiveCoEdgePolygonsOnTri(); + return aCounts; +} + +//================================================================================================= + void BRepGraphInc_Storage::SetActiveCounts(const BRepGraphInc_Load::Counts& theCounts) { myVertices.NbActive = theCounts.NbVertices; @@ -3047,12 +3288,12 @@ void BRepGraphInc_Storage::MarkUIDReverseIndexesDirty() { std::unique_lock aLock(myUIDToNodeIdMutex); myUIDToNodeId.Clear(); - myUIDToNodeIdDirty = true; + myUIDToNodeIdDirty.store(true, std::memory_order_release); } { std::unique_lock aLock(myRefUIDToRefIdMutex); myRefUIDToRefId.Clear(); - myRefUIDToRefIdDirty = true; + myRefUIDToRefIdDirty.store(true, std::memory_order_release); } } @@ -3060,8 +3301,14 @@ void BRepGraphInc_Storage::MarkUIDReverseIndexesDirty() void BRepGraphInc_Storage::EnsureUIDReverseIndex() const { + // Lock-free fast path: skip if not dirty. + if (!myUIDToNodeIdDirty.load(std::memory_order_acquire)) + { + return; + } + std::unique_lock aLock(myUIDToNodeIdMutex); - if (!myUIDToNodeIdDirty) + if (!myUIDToNodeIdDirty.load(std::memory_order_relaxed)) { return; } @@ -3181,15 +3428,21 @@ void BRepGraphInc_Storage::EnsureUIDReverseIndex() const break; } } - myUIDToNodeIdDirty = false; + myUIDToNodeIdDirty.store(false, std::memory_order_release); } //================================================================================================= void BRepGraphInc_Storage::EnsureRefUIDReverseIndex() const { + // Lock-free fast path: skip if not dirty. + if (!myRefUIDToRefIdDirty.load(std::memory_order_acquire)) + { + return; + } + std::unique_lock aLock(myRefUIDToRefIdMutex); - if (!myRefUIDToRefIdDirty) + if (!myRefUIDToRefIdDirty.load(std::memory_order_relaxed)) { return; } @@ -3279,7 +3532,7 @@ void BRepGraphInc_Storage::EnsureRefUIDReverseIndex() const break; } } - myRefUIDToRefIdDirty = false; + myRefUIDToRefIdDirty.store(false, std::memory_order_release); } //================================================================================================= diff --git a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.hxx b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.hxx index cfd551d43b..fbc0119f6f 100644 --- a/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.hxx +++ b/src/ModelingData/TKBRep/BRepGraphInc/BRepGraphInc_Storage.hxx @@ -1289,6 +1289,10 @@ public: } } + //! Copy TShape-to-NodeId and Original shape bindings from another storage. + //! Used by identity copy to preserve shape reconstruction bindings. + Standard_EXPORT void CopyShapeBindingsFrom(const BRepGraphInc_Storage& theSource); + //! Return the generation-validated node-to-shape reconstruction cache. [[nodiscard]] const NCollection_FlatDataMap& CurrentShapes() const { @@ -1334,6 +1338,12 @@ public: //! @param theCounts trusted active per-section counts. Standard_EXPORT void SetActiveCounts(const BRepGraphInc_Load::Counts& theCounts); + //! Build a Counts struct from current allocated slot counts. + [[nodiscard]] Standard_EXPORT BRepGraphInc_Load::Counts Counts() const; + + //! Build a Counts struct from current active (non-removed) counts. + [[nodiscard]] Standard_EXPORT BRepGraphInc_Load::Counts ActiveCounts() const; + //! Recount active-slot counters from current `IsRemoved` flags without rebuilding indexes. Standard_EXPORT void RecountActiveCounts(); @@ -1345,6 +1355,10 @@ public: //! Rebuild relation maps after a trusted load already restored active counts. Standard_EXPORT void RebuildDerivedRelationsPreservingActiveCounts(); + //! Bulk-copy all RemovedFlags bit-planes from theSource. + //! Source must have been loaded with the same entity counts (identity copy path). + Standard_EXPORT void CopyRemovedFlagsFrom(const BRepGraphInc_Storage& theSource); + //! Debug: verify relation-table consistency against entity/reference endpoints. //! @return true if all relations are consistent Standard_EXPORT bool ValidateRelations() const; @@ -1393,6 +1407,10 @@ public: //! Lazily rebuild the reference UID reverse index if it is stale. Standard_EXPORT void EnsureRefUIDReverseIndex() const; + //! Copy all forward/reverse relation vectors directly from theSource. + //! Used by identity copy to avoid the clear+rebuild cycle. + Standard_EXPORT void CopyDerivedRelationsFrom(const BRepGraphInc_Storage& theSource); + private: friend class BRepGraphInc_Populate; friend class BRepGraph; @@ -1868,8 +1886,8 @@ private: mutable std::shared_mutex myUIDToNodeIdMutex; mutable NCollection_FlatDataMap myRefUIDToRefId; mutable std::shared_mutex myRefUIDToRefIdMutex; - mutable bool myUIDToNodeIdDirty = false; - mutable bool myRefUIDToRefIdDirty = false; + mutable std::atomic myUIDToNodeIdDirty{false}; + mutable std::atomic myRefUIDToRefIdDirty{false}; //! Bindings from reconstructed / source OCCT shapes back to backend ids. NCollection_FlatDataMap myTShapeToNodeId; diff --git a/src/ModelingData/TKBRep/GTests/BRepGraphInc_Test.cxx b/src/ModelingData/TKBRep/GTests/BRepGraphInc_Test.cxx index 17004bd8a1..d36c5b3f02 100644 --- a/src/ModelingData/TKBRep/GTests/BRepGraphInc_Test.cxx +++ b/src/ModelingData/TKBRep/GTests/BRepGraphInc_Test.cxx @@ -493,10 +493,14 @@ TEST(BRepGraphIncTest, Box_Relations_EdgesToFaces) for (BRepGraph_EdgeId anEdgeId(0); anEdgeId.IsValid(aNbEdges); ++anEdgeId) { // Skip degenerate edges (e.g. sphere poles with no 3D curve). - BRepGraph_CacheDerivedState::EdgeEntry anEdgeState; - [[maybe_unused]] const bool isEdgeStateComputed = - BRepGraph_CacheDerivedState::ComputeEdgeStatus(aGraph, anEdgeId, anEdgeState); - if (anEdgeState.Status == BRepGraph_CacheDerivedState::EdgeGeometryStatus::DegenerateOnSurface) + bool anIsDegenerated = false; + bool anIsClosed = false; + [[maybe_unused]] const bool isEdgeStateComputed = + BRepGraph_CacheDerivedState::ComputeEdgeProperties(aGraph, + anEdgeId, + anIsDegenerated, + anIsClosed); + if (anIsDegenerated) { continue; } @@ -688,11 +692,15 @@ TEST(BRepGraphIncTest, Sphere_DegenerateEdges_Preserved) const uint32_t aNbEdges = aGraph.Topo().Edges().Nb(); for (BRepGraph_EdgeId anEdgeId(0); anEdgeId.IsValid(aNbEdges); ++anEdgeId) { - const BRepGraphInc::EdgeDef& anEdge = aGraph.Topo().Edges().Definition(anEdgeId); - BRepGraph_CacheDerivedState::EdgeEntry anEdgeState; - [[maybe_unused]] const bool isEdgeStateComputed = - BRepGraph_CacheDerivedState::ComputeEdgeStatus(aGraph, anEdgeId, anEdgeState); - if (anEdgeState.Status == BRepGraph_CacheDerivedState::EdgeGeometryStatus::DegenerateOnSurface) + const BRepGraphInc::EdgeDef& anEdge = aGraph.Topo().Edges().Definition(anEdgeId); + bool anIsDegenerated = false; + bool anIsClosed = false; + [[maybe_unused]] const bool isEdgeStateComputed = + BRepGraph_CacheDerivedState::ComputeEdgeProperties(aGraph, + anEdgeId, + anIsDegenerated, + anIsClosed); + if (anIsDegenerated) { ++aDegenerateCount; EXPECT_FALSE(anEdge.Curve3DRepId.IsValid()) diff --git a/src/ModelingData/TKBRep/GTests/BRepGraph_Copy_Test.cxx b/src/ModelingData/TKBRep/GTests/BRepGraph_Copy_Test.cxx index 37662fc0e0..4d8727fcb0 100644 --- a/src/ModelingData/TKBRep/GTests/BRepGraph_Copy_Test.cxx +++ b/src/ModelingData/TKBRep/GTests/BRepGraph_Copy_Test.cxx @@ -61,6 +61,32 @@ namespace { +bool edgeSameParameter(const BRepGraph& theGraph, BRepGraph_EdgeId theEdge) +{ + const auto& aRel = theGraph.Topo().Edges().Relations(theEdge); + for (const auto& aCoEdgeId : aRel.CoEdgeIds) + { + if (!BRepGraph_Tool::CoEdge::SameParameter(theGraph, aCoEdgeId)) + { + return false; + } + } + return true; +} + +bool edgeSameRange(const BRepGraph& theGraph, BRepGraph_EdgeId theEdge) +{ + const auto& aRel = theGraph.Topo().Edges().Relations(theEdge); + for (const auto& aCoEdgeId : aRel.CoEdgeIds) + { + if (!BRepGraph_Tool::CoEdge::SameRange(theGraph, aCoEdgeId)) + { + return false; + } + } + return true; +} + class CopyTestCacheService : public BRepGraph_Cache { public: @@ -940,9 +966,9 @@ TEST(BRepGraph_CopyTest, CopyBox_SameParameter_Preserved) const uint32_t aNbEdges = aCopyGraph.Topo().Edges().Nb(); for (BRepGraph_EdgeId anEdgeId(0); anEdgeId.IsValid(aNbEdges); ++anEdgeId) { - EXPECT_TRUE(BRepGraph_Tool::Edge::SameParameter(aCopyGraph, anEdgeId)) + EXPECT_TRUE(edgeSameParameter(aCopyGraph, anEdgeId)) << "Copied edge " << anEdgeId.Index << " lost SameParameter flag"; - EXPECT_TRUE(BRepGraph_Tool::Edge::SameRange(aCopyGraph, anEdgeId)) + EXPECT_TRUE(edgeSameRange(aCopyGraph, anEdgeId)) << "Copied edge " << anEdgeId.Index << " lost SameRange flag"; } } diff --git a/src/ModelingData/TKBRep/GTests/BRepGraph_Geometry_Test.cxx b/src/ModelingData/TKBRep/GTests/BRepGraph_Geometry_Test.cxx index 29e7f015af..0db9754415 100644 --- a/src/ModelingData/TKBRep/GTests/BRepGraph_Geometry_Test.cxx +++ b/src/ModelingData/TKBRep/GTests/BRepGraph_Geometry_Test.cxx @@ -58,6 +58,32 @@ namespace { +bool edgeSameParameter(const BRepGraph& theGraph, BRepGraph_EdgeId theEdge) +{ + const auto& aRel = theGraph.Topo().Edges().Relations(theEdge); + for (const auto& aCoEdgeId : aRel.CoEdgeIds) + { + if (!BRepGraph_Tool::CoEdge::SameParameter(theGraph, aCoEdgeId)) + { + return false; + } + } + return true; +} + +bool edgeSameRange(const BRepGraph& theGraph, BRepGraph_EdgeId theEdge) +{ + const auto& aRel = theGraph.Topo().Edges().Relations(theEdge); + for (const auto& aCoEdgeId : aRel.CoEdgeIds) + { + if (!BRepGraph_Tool::CoEdge::SameRange(theGraph, aCoEdgeId)) + { + return false; + } + } + return true; +} + static int componentKey(const BRepGraph_NodeId theNode) { return theNode.Index * BRepGraph_NodeId::THE_KIND_COUNT + static_cast(theNode.NodeKind); @@ -768,7 +794,7 @@ TEST(BRepGraph_GeometryTest, Box_EdgeDef_SameParameter_IsSet) // Box edges are well-formed; SameParameter should be true for all. for (BRepGraph_EdgeIterator anEdgeIt(aGraph); anEdgeIt.More(); anEdgeIt.Next()) { - EXPECT_TRUE(BRepGraph_Tool::Edge::SameParameter(aGraph, anEdgeIt.CurrentId())) + EXPECT_TRUE(edgeSameParameter(aGraph, anEdgeIt.CurrentId())) << "Edge def " << anEdgeIt.CurrentId().Index << " has SameParameter=false"; } } @@ -784,7 +810,7 @@ TEST(BRepGraph_GeometryTest, Box_EdgeDef_SameRange_IsSet) for (BRepGraph_EdgeIterator anEdgeIt(aGraph); anEdgeIt.More(); anEdgeIt.Next()) { - EXPECT_TRUE(BRepGraph_Tool::Edge::SameRange(aGraph, anEdgeIt.CurrentId())) + EXPECT_TRUE(edgeSameRange(aGraph, anEdgeIt.CurrentId())) << "Edge def " << anEdgeIt.CurrentId().Index << " has SameRange=false"; } } @@ -817,14 +843,14 @@ TEST(BRepGraph_GeometryTest, DerivedStateCache_LazyAndFreshAfterPCurveRangeMutat ASSERT_TRUE(anEdgeId.IsValid(aGraph.Topo().Edges().Nb())); ASSERT_TRUE(aCoEdgeId.IsValid(aGraph.Topo().CoEdges().Nb())); - ASSERT_TRUE(BRepGraph_Tool::Edge::SameRange(aGraph, anEdgeId)); + ASSERT_TRUE(edgeSameRange(aGraph, anEdgeId)); EXPECT_FALSE(aGraph.CacheRegistry().Find().IsNull()); const std::pair anEdgeRange = BRepGraph_Tool::Edge::Range(aGraph, anEdgeId); aGraph.Editor().CoEdges().SetParamRange(aCoEdgeId, anEdgeRange.first + 1.0, anEdgeRange.second); - EXPECT_FALSE(BRepGraph_Tool::Edge::SameRange(aGraph, anEdgeId)); - EXPECT_FALSE(BRepGraph_Tool::Edge::SameParameter(aGraph, anEdgeId)); + EXPECT_FALSE(edgeSameRange(aGraph, anEdgeId)); + EXPECT_FALSE(edgeSameParameter(aGraph, anEdgeId)); } // ============================================================