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