0030329: Move BRepMesh_IncAllocator to NCollection package
[occt.git] / src / BRepMesh / BRepMesh_FaceChecker.cxx
1 // Created on: 2016-07-04
2 // Copyright (c) 2016 OPEN CASCADE SAS
3 // Created by: Oleg AGASHIN
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BRepMesh_FaceChecker.hxx>
17 #include <IMeshData_Wire.hxx>
18 #include <IMeshData_Edge.hxx>
19 #include <OSD_Parallel.hxx>
20 #include <BRepMesh_GeomTool.hxx>
21
22 namespace
23 {
24   const Standard_Real MaxTangentAngle = 5. * M_PI / 180.;
25
26   //! Functor to be used to fill segments and bounding box tree in parallel.
27   class SegmentsFiller
28   {
29   public:
30     //! Constructor.
31     SegmentsFiller(const IMeshData::IFaceHandle&                    theDFace,
32                    Handle(BRepMesh_FaceChecker::ArrayOfSegments)&   theWiresSegments,
33                    Handle(BRepMesh_FaceChecker::ArrayOfBndBoxTree)& theWiresBndBoxTree)
34       : myDFace(theDFace),
35         myWiresSegments(theWiresSegments),
36         myWiresBndBoxTree(theWiresBndBoxTree)
37     {
38       myWiresSegments   = new BRepMesh_FaceChecker::ArrayOfSegments   (0, myDFace->WiresNb() - 1);
39       myWiresBndBoxTree = new BRepMesh_FaceChecker::ArrayOfBndBoxTree (0, myDFace->WiresNb() - 1);
40     }
41
42     //! Performs initialization of wire with the given index.
43     void operator()(const Standard_Integer theWireIndex) const
44     {
45       const IMeshData::IWireHandle& aDWire = myDFace->GetWire(theWireIndex);
46
47       Handle(NCollection_IncAllocator) aTmpAlloc1 = new NCollection_IncAllocator();
48
49       Handle(BRepMesh_FaceChecker::Segments) aSegments = 
50         new BRepMesh_FaceChecker::Segments(aDWire->EdgesNb(), aTmpAlloc1);
51       Handle(IMeshData::BndBox2dTree) aBndBoxTree = new IMeshData::BndBox2dTree(aTmpAlloc1);
52
53       myWiresSegments  ->ChangeValue(theWireIndex) = aSegments;
54       myWiresBndBoxTree->ChangeValue(theWireIndex) = aBndBoxTree;
55
56       Handle(NCollection_IncAllocator) aTmpAlloc2 = new NCollection_IncAllocator();
57       IMeshData::BndBox2dTreeFiller aBndBoxTreeFiller(*aBndBoxTree, aTmpAlloc2);
58
59       for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt)
60       {
61         // TODO: check 2d wire for consistency.
62
63         const IMeshData::IEdgePtr&      aDEdge  = aDWire->GetEdge(aEdgeIt);
64         const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(myDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt));
65
66         for (Standard_Integer aPointIt = 1; aPointIt < aPCurve->ParametersNb(); ++aPointIt)
67         {
68           gp_Pnt2d& aPnt1 = aPCurve->GetPoint(aPointIt - 1);
69           gp_Pnt2d& aPnt2 = aPCurve->GetPoint(aPointIt);
70
71           Bnd_Box2d aBox;
72           aBox.Add(aPnt1);
73           aBox.Add(aPnt2);
74           aBox.Enlarge(Precision::Confusion());
75
76           aBndBoxTreeFiller.Add(aSegments->Size(), aBox);
77           aSegments->Append(BRepMesh_FaceChecker::Segment(aDEdge, &aPnt1, &aPnt2));
78         }
79       }
80
81       aBndBoxTreeFiller.Fill();
82     }
83
84   private:
85
86     SegmentsFiller (const SegmentsFiller& theOther);
87
88     void operator=(const SegmentsFiller& theOther);
89
90   private:
91
92     const IMeshData::IFaceHandle&                    myDFace;
93     Handle(BRepMesh_FaceChecker::ArrayOfSegments)&   myWiresSegments;
94     Handle(BRepMesh_FaceChecker::ArrayOfBndBoxTree)& myWiresBndBoxTree;
95   };
96
97   //! Selector.
98   //! Used to identify segments with overlapped bounding boxes.
99   //! Selector.
100   //! Used to identify segments with overlapped bounding boxes.
101   class BndBox2dTreeSelector : public IMeshData::BndBox2dTree::Selector
102   {
103   public:
104     //! Constructor.
105     BndBox2dTreeSelector(const Standard_Real theTolerance)
106       : myMaxLoopSize(M_PI * theTolerance * theTolerance),
107         mySelfSegmentIndex(-1),
108         myIndices(256, new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE))
109     {
110     }
111
112     //! Sets working set of segments.
113     void SetSegments(const Handle(BRepMesh_FaceChecker::Segments)& theSegments)
114     {
115       mySegments = theSegments;
116     }
117
118     //! Resets current selector.
119     void Reset(const BRepMesh_FaceChecker::Segment* theSegment,
120                const Standard_Integer               theSelfSegmentIndex)
121     {
122       myIndices.Clear();
123
124       mySelfSegmentIndex = theSelfSegmentIndex;
125       mySegment = theSegment;
126
127       myBox.SetVoid();
128       myBox.Add(*mySegment->Point1);
129       myBox.Add(*mySegment->Point2);
130       myBox.Enlarge(Precision::Confusion());
131     }
132
133     //! Indicates should the given box be rejected or not.
134     virtual Standard_Boolean Reject(const Bnd_Box2d& theBox) const
135     {
136       return myBox.IsOut(theBox);
137     }
138
139     //! Accepts segment with the given index in case if it fits conditions.
140     virtual Standard_Boolean Accept(const Standard_Integer& theSegmentIndex)
141     {
142       const BRepMesh_FaceChecker::Segment& aSegment = mySegments->Value(theSegmentIndex);
143
144       gp_Pnt2d aIntPnt;
145       const BRepMesh_GeomTool::IntFlag aIntStatus = BRepMesh_GeomTool::IntSegSeg(
146         mySegment->Point1->XY(), mySegment->Point2->XY(),
147         aSegment.Point1->XY(), aSegment.Point2->XY(),
148         Standard_False, Standard_False, aIntPnt);
149
150       if (aIntStatus == BRepMesh_GeomTool::Cross)
151       {
152         const Standard_Real aAngle = gp_Vec2d(mySegment->Point1->XY(), mySegment->Point2->XY()).Angle(
153                                      gp_Vec2d(aSegment.Point1->XY(), aSegment.Point2->XY()));
154
155         if (Abs(aAngle) < MaxTangentAngle)
156         {
157           return Standard_False;
158         }
159
160         if (mySelfSegmentIndex != -1)
161         {
162           gp_XY aPrevVec;
163           Standard_Real aSumS = 0.;
164           const gp_XY& aRefPnt = aIntPnt.Coord();
165           for (Standard_Integer i = mySelfSegmentIndex; i < theSegmentIndex; ++i)
166           {
167             const BRepMesh_FaceChecker::Segment& aCurrSegment = mySegments->Value(i);
168             gp_XY aCurVec = aCurrSegment.Point2->XY() - aRefPnt;
169
170             if (aCurVec.SquareModulus() < gp::Resolution())
171               continue;
172
173             if (aPrevVec.SquareModulus() > gp::Resolution())
174               aSumS += aPrevVec ^ aCurVec;
175
176             aPrevVec = aCurVec;
177           }
178
179           if (Abs(aSumS / 2.) < myMaxLoopSize)
180           {
181             return Standard_False;
182           }
183         }
184
185         myIndices.Append(theSegmentIndex);
186         return Standard_True;
187       }
188
189       return Standard_False;
190     }
191
192     //! Returns indices of intersecting segments.
193     const IMeshData::VectorOfInteger& Indices() const
194     {
195       return myIndices;
196     }
197
198   private:
199
200     Standard_Real                          myMaxLoopSize;
201     Standard_Integer                       mySelfSegmentIndex;
202     Handle(BRepMesh_FaceChecker::Segments) mySegments;
203     const BRepMesh_FaceChecker::Segment*   mySegment;
204     Bnd_Box2d                              myBox;
205     IMeshData::VectorOfInteger             myIndices;
206   };
207 }
208
209 //=======================================================================
210 //function : Constructor
211 //purpose  : 
212 //=======================================================================
213 BRepMesh_FaceChecker::BRepMesh_FaceChecker(
214   const IMeshData::IFaceHandle& theFace,
215   const IMeshTools_Parameters&  theParameters)
216   : myDFace(theFace),
217     myParameters(theParameters)
218 {
219 }
220
221 //=======================================================================
222 //function : Destructor
223 //purpose  : 
224 //=======================================================================
225 BRepMesh_FaceChecker::~BRepMesh_FaceChecker()
226 {
227 }
228
229 //=======================================================================
230 //function : Perform
231 //purpose  : 
232 //=======================================================================
233 Standard_Boolean BRepMesh_FaceChecker::Perform()
234 {
235   myIntersectingEdges = new IMeshData::MapOfIEdgePtr;
236   collectSegments();
237
238   OSD_Parallel::For(0, myDFace->WiresNb(), *this, !isParallel());
239   collectResult();
240
241   myWiresBndBoxTree.Nullify();
242   myWiresSegments.Nullify();
243   myWiresIntersectingEdges.Nullify();
244   return myIntersectingEdges->IsEmpty();
245 }
246
247 //=======================================================================
248 //function : collectSegments
249 //purpose  : 
250 //=======================================================================
251 void BRepMesh_FaceChecker::collectSegments()
252 {
253   SegmentsFiller aSegmentsFiller(myDFace, myWiresSegments, myWiresBndBoxTree);
254   OSD_Parallel::For(0, myDFace->WiresNb(), aSegmentsFiller, !isParallel());
255
256   myWiresIntersectingEdges = new ArrayOfMapOfIEdgePtr(0, myDFace->WiresNb() - 1);
257 }
258
259 //=======================================================================
260 //function : perform
261 //purpose  : 
262 //=======================================================================
263 void BRepMesh_FaceChecker::perform(const Standard_Integer theWireIndex) const
264 {
265   const Handle(Segments)&           aSegments1     = myWiresSegments->Value(theWireIndex);
266   Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myWiresIntersectingEdges->ChangeValue(theWireIndex);
267
268   // TODO: Tolerance is set to twice value of face deflection in order to fit regressions.
269   BndBox2dTreeSelector aSelector(2 * myDFace->GetDeflection());
270   for (Standard_Integer aWireIt = theWireIndex; aWireIt < myDFace->WiresNb(); ++aWireIt)
271   {
272     const Handle(IMeshData::BndBox2dTree)& aBndBoxTree2 = myWiresBndBoxTree->Value(aWireIt);
273     const Handle(Segments)&                aSegments2 = myWiresSegments->Value(aWireIt);
274
275     aSelector.SetSegments(aSegments2);
276     for (Standard_Integer aSegmentIt = 0; aSegmentIt < aSegments1->Size(); ++aSegmentIt)
277     {
278       const BRepMesh_FaceChecker::Segment& aSegment1 = aSegments1->Value(aSegmentIt);
279       aSelector.Reset(&aSegment1, (aWireIt == theWireIndex) ? aSegmentIt : -1);
280       if (aBndBoxTree2->Select(aSelector) != 0)
281       {
282         if (aIntersections.IsNull())
283         {
284           aIntersections = new IMeshData::MapOfIEdgePtr;
285         }
286
287         aIntersections->Add(aSegment1.EdgePtr);
288
289         const IMeshData::VectorOfInteger& aSegments = aSelector.Indices();
290         for (Standard_Integer aSelIt = 0; aSelIt < aSegments.Size(); ++aSelIt)
291         {
292           const BRepMesh_FaceChecker::Segment& aSegment2 = aSegments2->Value(aSegments(aSelIt));
293           aIntersections->Add(aSegment2.EdgePtr);
294         }
295       }
296     }
297   }
298 }
299
300 //=======================================================================
301 //function : collectResult
302 //purpose  : 
303 //=======================================================================
304 void BRepMesh_FaceChecker::collectResult()
305 {
306   for (Standard_Integer aWireIt = 0; aWireIt < myDFace->WiresNb(); ++aWireIt)
307   {
308     const Handle(IMeshData::MapOfIEdgePtr)& aEdges = myWiresIntersectingEdges->Value(aWireIt);
309     if (!aEdges.IsNull())
310     {
311       myIntersectingEdges->Unite(*aEdges);
312     }
313   }
314 }