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> |
1155d05a |
27 | #include <BOPTools_BoxSelector.hxx> |
42cf5bc1 |
28 | #include <BRep_Builder.hxx> |
29 | #include <BRep_Tool.hxx> |
30 | #include <BRepBndLib.hxx> |
31 | #include <BRepTools.hxx> |
32 | #include <Geom_Surface.hxx> |
4e57c75e |
33 | #include <gp_Dir.hxx> |
42cf5bc1 |
34 | #include <gp_Pln.hxx> |
4e57c75e |
35 | #include <gp_Pnt.hxx> |
42cf5bc1 |
36 | #include <gp_Pnt2d.hxx> |
37 | #include <gp_Vec.hxx> |
38 | #include <IntTools_Context.hxx> |
39 | #include <IntTools_FClass2d.hxx> |
40 | #include <NCollection_DataMap.hxx> |
41 | #include <NCollection_UBTreeFiller.hxx> |
42 | #include <TColStd_MapIntegerHasher.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); |
446 | } |
447 | |
448 | // Classify holes relatively faces |
449 | |
450 | // Prepare tree filler with the boxes of the hole faces |
1155d05a |
451 | NCollection_UBTree<Standard_Integer, Bnd_Box2d> aBBTree; |
98b37659 |
452 | NCollection_UBTreeFiller <Standard_Integer, Bnd_Box2d> aTreeFiller(aBBTree); |
453 | |
454 | Standard_Integer i, aNbH = aHoleFaces.Extent(); |
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); |
461 | aTreeFiller.Add(i, aBox); |
462 | } |
463 | |
464 | // Shake TreeFiller |
465 | aTreeFiller.Fill(); |
466 | |
467 | // Find outer growth face that is most close to each hole face |
1155d05a |
468 | TopTools_IndexedDataMapOfShapeShape aHoleFaceMap; |
469 | |
470 | // Selector |
471 | BOPTools_BoxSelector<Bnd_Box2d> aSelector; |
98b37659 |
472 | |
1155d05a |
473 | TopTools_ListIteratorOfListOfShape aItLS(aNewFaces); |
98b37659 |
474 | for (; aItLS.More(); aItLS.Next()) |
475 | { |
476 | const TopoDS_Face& aFace = TopoDS::Face(aItLS.Value()); |
477 | |
478 | // Build box |
479 | Bnd_Box2d aBox; |
480 | BRepTools::AddUVBounds(aFace, aBox); |
481 | |
1155d05a |
482 | aSelector.Clear(); |
98b37659 |
483 | aSelector.SetBox(aBox); |
484 | aBBTree.Select(aSelector); |
485 | |
1155d05a |
486 | const TColStd_ListOfInteger& aLI = aSelector.Indices(); |
487 | TColStd_ListIteratorOfListOfInteger aItLI(aLI); |
98b37659 |
488 | for (; aItLI.More(); aItLI.Next()) |
489 | { |
490 | Standard_Integer k = aItLI.Value(); |
491 | const TopoDS_Shape& aHole = aHoleFaces(k); |
492 | // Check if it is inside |
493 | if (!IsInside(aHole, aFace, myContext)) |
4e57c75e |
494 | continue; |
98b37659 |
495 | |
496 | // Save the relation |
497 | TopoDS_Shape* pFaceWas = aHoleFaceMap.ChangeSeek(aHole); |
498 | if (pFaceWas) |
499 | { |
500 | if (IsInside(aFace, *pFaceWas, myContext)) |
501 | { |
502 | *pFaceWas = aFace; |
4e57c75e |
503 | } |
504 | } |
98b37659 |
505 | else |
506 | { |
507 | aHoleFaceMap.Add(aHole, aFace); |
4e57c75e |
508 | } |
509 | } |
98b37659 |
510 | } |
511 | |
512 | // Make the back map from faces to holes |
1155d05a |
513 | TopTools_IndexedDataMapOfShapeListOfShape aFaceHolesMap; |
98b37659 |
514 | |
515 | aNbH = aHoleFaceMap.Extent(); |
516 | for (i = 1; i <= aNbH; ++i) |
517 | { |
518 | const TopoDS_Shape& aHole = aHoleFaceMap.FindKey(i); |
519 | const TopoDS_Shape& aFace = aHoleFaceMap(i); |
4e57c75e |
520 | // |
1155d05a |
521 | TopTools_ListOfShape* pLHoles = aFaceHolesMap.ChangeSeek(aFace); |
98b37659 |
522 | if (!pLHoles) |
1155d05a |
523 | pLHoles = &aFaceHolesMap(aFaceHolesMap.Add(aFace, TopTools_ListOfShape())); |
98b37659 |
524 | pLHoles->Append(aHole); |
db8e4b9a |
525 | } |
98b37659 |
526 | |
527 | // Add unused holes to the original face |
528 | if (aHoleFaces.Extent() != aHoleFaceMap.Extent()) |
529 | { |
d2d9e8dc |
530 | Bnd_Box aBoxF; |
531 | BRepBndLib::Add(myFace, aBoxF); |
532 | if (aBoxF.IsOpenXmin() || aBoxF.IsOpenXmax() || |
533 | aBoxF.IsOpenYmin() || aBoxF.IsOpenYmax() || |
98b37659 |
534 | aBoxF.IsOpenZmin() || aBoxF.IsOpenZmax()) |
535 | { |
536 | TopoDS_Face aFace; |
537 | aBB.MakeFace(aFace, aS, aLoc, aTol); |
1155d05a |
538 | TopTools_ListOfShape& anUnUsedHoles = aFaceHolesMap(aFaceHolesMap.Add(aFace, TopTools_ListOfShape())); |
98b37659 |
539 | aNbH = aHoleFaces.Extent(); |
540 | for (i = 1; i <= aNbH; ++i) |
541 | { |
542 | const TopoDS_Shape& aHole = aHoleFaces(i); |
543 | if (!aHoleFaceMap.Contains(aHole)) |
544 | anUnUsedHoles.Append(aHole); |
d2d9e8dc |
545 | } |
98b37659 |
546 | // Save it |
547 | aNewFaces.Append(aFace); |
d2d9e8dc |
548 | } |
549 | } |
98b37659 |
550 | |
551 | // Add Holes to Faces and add them to myAreas |
552 | aItLS.Initialize(aNewFaces); |
553 | for ( ; aItLS.More(); aItLS.Next()) |
554 | { |
555 | TopoDS_Face& aFace = *(TopoDS_Face*)&aItLS.Value(); |
1155d05a |
556 | const TopTools_ListOfShape* pLHoles = aFaceHolesMap.Seek(aFace); |
98b37659 |
557 | if (pLHoles) |
558 | { |
559 | // update faces with the holes |
1155d05a |
560 | TopTools_ListIteratorOfListOfShape aItLH(*pLHoles); |
98b37659 |
561 | for (; aItLH.More(); aItLH.Next()) |
562 | { |
563 | const TopoDS_Shape& aFHole = aItLH.Value(); |
564 | // The hole face contains only one wire |
565 | TopoDS_Iterator aItW(aFHole); |
566 | aBB.Add(aFace, aItW.Value()); |
567 | } |
568 | |
569 | // update classifier |
570 | myContext->FClass2d(aFace).Init(aFace, aTol); |
db8e4b9a |
571 | } |
98b37659 |
572 | |
573 | // The face is just a draft that does not contain any internal shapes |
574 | myAreas.Append(aFace); |
4e57c75e |
575 | } |
576 | } |
577 | //======================================================================= |
578 | //function : PerformInternalShapes |
579 | //purpose : |
580 | //======================================================================= |
db8e4b9a |
581 | void BOPAlgo_BuilderFace::PerformInternalShapes() |
4e57c75e |
582 | { |
291fced1 |
583 | if (myAvoidInternalShapes) { |
584 | return; |
585 | } |
4e57c75e |
586 | // |
587 | Standard_Integer aNbWI=myLoopsInternal.Extent(); |
588 | if (!aNbWI) {// nothing to do |
589 | return; |
590 | } |
591 | // |
592 | //Standard_Real aTol; |
319da2e4 |
593 | Standard_Integer i; |
4e57c75e |
594 | BRep_Builder aBB; |
1155d05a |
595 | TopTools_ListIteratorOfListOfShape aIt1, aIt2; |
4e57c75e |
596 | TopoDS_Iterator aIt; |
1155d05a |
597 | TopTools_IndexedMapOfShape aME1, aME2, aMEP; |
598 | TopTools_IndexedDataMapOfShapeListOfShape aMVE; |
599 | TopTools_ListOfShape aLSI; |
4e57c75e |
600 | // |
601 | // 1. All internal edges |
602 | aIt1.Initialize(myLoopsInternal); |
603 | for (; aIt1.More(); aIt1.Next()) { |
604 | const TopoDS_Shape& aWire=aIt1.Value(); |
605 | aIt.Initialize(aWire); |
606 | for (; aIt.More(); aIt.Next()) { |
607 | const TopoDS_Shape& aE=aIt.Value(); |
319da2e4 |
608 | aME1.Add(aE); |
4e57c75e |
609 | } |
610 | } |
4e57c75e |
611 | // |
612 | // 2 Process faces |
613 | aIt2.Initialize(myAreas); |
614 | for ( ; aIt2.More(); aIt2.Next()) { |
615 | TopoDS_Face& aF=(*(TopoDS_Face *)(&aIt2.Value())); |
616 | // |
617 | aMVE.Clear(); |
1155d05a |
618 | TopExp::MapShapesAndAncestors(aF, TopAbs_VERTEX, TopAbs_EDGE, aMVE); |
4e57c75e |
619 | // |
620 | // 2.1 Separate faces to process aMEP |
319da2e4 |
621 | aME2.Clear(); |
4e57c75e |
622 | aMEP.Clear(); |
319da2e4 |
623 | aNbWI = aME1.Extent(); |
624 | for (i = 1; i <= aNbWI; ++i) { |
625 | const TopoDS_Edge& aE=(*(TopoDS_Edge *)(&aME1(i))); |
4e57c75e |
626 | if (IsInside(aE, aF, myContext)) { |
627 | aMEP.Add(aE); |
628 | } |
319da2e4 |
629 | else { |
630 | aME2.Add(aE); |
631 | } |
4e57c75e |
632 | } |
633 | // |
634 | // 2.2 Make Internal Wires |
635 | aLSI.Clear(); |
636 | MakeInternalWires(aMEP, aLSI); |
637 | // |
638 | // 2.3 Add them to aF |
639 | aIt1.Initialize(aLSI); |
640 | for (; aIt1.More(); aIt1.Next()) { |
641 | const TopoDS_Shape& aSI=aIt1.Value(); |
642 | aBB.Add (aF, aSI); |
643 | } |
644 | // |
645 | // 2.4 Remove faces aMFP from aMF |
319da2e4 |
646 | aME1 = aME2; |
4e57c75e |
647 | // |
319da2e4 |
648 | aNbWI = aME1.Extent(); |
4e57c75e |
649 | if (!aNbWI) { |
650 | break; |
651 | } |
652 | } //for ( ; aIt2.More(); aIt2.Next()) { |
653 | } |
654 | //======================================================================= |
655 | //function : MakeInternalWires |
656 | //purpose : |
657 | //======================================================================= |
1155d05a |
658 | void MakeInternalWires(const TopTools_IndexedMapOfShape& theME, |
659 | TopTools_ListOfShape& theWires) |
4e57c75e |
660 | { |
319da2e4 |
661 | Standard_Integer i, aNbE; |
1155d05a |
662 | TopTools_MapOfShape aAddedMap; |
663 | TopTools_ListIteratorOfListOfShape aItE; |
664 | TopTools_IndexedDataMapOfShapeListOfShape aMVE; |
4e57c75e |
665 | BRep_Builder aBB; |
666 | // |
319da2e4 |
667 | aNbE = theME.Extent(); |
668 | for (i = 1; i <= aNbE; ++i) { |
669 | const TopoDS_Shape& aE = theME(i); |
1155d05a |
670 | TopExp::MapShapesAndAncestors(aE, TopAbs_VERTEX, TopAbs_EDGE, aMVE); |
4e57c75e |
671 | } |
672 | // |
319da2e4 |
673 | for (i = 1; i <= aNbE; ++i) { |
674 | TopoDS_Shape aEE = theME(i); |
4e57c75e |
675 | if (!aAddedMap.Add(aEE)) { |
676 | continue; |
677 | } |
678 | // |
679 | // make a new shell |
680 | TopoDS_Wire aW; |
681 | aBB.MakeWire(aW); |
682 | aEE.Orientation(TopAbs_INTERNAL); |
683 | aBB.Add(aW, aEE); |
684 | // |
685 | TopoDS_Iterator aItAdded (aW); |
686 | for (; aItAdded.More(); aItAdded.Next()) { |
687 | const TopoDS_Shape& aE =aItAdded.Value(); |
688 | // |
689 | TopExp_Explorer aExp(aE, TopAbs_VERTEX); |
690 | for (; aExp.More(); aExp.Next()) { |
691 | const TopoDS_Shape& aV =aExp.Current(); |
1155d05a |
692 | const TopTools_ListOfShape& aLE=aMVE.FindFromKey(aV); |
4e57c75e |
693 | aItE.Initialize(aLE); |
694 | for (; aItE.More(); aItE.Next()) { |
695 | TopoDS_Shape aEL=aItE.Value(); |
696 | if (aAddedMap.Add(aEL)){ |
697 | aEL.Orientation(TopAbs_INTERNAL); |
698 | aBB.Add(aW, aEL); |
699 | } |
700 | } |
701 | } |
702 | } |
c5d8782c |
703 | aW.Closed(BRep_Tool::IsClosed(aW)); |
4e57c75e |
704 | theWires.Append(aW); |
705 | } |
706 | } |
707 | //======================================================================= |
708 | //function : IsInside |
709 | //purpose : |
710 | //======================================================================= |
f8163956 |
711 | Standard_Boolean IsInside(const TopoDS_Shape& theWire, |
712 | const TopoDS_Shape& theF, |
1e143abb |
713 | Handle(IntTools_Context)& theContext) |
4e57c75e |
714 | { |
f8163956 |
715 | // Check if the wire is located inside the face: |
716 | // take unique point from the wire and classify it relatively the face |
717 | |
718 | // Avoid edges of the face |
719 | TopTools_IndexedMapOfShape aFaceEdgesMap; |
720 | TopExp::MapShapes(theF, TopAbs_EDGE, aFaceEdgesMap); |
721 | |
722 | // Get classification tool from the context |
723 | const TopoDS_Face& aF = TopoDS::Face(theF); |
724 | IntTools_FClass2d& aClassifier = theContext->FClass2d(aF); |
725 | |
726 | Standard_Boolean isInside = Standard_False; |
727 | |
728 | // Iterate on wire edges until first classification is performed |
729 | TopExp_Explorer anExp(theWire, TopAbs_EDGE); |
730 | for (; anExp.More(); anExp.Next()) |
731 | { |
732 | const TopoDS_Edge& aE = TopoDS::Edge(anExp.Current()); |
733 | if (BRep_Tool::Degenerated(aE)) |
734 | // Avoid checking degenerated edges. |
735 | continue; |
736 | |
737 | if (aFaceEdgesMap.Contains(aE)) |
738 | // Face contains the edge from the wire, thus the wire cannot be |
739 | // inside that face. |
740 | return isInside; |
741 | |
742 | // Get 2d curve of the edge on the face |
743 | Standard_Real aT1, aT2; |
744 | const Handle(Geom2d_Curve)& aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2); |
745 | if (aC2D.IsNull()) |
746 | continue; |
747 | |
748 | // Get middle point on the curve |
749 | gp_Pnt2d aP2D = aC2D->Value((aT1 + aT2) / 2.); |
750 | |
751 | // Classify the point |
752 | TopAbs_State aState = aClassifier.Perform(aP2D); |
753 | isInside = (aState == TopAbs_IN); |
754 | break; |
4e57c75e |
755 | } |
f8163956 |
756 | return isInside; |
4e57c75e |
757 | } |
4e57c75e |
758 | //======================================================================= |
759 | //function : IsGrowthWire |
760 | //purpose : |
761 | //======================================================================= |
762 | Standard_Boolean IsGrowthWire(const TopoDS_Shape& theWire, |
1155d05a |
763 | const TopTools_IndexedMapOfShape& theMHE) |
4e57c75e |
764 | { |
98b37659 |
765 | if (theMHE.Extent()) |
766 | { |
767 | TopoDS_Iterator aIt(theWire); |
768 | for(; aIt.More(); aIt.Next()) |
769 | { |
770 | if (theMHE.Contains(aIt.Value())) |
771 | return Standard_True; |
4e57c75e |
772 | } |
773 | } |
98b37659 |
774 | return Standard_False; |
4e57c75e |
775 | } |