4e57c75e |
1 | // Created by: Peter KURNEV |
db8e4b9a |
2 | // Copyright (c) 2010-2012 OPEN CASCADE SAS |
4e57c75e |
3 | // Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE |
4 | // Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT, |
5 | // EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS |
6 | // |
4e57c75e |
7 | // |
d5f74e42 |
8 | // This file is part of Open CASCADE Technology software library. |
4e57c75e |
9 | // |
d5f74e42 |
10 | // This library is free software; you can redistribute it and/or modify it under |
11 | // the terms of the GNU Lesser General Public License version 2.1 as published |
12 | // by the Free Software Foundation, with special exception defined in the file |
13 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
14 | // distribution for complete text of the license and disclaimer of any warranty. |
15 | // |
16 | // Alternatively, this file may be used under the terms of Open CASCADE |
17 | // commercial license or contractual agreement. |
4e57c75e |
18 | |
42cf5bc1 |
19 | #include <Bnd_Box.hxx> |
1155d05a |
20 | #include <Bnd_Box2d.hxx> |
42cf5bc1 |
21 | #include <BOPAlgo_BuilderFace.hxx> |
22 | #include <BOPAlgo_WireEdgeSet.hxx> |
23 | #include <BOPAlgo_WireSplitter.hxx> |
33ba8565 |
24 | #include <BOPAlgo_Alerts.hxx> |
42cf5bc1 |
25 | #include <BOPTools_AlgoTools.hxx> |
26 | #include <BOPTools_AlgoTools2D.hxx> |
9324aa2d |
27 | #include <BOPTools_BoxTree.hxx> |
28 | #include <Bnd_Tools.hxx> |
42cf5bc1 |
29 | #include <BRep_Builder.hxx> |
30 | #include <BRep_Tool.hxx> |
31 | #include <BRepBndLib.hxx> |
32 | #include <BRepTools.hxx> |
33 | #include <Geom_Surface.hxx> |
4e57c75e |
34 | #include <gp_Dir.hxx> |
42cf5bc1 |
35 | #include <gp_Pln.hxx> |
4e57c75e |
36 | #include <gp_Pnt.hxx> |
42cf5bc1 |
37 | #include <gp_Pnt2d.hxx> |
38 | #include <gp_Vec.hxx> |
39 | #include <IntTools_Context.hxx> |
40 | #include <IntTools_FClass2d.hxx> |
41 | #include <NCollection_DataMap.hxx> |
d3578357 |
42 | #include <TColStd_MapOfInteger.hxx> |
4e57c75e |
43 | #include <TopAbs.hxx> |
42cf5bc1 |
44 | #include <TopExp.hxx> |
45 | #include <TopExp_Explorer.hxx> |
4e57c75e |
46 | #include <TopLoc_Location.hxx> |
98b37659 |
47 | #include <TopoDS.hxx> |
42cf5bc1 |
48 | #include <TopoDS_Edge.hxx> |
4e57c75e |
49 | #include <TopoDS_Face.hxx> |
42cf5bc1 |
50 | #include <TopoDS_Iterator.hxx> |
4e57c75e |
51 | #include <TopoDS_Shape.hxx> |
4e57c75e |
52 | #include <TopoDS_Vertex.hxx> |
42cf5bc1 |
53 | #include <TopoDS_Wire.hxx> |
1155d05a |
54 | #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx> |
55 | #include <TopTools_IndexedDataMapOfShapeShape.hxx> |
56 | #include <TopTools_ListOfShape.hxx> |
57 | #include <TopTools_MapOfShape.hxx> |
58 | #include <TopTools_MapOfOrientedShape.hxx> |
36f4947b |
59 | // |
4e57c75e |
60 | static |
61 | Standard_Boolean IsGrowthWire(const TopoDS_Shape& , |
1155d05a |
62 | const TopTools_IndexedMapOfShape& ); |
4e57c75e |
63 | |
64 | static |
65 | Standard_Boolean IsInside(const TopoDS_Shape& , |
66 | const TopoDS_Shape& , |
1e143abb |
67 | Handle(IntTools_Context)& ); |
4e57c75e |
68 | static |
1155d05a |
69 | void MakeInternalWires(const TopTools_IndexedMapOfShape& , |
70 | TopTools_ListOfShape& ); |
b858a698 |
71 | |
4e57c75e |
72 | //======================================================================= |
73 | //function : |
74 | //purpose : |
75 | //======================================================================= |
db8e4b9a |
76 | BOPAlgo_BuilderFace::BOPAlgo_BuilderFace() |
4e57c75e |
77 | : |
78 | BOPAlgo_BuilderArea() |
79 | { |
acccace3 |
80 | myOrientation=TopAbs_EXTERNAL; |
4e57c75e |
81 | } |
82 | //======================================================================= |
83 | //function : |
84 | //purpose : |
85 | //======================================================================= |
db8e4b9a |
86 | BOPAlgo_BuilderFace::BOPAlgo_BuilderFace |
87 | (const Handle(NCollection_BaseAllocator)& theAllocator) |
4e57c75e |
88 | : |
89 | BOPAlgo_BuilderArea(theAllocator) |
acccace3 |
90 | { |
91 | myOrientation=TopAbs_EXTERNAL; |
4e57c75e |
92 | } |
93 | //======================================================================= |
94 | //function : ~ |
95 | //purpose : |
96 | //======================================================================= |
97 | BOPAlgo_BuilderFace::~BOPAlgo_BuilderFace() |
98 | { |
99 | } |
100 | //======================================================================= |
101 | //function : SetFace |
102 | //purpose : |
103 | //======================================================================= |
db8e4b9a |
104 | void BOPAlgo_BuilderFace::SetFace(const TopoDS_Face& theFace) |
4e57c75e |
105 | { |
acccace3 |
106 | myOrientation=theFace.Orientation(); |
4e57c75e |
107 | myFace=theFace; |
acccace3 |
108 | myFace.Orientation(TopAbs_FORWARD); |
109 | } |
110 | //======================================================================= |
111 | //function : Orientation |
112 | //purpose : |
113 | //======================================================================= |
114 | TopAbs_Orientation BOPAlgo_BuilderFace::Orientation()const |
115 | { |
116 | return myOrientation; |
4e57c75e |
117 | } |
118 | //======================================================================= |
119 | //function : Face |
120 | //purpose : |
121 | //======================================================================= |
db8e4b9a |
122 | const TopoDS_Face& BOPAlgo_BuilderFace::Face()const |
4e57c75e |
123 | { |
124 | return myFace; |
125 | } |
126 | //======================================================================= |
127 | //function : CheckData |
128 | //purpose : |
129 | //======================================================================= |
db8e4b9a |
130 | void BOPAlgo_BuilderFace::CheckData() |
4e57c75e |
131 | { |
4e57c75e |
132 | if (myFace.IsNull()) { |
33ba8565 |
133 | AddError (new BOPAlgo_AlertNullInputShapes); |
4e57c75e |
134 | return; |
135 | } |
db8e4b9a |
136 | if (myContext.IsNull()) { |
1e143abb |
137 | myContext = new IntTools_Context; |
db8e4b9a |
138 | } |
4e57c75e |
139 | } |
140 | //======================================================================= |
141 | //function : Perform |
142 | //purpose : |
143 | //======================================================================= |
db8e4b9a |
144 | void BOPAlgo_BuilderFace::Perform() |
4e57c75e |
145 | { |
33ba8565 |
146 | GetReport()->Clear(); |
4e57c75e |
147 | // |
148 | CheckData(); |
33ba8565 |
149 | if (HasErrors()) { |
4e57c75e |
150 | return; |
151 | } |
152 | // |
36f4947b |
153 | UserBreak(); |
154 | // |
4e57c75e |
155 | PerformShapesToAvoid(); |
33ba8565 |
156 | if (HasErrors()) { |
4e57c75e |
157 | return; |
158 | } |
159 | // |
36f4947b |
160 | UserBreak(); |
161 | // |
4e57c75e |
162 | PerformLoops(); |
33ba8565 |
163 | if (HasErrors()) { |
4e57c75e |
164 | return; |
165 | } |
166 | // |
36f4947b |
167 | UserBreak(); |
168 | // |
4e57c75e |
169 | PerformAreas(); |
33ba8565 |
170 | if (HasErrors()) { |
4e57c75e |
171 | return; |
172 | } |
173 | // |
36f4947b |
174 | UserBreak(); |
175 | // |
4e57c75e |
176 | PerformInternalShapes(); |
33ba8565 |
177 | if (HasErrors()) { |
4e57c75e |
178 | return; |
179 | } |
180 | } |
181 | //======================================================================= |
182 | //function :PerformShapesToAvoid |
183 | //purpose : |
184 | //======================================================================= |
db8e4b9a |
185 | void BOPAlgo_BuilderFace::PerformShapesToAvoid() |
4e57c75e |
186 | { |
187 | Standard_Boolean bFound; |
188 | Standard_Integer i, iCnt, aNbV, aNbE; |
1155d05a |
189 | TopTools_IndexedDataMapOfShapeListOfShape aMVE; |
190 | TopTools_ListIteratorOfListOfShape aIt; |
4e57c75e |
191 | // |
192 | myShapesToAvoid.Clear(); |
193 | // |
194 | iCnt=0; |
302f96fb |
195 | for(;;) { |
4e57c75e |
196 | ++iCnt; |
197 | bFound=Standard_False; |
198 | // |
199 | // 1. MEF |
200 | aMVE.Clear(); |
201 | aIt.Initialize (myShapes); |
202 | for (; aIt.More(); aIt.Next()) { |
203 | const TopoDS_Shape& aE=aIt.Value(); |
204 | if (!myShapesToAvoid.Contains(aE)) { |
1155d05a |
205 | TopExp::MapShapesAndAncestors(aE, TopAbs_VERTEX, TopAbs_EDGE, aMVE); |
4e57c75e |
206 | } |
4e57c75e |
207 | } |
208 | aNbV=aMVE.Extent(); |
209 | // |
210 | // 2. myEdgesToAvoid |
211 | for (i=1; i<=aNbV; ++i) { |
212 | const TopoDS_Vertex& aV=(*(TopoDS_Vertex *)(&aMVE.FindKey(i))); |
213 | // |
1155d05a |
214 | TopTools_ListOfShape& aLE=aMVE.ChangeFromKey(aV); |
4e57c75e |
215 | aNbE=aLE.Extent(); |
216 | if (!aNbE) { |
217 | continue; |
218 | } |
219 | // |
220 | const TopoDS_Edge& aE1=(*(TopoDS_Edge *)(&aLE.First())); |
221 | if (aNbE==1) { |
222 | if (BRep_Tool::Degenerated(aE1)) { |
223 | continue; |
224 | } |
225 | if (aV.Orientation()==TopAbs_INTERNAL) { |
226 | continue; |
227 | } |
228 | bFound=Standard_True; |
229 | myShapesToAvoid.Add(aE1); |
230 | } |
231 | else if (aNbE==2) { |
232 | const TopoDS_Edge& aE2=(*(TopoDS_Edge *)(&aLE.Last())); |
233 | if (aE2.IsSame(aE1)) { |
234 | TopoDS_Vertex aV1x, aV2x; |
235 | // |
236 | TopExp::Vertices(aE1, aV1x, aV2x); |
237 | if (aV1x.IsSame(aV2x)) { |
238 | continue; |
239 | } |
240 | bFound=Standard_True; |
241 | myShapesToAvoid.Add(aE1); |
242 | myShapesToAvoid.Add(aE2); |
243 | } |
244 | } |
245 | }// for (i=1; i<=aNbE; ++i) { |
246 | // |
247 | if (!bFound) { |
248 | break; |
249 | } |
250 | // |
251 | }//while (1) |
252 | //printf(" EdgesToAvoid=%d, iCnt=%d\n", EdgesToAvoid.Extent(), iCnt); |
253 | } |
254 | //======================================================================= |
255 | //function : PerformLoops |
256 | //purpose : |
257 | //======================================================================= |
db8e4b9a |
258 | void BOPAlgo_BuilderFace::PerformLoops() |
4e57c75e |
259 | { |
4e57c75e |
260 | Standard_Boolean bFlag; |
33ba8565 |
261 | Standard_Integer i, aNbEA; |
1155d05a |
262 | TopTools_ListIteratorOfListOfShape aIt; |
263 | TopTools_IndexedDataMapOfShapeListOfShape aVEMap; |
264 | TopTools_MapOfOrientedShape aMAdded; |
4e57c75e |
265 | TopoDS_Iterator aItW; |
266 | BRep_Builder aBB; |
267 | BOPAlgo_WireEdgeSet aWES(myAllocator); |
268 | BOPAlgo_WireSplitter aWSp(myAllocator); |
269 | // |
270 | // 1. |
271 | myLoops.Clear(); |
272 | aWES.SetFace(myFace); |
273 | // |
274 | aIt.Initialize(myShapes); |
275 | for (; aIt.More(); aIt.Next()) { |
276 | const TopoDS_Shape& aE=aIt.Value(); |
277 | if (!myShapesToAvoid.Contains(aE)) { |
278 | aWES.AddStartElement(aE); |
279 | } |
280 | } |
281 | // |
282 | aWSp.SetWES(aWES); |
db8e4b9a |
283 | aWSp.SetRunParallel(myRunParallel); |
51db0179 |
284 | aWSp.SetContext(myContext); |
4e57c75e |
285 | aWSp.Perform(); |
33ba8565 |
286 | if (aWSp.HasErrors()) { |
4e57c75e |
287 | return; |
288 | } |
289 | // |
1155d05a |
290 | const TopTools_ListOfShape& aLW=aWES.Shapes(); |
4e57c75e |
291 | aIt.Initialize (aLW); |
292 | for (; aIt.More(); aIt.Next()) { |
293 | const TopoDS_Shape& aW=aIt.Value(); |
294 | myLoops.Append(aW); |
295 | } |
296 | // Post Treatment |
1155d05a |
297 | TopTools_MapOfOrientedShape aMEP; |
4e57c75e |
298 | // |
299 | // a. collect all edges that are in loops |
300 | aIt.Initialize (myLoops); |
301 | for (; aIt.More(); aIt.Next()) { |
302 | const TopoDS_Shape& aW=aIt.Value(); |
303 | aItW.Initialize(aW); |
304 | for (; aItW.More(); aItW.Next()) { |
305 | const TopoDS_Shape& aE=aItW.Value(); |
306 | aMEP.Add(aE); |
307 | } |
308 | } |
309 | // |
310 | // b. collect all edges that are to avoid |
319da2e4 |
311 | aNbEA = myShapesToAvoid.Extent(); |
312 | for (i = 1; i <= aNbEA; ++i) { |
313 | const TopoDS_Shape& aE = myShapesToAvoid(i); |
4e57c75e |
314 | aMEP.Add(aE); |
315 | } |
316 | // |
317 | // c. add all edges that are not processed to myShapesToAvoid |
318 | aIt.Initialize (myShapes); |
319 | for (; aIt.More(); aIt.Next()) { |
320 | const TopoDS_Shape& aE=aIt.Value(); |
321 | if (!aMEP.Contains(aE)) { |
322 | myShapesToAvoid.Add(aE); |
323 | } |
324 | } |
325 | // |
326 | // 2. Internal Wires |
327 | myLoopsInternal.Clear(); |
328 | // |
319da2e4 |
329 | aNbEA = myShapesToAvoid.Extent(); |
330 | for (i = 1; i <= aNbEA; ++i) { |
331 | const TopoDS_Shape& aEE = myShapesToAvoid(i); |
1155d05a |
332 | TopExp::MapShapesAndAncestors(aEE, |
1e143abb |
333 | TopAbs_VERTEX, |
334 | TopAbs_EDGE, |
335 | aVEMap); |
4e57c75e |
336 | } |
337 | // |
338 | bFlag=Standard_True; |
319da2e4 |
339 | for (i = 1; (i <= aNbEA) && bFlag; ++i) { |
340 | const TopoDS_Shape& aEE = myShapesToAvoid(i); |
4e57c75e |
341 | if (!aMAdded.Add(aEE)) { |
342 | continue; |
343 | } |
344 | // |
345 | // make new wire |
346 | TopoDS_Wire aW; |
347 | aBB.MakeWire(aW); |
348 | aBB.Add(aW, aEE); |
349 | // |
350 | aItW.Initialize(aW); |
351 | for (; aItW.More()&&bFlag; aItW.Next()) { |
352 | const TopoDS_Edge& aE=(*(TopoDS_Edge *)(&aItW.Value())); |
353 | // |
354 | TopoDS_Iterator aItE(aE); |
355 | for (; aItE.More()&&bFlag; aItE.Next()) { |
356 | const TopoDS_Vertex& aV = (*(TopoDS_Vertex *)(&aItE.Value())); |
1155d05a |
357 | const TopTools_ListOfShape& aLE=aVEMap.FindFromKey(aV); |
4e57c75e |
358 | aIt.Initialize(aLE); |
359 | for (; aIt.More()&&bFlag; aIt.Next()) { |
360 | const TopoDS_Shape& aEx=aIt.Value(); |
361 | if (aMAdded.Add(aEx)) { |
362 | aBB.Add(aW, aEx); |
363 | if(aMAdded.Extent()==aNbEA) { |
364 | bFlag=!bFlag; |
365 | } |
366 | } |
367 | }//for (; aIt.More(); aIt.Next()) { |
368 | }//for (; aItE.More(); aItE.Next()) { |
369 | }//for (; aItW.More(); aItW.Next()) { |
c5d8782c |
370 | aW.Closed(BRep_Tool::IsClosed(aW)); |
4e57c75e |
371 | myLoopsInternal.Append(aW); |
319da2e4 |
372 | }//for (i = 1; (i <= aNbEA) && bFlag; ++i) { |
4e57c75e |
373 | } |
374 | //======================================================================= |
375 | //function : PerformAreas |
376 | //purpose : |
377 | //======================================================================= |
db8e4b9a |
378 | void BOPAlgo_BuilderFace::PerformAreas() |
4e57c75e |
379 | { |
4e57c75e |
380 | myAreas.Clear(); |
98b37659 |
381 | BRep_Builder aBB; |
382 | // Location of the myFace |
383 | TopLoc_Location aLoc; |
384 | // Get surface from myFace |
385 | const Handle(Geom_Surface)& aS = BRep_Tool::Surface(myFace, aLoc); |
386 | // Get tolerance of myFace |
387 | Standard_Real aTol = BRep_Tool::Tolerance(myFace); |
388 | |
389 | // Check if there are no loops at all |
390 | if (myLoops.IsEmpty()) |
391 | { |
392 | if (myContext->IsInfiniteFace(myFace)) |
393 | { |
394 | TopoDS_Face aFace; |
f47b8d2b |
395 | aBB.MakeFace(aFace, aS, aLoc, aTol); |
98b37659 |
396 | if (BRep_Tool::NaturalRestriction(myFace)) |
f47b8d2b |
397 | aBB.NaturalRestriction(aFace, Standard_True); |
98b37659 |
398 | myAreas.Append(aFace); |
f47b8d2b |
399 | } |
400 | return; |
401 | } |
98b37659 |
402 | |
403 | // The new faces |
1155d05a |
404 | TopTools_ListOfShape aNewFaces; |
98b37659 |
405 | // The hole faces which has to be classified relatively new faces |
1155d05a |
406 | TopTools_IndexedMapOfShape aHoleFaces; |
98b37659 |
407 | // Map of the edges of the hole faces for quick check of the growths. |
408 | // If the analyzed wire contains any of the edges from the hole faces |
409 | // it is considered as growth. |
1155d05a |
410 | TopTools_IndexedMapOfShape aMHE; |
98b37659 |
411 | |
412 | // Analyze the new wires - classify them to be the holes and growths |
1155d05a |
413 | TopTools_ListIteratorOfListOfShape aItLL(myLoops); |
98b37659 |
414 | for (; aItLL.More(); aItLL.Next()) |
415 | { |
416 | const TopoDS_Shape& aWire = aItLL.Value(); |
417 | |
418 | TopoDS_Face aFace; |
db8e4b9a |
419 | aBB.MakeFace(aFace, aS, aLoc, aTol); |
98b37659 |
420 | aBB.Add(aFace, aWire); |
421 | |
422 | Standard_Boolean bIsGrowth = IsGrowthWire(aWire, aMHE); |
423 | if (!bIsGrowth) |
424 | { |
425 | // Fast check did not give the result, run classification |
426 | IntTools_FClass2d& aClsf = myContext->FClass2d(aFace); |
427 | bIsGrowth = !aClsf.IsHole(); |
4e57c75e |
428 | } |
98b37659 |
429 | |
430 | // Save the face |
431 | if (bIsGrowth) |
432 | { |
433 | aNewFaces.Append(aFace); |
4e57c75e |
434 | } |
98b37659 |
435 | else |
436 | { |
437 | aHoleFaces.Add(aFace); |
1155d05a |
438 | TopExp::MapShapes(aWire, TopAbs_EDGE, aMHE); |
db8e4b9a |
439 | } |
4e57c75e |
440 | } |
98b37659 |
441 | |
442 | if (aHoleFaces.IsEmpty()) |
443 | { |
444 | // No holes, stop the analysis |
445 | myAreas.Append(aNewFaces); |
d3578357 |
446 | return; |
98b37659 |
447 | } |
448 | |
449 | // Classify holes relatively faces |
450 | |
9324aa2d |
451 | // Prepare tree with the boxes of the hole faces |
452 | BOPTools_Box2dTree aBoxTree; |
98b37659 |
453 | Standard_Integer i, aNbH = aHoleFaces.Extent(); |
9324aa2d |
454 | aBoxTree.SetSize (aNbH); |
98b37659 |
455 | for (i = 1; i <= aNbH; ++i) |
456 | { |
457 | const TopoDS_Face& aHFace = TopoDS::Face(aHoleFaces(i)); |
db8e4b9a |
458 | // |
98b37659 |
459 | Bnd_Box2d aBox; |
460 | BRepTools::AddUVBounds(aHFace, aBox); |
9324aa2d |
461 | aBoxTree.Add(i, Bnd_Tools::Bnd2BVH (aBox)); |
98b37659 |
462 | } |
463 | |
9324aa2d |
464 | // Build BVH |
465 | aBoxTree.Build(); |
98b37659 |
466 | |
467 | // Find outer growth face that is most close to each hole face |
1155d05a |
468 | TopTools_IndexedDataMapOfShapeShape aHoleFaceMap; |
469 | |
470 | // Selector |
9324aa2d |
471 | BOPTools_Box2dTreeSelector aSelector; |
472 | aSelector.SetBVHSet (&aBoxTree); |
98b37659 |
473 | |
1155d05a |
474 | TopTools_ListIteratorOfListOfShape aItLS(aNewFaces); |
98b37659 |
475 | for (; aItLS.More(); aItLS.Next()) |
476 | { |
477 | const TopoDS_Face& aFace = TopoDS::Face(aItLS.Value()); |
478 | |
479 | // Build box |
480 | Bnd_Box2d aBox; |
481 | BRepTools::AddUVBounds(aFace, aBox); |
482 | |
1155d05a |
483 | aSelector.Clear(); |
9324aa2d |
484 | aSelector.SetBox(Bnd_Tools::Bnd2BVH (aBox)); |
485 | aSelector.Select(); |
98b37659 |
486 | |
1155d05a |
487 | const TColStd_ListOfInteger& aLI = aSelector.Indices(); |
488 | TColStd_ListIteratorOfListOfInteger aItLI(aLI); |
98b37659 |
489 | for (; aItLI.More(); aItLI.Next()) |
490 | { |
491 | Standard_Integer k = aItLI.Value(); |
492 | const TopoDS_Shape& aHole = aHoleFaces(k); |
493 | // Check if it is inside |
494 | if (!IsInside(aHole, aFace, myContext)) |
4e57c75e |
495 | continue; |
98b37659 |
496 | |
497 | // Save the relation |
498 | TopoDS_Shape* pFaceWas = aHoleFaceMap.ChangeSeek(aHole); |
499 | if (pFaceWas) |
500 | { |
501 | if (IsInside(aFace, *pFaceWas, myContext)) |
502 | { |
503 | *pFaceWas = aFace; |
4e57c75e |
504 | } |
505 | } |
98b37659 |
506 | else |
507 | { |
508 | aHoleFaceMap.Add(aHole, aFace); |
4e57c75e |
509 | } |
510 | } |
98b37659 |
511 | } |
512 | |
513 | // Make the back map from faces to holes |
1155d05a |
514 | TopTools_IndexedDataMapOfShapeListOfShape aFaceHolesMap; |
98b37659 |
515 | |
516 | aNbH = aHoleFaceMap.Extent(); |
517 | for (i = 1; i <= aNbH; ++i) |
518 | { |
519 | const TopoDS_Shape& aHole = aHoleFaceMap.FindKey(i); |
520 | const TopoDS_Shape& aFace = aHoleFaceMap(i); |
4e57c75e |
521 | // |
1155d05a |
522 | TopTools_ListOfShape* pLHoles = aFaceHolesMap.ChangeSeek(aFace); |
98b37659 |
523 | if (!pLHoles) |
1155d05a |
524 | pLHoles = &aFaceHolesMap(aFaceHolesMap.Add(aFace, TopTools_ListOfShape())); |
98b37659 |
525 | pLHoles->Append(aHole); |
db8e4b9a |
526 | } |
98b37659 |
527 | |
528 | // Add unused holes to the original face |
529 | if (aHoleFaces.Extent() != aHoleFaceMap.Extent()) |
530 | { |
d2d9e8dc |
531 | Bnd_Box aBoxF; |
532 | BRepBndLib::Add(myFace, aBoxF); |
533 | if (aBoxF.IsOpenXmin() || aBoxF.IsOpenXmax() || |
534 | aBoxF.IsOpenYmin() || aBoxF.IsOpenYmax() || |
98b37659 |
535 | aBoxF.IsOpenZmin() || aBoxF.IsOpenZmax()) |
536 | { |
537 | TopoDS_Face aFace; |
538 | aBB.MakeFace(aFace, aS, aLoc, aTol); |
1155d05a |
539 | TopTools_ListOfShape& anUnUsedHoles = aFaceHolesMap(aFaceHolesMap.Add(aFace, TopTools_ListOfShape())); |
98b37659 |
540 | aNbH = aHoleFaces.Extent(); |
541 | for (i = 1; i <= aNbH; ++i) |
542 | { |
543 | const TopoDS_Shape& aHole = aHoleFaces(i); |
544 | if (!aHoleFaceMap.Contains(aHole)) |
545 | anUnUsedHoles.Append(aHole); |
d2d9e8dc |
546 | } |
98b37659 |
547 | // Save it |
548 | aNewFaces.Append(aFace); |
d2d9e8dc |
549 | } |
550 | } |
98b37659 |
551 | |
552 | // Add Holes to Faces and add them to myAreas |
553 | aItLS.Initialize(aNewFaces); |
554 | for ( ; aItLS.More(); aItLS.Next()) |
555 | { |
556 | TopoDS_Face& aFace = *(TopoDS_Face*)&aItLS.Value(); |
1155d05a |
557 | const TopTools_ListOfShape* pLHoles = aFaceHolesMap.Seek(aFace); |
98b37659 |
558 | if (pLHoles) |
559 | { |
560 | // update faces with the holes |
1155d05a |
561 | TopTools_ListIteratorOfListOfShape aItLH(*pLHoles); |
98b37659 |
562 | for (; aItLH.More(); aItLH.Next()) |
563 | { |
564 | const TopoDS_Shape& aFHole = aItLH.Value(); |
565 | // The hole face contains only one wire |
566 | TopoDS_Iterator aItW(aFHole); |
567 | aBB.Add(aFace, aItW.Value()); |
568 | } |
569 | |
570 | // update classifier |
571 | myContext->FClass2d(aFace).Init(aFace, aTol); |
db8e4b9a |
572 | } |
98b37659 |
573 | |
574 | // The face is just a draft that does not contain any internal shapes |
575 | myAreas.Append(aFace); |
4e57c75e |
576 | } |
577 | } |
578 | //======================================================================= |
579 | //function : PerformInternalShapes |
580 | //purpose : |
581 | //======================================================================= |
db8e4b9a |
582 | void BOPAlgo_BuilderFace::PerformInternalShapes() |
4e57c75e |
583 | { |
d3578357 |
584 | if (myAvoidInternalShapes) |
585 | // User-defined option to avoid internal edges |
586 | // in the result is in force. |
291fced1 |
587 | return; |
d3578357 |
588 | |
589 | if (myLoopsInternal.IsEmpty()) |
590 | // No edges left for classification |
4e57c75e |
591 | return; |
d3578357 |
592 | |
9324aa2d |
593 | // Prepare tree with the boxes of the edges to classify |
594 | BOPTools_Box2dTree aBoxTree; |
d3578357 |
595 | |
596 | // Map of edges to classify |
597 | TopTools_IndexedMapOfShape anEdgesMap; |
598 | |
599 | // Fill the tree and the map |
600 | TopTools_ListIteratorOfListOfShape itLE(myLoopsInternal); |
601 | for (; itLE.More(); itLE.Next()) |
602 | { |
603 | TopoDS_Iterator itE(itLE.Value()); |
604 | for (; itE.More(); itE.Next()) |
605 | { |
606 | const TopoDS_Edge& aE = TopoDS::Edge(itE.Value()); |
607 | if (!anEdgesMap.Contains(aE)) |
608 | { |
609 | Bnd_Box2d aBoxE; |
610 | BRepTools::AddUVBounds(myFace, aE, aBoxE); |
611 | // Make sure the index of edge in the map and |
612 | // of the box in the tree is the same |
9324aa2d |
613 | aBoxTree.Add(anEdgesMap.Add(aE), Bnd_Tools::Bnd2BVH (aBoxE)); |
d3578357 |
614 | } |
4e57c75e |
615 | } |
616 | } |
d3578357 |
617 | |
9324aa2d |
618 | // Build BVH |
619 | aBoxTree.Build(); |
d3578357 |
620 | |
621 | // Fence map |
622 | TColStd_MapOfInteger aMEDone; |
623 | |
624 | // Classify edges relatively faces |
625 | TopTools_ListIteratorOfListOfShape itLF(myAreas); |
626 | for (; itLF.More(); itLF.Next()) |
627 | { |
628 | TopoDS_Face& aF = *(TopoDS_Face*)&itLF.Value(); |
629 | |
630 | // Build box |
631 | Bnd_Box2d aBoxF; |
632 | BRepTools::AddUVBounds(aF, aBoxF); |
633 | |
634 | // Select edges for the classification |
9324aa2d |
635 | BOPTools_Box2dTreeSelector aSelector; |
636 | aSelector.SetBVHSet (&aBoxTree); |
637 | aSelector.SetBox(Bnd_Tools::Bnd2BVH (aBoxF)); |
638 | if (!aSelector.Select()) |
d3578357 |
639 | continue; |
640 | |
641 | // Collect edges inside the face |
642 | TopTools_IndexedMapOfShape anEdgesInside; |
643 | |
644 | const TColStd_ListOfInteger& aLI = aSelector.Indices(); |
645 | TColStd_ListIteratorOfListOfInteger itLI(aLI); |
646 | for (; itLI.More(); itLI.Next()) |
647 | { |
648 | const Standard_Integer nE = itLI.Value(); |
649 | if (aMEDone.Contains(nE)) |
650 | continue; |
651 | |
652 | const TopoDS_Edge& aE = TopoDS::Edge(anEdgesMap(nE)); |
653 | if (IsInside(aE, aF, myContext)) |
654 | { |
655 | anEdgesInside.Add(aE); |
656 | aMEDone.Add(nE); |
319da2e4 |
657 | } |
4e57c75e |
658 | } |
d3578357 |
659 | |
660 | if (anEdgesInside.IsEmpty()) |
661 | continue; |
662 | |
663 | // Make internal wires |
664 | TopTools_ListOfShape aLSI; |
665 | MakeInternalWires(anEdgesInside, aLSI); |
666 | |
667 | // Add wires to a face |
668 | TopTools_ListIteratorOfListOfShape itLSI(aLSI); |
669 | for (; itLSI.More(); itLSI.Next()) |
670 | { |
671 | const TopoDS_Shape& aWI = itLSI.Value(); |
672 | BRep_Builder().Add(aF, aWI); |
4e57c75e |
673 | } |
d3578357 |
674 | |
675 | // Condition of early exit |
676 | if (aMEDone.Extent() == anEdgesMap.Extent()) |
677 | // All edges are classified and added into the faces |
678 | return; |
679 | } |
680 | |
681 | // Some edges are left unclassified - warn user about them |
682 | TopTools_IndexedMapOfShape anEdgesUnUsed; |
683 | for (Standard_Integer i = 1; i <= anEdgesMap.Extent(); ++i) |
684 | { |
685 | if (!aMEDone.Contains(i)) |
686 | anEdgesUnUsed.Add(anEdgesMap(i)); |
687 | } |
688 | |
689 | // Make internal wires |
690 | TopTools_ListOfShape aLSI; |
691 | MakeInternalWires(anEdgesUnUsed, aLSI); |
692 | |
693 | // Make compound |
694 | TopoDS_Compound aWShape; |
695 | BRep_Builder().MakeCompound(aWShape); |
696 | BRep_Builder().Add(aWShape, myFace); |
697 | if (aLSI.Extent() == 1) |
698 | BRep_Builder().Add(aWShape, aLSI.First()); |
699 | else |
700 | { |
701 | TopoDS_Compound aCE; |
702 | BRep_Builder().MakeCompound(aCE); |
703 | for (TopTools_ListIteratorOfListOfShape it(aLSI); it.More(); it.Next()) |
704 | BRep_Builder().Add(aCE, it.Value()); |
705 | BRep_Builder().Add(aWShape, aCE); |
706 | } |
707 | |
708 | // Add warning |
709 | AddWarning(new BOPAlgo_AlertFaceBuilderUnusedEdges(aWShape)); |
4e57c75e |
710 | } |
711 | //======================================================================= |
712 | //function : MakeInternalWires |
713 | //purpose : |
714 | //======================================================================= |
1155d05a |
715 | void MakeInternalWires(const TopTools_IndexedMapOfShape& theME, |
716 | TopTools_ListOfShape& theWires) |
4e57c75e |
717 | { |
319da2e4 |
718 | Standard_Integer i, aNbE; |
1155d05a |
719 | TopTools_MapOfShape aAddedMap; |
720 | TopTools_ListIteratorOfListOfShape aItE; |
721 | TopTools_IndexedDataMapOfShapeListOfShape aMVE; |
4e57c75e |
722 | BRep_Builder aBB; |
723 | // |
319da2e4 |
724 | aNbE = theME.Extent(); |
725 | for (i = 1; i <= aNbE; ++i) { |
726 | const TopoDS_Shape& aE = theME(i); |
1155d05a |
727 | TopExp::MapShapesAndAncestors(aE, TopAbs_VERTEX, TopAbs_EDGE, aMVE); |
4e57c75e |
728 | } |
729 | // |
319da2e4 |
730 | for (i = 1; i <= aNbE; ++i) { |
731 | TopoDS_Shape aEE = theME(i); |
4e57c75e |
732 | if (!aAddedMap.Add(aEE)) { |
733 | continue; |
734 | } |
735 | // |
736 | // make a new shell |
737 | TopoDS_Wire aW; |
738 | aBB.MakeWire(aW); |
739 | aEE.Orientation(TopAbs_INTERNAL); |
740 | aBB.Add(aW, aEE); |
741 | // |
742 | TopoDS_Iterator aItAdded (aW); |
743 | for (; aItAdded.More(); aItAdded.Next()) { |
744 | const TopoDS_Shape& aE =aItAdded.Value(); |
745 | // |
746 | TopExp_Explorer aExp(aE, TopAbs_VERTEX); |
747 | for (; aExp.More(); aExp.Next()) { |
748 | const TopoDS_Shape& aV =aExp.Current(); |
1155d05a |
749 | const TopTools_ListOfShape& aLE=aMVE.FindFromKey(aV); |
4e57c75e |
750 | aItE.Initialize(aLE); |
751 | for (; aItE.More(); aItE.Next()) { |
752 | TopoDS_Shape aEL=aItE.Value(); |
753 | if (aAddedMap.Add(aEL)){ |
754 | aEL.Orientation(TopAbs_INTERNAL); |
755 | aBB.Add(aW, aEL); |
756 | } |
757 | } |
758 | } |
759 | } |
c5d8782c |
760 | aW.Closed(BRep_Tool::IsClosed(aW)); |
4e57c75e |
761 | theWires.Append(aW); |
762 | } |
763 | } |
764 | //======================================================================= |
765 | //function : IsInside |
766 | //purpose : |
767 | //======================================================================= |
f8163956 |
768 | Standard_Boolean IsInside(const TopoDS_Shape& theWire, |
769 | const TopoDS_Shape& theF, |
1e143abb |
770 | Handle(IntTools_Context)& theContext) |
4e57c75e |
771 | { |
f8163956 |
772 | // Check if the wire is located inside the face: |
773 | // take unique point from the wire and classify it relatively the face |
774 | |
775 | // Avoid edges of the face |
776 | TopTools_IndexedMapOfShape aFaceEdgesMap; |
777 | TopExp::MapShapes(theF, TopAbs_EDGE, aFaceEdgesMap); |
778 | |
779 | // Get classification tool from the context |
780 | const TopoDS_Face& aF = TopoDS::Face(theF); |
781 | IntTools_FClass2d& aClassifier = theContext->FClass2d(aF); |
782 | |
783 | Standard_Boolean isInside = Standard_False; |
784 | |
785 | // Iterate on wire edges until first classification is performed |
786 | TopExp_Explorer anExp(theWire, TopAbs_EDGE); |
787 | for (; anExp.More(); anExp.Next()) |
788 | { |
789 | const TopoDS_Edge& aE = TopoDS::Edge(anExp.Current()); |
790 | if (BRep_Tool::Degenerated(aE)) |
791 | // Avoid checking degenerated edges. |
792 | continue; |
793 | |
794 | if (aFaceEdgesMap.Contains(aE)) |
795 | // Face contains the edge from the wire, thus the wire cannot be |
796 | // inside that face. |
797 | return isInside; |
798 | |
799 | // Get 2d curve of the edge on the face |
800 | Standard_Real aT1, aT2; |
801 | const Handle(Geom2d_Curve)& aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2); |
802 | if (aC2D.IsNull()) |
803 | continue; |
804 | |
805 | // Get middle point on the curve |
806 | gp_Pnt2d aP2D = aC2D->Value((aT1 + aT2) / 2.); |
807 | |
808 | // Classify the point |
809 | TopAbs_State aState = aClassifier.Perform(aP2D); |
810 | isInside = (aState == TopAbs_IN); |
811 | break; |
4e57c75e |
812 | } |
f8163956 |
813 | return isInside; |
4e57c75e |
814 | } |
4e57c75e |
815 | //======================================================================= |
816 | //function : IsGrowthWire |
817 | //purpose : |
818 | //======================================================================= |
819 | Standard_Boolean IsGrowthWire(const TopoDS_Shape& theWire, |
1155d05a |
820 | const TopTools_IndexedMapOfShape& theMHE) |
4e57c75e |
821 | { |
98b37659 |
822 | if (theMHE.Extent()) |
823 | { |
824 | TopoDS_Iterator aIt(theWire); |
825 | for(; aIt.More(); aIt.Next()) |
826 | { |
827 | if (theMHE.Contains(aIt.Value())) |
828 | return Standard_True; |
4e57c75e |
829 | } |
830 | } |
98b37659 |
831 | return Standard_False; |
4e57c75e |
832 | } |