cc2491df7029fc6f069e992e082903ea5b3b5659
[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   class BndBox2dTreeSelector : public IMeshData::BndBox2dTree::Selector
100   {
101   public:
102     //! Constructor.
103     BndBox2dTreeSelector(const Standard_Real theTolerance)
104       : myMaxLoopSize(M_PI * theTolerance * theTolerance),
105         mySelfSegmentIndex(-1),
106         myIndices(256, new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE))
107     {
108     }
109
110     //! Sets working set of segments.
111     void SetSegments(const Handle(BRepMesh_FaceChecker::Segments)& theSegments)
112     {
113       mySegments = theSegments;
114     }
115
116     //! Resets current selector.
117     void Reset(const BRepMesh_FaceChecker::Segment* theSegment,
118                const Standard_Integer               theSelfSegmentIndex)
119     {
120       myIndices.Clear();
121
122       mySelfSegmentIndex = theSelfSegmentIndex;
123       mySegment = theSegment;
124
125       myBox.SetVoid();
126       myBox.Add(*mySegment->Point1);
127       myBox.Add(*mySegment->Point2);
128       myBox.Enlarge(Precision::Confusion());
129     }
130
131     //! Indicates should the given box be rejected or not.
132     virtual Standard_Boolean Reject(const Bnd_Box2d& theBox) const
133     {
134       return myBox.IsOut(theBox);
135     }
136
137     //! Accepts segment with the given index in case if it fits conditions.
138     virtual Standard_Boolean Accept(const Standard_Integer& theSegmentIndex)
139     {
140       const BRepMesh_FaceChecker::Segment& aSegment = mySegments->Value(theSegmentIndex);
141
142       gp_Pnt2d aIntPnt;
143       const BRepMesh_GeomTool::IntFlag aIntStatus = BRepMesh_GeomTool::IntSegSeg(
144         mySegment->Point1->XY(), mySegment->Point2->XY(),
145         aSegment.Point1->XY(), aSegment.Point2->XY(),
146         Standard_False, Standard_False, aIntPnt);
147
148       if (aIntStatus == BRepMesh_GeomTool::Cross)
149       {
150         const Standard_Real aAngle = gp_Vec2d(mySegment->Point1->XY(), mySegment->Point2->XY()).Angle(
151                                      gp_Vec2d(aSegment.Point1->XY(), aSegment.Point2->XY()));
152
153         if (Abs(aAngle) < MaxTangentAngle)
154         {
155           return Standard_False;
156         }
157
158         if (mySelfSegmentIndex != -1)
159         {
160           gp_XY aPrevVec;
161           Standard_Real aSumS = 0.;
162           const gp_XY& aRefPnt = aIntPnt.Coord();
163           for (Standard_Integer i = mySelfSegmentIndex; i < theSegmentIndex; ++i)
164           {
165             const BRepMesh_FaceChecker::Segment& aCurrSegment = mySegments->Value(i);
166             gp_XY aCurVec = aCurrSegment.Point2->XY() - aRefPnt;
167
168             if (aCurVec.SquareModulus() < gp::Resolution())
169               continue;
170
171             if (aPrevVec.SquareModulus() > gp::Resolution())
172               aSumS += aPrevVec ^ aCurVec;
173
174             aPrevVec = aCurVec;
175           }
176
177           if (Abs(aSumS / 2.) < myMaxLoopSize)
178           {
179             return Standard_False;
180           }
181         }
182
183         myIndices.Append(theSegmentIndex);
184         return Standard_True;
185       }
186
187       return Standard_False;
188     }
189
190     //! Returns indices of intersecting segments.
191     const IMeshData::VectorOfInteger& Indices() const
192     {
193       return myIndices;
194     }
195
196   private:
197
198     Standard_Real                          myMaxLoopSize;
199     Standard_Integer                       mySelfSegmentIndex;
200     Handle(BRepMesh_FaceChecker::Segments) mySegments;
201     const BRepMesh_FaceChecker::Segment*   mySegment;
202     Bnd_Box2d                              myBox;
203     IMeshData::VectorOfInteger             myIndices;
204   };
205 }
206
207 //=======================================================================
208 //function : Constructor
209 //purpose  : 
210 //=======================================================================
211 BRepMesh_FaceChecker::BRepMesh_FaceChecker(
212   const IMeshData::IFaceHandle& theFace,
213   const IMeshTools_Parameters&  theParameters)
214   : myDFace(theFace),
215     myParameters(theParameters)
216 {
217 }
218
219 //=======================================================================
220 //function : Destructor
221 //purpose  : 
222 //=======================================================================
223 BRepMesh_FaceChecker::~BRepMesh_FaceChecker()
224 {
225 }
226
227 //=======================================================================
228 //function : Perform
229 //purpose  : 
230 //=======================================================================
231 Standard_Boolean BRepMesh_FaceChecker::Perform()
232 {
233   myIntersectingEdges = new IMeshData::MapOfIEdgePtr;
234   collectSegments();
235
236   OSD_Parallel::For(0, myDFace->WiresNb(), *this, !isParallel());
237   collectResult();
238
239   myWiresBndBoxTree.Nullify();
240   myWiresSegments.Nullify();
241   myWiresIntersectingEdges.Nullify();
242   return myIntersectingEdges->IsEmpty();
243 }
244
245 //=======================================================================
246 //function : collectSegments
247 //purpose  : 
248 //=======================================================================
249 void BRepMesh_FaceChecker::collectSegments()
250 {
251   SegmentsFiller aSegmentsFiller(myDFace, myWiresSegments, myWiresBndBoxTree);
252   OSD_Parallel::For(0, myDFace->WiresNb(), aSegmentsFiller, !isParallel());
253
254   myWiresIntersectingEdges = new ArrayOfMapOfIEdgePtr(0, myDFace->WiresNb() - 1);
255 }
256
257 //=======================================================================
258 //function : perform
259 //purpose  : 
260 //=======================================================================
261 void BRepMesh_FaceChecker::perform(const Standard_Integer theWireIndex) const
262 {
263   const Handle(Segments)&           aSegments1     = myWiresSegments->Value(theWireIndex);
264   Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myWiresIntersectingEdges->ChangeValue(theWireIndex);
265
266   // TODO: Tolerance is set to twice value of face deflection in order to fit regressions.
267   BndBox2dTreeSelector aSelector(2 * myDFace->GetDeflection());
268   for (Standard_Integer aWireIt = theWireIndex; aWireIt < myDFace->WiresNb(); ++aWireIt)
269   {
270     const Handle(IMeshData::BndBox2dTree)& aBndBoxTree2 = myWiresBndBoxTree->Value(aWireIt);
271     const Handle(Segments)&                aSegments2 = myWiresSegments->Value(aWireIt);
272
273     aSelector.SetSegments(aSegments2);
274     for (Standard_Integer aSegmentIt = 0; aSegmentIt < aSegments1->Size(); ++aSegmentIt)
275     {
276       const BRepMesh_FaceChecker::Segment& aSegment1 = aSegments1->Value(aSegmentIt);
277       aSelector.Reset(&aSegment1, (aWireIt == theWireIndex) ? aSegmentIt : -1);
278       if (aBndBoxTree2->Select(aSelector) != 0)
279       {
280         if (aIntersections.IsNull())
281         {
282           aIntersections = new IMeshData::MapOfIEdgePtr;
283         }
284
285         aIntersections->Add(aSegment1.EdgePtr);
286
287         const IMeshData::VectorOfInteger& aSegments = aSelector.Indices();
288         for (Standard_Integer aSelIt = 0; aSelIt < aSegments.Size(); ++aSelIt)
289         {
290           const BRepMesh_FaceChecker::Segment& aSegment2 = aSegments2->Value(aSegments(aSelIt));
291           aIntersections->Add(aSegment2.EdgePtr);
292         }
293       }
294     }
295   }
296 }
297
298 //=======================================================================
299 //function : collectResult
300 //purpose  : 
301 //=======================================================================
302 void BRepMesh_FaceChecker::collectResult()
303 {
304   for (Standard_Integer aWireIt = 0; aWireIt < myDFace->WiresNb(); ++aWireIt)
305   {
306     const Handle(IMeshData::MapOfIEdgePtr)& aEdges = myWiresIntersectingEdges->Value(aWireIt);
307     if (!aEdges.IsNull())
308     {
309       myIntersectingEdges->Unite(*aEdges);
310     }
311   }
312 }