1 // Created on: 2014-06-03
2 // Created by: Oleg AGASHIN
3 // Copyright (c) 1997-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <BRepMesh_WireChecker.hxx>
19 #include <Precision.hxx>
20 #include <TColStd_Array1OfInteger.hxx>
21 #include <gp_Pnt2d.hxx>
22 #include <BRepTools_WireExplorer.hxx>
23 #include <TopAbs_Orientation.hxx>
25 #include <TopoDS_Iterator.hxx>
26 #include <Poly_PolygonOnTriangulation.hxx>
27 #include <BRepMesh_PairOfPolygon.hxx>
28 #include <TColStd_SequenceOfInteger.hxx>
29 #include <TColStd_IndexedMapOfInteger.hxx>
30 #include <BRepMesh_DataStructureOfDelaun.hxx>
31 #include <BRepMesh_Classifier.hxx>
32 #include <BRepMesh_WireInterferenceChecker.hxx>
35 // paralleling using Intel TBB
36 #include <tbb/parallel_for.h>
37 #include <tbb/blocked_range.h>
40 //=======================================================================
41 //function : Selector::Constructor
43 //=======================================================================
44 BRepMesh_WireChecker::BndBox2dTreeSelector::BndBox2dTreeSelector(
45 const Standard_Integer theReservedSize)
47 myIndices(0, theReservedSize - 1),
52 //=======================================================================
55 //=======================================================================
56 Standard_Boolean BRepMesh_WireChecker::BndBox2dTreeSelector::Reject(
57 const Bnd_Box2d& theBox2D) const
59 return myBox2D.IsOut(theBox2D);
62 //=======================================================================
65 //=======================================================================
66 Standard_Boolean BRepMesh_WireChecker::BndBox2dTreeSelector::Accept(
67 const Standard_Integer& theIndex)
69 if (theIndex <= mySkippedIndex)
70 return Standard_False;
72 myIndices(myIndicesNb++) = theIndex;
76 //=======================================================================
79 //=======================================================================
80 void BRepMesh_WireChecker::BndBox2dTreeSelector::Clear()
86 //=======================================================================
89 //=======================================================================
90 void BRepMesh_WireChecker::BndBox2dTreeSelector::SetBox(
91 const Bnd_Box2d& theBox2D)
96 //=======================================================================
99 //=======================================================================
100 void BRepMesh_WireChecker::BndBox2dTreeSelector::SetSkippedIndex(
101 const Standard_Integer theIndex)
103 mySkippedIndex = theIndex;
106 //=======================================================================
109 //=======================================================================
110 const BRepMeshCol::Array1OfInteger&
111 BRepMesh_WireChecker::BndBox2dTreeSelector::Indices() const
116 //=======================================================================
117 //function : IndicesNb
119 //=======================================================================
120 Standard_Integer BRepMesh_WireChecker::BndBox2dTreeSelector::IndicesNb() const
125 //=======================================================================
126 //function : Constructor
128 //=======================================================================
129 BRepMesh_WireChecker::BRepMesh_WireChecker(
130 const TopoDS_Face& theFace,
131 const Standard_Real theTolUV,
132 const BRepMeshCol::DMapOfShapePairOfPolygon& theEdges,
133 const TColStd_IndexedMapOfInteger& theVertexMap,
134 const Handle(BRepMesh_DataStructureOfDelaun)& theStructure,
135 const Standard_Real theUmin,
136 const Standard_Real theUmax,
137 const Standard_Real theVmin,
138 const Standard_Real theVmax,
139 const Standard_Boolean isInParallel)
142 myVertexMap(theVertexMap),
143 myStructure(theStructure),
148 myStatus(BRepMesh_NoError),
149 myIsInParallel(isInParallel)
151 TopoDS_Face aFace = theFace;
152 aFace.Orientation(TopAbs_FORWARD);
154 TopoDS_Iterator aFaceExplorer(aFace);
155 for (; aFaceExplorer.More(); aFaceExplorer.Next())
157 const TopoDS_Shape& aWire = aFaceExplorer.Value();
158 if (aWire.ShapeType() != TopAbs_WIRE)
161 myWiresEdges.push_back(ListOfEdges());
162 ListOfEdges& aEdges = myWiresEdges.back();
164 // Start traversing the wires
165 BRepTools_WireExplorer aWireExplorer(TopoDS::Wire(aWire), aFace);
166 for (; aWireExplorer.More(); aWireExplorer.Next())
168 const TopoDS_Edge& aEdge = aWireExplorer.Current();
169 TopAbs_Orientation aOrient = aEdge.Orientation();
170 if (aOrient != TopAbs_FORWARD && aOrient != TopAbs_REVERSED)
173 aEdges.Append(aEdge);
176 if (aEdges.IsEmpty())
177 myWiresEdges.pop_back();
181 //=======================================================================
182 //function : ReCompute
184 //=======================================================================
185 void BRepMesh_WireChecker::ReCompute(BRepMeshCol::HClassifier& theClassifier)
187 if (theClassifier.IsNull())
190 theClassifier->Destroy();
191 myStatus = BRepMesh_NoError;
194 if (!collectDiscretizedWires(aDWires))
197 const Standard_Integer aNbWires = (Standard_Integer)aDWires.size();
199 BRepMeshCol::Array1OfSegmentsTree aWiresBiPoints(aNbWires);
200 fillSegmentsTree(aDWires, aWiresBiPoints);
203 Standard_Mutex aWireMutex;
204 BRepMesh_WireInterferenceChecker aIntChecker(aWiresBiPoints,
205 &myStatus, &aWireMutex);
207 if (myIsInParallel && aNbWires > 1)
209 // check wires in parallel threads using TBB
210 tbb::parallel_for(tbb::blocked_range<Standard_Integer>(0, aNbWires),
216 BRepMesh_WireInterferenceChecker aIntChecker(aWiresBiPoints, &myStatus);
218 for (Standard_Integer i = 0; i < aNbWires; ++i)
224 if (myStatus == BRepMesh_SelfIntersectingWire)
228 SeqOfDWires::iterator aDWiresIt = aDWires.begin();
229 for (; aDWiresIt != aDWires.end(); ++aDWiresIt)
231 const SeqOfPnt2d& aDWire = *aDWiresIt;
232 theClassifier->RegisterWire(aDWire, myTolUV, myUmin, myUmax, myVmin, myVmax);
236 //=======================================================================
237 //function : collectDiscretizedWires
239 //=======================================================================
240 Standard_Boolean BRepMesh_WireChecker::collectDiscretizedWires(
241 SeqOfDWires& theDWires)
243 // TODO: Collect disretized wires in parallel
244 SeqOfWireEdges::iterator aWireIt = myWiresEdges.begin();
245 for(; aWireIt != myWiresEdges.end(); ++aWireIt)
247 const ListOfEdges& aEdges = *aWireIt;
248 // For each wire we create a data map, linking vertices (only
249 // the ends of edges) with their positions in the sequence of
250 // all 2d points from this wire.
251 // When we meet some vertex for the second time - the piece
252 // of sequence is treated for a HOLE and quits the sequence.
253 // Actually, we must unbind the vertices belonging to the
254 // loop from the map, but since they can't appear twice on the
255 // valid wire, leave them for a little speed up.
257 SeqOfPnt2d aSeqPnt2d;
258 DataMapIntInt aNodeInSeq;
259 Standard_Integer aFirstIndex = 0, aLastIndex = 0;
261 // Start traversing the wire
262 ListOfEdges::Iterator aEdgeIt(aEdges);
263 for (; aEdgeIt.More(); aEdgeIt.Next())
265 const TopoDS_Edge& aEdge = aEdgeIt.Value();
266 TopAbs_Orientation aOrient = aEdge.Orientation();
267 if (!myEdges.IsBound(aEdge))
271 // Define the direction for adding points to aSeqPnt2d
272 Standard_Integer aStartId, aEndId, aIncrement;
273 const BRepMesh_PairOfPolygon& aPair = myEdges.Find(aEdge);
274 Handle(Poly_PolygonOnTriangulation) aNOD;
275 if (aOrient == TopAbs_FORWARD)
277 aNOD = aPair.First();
279 aEndId = aNOD->NbNodes();
285 aStartId = aNOD->NbNodes();
290 const TColStd_Array1OfInteger& aIndices = aNOD->Nodes();
291 const Standard_Integer aFirstVertexId = myVertexMap.FindKey(aIndices(aStartId));
292 const Standard_Integer aLastVertexId = myVertexMap.FindKey(aIndices(aEndId) );
294 if (aFirstVertexId == aLastVertexId && (aEndId - aStartId) == aIncrement)
296 // case of continuous set of degenerated edges
297 aLastIndex = aLastVertexId;
301 if (aFirstIndex != 0)
303 if (aFirstVertexId != aLastIndex)
305 // there's a gap between edges
306 myStatus = BRepMesh_OpenWire;
307 return Standard_False;
311 aFirstIndex = aFirstVertexId;
313 aLastIndex = aLastVertexId;
315 // Record first vertex (to detect loops)
316 aNodeInSeq.Bind(aFirstVertexId, (aSeqPnt2d.Length() + 1));
318 // Add vertices in sequence
319 for (Standard_Integer i = aStartId; i != aEndId; i += aIncrement)
321 Standard_Integer aIndex = ((i == aStartId) ?
323 myVertexMap.FindKey(aIndices(i)));
325 aSeqPnt2d.Append(gp_Pnt2d(myStructure->GetNode(aIndex).Coord()));
328 // Now, is there a loop?
329 if (aNodeInSeq.IsBound(aLastVertexId))
331 // Yes, treat it separately as a hole
332 // Divide points into main wire and a loop
333 const Standard_Integer aIdxWireStart = aNodeInSeq(aLastVertexId);
334 if(aIdxWireStart < aSeqPnt2d.Length())
336 theDWires.push_back(SeqOfPnt2d());
337 SeqOfPnt2d& aWire = theDWires.back();
338 aSeqPnt2d.Split(aIdxWireStart, aWire);
343 if (aFirstIndex == 0)
347 if (aFirstIndex != aLastIndex || aSeqPnt2d.Length() > 1)
349 myStatus = BRepMesh_OpenWire;
350 return Standard_False;
354 return Standard_True;
357 //=======================================================================
358 //function : fillSegmentsTree
360 //=======================================================================
361 void BRepMesh_WireChecker::fillSegmentsTree(
362 const SeqOfDWires& theDWires,
363 BRepMeshCol::Array1OfSegmentsTree& theWiresSegmentsTree)
365 const size_t aNbWires = theDWires.size();
366 for (size_t aWireIt = 0; aWireIt < aNbWires; ++aWireIt)
368 const SeqOfPnt2d& aWire = theDWires[aWireIt];
369 const Standard_Integer aWireLen = aWire.Size();
371 BRepMeshCol::HArray1OfSegments aWireSegments =
372 new BRepMeshCol::Array1OfSegments(aWireLen);
374 BRepMeshCol::HBndBox2dTree aBndBoxTree =
375 new BRepMeshCol::BndBox2dTree;
377 BRepMeshCol::BndBox2dTreeFiller aBndBoxTreeFiller(*aBndBoxTree);
379 Standard_Real x1 = 0., y1 = 0., aXstart = 0., aYstart = 0.;
380 for (Standard_Integer aPntIt = 0; aPntIt <= aWireLen; ++aPntIt)
382 Standard_Real x2, y2;
383 // Obtain last point of the segment
384 if (aPntIt == aWireLen)
391 const gp_Pnt2d& aPnt = aWire(aPntIt + 1);
396 // Build segment (bi-point)
404 gp_Pnt2d aStartPnt(x1, y1);
405 gp_Pnt2d aEndPnt(x2, y2);
407 const Standard_Integer aPointId = aPntIt - 1;
408 BRepMeshCol::Segment& aSegment = aWireSegments->at(aPointId);
409 aSegment.StartPnt = aStartPnt.XY();
410 aSegment.EndPnt = aEndPnt.XY();
415 aBndBoxTreeFiller.Add(aPointId, aBox);
420 aBndBoxTreeFiller.Fill();
422 BRepMeshCol::SegmentsTree& aSegmentsTree = theWiresSegmentsTree[aWireIt];
423 aSegmentsTree.first = aWireSegments;
424 aSegmentsTree.second = aBndBoxTree;