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<uint8_t> (GeomStatus+IsClosed+IsComputed)
- CoEdgeSameRangeEntry: packed atomic<uint8_t> (SameRange+SameParameter+Computed)
- WireEntry: packed atomic<uint8_t> (IsClosed+IsComputed)
- ShellEntry: atomic<ClosureStatus> 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
This commit is contained in:
Pasukhin Dmitry
2026-06-14 14:15:32 +01:00
committed by GitHub
parent 2b379b9f08
commit ea3fc1f8bd
31 changed files with 2059 additions and 1350 deletions
@@ -22,12 +22,15 @@
#include <Geom2d_Curve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <Precision.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_FlatMap.hxx>
#include <NCollection_Map.hxx>
#include <cmath>
IMPLEMENT_STANDARD_RTTIEXT(BRepGraph_CacheDerivedState, BRepGraph_Cache)
@@ -41,6 +44,15 @@ const Standard_GUID& theGUID()
return aGUID;
}
template <typename T>
void ensureSize(NCollection_DynamicArray<T>& theArray, uint32_t theIndex)
{
if (static_cast<size_t>(theIndex) >= theArray.Size())
{
theArray.SetValue(static_cast<size_t>(theIndex), T());
}
}
template <typename IdT>
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<double, double>& 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<double, double> 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<double, double> anEdgeRange = BRepGraph_Tool::Edge::Range(theGraph, theEdge);
const std::pair<double, double> 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<Geom_Curve>& theCurve3D,
const std::pair<double, double>& theEdgeRange)
bool isCoEdgeSameParameter(const BRepGraph& theGraph,
const BRepGraph_CoEdgeId theCoEdge,
const BRepGraphInc::EdgeDef& theEdgeDef,
const occ::handle<Geom_Curve>& theCurve3D,
const std::pair<double, double>& 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<Geom2d_Curve>& aPCurve = coEdgePCurve(theGraph, theCoEdge);
if (aPCurve.IsNull())
{
return true;
}
const occ::handle<Geom_Surface> 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<Geom2d_Curve>& aPCurve = coEdgePCurve(theGraph, aCoEdgeId);
if (aPCurve.IsNull())
{
continue;
}
const occ::handle<Geom_Surface> 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<BRepGraph_CacheDerivedState> aTargetCache =
theCopy.TargetGraph().CacheRegistry().Ensure<BRepGraph_CacheDerivedState>();
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<BRepGraph_EdgeId, EdgeEntry>::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<size_t>(aTargetEdge.Index)) =
aTargetEntry;
}
}
for (NCollection_DataMap<BRepGraph_WireId, WireEntry>::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<size_t>(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<size_t>(aTargetWire.Index)) =
aTargetEntry;
}
}
for (NCollection_DataMap<BRepGraph_ShellId, ShellEntry>::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<size_t>(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<Geom_Curve>& 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<Geom_Curve>& 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<Geom_Curve>& aCurve3D = edgeCurve3D(theGraph, anEdge);
if (!aCurve3D.IsNull())
{
if (theEntry.SameRange())
{
const std::pair<double, double> 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<size_t>(theEdge.Index) < myEdgeEntries.Size())
{
const EdgeEntry& aCached = myEdgeEntries.Value(static_cast<size_t>(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<size_t>(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<size_t>(theCoEdge.Index) < myCoEdgeSameRangeEntries.Size())
{
const CoEdgeSameRangeEntry& aCached =
myCoEdgeSameRangeEntries.Value(static_cast<size_t>(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<size_t>(theCoEdge.Index) < myCoEdgeSameRangeEntries.Size())
{
const CoEdgeSameRangeEntry& aCached =
myCoEdgeSameRangeEntries.Value(static_cast<size_t>(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<size_t>(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<Geom_Curve>& aCurve3D = edgeCurve3D(theGraph, theEdge);
const bool hasCurve3D = !aCurve3D.IsNull();
theEntry.Status =
hasCurve3D ? EdgeGeometryStatus::HasCurve3D : EdgeGeometryStatus::MissingCurve3D;
if (hasCurve3D)
{
const std::pair<double, double> 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<BRepGraph_FaceId> 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<BRepGraph_EdgeId, uint32_t> 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<size_t>(theWire.Index) < myWireEntries.Size())
{
const WireEntry& aCached = myWireEntries.Value(static_cast<size_t>(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<size_t>(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<size_t>(theShell.Index) < myShellEntries.Size())
{
return false;
const ShellEntry& aCached = myShellEntries.Value(static_cast<size_t>(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<size_t>(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<size_t>(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);
}
@@ -16,73 +16,23 @@
#include <BRepGraph_Cache.hxx>
#include <BRepGraph_NodeId.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_DynamicArray.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_GUID.hxx>
#include <shared_mutex>
#include <atomic>
#include <mutex>
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<BRepGraph_EdgeId, EdgeEntry> myEdgeEntries;
NCollection_DataMap<BRepGraph_WireId, WireEntry> myWireEntries;
NCollection_DataMap<BRepGraph_ShellId, ShellEntry> myShellEntries;
enum Flags : uint8_t
{
FlagNone = 0,
StatusMask = 0x07,
FlagClosed = 1 << 3,
FlagComputed = 1 << 4,
};
std::atomic<uint8_t> 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<GeomStatus>(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<uint8_t>(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<uint8_t> 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<uint8_t> 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<ClosureStatus> 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<EdgeEntry> myEdgeEntries;
NCollection_DynamicArray<CoEdgeSameRangeEntry> myCoEdgeSameRangeEntries;
NCollection_DynamicArray<WireEntry> myWireEntries;
NCollection_DynamicArray<ShellEntry> myShellEntries;
};
#endif // _BRepGraph_CacheDerivedState_HeaderFile
@@ -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(
@@ -126,6 +126,36 @@ occ::handle<BRepGraph_Cache> BRepGraph_CacheRegistry::FindCache(const Standard_G
//=================================================================================================
occ::handle<BRepGraph_Cache> BRepGraph_CacheRegistry::ensureCache(
const Standard_GUID& theGUID,
const std::function<occ::handle<BRepGraph_Cache>()>& theFactory)
{
// Fast path: shared lock for read-only lookup.
{
std::shared_lock<std::shared_mutex> aLock(myMutex);
occ::handle<BRepGraph_Cache> aCache = findCacheLocked(theGUID);
if (!aCache.IsNull())
{
return aCache;
}
}
// Slow path: exclusive lock for creation.
{
std::unique_lock<std::shared_mutex> aLock(myMutex);
// Re-check after acquiring exclusive lock (another thread may have created it).
occ::handle<BRepGraph_Cache> 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<std::shared_mutex> 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<std::shared_mutex> aLock(myMutex);
aSourceGraph = myGraph;
}
if (aSourceGraph == nullptr)
{
return;
}
const BRepGraph_CopyRemap aCopy(*aSourceGraph, theTargetGraph, theMappingKind, theMode);
for (uint32_t aSlot = 0;; ++aSlot)
{
occ::handle<BRepGraph_Cache> aCache = cacheAt(aSlot);
if (aCache.IsNull())
{
return;
}
aCache->CopyFreshTo(aCopy);
}
}
//=================================================================================================
occ::handle<BRepGraph_Cache> BRepGraph_CacheRegistry::findCacheLocked(
const Standard_GUID& theGUID) const
{
@@ -22,6 +22,7 @@
#include <Standard_DefineAlloc.hxx>
#include <Standard_GUID.hxx>
#include <functional>
#include <mutex>
#include <shared_mutex>
@@ -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 <typename T>
[[nodiscard]] occ::handle<T> Ensure()
{
std::unique_lock<std::shared_mutex> aLock(myMutex);
occ::handle<T> aCache = occ::down_cast<T>(findCacheLocked(T::GetID()));
if (aCache.IsNull())
{
aCache = new T();
registerCacheLocked(aCache);
}
return aCache;
return occ::down_cast<T>(
ensureCache(T::GetID(), []() -> occ::handle<BRepGraph_Cache> { return new T(); }));
}
//! Return current graph-local slot for a GUID.
@@ -133,6 +129,11 @@ public:
const NCollection_FlatDataMap<BRepGraph_ItemId, BRepGraph_ItemId>& 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<BRepGraph_Cache> 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<BRepGraph_Cache> ensureCache(
const Standard_GUID& theGUID,
const std::function<occ::handle<BRepGraph_Cache>()>& theFactory);
[[nodiscard]] Standard_EXPORT occ::handle<BRepGraph_Cache> cacheAt(uint32_t theSlot) const;
Standard_EXPORT uint32_t registerCacheLocked(const occ::handle<BRepGraph_Cache>& theCache);
@@ -24,6 +24,7 @@
#include <BRepGraph_RefsView.hxx>
#include <BRepGraph_Tool.hxx>
#include <BRepGraph_TopoView.hxx>
#include <BRepGraphInc_Load.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
@@ -299,146 +300,6 @@ size_t itemCapacityUpperBound(const BRepGraphInc_Storage& theStorage)
//=================================================================================================
template <typename IdT>
void bindIdentityRange(const uint32_t theSourceCount,
const uint32_t theTargetCount,
NCollection_FlatDataMap<BRepGraph_ItemId, BRepGraph_ItemId>& 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<BRepGraph_ItemId, BRepGraph_ItemId>& theItemRemap)
{
theItemRemap.Reserve(itemCapacityUpperBound(theSource));
bindIdentityRange<BRepGraph_VertexId>(theSource.NbVertices(),
theTarget.NbVertices(),
theItemRemap);
bindIdentityRange<BRepGraph_EdgeId>(theSource.NbEdges(), theTarget.NbEdges(), theItemRemap);
bindIdentityRange<BRepGraph_CoEdgeId>(theSource.NbCoEdges(), theTarget.NbCoEdges(), theItemRemap);
bindIdentityRange<BRepGraph_WireId>(theSource.NbWires(), theTarget.NbWires(), theItemRemap);
bindIdentityRange<BRepGraph_FaceId>(theSource.NbFaces(), theTarget.NbFaces(), theItemRemap);
bindIdentityRange<BRepGraph_ShellId>(theSource.NbShells(), theTarget.NbShells(), theItemRemap);
bindIdentityRange<BRepGraph_SolidId>(theSource.NbSolids(), theTarget.NbSolids(), theItemRemap);
bindIdentityRange<BRepGraph_CompoundId>(theSource.NbCompounds(),
theTarget.NbCompounds(),
theItemRemap);
bindIdentityRange<BRepGraph_CompSolidId>(theSource.NbCompSolids(),
theTarget.NbCompSolids(),
theItemRemap);
bindIdentityRange<BRepGraph_ProductId>(theSource.NbProducts(),
theTarget.NbProducts(),
theItemRemap);
bindIdentityRange<BRepGraph_OccurrenceId>(theSource.NbOccurrences(),
theTarget.NbOccurrences(),
theItemRemap);
bindIdentityRange<BRepGraph_ShellRefId>(theSource.NbShellRefs(),
theTarget.NbShellRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_FaceRefId>(theSource.NbFaceRefs(),
theTarget.NbFaceRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_WireRefId>(theSource.NbWireRefs(),
theTarget.NbWireRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_VertexRefId>(theSource.NbVertexRefs(),
theTarget.NbVertexRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_SolidRefId>(theSource.NbSolidRefs(),
theTarget.NbSolidRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_ChildRefId>(theSource.NbChildRefs(),
theTarget.NbChildRefs(),
theItemRemap);
bindIdentityRange<BRepGraph_OccurrenceRefId>(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<Geom_Surface>(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<Geom_Curve>(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<Geom2d_Curve>(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<Geom_Curve>& anEdgeSrcCurve =
BRepGraph_Tool::Edge::Curve(theSourceGraph, anEdgeId);
occ::handle<Geom_Curve> 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<BRepGraph_CoEdgeId> 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<Geom_Surface>& aFaceSrcSurf =
BRepGraph_Tool::Face::Surface(theSourceGraph, aFaceId);
occ::handle<Geom_Surface> aSurf = copySurface(aFaceSrcSurf, theGeomPolicy);
BRepGraph_WireId aFirstWire;
NCollection_LinearVector<BRepGraph_WireId> 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<BRepGraph_NodeId> 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<BRepGraph_SolidId> 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<BRepGraph_ProductId> 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<BRepGraph_ItemId, BRepGraph_ItemId> 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);
}
//=================================================================================================
@@ -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();
}
//=================================================================================================
@@ -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_ItemId, BRepGraph_ItemId>;
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
@@ -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<size_t>(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<ChildId, BRepGraph_NodeId>)
{
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<size_t>(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<RefId>* myRefIds = nullptr;
const NCollection_LinearVector<RefId>* 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());
}
@@ -209,12 +209,12 @@ protected:
{
return BRepGraph_NodeId::Typed<TheKind>();
}
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<TheKind>();
}
return BRepGraph_NodeId::Typed<TheKind>::FromNodeId(aMapped->NodeId());
return BRepGraph_NodeId::Typed<TheKind>::FromNodeId(aMapped.NodeId());
}
template <BRepGraph_RefId::Kind TheKind>
@@ -226,12 +226,12 @@ protected:
{
return BRepGraph_RefId::Typed<TheKind>();
}
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<TheKind>();
}
return BRepGraph_RefId::Typed<TheKind>::FromRefId(aMapped->RefId());
return BRepGraph_RefId::Typed<TheKind>::FromRefId(aMapped.RefId());
}
//! Called after the layer is attached to a graph registry.
@@ -430,8 +430,8 @@ void BRepGraph_LayerDeferred::CopyTo(const BRepGraph_CopyRemap& theCopy) const
for (NCollection_DataMap<BRepGraph_ItemId, Entry>::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,
@@ -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<BRepGraph_NodeId> 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<BRepGraph_ItemId>& 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<BRepGraph_ItemUID> aTargetImageUIDs(THE_HISTORY_FILTERED_BLOCK_SIZE);
NCollection_LinearVector<BRepGraph_NodeId> 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<BRepGraph_NodeId> 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<BRepGraph_NodeId> 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);
@@ -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)
@@ -30,14 +30,16 @@ BRepGraph_LayerRegistry::BRepGraph_LayerRegistry() = default;
BRepGraph_LayerRegistry::BRepGraph_LayerRegistry(BRepGraph_LayerRegistry&& theOther) noexcept
{
std::unique_lock<std::shared_mutex> 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::handle<BRepGrap
theLayer->attachGraph(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_Layer> BRepGraph_LayerRegistry::findLayerLocked(
//=================================================================================================
occ::handle<BRepGraph_Layer> BRepGraph_LayerRegistry::ensureLayer(
const Standard_GUID& theGUID,
const std::function<occ::handle<BRepGraph_Layer>()>& theFactory)
{
// Fast path: shared lock for read-only lookup.
{
std::shared_lock<std::shared_mutex> aLock(myMutex);
occ::handle<BRepGraph_Layer> aLayer = findLayerLocked(theGUID);
if (!aLayer.IsNull())
{
return aLayer;
}
}
// Slow path: exclusive lock for creation.
{
std::unique_lock<std::shared_mutex> aLock(myMutex);
occ::handle<BRepGraph_Layer> 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<std::shared_mutex> 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<std::shared_mutex> 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<BRepGraph_NodeId>& 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<std::shared_mutex> 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<std::shared_mutex> aLock(myMutex);
aSourceGraph = myGraph;
}
const BRepGraph_CopyRemap aCopy(*aSourceGraph, theTargetGraph, theMappingKind, theMode);
for (uint32_t aSlot = 0;; ++aSlot)
{
occ::handle<BRepGraph_Layer> 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<std::shared_mutex> 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<BRepGraph_RefId>& 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<std::shared_mutex> 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<BRepGraph_Layer>& 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);
}
@@ -23,8 +23,10 @@
#include <Standard_DefineAlloc.hxx>
#include <Standard_GUID.hxx>
#include <functional>
#include <mutex>
#include <shared_mutex>
#include <atomic>
//! @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 <typename T>
[[nodiscard]] occ::handle<T> Ensure()
{
std::unique_lock<std::shared_mutex> aLock(myMutex);
occ::handle<T> aLayer = occ::down_cast<T>(findLayerLocked(T::GetID()));
if (aLayer.IsNull())
{
aLayer = new T();
registerLayerLocked(aLayer);
}
return aLayer;
return occ::down_cast<T>(
ensureLayer(T::GetID(), []() -> occ::handle<BRepGraph_Layer> { 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<std::shared_mutex> 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<std::shared_mutex> aLock(myMutex);
return mySubscribedKindsMask;
return static_cast<int>(mySubscribedKindsMask.load(std::memory_order_acquire));
}
//! Dispatch OnNodeRemoved to all registered layers.
@@ -141,18 +136,25 @@ public:
const NCollection_FlatDataMap<BRepGraph_ItemId, BRepGraph_ItemId>& 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<std::shared_mutex> 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<std::shared_mutex> aLock(myMutex);
return mySubscribedRefKindsMask;
return static_cast<int>(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<BRepGraph_Layer> 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<BRepGraph_Layer> ensureLayer(
const Standard_GUID& theGUID,
const std::function<occ::handle<BRepGraph_Layer>()>& theFactory);
[[nodiscard]] Standard_EXPORT occ::handle<BRepGraph_Layer> layerAt(uint32_t theSlot) const;
Standard_EXPORT uint32_t registerLayerLocked(const occ::handle<BRepGraph_Layer>& theLayer);
@@ -195,9 +204,9 @@ private:
private:
NCollection_LinearVector<occ::handle<BRepGraph_Layer>> myLayers;
NCollection_DataMap<Standard_GUID, uint32_t> myGuidToSlot;
uint32_t mySubscribedKindsMask = 0;
uint32_t mySubscribedRefKindsMask = 0;
BRepGraph* myGraph = nullptr;
std::atomic<uint32_t> mySubscribedKindsMask{0};
std::atomic<uint32_t> mySubscribedRefKindsMask{0};
BRepGraph* myGraph = nullptr;
mutable std::shared_mutex myMutex;
};
@@ -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;
@@ -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<size_t>(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<ChildId, BRepGraph_NodeId>)
{
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<size_t>(myIndex)); }
[[nodiscard]] RefId CurrentId() const
{
Standard_ASSERT_VOID(More(), "RefsOfParent::CurrentId() called on exhausted iterator");
return myRefIds->Value(static_cast<size_t>(myIndex));
}
[[nodiscard]] uint32_t Index() const { return myIndex; }
@@ -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<BRepGraph_ProductId> 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;
@@ -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<double, double> BRepGraph_Tool::Edge::Range(const BRepGraph& the
//=================================================================================================
std::pair<double, double> 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<double, double>{0.0, 0.0};
}
//=================================================================================================
bool BRepGraph_Tool::Edge::HasCurve(const BRepGraph& theGraph, const BRepGraph_EdgeId theEdge)
{
const occ::handle<Geom_Curve> 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<Geom_Curve>& BRepGraph_Tool::Edge::Curve(const BRepGraph&
//=================================================================================================
const occ::handle<Geom_Curve>& 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<Geom_Curve> 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<gp_Pnt2d, gp_Pnt2d> 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);
}
//=================================================================================================
@@ -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<double, double> 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<Geom_Curve>& 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
@@ -22,6 +22,7 @@
#include <BRepGraphInc_Storage.hxx>
#include <Adaptor3d_CurveOnSurface.hxx>
#include <Geom2d_Curve.hxx>
#include <NCollection_LocalArray.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
@@ -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<BRepGraph_CoEdgeId>& 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<BRepGraph_FaceId, 32> 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<size_t>(aSeenBuf.Size() * 1.5));
}
aSeenBuf[aNbSeen++] = aFace;
}
return aNbSeen;
}
//=================================================================================================
@@ -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)
{
@@ -16,6 +16,7 @@
#include <BRepGraph.hxx>
#include <BRepGraphInc_Storage.hxx>
#include <BRepGraph_CacheDerivedState.hxx>
#include <BRepGraph_CacheRegistry.hxx>
#include <BRepGraph_LayerRegistry.hxx>
#include <BRepGraph_LayerTopoSupplement.hxx>
#include <BRepGraph_TopoView.hxx>
@@ -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<BRepGraph_CacheDerivedState>();
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<BRepGraph_CacheDerivedState>();
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,
@@ -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);
@@ -93,6 +93,14 @@ void appendUniqueRelationId(NCollection_LinearVector<IdT>& 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 <typename IdT>
void appendRelationIdDirect(NCollection_LinearVector<IdT>& theIds, const IdT theId)
{
theIds.Append(theId);
}
template <typename IdT>
bool eraseRelationId(NCollection_LinearVector<IdT>& theIds, const IdT theId)
{
@@ -995,11 +1003,7 @@ void BRepGraphInc_Storage::SetHasOccurrenceParent(const BRepGraph_NodeId theNode
NCollection_LinearVector<BRepGraph_ChildRefId>& BRepGraphInc_Storage::
ChangeCompoundRefsOfNodeInternal(const BRepGraph_NodeId theNode)
{
if (!myNodeToCompounds.IsBound(theNode))
{
myNodeToCompounds.Bind(theNode, NCollection_LinearVector<BRepGraph_ChildRefId>());
}
return *myNodeToCompounds.ChangeSeek(theNode);
return myNodeToCompounds.TryBound(theNode, NCollection_LinearVector<BRepGraph_ChildRefId>());
}
//=================================================================================================
@@ -1007,11 +1011,8 @@ NCollection_LinearVector<BRepGraph_ChildRefId>& BRepGraphInc_Storage::
NCollection_LinearVector<BRepGraph_OccurrenceRefId>& BRepGraphInc_Storage::
ChangeOccurrenceRefsOfNodeInternal(const BRepGraph_NodeId theNode)
{
if (!myNodeToOccurrences.IsBound(theNode))
{
myNodeToOccurrences.Bind(theNode, NCollection_LinearVector<BRepGraph_OccurrenceRefId>());
}
return *myNodeToOccurrences.ChangeSeek(theNode);
return myNodeToOccurrences.TryBound(theNode,
NCollection_LinearVector<BRepGraph_OccurrenceRefId>());
}
//=================================================================================================
@@ -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<BRepGraph_NodeId,
NCollection_LinearVector<BRepGraph_ChildRefId>>::Iterator
anIt(theSource.myNodeToCompounds);
anIt.More();
anIt.Next())
{
myNodeToCompounds.Bind(anIt.Key(), anIt.Value());
}
myNodeToOccurrences.Clear();
for (NCollection_DataMap<BRepGraph_NodeId,
NCollection_LinearVector<BRepGraph_OccurrenceRefId>>::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<std::shared_mutex> aLock(myUIDToNodeIdMutex);
myUIDToNodeId.Clear();
myUIDToNodeIdDirty = false;
myUIDToNodeIdDirty.store(false, std::memory_order_relaxed);
}
{
std::unique_lock<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> aLock(myUIDToNodeIdMutex);
myUIDToNodeId.Clear();
myUIDToNodeIdDirty = true;
myUIDToNodeIdDirty.store(true, std::memory_order_release);
}
{
std::unique_lock<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> 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);
}
//=================================================================================================
@@ -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<BRepGraph_NodeId, CachedShape>& 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<BRepGraph_RefUID, BRepGraph_RefId> myRefUIDToRefId;
mutable std::shared_mutex myRefUIDToRefIdMutex;
mutable bool myUIDToNodeIdDirty = false;
mutable bool myRefUIDToRefIdDirty = false;
mutable std::atomic<bool> myUIDToNodeIdDirty{false};
mutable std::atomic<bool> myRefUIDToRefIdDirty{false};
//! Bindings from reconstructed / source OCCT shapes back to backend ids.
NCollection_FlatDataMap<const TopoDS_TShape*, BRepGraph_NodeId> myTShapeToNodeId;
@@ -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())
@@ -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";
}
}
@@ -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<int>(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<BRepGraph_CacheDerivedState>().IsNull());
const std::pair<double, double> 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));
}
// ============================================================