1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
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
7 // This file is part of Open CASCADE Technology software library.
9 // This library is free software; you can redistribute it and/or modify it under
10 // the terms of the GNU Lesser General Public License version 2.1 as published
11 // by the Free Software Foundation, with special exception defined in the file
12 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 // distribution for complete text of the license and disclaimer of any warranty.
15 // Alternatively, this file may be used under the terms of Open CASCADE
16 // commercial license or contractual agreement.
18 #include <BOPAlgo_BuilderSolid.hxx>
19 #include <BOPAlgo_ShellSplitter.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPAlgo_Tools.hxx>
22 #include <BOPTools_AlgoTools.hxx>
23 #include <BOPTools_BoxTree.hxx>
24 #include <BOPTools_Parallel.hxx>
25 #include <Bnd_Tools.hxx>
26 #include <BRep_Builder.hxx>
27 #include <BRep_Tool.hxx>
28 #include <BRepBndLib.hxx>
29 #include <BRepClass3d_SolidClassifier.hxx>
30 #include <IntTools_Context.hxx>
31 #include <NCollection_DataMap.hxx>
32 #include <NCollection_List.hxx>
34 #include <TopExp_Explorer.hxx>
36 #include <TopoDS_Compound.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <TopoDS_Face.hxx>
39 #include <TopoDS_Iterator.hxx>
40 #include <TopoDS_Shape.hxx>
41 #include <TopoDS_Shell.hxx>
42 #include <TopoDS_Solid.hxx>
43 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
44 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
45 #include <TColStd_ListOfInteger.hxx>
46 #include <TopTools_ListOfShape.hxx>
47 #include <TopTools_MapOfOrientedShape.hxx>
48 #include <TopTools_MapOfShape.hxx>
52 Standard_Boolean IsGrowthShell(const TopoDS_Shape& ,
53 const TopTools_IndexedMapOfShape& );
55 Standard_Boolean IsHole(const TopoDS_Shape& ,
56 Handle(IntTools_Context)& );
58 Standard_Boolean IsInside(const TopoDS_Shape& ,
60 Handle(IntTools_Context)& );
62 void MakeInternalShells(const TopTools_IndexedMapOfShape& ,
63 TopTools_ListOfShape& );
65 //=======================================================================
68 //=======================================================================
69 BOPAlgo_BuilderSolid::BOPAlgo_BuilderSolid()
74 //=======================================================================
77 //=======================================================================
78 BOPAlgo_BuilderSolid::BOPAlgo_BuilderSolid
79 (const Handle(NCollection_BaseAllocator)& theAllocator)
81 BOPAlgo_BuilderArea(theAllocator)
84 //=======================================================================
87 //=======================================================================
88 BOPAlgo_BuilderSolid::~BOPAlgo_BuilderSolid()
91 //=======================================================================
94 //=======================================================================
95 void BOPAlgo_BuilderSolid::Perform(const Message_ProgressRange& theRange)
97 Message_ProgressScope aPS (theRange, NULL, 100);
101 if (myShapes.IsEmpty())
104 if (myContext.IsNull()) {
105 myContext=new IntTools_Context;
112 TopTools_ListIteratorOfListOfShape aIt;
114 aBB.MakeCompound(aC);
115 aIt.Initialize(myShapes);
116 for(; aIt.More(); aIt.Next()) {
117 const TopoDS_Shape& aF=aIt.Value();
121 PerformShapesToAvoid (aPS.Next(1));
126 PerformLoops (aPS.Next(10));
131 PerformAreas (aPS.Next(80));
136 PerformInternalShapes (aPS.Next(9));
138 //=======================================================================
139 //function :PerformShapesToAvoid
141 //=======================================================================
142 void BOPAlgo_BuilderSolid::PerformShapesToAvoid(const Message_ProgressRange& theRange)
144 Standard_Boolean bFound;
145 Standard_Integer i, aNbE, aNbF;
146 TopAbs_Orientation aOrE;
147 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
148 TopTools_ListIteratorOfListOfShape aIt;
150 myShapesToAvoid.Clear();
152 Message_ProgressScope aPS(theRange, NULL, 1);
155 if (UserBreak(aPS)) {
158 bFound=Standard_False;
162 aIt.Initialize (myShapes);
163 for (; aIt.More(); aIt.Next()) {
164 const TopoDS_Shape& aF=aIt.Value();
165 if (!myShapesToAvoid.Contains(aF)) {
166 TopExp::MapShapesAndAncestors(aF,
175 for (i=1; i<=aNbE; ++i) {
176 const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aMEF.FindKey(i)));
177 if (BRep_Tool::Degenerated(aE)) {
181 TopTools_ListOfShape& aLF=aMEF.ChangeFromKey(aE);
187 aOrE=aE.Orientation();
189 const TopoDS_Face& aF1=(*(TopoDS_Face*)(&aLF.First()));
191 if (aOrE==TopAbs_INTERNAL) {
194 bFound=Standard_True;
195 myShapesToAvoid.Add(aF1);
198 const TopoDS_Face& aF2=(*(TopoDS_Face*)(&aLF.Last()));
199 if (aF2.IsSame(aF1)) {
200 if (BRep_Tool::IsClosed(aE, aF1)) {
204 if (aOrE==TopAbs_INTERNAL) {
208 bFound=Standard_True;
209 myShapesToAvoid.Add(aF1);
210 myShapesToAvoid.Add(aF2);
213 }// for (i=1; i<=aNbE; ++i) {
221 //=======================================================================
222 //function : PerformLoops
224 //=======================================================================
225 void BOPAlgo_BuilderSolid::PerformLoops(const Message_ProgressRange& theRange)
227 Standard_Integer i, aNbSh;
228 TopTools_ListIteratorOfListOfShape aIt;
229 TopoDS_Iterator aItS;
230 Handle(NCollection_BaseAllocator) aAlr;
235 NCollection_BaseAllocator::CommonBaseAllocator();
236 BOPAlgo_ShellSplitter aSSp(aAlr);
238 Message_ProgressScope aMainScope (theRange, "Building shells", 10);
241 aIt.Initialize (myShapes);
242 for (; aIt.More(); aIt.Next()) {
243 const TopoDS_Face& aF=*((TopoDS_Face*)&aIt.Value());
244 if (myContext->IsInfiniteFace(aF)) {
254 if (!myShapesToAvoid.Contains(aF)) {
255 aSSp.AddStartElement(aF);
259 aSSp.SetRunParallel(myRunParallel);
260 aSSp.Perform(aMainScope.Next(9));
261 if (aSSp.HasErrors()) {
262 // add warning status
263 if (aMainScope.More())
265 TopoDS_Compound aFacesSp;
266 BRep_Builder().MakeCompound(aFacesSp);
267 TopTools_ListIteratorOfListOfShape aItLF(aSSp.StartElements());
268 for (; aItLF.More(); aItLF.Next()) {
269 BRep_Builder().Add(aFacesSp, aItLF.Value());
271 AddWarning (new BOPAlgo_AlertShellSplitterFailed (aFacesSp));
276 const TopTools_ListOfShape& aLSh=aSSp.Shells();
277 aIt.Initialize (aLSh);
278 for (; aIt.More(); aIt.Next()) {
279 const TopoDS_Shape& aSh=aIt.Value();
282 //=================================================
286 TopTools_MapOfOrientedShape AddedFacesMap;
287 TopTools_IndexedDataMapOfShapeListOfShape aEFMap;
288 TopTools_MapOfOrientedShape aMP;
290 // a. collect all edges that are in loops
291 aIt.Initialize (myLoops);
292 for (; aIt.More(); aIt.Next()) {
293 const TopoDS_Shape& aS=aIt.Value();
295 for (; aItS.More(); aItS.Next()) {
296 const TopoDS_Shape& aF=aItS.Value();
300 if (UserBreak (aMainScope)) {
304 // b. collect all edges that are to avoid
305 aNbSh = myShapesToAvoid.Extent();
306 for (i = 1; i <= aNbSh; ++i) {
307 const TopoDS_Shape& aF = myShapesToAvoid(i);
311 // c. add all edges that are not processed to myShapesToAvoid
312 aIt.Initialize (myShapes);
313 for (; aIt.More(); aIt.Next()) {
314 const TopoDS_Face& aF=*((TopoDS_Face*)&aIt.Value());
315 if (!myContext->IsInfiniteFace(aF)) {
316 if (!aMP.Contains(aF)) {
317 myShapesToAvoid.Add(aF);
321 //=================================================
322 if (UserBreak (aMainScope)) {
327 myLoopsInternal.Clear();
330 AddedFacesMap.Clear();
332 aNbSh = myShapesToAvoid.Extent();
333 for (i = 1; i <= aNbSh; ++i) {
334 const TopoDS_Shape& aFF = myShapesToAvoid(i);
335 TopExp::MapShapesAndAncestors(aFF,
336 TopAbs_EDGE, TopAbs_FACE,
340 for (i = 1; i <= aNbSh; ++i) {
341 if (UserBreak(aMainScope)) {
344 const TopoDS_Shape& aFF = myShapesToAvoid(i);
345 if (!AddedFacesMap.Add(aFF)) {
350 TopExp_Explorer aExp;
352 aBB.MakeShell(aShell);
353 aBB.Add(aShell, aFF);
355 aItS.Initialize(aShell);
356 for (; aItS.More(); aItS.Next()) {
357 const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value()));
359 aExp.Init(aF, TopAbs_EDGE);
360 for (; aExp.More(); aExp.Next()) {
361 const TopoDS_Edge& aE = (*(TopoDS_Edge*)(&aExp.Current()));
362 const TopTools_ListOfShape& aLF=aEFMap.FindFromKey(aE);
364 for (; aIt.More(); aIt.Next()) {
365 const TopoDS_Face& aFL=(*(TopoDS_Face*)(&aIt.Value()));
366 if (AddedFacesMap.Add(aFL)){
367 aBB.Add(aShell, aFL);
372 aShell.Closed (BRep_Tool::IsClosed (aShell));
373 myLoopsInternal.Append(aShell);
376 //=======================================================================
377 //function : PerformAreas
379 //=======================================================================
380 void BOPAlgo_BuilderSolid::PerformAreas(const Message_ProgressRange& theRange)
385 TopTools_ListOfShape aNewSolids;
386 // The hole shells which has to be classified relatively new solids
387 TopTools_IndexedMapOfShape aHoleShells;
388 // Map of the faces of the hole shells for quick check of the growths.
389 // If the analyzed shell contains any of the hole faces, it is considered as growth.
390 TopTools_IndexedMapOfShape aMHF;
392 Message_ProgressScope aMainScope(theRange, "Building solids", 10);
394 // Analyze the shells
395 Message_ProgressScope aPSClass(aMainScope.Next(5), "Classify solids", myLoops.Size());
396 TopTools_ListIteratorOfListOfShape aItLL(myLoops);
397 for (; aItLL.More(); aItLL.Next(), aPSClass.Next())
399 if (UserBreak (aPSClass))
403 const TopoDS_Shape& aShell = aItLL.Value();
405 Standard_Boolean bIsGrowth = IsGrowthShell(aShell, aMHF);
408 // Fast check did not give the result, run classification
409 bIsGrowth = !IsHole(aShell, myContext);
416 aBB.MakeSolid(aSolid);
417 aBB.Add (aSolid, aShell);
418 aNewSolids.Append (aSolid);
422 aHoleShells.Add(aShell);
423 TopExp::MapShapes(aShell, TopAbs_FACE, aMHF);
427 if (aHoleShells.IsEmpty())
429 // No holes, stop the analysis
430 TopTools_ListIteratorOfListOfShape aItLS(aNewSolids);
431 for (; aItLS.More(); aItLS.Next())
433 const TopoDS_Shape& aSol = aItLS.Value();
434 myAreas.Append(aSol);
437 BRepBndLib::Add(aSol, aBox);
438 myBoxes.Bind(aSol, aBox);
443 // Classify holes relatively solids
445 // Prepare tree with the boxes of the hole shells
446 BOPTools_BoxTree aBBTree;
447 Standard_Integer i, aNbH = aHoleShells.Extent();
448 aBBTree.SetSize (aNbH);
449 for (i = 1; i <= aNbH; ++i)
451 const TopoDS_Shape& aHShell = aHoleShells(i);
454 BRepBndLib::Add(aHShell, aBox);
455 aBBTree.Add(i, Bnd_Tools::Bnd2BVH(aBox));
457 myBoxes.Bind(aHShell, aBox);
463 // Find outer growth shell that is most close to each hole shell
464 TopTools_IndexedDataMapOfShapeShape aHoleSolidMap;
466 Message_ProgressScope aPSH(aMainScope.Next(4), "Adding holes", aNewSolids.Size());
467 TopTools_ListIteratorOfListOfShape aItLS(aNewSolids);
468 for (; aItLS.More(); aItLS.Next(), aPSH.Next())
470 if (UserBreak (aPSH))
474 const TopoDS_Shape& aSolid = aItLS.Value();
478 BRepBndLib::Add(aSolid, aBox);
480 myBoxes.Bind(aSolid, aBox);
482 BOPTools_BoxTreeSelector aSelector;
483 aSelector.SetBox(Bnd_Tools::Bnd2BVH(aBox));
484 aSelector.SetBVHSet (&aBBTree);
487 const TColStd_ListOfInteger& aLI = aSelector.Indices();
488 TColStd_ListIteratorOfListOfInteger aItLI(aLI);
489 for (; aItLI.More(); aItLI.Next())
491 Standard_Integer k = aItLI.Value();
492 const TopoDS_Shape& aHole = aHoleShells(k);
493 // Check if it is inside
494 if (!IsInside(aHole, aSolid, myContext))
498 TopoDS_Shape* pSolidWas = aHoleSolidMap.ChangeSeek(aHole);
501 if (IsInside(aSolid, *pSolidWas, myContext))
508 aHoleSolidMap.Add(aHole, aSolid);
513 // Make the back map from solids to holes
514 TopTools_IndexedDataMapOfShapeListOfShape aSolidHolesMap;
516 aNbH = aHoleSolidMap.Extent();
517 for (i = 1; i <= aNbH; ++i)
519 const TopoDS_Shape& aHole = aHoleSolidMap.FindKey(i);
520 const TopoDS_Shape& aSolid = aHoleSolidMap(i);
522 TopTools_ListOfShape* pLHoles = aSolidHolesMap.ChangeSeek(aSolid);
524 pLHoles = &aSolidHolesMap(aSolidHolesMap.Add(aSolid, TopTools_ListOfShape()));
525 pLHoles->Append(aHole);
528 // Add Holes to Solids and add them to myAreas
529 Message_ProgressScope aPSU (aMainScope.Next(), NULL, aNewSolids.Size());
530 aItLS.Initialize(aNewSolids);
531 for ( ; aItLS.More(); aItLS.Next(), aPSU.Next())
533 if (UserBreak (aPSU))
537 TopoDS_Solid& aSolid = *(TopoDS_Solid*)&aItLS.Value();
538 const TopTools_ListOfShape* pLHoles = aSolidHolesMap.Seek(aSolid);
542 TopTools_ListIteratorOfListOfShape aItLH(*pLHoles);
543 for (; aItLH.More(); aItLH.Next())
545 const TopoDS_Shape& aHole = aItLH.Value();
546 aBB.Add(aSolid, aHole);
550 myContext->SolidClassifier(aSolid).Load(aSolid);
553 myAreas.Append(aSolid);
556 // Add holes that outside the solids to myAreas
557 aNbH = aHoleShells.Extent();
558 for (i = 1; i <= aNbH; ++i)
560 const TopoDS_Shape& aHole = aHoleShells(i);
561 if (!aHoleSolidMap.Contains(aHole))
564 aBB.MakeSolid(aSolid);
565 aBB.Add (aSolid, aHole);
567 myAreas.Append(aSolid);
568 // Make an infinite box for the hole
571 myBoxes.Bind(aSolid, aBox);
574 myBoxes.UnBind(aHole);
577 //=======================================================================
578 //function : PerformInternalShapes
580 //=======================================================================
581 void BOPAlgo_BuilderSolid::PerformInternalShapes(const Message_ProgressRange& theRange)
583 if (myAvoidInternalShapes)
584 // user-defined option to avoid internal parts is in force
587 if (myLoopsInternal.IsEmpty())
591 Message_ProgressScope aMainScope (theRange, "Adding internal shapes", 2);
593 // Get all faces to classify
594 TopTools_IndexedMapOfShape aMFs;
595 TopTools_ListIteratorOfListOfShape aItLS(myLoopsInternal);
596 for (; aItLS.More(); aItLS.Next())
598 const TopoDS_Shape& aShell = aItLS.Value();
599 TopoDS_Iterator aIt(aShell);
600 for (; aIt.More(); aIt.Next())
601 aMFs.Add(aIt.Value());
605 // Check existence of the growths solids
606 if (myAreas.IsEmpty())
609 // Just make solid of the faces
611 aBB.MakeSolid(aSolid);
613 TopTools_ListOfShape aLSI;
614 MakeInternalShells(aMFs, aLSI);
616 aItLS.Initialize(aLSI);
617 for (; aItLS.More(); aItLS.Next())
618 aBB.Add(aSolid, aItLS.Value());
620 myAreas.Append(aSolid);
624 if (UserBreak (aMainScope))
629 // Classify faces relatively solids
631 // Prepare list of faces to classify
632 TopTools_ListOfShape aLFaces;
633 Standard_Integer i, aNbF = aMFs.Extent();
634 for (i = 1; i <= aNbF; ++i)
635 aLFaces.Append(aMFs(i));
637 // Map of solids with IN faces
638 TopTools_IndexedDataMapOfShapeListOfShape aMSLF;
640 // Perform classification
641 BOPAlgo_Tools::ClassifyFaces(aLFaces,
647 TopTools_DataMapOfShapeListOfShape(),
650 // Update Solids by internal Faces
652 TopTools_MapOfShape aMFDone;
654 Standard_Integer aNbS = aMSLF.Extent();
655 Message_ProgressScope aPSLoop(aMainScope.Next(), NULL, aNbS);
656 for (i = 1; i <= aNbS; ++i, aPSLoop.Next())
658 if (UserBreak (aPSLoop))
662 const TopoDS_Shape& aSolid = aMSLF.FindKey(i);
663 TopoDS_Shape *pSolid = (TopoDS_Shape*)&aSolid;
665 const TopTools_ListOfShape& aLF = aMSLF(i);
669 TopTools_IndexedMapOfShape aMF;
670 aItLS.Initialize(aLF);
671 for (; aItLS.More(); aItLS.Next())
673 const TopoDS_Shape& aF = aItLS.Value();
678 TopTools_ListOfShape aLSI;
679 MakeInternalShells(aMF, aLSI);
681 aItLS.Initialize(aLSI);
682 for (; aItLS.More(); aItLS.Next())
684 const TopoDS_Shape& aSI = aItLS.Value();
685 aBB.Add (*pSolid, aSI);
689 // Find all unclassified faces and warn the user about them.
690 // Do not put such faces into result as they will form not closed solid.
691 TopTools_IndexedMapOfShape aMFUnUsed;
693 for (i = 1; i <= aNbF; ++i)
695 const TopoDS_Shape& aF = aMFs(i);
696 if (!aMFDone.Contains(aF))
700 if (aMFUnUsed.Extent())
702 TopTools_ListOfShape aLSI;
703 MakeInternalShells(aMFUnUsed, aLSI);
705 TopoDS_Shape aWShape;
706 if (aLSI.Extent() == 1)
707 aWShape = aLSI.First();
710 aBB.MakeCompound(TopoDS::Compound(aWShape));
711 aItLS.Initialize(aLSI);
712 for (; aItLS.More(); aItLS.Next())
713 aBB.Add(aWShape, aItLS.Value());
716 AddWarning(new BOPAlgo_AlertSolidBuilderUnusedFaces(aWShape));
719 //=======================================================================
720 //function : MakeInternalShells
722 //=======================================================================
723 void MakeInternalShells(const TopTools_IndexedMapOfShape& theMF,
724 TopTools_ListOfShape& theShells)
726 Standard_Integer i, aNbF;
728 TopTools_ListIteratorOfListOfShape aItF;
729 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
730 TopTools_MapOfShape aAddedFacesMap;
732 aNbF = theMF.Extent();
733 for (i = 1; i <= aNbF; ++i) {
734 const TopoDS_Shape& aF = theMF(i);
735 TopExp::MapShapesAndAncestors(aF,
736 TopAbs_EDGE, TopAbs_FACE,
740 for (i = 1; i <= aNbF; ++i) {
741 TopoDS_Shape aFF = theMF(i);
742 if (!aAddedFacesMap.Add(aFF)) {
748 aBB.MakeShell(aShell);
749 aFF.Orientation(TopAbs_INTERNAL);
750 aBB.Add(aShell, aFF);
752 TopoDS_Iterator aItAddedF (aShell);
753 for (; aItAddedF.More(); aItAddedF.Next()) {
754 const TopoDS_Shape& aF =aItAddedF.Value();
756 TopExp_Explorer aEdgeExp(aF, TopAbs_EDGE);
757 for (; aEdgeExp.More(); aEdgeExp.Next()) {
758 const TopoDS_Shape& aE =aEdgeExp.Current();
759 const TopTools_ListOfShape& aLF=aMEF.FindFromKey(aE);
760 aItF.Initialize(aLF);
761 for (; aItF.More(); aItF.Next()) {
762 TopoDS_Shape aFL=aItF.Value();
763 if (aAddedFacesMap.Add(aFL)){
764 aFL.Orientation(TopAbs_INTERNAL);
765 aBB.Add(aShell, aFL);
770 aShell.Closed (BRep_Tool::IsClosed (aShell));
771 theShells.Append(aShell);
774 //=======================================================================
777 //=======================================================================
778 Standard_Boolean IsHole(const TopoDS_Shape& theS2,
779 Handle(IntTools_Context)& theContext)
781 TopoDS_Solid *pS2=(TopoDS_Solid *)&theS2;
782 BRepClass3d_SolidClassifier& aClsf=theContext->SolidClassifier(*pS2);
784 aClsf.PerformInfinitePoint(::RealSmall());
786 return (aClsf.State()==TopAbs_IN);
788 //=======================================================================
789 //function : IsInside
791 //=======================================================================
792 Standard_Boolean IsInside(const TopoDS_Shape& theS1,
793 const TopoDS_Shape& theS2,
794 Handle(IntTools_Context)& theContext)
796 TopExp_Explorer aExp;
799 TopoDS_Solid *pS2=(TopoDS_Solid *)&theS2;
801 aExp.Init(theS1, TopAbs_FACE);
803 BRepClass3d_SolidClassifier& aClsf=theContext->SolidClassifier(*pS2);
804 aClsf.PerformInfinitePoint(::RealSmall());
805 aState=aClsf.State();
808 TopTools_IndexedMapOfShape aBounds;
809 TopExp::MapShapes(*pS2, TopAbs_EDGE, aBounds);
810 const TopoDS_Face& aF = (*(TopoDS_Face*)(&aExp.Current()));
811 aState=BOPTools_AlgoTools::ComputeState(aF, *pS2,
812 Precision::Confusion(),
813 aBounds, theContext);
815 return (aState==TopAbs_IN);
817 //=======================================================================
818 //function : IsGrowthShell
820 //=======================================================================
821 Standard_Boolean IsGrowthShell(const TopoDS_Shape& theShell,
822 const TopTools_IndexedMapOfShape& theMHF)
826 TopoDS_Iterator aIt(theShell);
827 for(; aIt.More(); aIt.Next())
829 if (theMHF.Contains(aIt.Value()))
830 return Standard_True;
833 return Standard_False;