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