Skip to content

Commit a7369d0

Browse files
taras113claude
andcommitted
Perf: refactor IntSurf_LineOn2S to std::vector, hash-op cleanups
Profile-guided changes on top of OCCT 8.0.0. 1. IntSurf_LineOn2S: NCollection_Sequence -> std::vector - Sequence::operator()(i) breaks O(1) under non-sequential access in IntPatch_WLine::Point(i); sample(1) had NCollection_BaseSequence::Find as the #1 hot function in Boolean Fuse profile. - All ops translated; class API preserved. Allocator arg ignored. - Measured: -3.2% on a 4.2s Boolean Fuse benchmark (3x3 grid of cylinders+tori, 36 non-planar faces per side, serial). Profile confirms BaseSequence::Find gone from top. 2. BOPAlgo_PaveFiller_6: cache IsClosedFF in PerformFF 4-nested loop - Lift anIsClosed1 out of W2/E2 loops; memoize anIsClosed2 by F2 edge index. Cuts IsClosedFF calls 3.55x (4160 -> 1170 per Fuse on the bench above). Wall-clock change below noise because each call was already cheap, but it's a clean refactor. 3. BRepMesh_BaseMeshAlgo: replace IsBound+Bind+Find / IsBound+Find with ChangeSeek+Bound / Seek in collectTriangles and collectNodes. Behavior-preserving; impact below noise on collectTriangles (not in profile hot path). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d3056ef commit a7369d0

5 files changed

Lines changed: 56 additions & 45 deletions

File tree

src/ModelingAlgorithms/TKBO/BOPAlgo/BOPAlgo_PaveFiller_6.cxx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,16 @@ void BOPAlgo_PaveFiller::PerformFF(const Message_ProgressRange& theRange)
415415
BRep_Tool::Triangulation(aF2, aLocation2);
416416
const bool anIsPlane2 = IsPlaneFF(aSurface2);
417417

418-
bool anIsFound = false;
418+
bool anIsFound = false;
419+
NCollection_DataMap<int, bool> aIsClosedF2Cache;
419420
for (TopoDS_Iterator aItW1(aF1); !anIsFound && aItW1.More(); aItW1.Next())
420421
{
421422
for (TopoDS_Iterator aItE1(aItW1.Value()); !anIsFound && aItE1.More(); aItE1.Next())
422423
{
423424
const TopoDS_Edge& anEdge1 = TopoDS::Edge(aItE1.Value());
424425
const int anEdgeIndex1 = myDS->Index(anEdge1);
426+
const bool anIsClosed1 =
427+
IsClosedFF(anEdge1, aSurface1, aTriangulation1, aLocation1, anIsPlane1);
425428

426429
for (TopoDS_Iterator aItW2(aF2); !anIsFound && aItW2.More(); aItW2.Next())
427430
{
@@ -430,10 +433,13 @@ void BOPAlgo_PaveFiller::PerformFF(const Message_ProgressRange& theRange)
430433
const TopoDS_Edge& anEdge2 = TopoDS::Edge(aItE2.Value());
431434
const int anEdgeIndex2 = myDS->Index(anEdge2);
432435

433-
const bool anIsClosed1 =
434-
IsClosedFF(anEdge1, aSurface1, aTriangulation1, aLocation1, anIsPlane1);
435-
const bool anIsClosed2 =
436-
IsClosedFF(anEdge2, aSurface2, aTriangulation2, aLocation2, anIsPlane2);
436+
bool anIsClosed2;
437+
if (!aIsClosedF2Cache.Find(anEdgeIndex2, anIsClosed2))
438+
{
439+
anIsClosed2 =
440+
IsClosedFF(anEdge2, aSurface2, aTriangulation2, aLocation2, anIsPlane2);
441+
aIsClosedF2Cache.Bind(anEdgeIndex2, anIsClosed2);
442+
}
437443
if (!anIsClosed1 && !anIsClosed2)
438444
{
439445
continue;

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.cxx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,39 @@
1818

1919
IMPLEMENT_STANDARD_RTTIEXT(IntSurf_LineOn2S, Standard_Transient)
2020

21-
IntSurf_LineOn2S::IntSurf_LineOn2S(const IntSurf_Allocator& theAllocator)
22-
: mySeq(theAllocator)
21+
IntSurf_LineOn2S::IntSurf_LineOn2S(const IntSurf_Allocator& /*theAllocator*/)
2322
{
23+
// The allocator hint is ignored: std::vector uses the default allocator.
24+
// Profiles show this is a net win because random access through the line is
25+
// O(1) instead of O(N) (NCollection_BaseSequence::Find).
2426
myBuv1.SetWhole();
2527
myBuv2.SetWhole();
2628
myBxyz.SetWhole();
2729
}
2830

2931
occ::handle<IntSurf_LineOn2S> IntSurf_LineOn2S::Split(const int Index)
3032
{
31-
NCollection_Sequence<IntSurf_PntOn2S> SS;
32-
mySeq.Split(Index, SS);
3333
occ::handle<IntSurf_LineOn2S> NS = new IntSurf_LineOn2S();
34-
int i;
35-
int leng = SS.Length();
36-
for (i = 1; i <= leng; i++)
34+
if (Index >= 1 && Index <= static_cast<int>(mySeq.size()))
3735
{
38-
NS->Add(SS(i));
36+
for (auto it = mySeq.begin() + (Index - 1); it != mySeq.end(); ++it)
37+
{
38+
NS->Add(*it);
39+
}
40+
mySeq.erase(mySeq.begin() + (Index - 1), mySeq.end());
3941
}
4042
return NS;
4143
}
4244

4345
void IntSurf_LineOn2S::InsertBefore(const int index, const IntSurf_PntOn2S& P)
4446
{
45-
if (index > mySeq.Length())
47+
if (index > static_cast<int>(mySeq.size()))
4648
{
47-
mySeq.Append(P);
49+
mySeq.push_back(P);
4850
}
4951
else
5052
{
51-
mySeq.InsertBefore(index, P);
53+
mySeq.insert(mySeq.begin() + (index - 1), P);
5254
}
5355

5456
if (!myBxyz.IsWhole())
@@ -69,7 +71,10 @@ void IntSurf_LineOn2S::InsertBefore(const int index, const IntSurf_PntOn2S& P)
6971

7072
void IntSurf_LineOn2S::RemovePoint(const int index)
7173
{
72-
mySeq.Remove(index);
74+
if (index >= 1 && index <= static_cast<int>(mySeq.size()))
75+
{
76+
mySeq.erase(mySeq.begin() + (index - 1));
77+
}
7378
myBuv1.SetWhole();
7479
myBuv2.SetWhole();
7580
myBxyz.SetWhole();
@@ -86,11 +91,11 @@ bool IntSurf_LineOn2S::IsOutBox(const gp_Pnt& Pxyz)
8691
{
8792
int n = NbPoints();
8893
myBxyz.SetVoid();
89-
for (int i = 1; i <= n; i++)
94+
for (const auto& pt : mySeq)
9095
{
91-
gp_Pnt P = mySeq(i).Value();
92-
myBxyz.Add(P);
96+
myBxyz.Add(pt.Value());
9397
}
98+
(void)n;
9499
double x0, y0, z0, x1, y1, z1;
95100
myBxyz.Get(x0, y0, z0, x1, y1, z1);
96101
x1 -= x0;
@@ -132,12 +137,11 @@ bool IntSurf_LineOn2S::IsOutSurf1Box(const gp_Pnt2d& P1uv)
132137

133138
if (myBuv1.IsWhole())
134139
{
135-
int n = NbPoints();
136140
double pu1, pu2, pv1, pv2;
137141
myBuv1.SetVoid();
138-
for (int i = 1; i <= n; i++)
142+
for (const auto& pt : mySeq)
139143
{
140-
mySeq(i).Parameters(pu1, pv1, pu2, pv2);
144+
pt.Parameters(pu1, pv1, pu2, pv2);
141145
myBuv1.Add(gp_Pnt2d(pu1, pv1));
142146
}
143147
myBuv1.Get(pu1, pv1, pu2, pv2);
@@ -165,12 +169,11 @@ bool IntSurf_LineOn2S::IsOutSurf2Box(const gp_Pnt2d& P2uv)
165169

166170
if (myBuv2.IsWhole())
167171
{
168-
int n = NbPoints();
169172
double pu1, pu2, pv1, pv2;
170173
myBuv2.SetVoid();
171-
for (int i = 1; i <= n; i++)
174+
for (const auto& pt : mySeq)
172175
{
173-
mySeq(i).Parameters(pu1, pv1, pu2, pv2);
176+
pt.Parameters(pu1, pv1, pu2, pv2);
174177
myBuv2.Add(gp_Pnt2d(pu2, pv2));
175178
}
176179
myBuv2.Get(pu1, pv1, pu2, pv2);
@@ -193,7 +196,7 @@ bool IntSurf_LineOn2S::IsOutSurf2Box(const gp_Pnt2d& P2uv)
193196

194197
void IntSurf_LineOn2S::Add(const IntSurf_PntOn2S& P)
195198
{
196-
mySeq.Append(P);
199+
mySeq.push_back(P);
197200
if (!myBxyz.IsWhole())
198201
{
199202
myBxyz.Add(P.Value());
@@ -214,7 +217,7 @@ void IntSurf_LineOn2S::Add(const IntSurf_PntOn2S& P)
214217

215218
void IntSurf_LineOn2S::SetUV(const int Index, const bool OnFirst, const double U, const double V)
216219
{
217-
mySeq(Index).SetValue(OnFirst, U, V);
220+
mySeq[Index - 1].SetValue(OnFirst, U, V);
218221

219222
if (OnFirst && !myBuv1.IsWhole())
220223
{

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.hxx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
#include <Bnd_Box.hxx>
2323
#include <Bnd_Box2d.hxx>
2424
#include <IntSurf_PntOn2S.hxx>
25-
#include <NCollection_Sequence.hxx>
2625
#include <Standard_Transient.hxx>
26+
#include <vector>
2727
#include <IntSurf_Allocator.hxx>
2828
#include <Standard_Integer.hxx>
2929
#include <Standard_Real.hxx>
@@ -81,7 +81,10 @@ public:
8181
DEFINE_STANDARD_RTTIEXT(IntSurf_LineOn2S, Standard_Transient)
8282

8383
private:
84-
NCollection_Sequence<IntSurf_PntOn2S> mySeq;
84+
// Contiguous storage gives O(1) random access; the previous NCollection_Sequence
85+
// had O(N) operator()(i) which dominated profiles of surface-surface intersection
86+
// (BOPAlgo Fuse, IntPatch_WLine::Point) — see [[occt-bench-results]].
87+
std::vector<IntSurf_PntOn2S> mySeq;
8588
Bnd_Box2d myBuv1;
8689
Bnd_Box2d myBuv2;
8790
Bnd_Box myBxyz;

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.lxx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,42 @@
1313
// commercial license or contractual agreement.
1414

1515
#include <IntSurf_PntOn2S.hxx>
16+
#include <algorithm>
1617

1718
inline int IntSurf_LineOn2S::NbPoints() const
1819
{
19-
20-
return mySeq.Length();
20+
return static_cast<int>(mySeq.size());
2121
}
2222

2323
inline void IntSurf_LineOn2S::Reverse()
2424
{
25-
mySeq.Reverse();
25+
std::reverse(mySeq.begin(), mySeq.end());
2626
}
2727

2828
inline const IntSurf_PntOn2S& IntSurf_LineOn2S::Value(const int Index) const
2929
{
30-
return mySeq(Index);
30+
return mySeq[Index - 1];
3131
}
3232

3333
inline void IntSurf_LineOn2S::Value(const int Index, const IntSurf_PntOn2S& P)
3434
{
35-
mySeq(Index) = P;
35+
mySeq[Index - 1] = P;
3636
myBuv1.SetWhole();
3737
myBuv2.SetWhole();
3838
myBxyz.SetWhole();
3939
}
4040

4141
inline void IntSurf_LineOn2S::SetPoint(const int Index, const gp_Pnt& thePnt)
4242
{
43-
mySeq(Index).SetValue(thePnt);
43+
mySeq[Index - 1].SetValue(thePnt);
4444
myBuv1.SetWhole();
4545
myBuv2.SetWhole();
4646
myBxyz.SetWhole();
4747
}
4848

4949
inline void IntSurf_LineOn2S::Clear()
5050
{
51-
mySeq.Clear();
51+
mySeq.clear();
5252
myBuv1.SetWhole();
5353
myBuv2.SetWhole();
5454
myBxyz.SetWhole();

src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_BaseMeshAlgo.cxx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,12 @@ occ::handle<Poly_Triangulation> BRepMesh_BaseMeshAlgo::collectTriangles()
262262

263263
for (int i = 0; i < 3; ++i)
264264
{
265-
if (!myUsedNodes->IsBound(aNode[i]))
265+
int* pIdx = myUsedNodes->ChangeSeek(aNode[i]);
266+
if (!pIdx)
266267
{
267-
myUsedNodes->Bind(aNode[i], myUsedNodes->Length() + 1);
268+
pIdx = myUsedNodes->Bound(aNode[i], myUsedNodes->Length() + 1);
268269
}
269-
270-
aNode[i] = myUsedNodes->Find(aNode[i]);
270+
aNode[i] = *pIdx;
271271
}
272272

273273
aRes->SetTriangle(aTriangeId, Poly_Triangle(aNode[0], aNode[1], aNode[2]));
@@ -283,11 +283,10 @@ void BRepMesh_BaseMeshAlgo::collectNodes(const occ::handle<Poly_Triangulation>&
283283
{
284284
for (int i = 1; i <= myNodesMap->Length(); ++i)
285285
{
286-
if (myUsedNodes->IsBound(i))
286+
if (const int* pIdx = myUsedNodes->Seek(i))
287287
{
288-
const BRepMesh_Vertex& aVertex = myStructure->GetNode(i);
289-
290-
const int aNodeIndex = myUsedNodes->Find(i);
288+
const BRepMesh_Vertex& aVertex = myStructure->GetNode(i);
289+
const int aNodeIndex = *pIdx;
291290
theTriangulation->SetNode(aNodeIndex, myNodesMap->Value(aVertex.Location3d()));
292291
theTriangulation->SetUVNode(aNodeIndex, getNodePoint2d(aVertex));
293292
}

0 commit comments

Comments
 (0)