7bd071ed |
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 | } |