1 // Created by: Peter KURNEV
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
16 #include <BOPAlgo_BOP.hxx>
17 #include <BOPAlgo_BuilderSolid.hxx>
18 #include <BOPAlgo_PaveFiller.hxx>
19 #include <BOPAlgo_Tools.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPDS_DS.hxx>
22 #include <BOPTools_AlgoTools.hxx>
23 #include <BOPTools_AlgoTools3D.hxx>
24 #include <BOPTools_IndexedDataMapOfSetShape.hxx>
25 #include <BOPTools_Set.hxx>
26 #include <BRep_Builder.hxx>
27 #include <BRep_Tool.hxx>
28 #include <NCollection_DataMap.hxx>
29 #include <TopAbs_ShapeEnum.hxx>
31 #include <TopExp_Explorer.hxx>
33 #include <TopoDS_Compound.hxx>
34 #include <TopoDS_Edge.hxx>
35 #include <TopoDS_Iterator.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
38 #include <TopTools_IndexedMapOfShape.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <TopTools_MapOfShape.hxx>
43 TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim);
46 void CollectContainers(const TopoDS_Shape& theS,
47 TopTools_ListOfShape& theLSC);
50 void RemoveDuplicates(TopTools_ListOfShape& theContainers);
53 void RemoveDuplicates(TopTools_ListOfShape& theContainers,
54 const TopAbs_ShapeEnum theType);
57 Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
58 const TopTools_MapOfShape& theM2);
61 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
62 TopTools_IndexedDataMapOfShapeListOfShape& theMFS);
64 //=======================================================================
67 //=======================================================================
68 BOPAlgo_BOP::BOPAlgo_BOP()
69 : BOPAlgo_ToolsProvider()
73 //=======================================================================
76 //=======================================================================
77 BOPAlgo_BOP::BOPAlgo_BOP(const Handle(NCollection_BaseAllocator)& theAllocator)
78 : BOPAlgo_ToolsProvider(theAllocator)
82 //=======================================================================
85 //=======================================================================
86 BOPAlgo_BOP::~BOPAlgo_BOP()
89 //=======================================================================
92 //=======================================================================
93 void BOPAlgo_BOP::Clear()
95 myOperation=BOPAlgo_UNKNOWN;
99 BOPAlgo_ToolsProvider::Clear();
101 //=======================================================================
102 //function : SetOperation
104 //=======================================================================
105 void BOPAlgo_BOP::SetOperation(const BOPAlgo_Operation theOperation)
107 myOperation=theOperation;
109 //=======================================================================
110 //function : Operation
112 //=======================================================================
113 BOPAlgo_Operation BOPAlgo_BOP::Operation()const
117 //=======================================================================
118 //function : CheckData
120 //=======================================================================
121 void BOPAlgo_BOP::CheckData()
123 Standard_Integer i, j, aNbArgs, aNbTools;
124 Standard_Boolean bFuse;
125 TopTools_ListIteratorOfListOfShape aItLS;
127 if (!(myOperation==BOPAlgo_COMMON ||
128 myOperation==BOPAlgo_FUSE ||
129 myOperation==BOPAlgo_CUT||
130 myOperation==BOPAlgo_CUT21)) {
131 // non-licit operation
132 AddError (new BOPAlgo_AlertBOPNotSet);
136 aNbArgs=myArguments.Extent();
138 // invalid number of Arguments
139 AddError (new BOPAlgo_AlertTooFewArguments);
143 aNbTools=myTools.Extent();
145 // invalid number of Tools
146 AddError (new BOPAlgo_AlertTooFewArguments);
155 bFuse = (myOperation == BOPAlgo_FUSE);
157 // The rules for different types of operations are the following:
158 // 1. FUSE: All arguments and tools should have the same dimension;
159 // 2. CUT: The MAXIMAL dimension of the ARGUMENTS should be less
160 // or equal to the MINIMAL dimension of the TOOLS;
161 // 3. CUT21: The MINIMAL dimension of ARGUMENTS should be grater
162 // or equal to the MAXIMAL dimension of the TOOLS;
163 // 4. COMMON: The arguments and tools could have any dimensions.
165 Standard_Integer iDimMin[2] = { 3, 3 },
166 iDimMax[2] = { 0, 0 };
167 Standard_Boolean bHasValid[2] = {Standard_False, Standard_False};
169 for (i=0; i<2; ++i) {
170 const TopTools_ListOfShape& aLS=(!i)? myArguments : myTools;
171 aItLS.Initialize(aLS);
172 for (j=0; aItLS.More(); aItLS.Next(), ++j) {
173 const TopoDS_Shape& aS=aItLS.Value();
174 Standard_Boolean bIsEmpty = BOPTools_AlgoTools3D::IsEmptyShape(aS);
177 AddWarning(new BOPAlgo_AlertEmptyShape (aS));
181 Standard_Integer iDMin, iDMax;
182 BOPTools_AlgoTools::Dimensions(aS, iDMin, iDMax);
184 if (iDMin < iDimMin[i])
186 if (iDMax > iDimMax[i])
189 if (bFuse && (iDimMin[i] != iDimMax[i]))
191 // non-homogeneous argument
192 AddError (new BOPAlgo_AlertBOPNotAllowed);
195 bHasValid[i] = Standard_True;
199 if (bHasValid[0] && bHasValid[1]) {
200 if (((myOperation == BOPAlgo_FUSE) && (iDimMax[0] != iDimMax[1])) ||
201 ((myOperation == BOPAlgo_CUT) && (iDimMax[0] > iDimMin[1])) ||
202 ((myOperation == BOPAlgo_CUT21) && (iDimMin[0] < iDimMax[1])) )
204 // non-licit operation for the arguments
205 AddError (new BOPAlgo_AlertBOPNotAllowed);
210 if (bHasValid[0] || bHasValid[1])
212 // In case of all empty shapes in one of the groups
213 // this group acquires the dimension of other group
214 myDims[0] = bHasValid[0] ? iDimMin[0] : iDimMin[1];
215 myDims[1] = bHasValid[1] ? iDimMin[1] : iDimMin[0];
218 //=======================================================================
219 //function : TreatEmtpyShape
221 //=======================================================================
222 Standard_Boolean BOPAlgo_BOP::TreatEmptyShape()
224 if (! GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
226 return Standard_False;
229 // Find non-empty objects
230 TopTools_ListOfShape aLValidObjs;
231 TopTools_ListIteratorOfListOfShape aItLS(myArguments);
232 for (; aItLS.More(); aItLS.Next()) {
233 if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
234 aLValidObjs.Append(aItLS.Value());
238 // Find non-empty tools
239 TopTools_ListOfShape aLValidTools;
240 aItLS.Initialize(myTools);
241 for (; aItLS.More() ; aItLS.Next()) {
242 if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
243 aLValidTools.Append(aItLS.Value());
247 Standard_Boolean bHasValidObj = (aLValidObjs .Extent() > 0);
248 Standard_Boolean bHasValidTool = (aLValidTools.Extent() > 0);
250 if (bHasValidObj && bHasValidTool) {
251 // We need to continue the operation to obtain the result
252 return Standard_False;
255 if (!bHasValidObj && !bHasValidTool) {
256 // All shapes are empty shapes, the result will always be empty shape
257 return Standard_True;
260 // One of the groups of arguments consists of empty shapes only,
261 // so we can build the result of operation right away just by
262 // choosing the list of shapes to add to result, depending on
263 // the type of the operation.
264 // Although, if the group with valid shapes consists from more
265 // than just one shape, depending on the operation type we may need
266 // to split the shapes in this group before adding them into result.
268 TopTools_ListOfShape *pLResult = NULL;
270 switch (myOperation) {
273 if (aLValidObjs.Extent() + aLValidTools.Extent() > 1)
274 // The arguments must be split before adding into result
275 return Standard_False;
277 // Add not empty shapes into result
278 pLResult = bHasValidObj ? &aLValidObjs : &aLValidTools;
283 if (aLValidObjs.Extent() > 1)
284 // The objects must be split before adding into result
285 return Standard_False;
287 // Add objects into result
288 pLResult = &aLValidObjs;
293 if (aLValidTools.Extent() > 1)
294 // The tools must be split before adding into result
295 return Standard_False;
297 // Add tools into result
298 pLResult = &aLValidTools;
302 // Common will always be empty
309 aItLS.Initialize(*pLResult);
310 for (; aItLS.More(); aItLS.Next()) {
311 BRep_Builder().Add(myShape, aItLS.Value());
314 return Standard_True;
316 //=======================================================================
317 //function : BuildResult
319 //=======================================================================
320 void BOPAlgo_BOP::BuildResult(const TopAbs_ShapeEnum theType)
322 TopAbs_ShapeEnum aType;
324 TopTools_MapOfShape aM;
325 TopTools_ListIteratorOfListOfShape aIt, aItIm;
327 const TopTools_ListOfShape& aLA=myDS->Arguments();
329 for (; aIt.More(); aIt.Next()) {
330 const TopoDS_Shape& aS=aIt.Value();
331 aType=aS.ShapeType();
332 if (aType==theType) {
333 if (myImages.IsBound(aS)){
334 const TopTools_ListOfShape& aLSIm=myImages.Find(aS);
335 aItIm.Initialize(aLSIm);
336 for (; aItIm.More(); aItIm.Next()) {
337 const TopoDS_Shape& aSIm=aItIm.Value();
339 aBB.Add(myShape, aSIm);
345 aBB.Add(myShape, aS);
351 //=======================================================================
354 //=======================================================================
355 void BOPAlgo_BOP::Perform(const Message_ProgressRange& theRange)
357 Handle(NCollection_BaseAllocator) aAllocator;
358 BOPAlgo_PaveFiller* pPF;
359 TopTools_ListIteratorOfListOfShape aItLS;
361 GetReport()->Clear();
363 if (myEntryPoint==1) {
371 NCollection_BaseAllocator::CommonBaseAllocator();
372 TopTools_ListOfShape aLS(aAllocator);
374 aItLS.Initialize(myArguments);
375 for (; aItLS.More(); aItLS.Next()) {
376 const TopoDS_Shape& aS=aItLS.Value();
380 aItLS.Initialize(myTools);
381 for (; aItLS.More(); aItLS.Next()) {
382 const TopoDS_Shape& aS=aItLS.Value();
386 pPF=new BOPAlgo_PaveFiller(aAllocator);
387 pPF->SetArguments(aLS);
388 pPF->SetRunParallel(myRunParallel);
389 Message_ProgressScope aPS(theRange, "Performing Boolean operation", 10);
391 pPF->SetFuzzyValue(myFuzzyValue);
392 pPF->SetNonDestructive(myNonDestructive);
393 pPF->SetGlue(myGlue);
394 pPF->SetUseOBB(myUseOBB);
396 pPF->Perform(aPS.Next(9));
399 PerformInternal(*pPF, aPS.Next());
402 //=======================================================================
403 // function: fillPIConstants
405 //=======================================================================
406 void BOPAlgo_BOP::fillPIConstants (const Standard_Real theWhole, BOPAlgo_PISteps& theSteps) const
408 BOPAlgo_Builder::fillPIConstants(theWhole, theSteps);
409 theSteps.SetStep (PIOperation_BuildShape, (myOperation == BOPAlgo_FUSE ? 10. : 5.) * theWhole / 100.);
412 //=======================================================================
413 //function : PerformInternal1
415 //=======================================================================
416 void BOPAlgo_BOP::PerformInternal1(const BOPAlgo_PaveFiller& theFiller,
417 const Message_ProgressRange& theRange)
419 myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
420 myDS=myPaveFiller->PDS();
421 myContext=myPaveFiller->Context();
422 myFuzzyValue = myPaveFiller->FuzzyValue();
423 myNonDestructive = myPaveFiller->NonDestructive();
437 if (GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
439 Standard_Boolean bDone = TreatEmptyShape();
441 PrepareHistory (theRange);
445 Message_ProgressScope aPS(theRange, "Building the result of Boolean operation", 100);
447 BOPAlgo_PISteps aSteps (PIOperation_Last);
448 analyzeProgress (100, aSteps);
452 FillImagesVertices(aPS.Next(aSteps.GetStep(PIOperation_TreatVertices)));
457 BuildResult(TopAbs_VERTEX);
462 FillImagesEdges(aPS.Next(aSteps.GetStep(PIOperation_TreatEdges)));
467 BuildResult(TopAbs_EDGE);
473 FillImagesContainers(TopAbs_WIRE, aPS.Next(aSteps.GetStep(PIOperation_TreatWires)));
478 BuildResult(TopAbs_WIRE);
484 FillImagesFaces(aPS.Next(aSteps.GetStep(PIOperation_TreatFaces)));
489 BuildResult(TopAbs_FACE);
495 FillImagesContainers(TopAbs_SHELL, aPS.Next(aSteps.GetStep(PIOperation_TreatShells)));
500 BuildResult(TopAbs_SHELL);
506 FillImagesSolids(aPS.Next(aSteps.GetStep(PIOperation_TreatSolids)));
511 BuildResult(TopAbs_SOLID);
517 FillImagesContainers(TopAbs_COMPSOLID, aPS.Next(aSteps.GetStep(PIOperation_TreatCompsolids)));
522 BuildResult(TopAbs_COMPSOLID);
528 FillImagesCompounds(aPS.Next(aSteps.GetStep(PIOperation_TreatCompounds)));
533 BuildResult(TopAbs_COMPOUND);
539 BuildShape(aPS.Next(aSteps.GetStep(PIOperation_BuildShape)));
545 PrepareHistory(aPS.Next(aSteps.GetStep(PIOperation_FillHistory)));
551 PostTreat(aPS.Next(aSteps.GetStep(PIOperation_PostTreat)));
553 //=======================================================================
556 //=======================================================================
557 void BOPAlgo_BOP::BuildRC(const Message_ProgressRange& theRange)
559 Message_ProgressScope aPS(theRange, NULL, 1);
561 TopAbs_ShapeEnum aType;
565 aBB.MakeCompound(aC);
568 if (myOperation == BOPAlgo_FUSE) {
569 TopTools_MapOfShape aMFence;
570 aType = TypeToExplore(myDims[0]);
571 TopExp_Explorer aExp(myShape, aType);
572 for (; aExp.More(); aExp.Next()) {
573 const TopoDS_Shape& aS = aExp.Current();
574 if (aMFence.Add(aS)) {
586 // B. Common, Cut, Cut21
588 Standard_Integer i, j, aNb, iDim;
589 Standard_Boolean bCheckEdges, bContains, bCut21, bCommon;
590 TopTools_ListIteratorOfListOfShape aItLS;
592 // prepare the building elements of arguments to get its splits
593 TopTools_IndexedMapOfShape aMArgs, aMTools;
594 for (i = 0; i < 2; ++i) {
595 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
596 TopTools_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
597 aItLS.Initialize(aLS);
598 for (; aItLS.More(); aItLS.Next()) {
599 const TopoDS_Shape& aS = aItLS.Value();
600 TopTools_ListOfShape aList;
601 BOPTools_AlgoTools::TreatCompound (aS, aList);
602 for (TopTools_ListOfShape::Iterator itList (aList); itList.More(); itList.Next())
604 const TopoDS_Shape& aSS = itList.Value();
605 iDim = BOPTools_AlgoTools::Dimension (aSS);
608 aType = TypeToExplore (iDim);
609 TopExp::MapShapes (aSS, aType, aMS);
619 bCheckEdges = Standard_False;
621 // get splits of building elements
622 TopTools_IndexedMapOfShape aMArgsIm, aMToolsIm;
623 BOPTools_IndexedDataMapOfSetShape aMSetArgs, aMSetTools;
625 for (i = 0; i < 2; ++i) {
626 const TopTools_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
627 TopTools_IndexedMapOfShape& aMSIm = !i ? aMArgsIm : aMToolsIm;
628 BOPTools_IndexedDataMapOfSetShape& aMSet = !i ? aMSetArgs : aMSetTools;
631 for (j = 1; j <= aNb; ++j) {
632 const TopoDS_Shape& aS = aMS(j);
633 aType = aS.ShapeType();
634 if (aType == TopAbs_EDGE) {
635 const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
636 bCheckEdges = Standard_True;
637 if (BRep_Tool::Degenerated(aE)) {
642 if (myImages.IsBound(aS)) {
643 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
644 aItLS.Initialize(aLSIm);
645 for (; aItLS.More(); aItLS.Next()) {
646 const TopoDS_Shape& aSIm = aItLS.Value();
652 if (aS.ShapeType() == TopAbs_SOLID) {
654 aST.Add(aS, TopAbs_FACE);
655 if (!aMSet.Contains(aST)) {
663 // compare the maps and make the result
665 Standard_Integer iDimMin, iDimMax;
667 iDimMin = Min(myDims[0], myDims[1]);
668 bCommon = (myOperation == BOPAlgo_COMMON);
669 bCut21 = (myOperation == BOPAlgo_CUT21);
671 const TopTools_IndexedMapOfShape& aMIt = bCut21 ? aMToolsIm : aMArgsIm;
672 const TopTools_IndexedMapOfShape& aMCheck = bCut21 ? aMArgsIm : aMToolsIm;
673 const BOPTools_IndexedDataMapOfSetShape& aMSetCheck = bCut21 ? aMSetArgs : aMSetTools;
675 TopTools_IndexedMapOfShape aMCheckExp, aMItExp;
679 for (i = 1; i <= aNb; ++i) {
680 const TopoDS_Shape& aS = aMIt(i);
681 iDimMax = BOPTools_AlgoTools::Dimension(aS);
682 for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
683 aType = TypeToExplore(iDim);
684 TopExp::MapShapes(aS, aType, aMItExp);
693 aNb = aMCheck.Extent();
694 for (i = 1; i <= aNb; ++i) {
695 const TopoDS_Shape& aS = aMCheck(i);
696 iDimMax = BOPTools_AlgoTools::Dimension(aS);
697 for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
698 aType = TypeToExplore(iDim);
699 TopExp::MapShapes(aS, aType, aMCheckExp);
704 aNb = aMItExp.Extent();
705 for (i = 1; i <= aNb; ++i) {
706 const TopoDS_Shape& aS = aMItExp(i);
708 bContains = aMCheckExp.Contains(aS);
709 if (!bContains && aS.ShapeType() == TopAbs_SOLID) {
711 aST.Add(aS, TopAbs_FACE);
712 bContains = aMSetCheck.Contains(aST);
727 // filter result for COMMON operation
729 TopTools_MapOfShape aMFence;
730 TopExp_Explorer aExp;
732 aBB.MakeCompound(aCx);
734 for (iDim = 3; iDim >= iDimMin; --iDim) {
735 aType = TypeToExplore(iDim);
736 aExp.Init(aC, aType);
737 for (; aExp.More(); aExp.Next()) {
738 const TopoDS_Shape& aS = aExp.Current();
739 if (aMFence.Add(aS)) {
741 TopExp::MapShapes(aS, aMFence);
757 // The squats around degenerated edges
758 Standard_Integer nVD;
759 TopTools_IndexedMapOfShape aMVC;
762 TopExp::MapShapes(aC, TopAbs_VERTEX, aMVC);
765 aNb = myDS->NbSourceShapes();
766 for (i = 0; i < aNb; ++i) {
767 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
768 aType = aSI.ShapeType();
769 if (aType != TopAbs_EDGE) {
773 const TopoDS_Edge& aE = *((TopoDS_Edge*)&aSI.Shape());
774 if (!BRep_Tool::Degenerated(aE)) {
778 nVD = aSI.SubShapes().First();
779 const TopoDS_Shape& aVD = myDS->Shape(nVD);
781 if (!aMVC.Contains(aVD)) {
785 if (myDS->IsNewShape(nVD)) {
789 if (myDS->HasInterf(nVD)) {
798 //=======================================================================
799 //function : BuildShape
801 //=======================================================================
802 void BOPAlgo_BOP::BuildShape(const Message_ProgressRange& theRange)
804 Message_ProgressScope aPS(theRange, NULL, 10.);
806 if (myDims[0] == 3 && myDims[1] == 3)
808 // For the Boolean operation on solids we need to check first
809 // if we are dealing with closed solids, because for open solids
810 // we cannot expect the BuilderSolid algorithm to produce good
811 // splits for them and have to try the alternative approach for
812 // building the result shape.
813 // This approach is not used by default as it will loose the
814 // modification history for solids, because the result solid
815 // will be built from scratch using the splits of faces.
816 Standard_Boolean hasNotClosedSolids = CheckArgsForOpenSolid();
817 if (hasNotClosedSolids)
819 Handle(Message_Report) aReport = new Message_Report();
820 BuildBOP(myArguments, myTools, myOperation, Message_ProgressRange(), aReport);
821 if (aReport->GetAlerts(Message_Fail).IsEmpty())
823 // Success. Merge the report into the main report.
824 myReport->Merge(aReport);
830 // Build the result using splits of arguments.
831 BuildRC(aPS.Next(2.));
833 if ((myOperation == BOPAlgo_FUSE) && (myDims[0] == 3)) {
834 BuildSolid(aPS.Next(8.));
838 // Check for user break
845 TopAbs_ShapeEnum aType, aT1, aT2;
846 TopTools_ListOfShape aLSC, aLCB;
847 TopTools_ListIteratorOfListOfShape aItLS, aItLSIm, aItLCB;
850 TopoDS_Shape aRC, aRCB;
852 TopTools_MapOfShape aMSRC;
853 TopExp::MapShapes(myRC, aMSRC);
855 // collect images of containers
856 for (i = 0; i < 2; ++i) {
857 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
859 aItLS.Initialize(aLS);
860 for (; aItLS.More(); aItLS.Next()) {
861 const TopoDS_Shape& aS = aItLS.Value();
863 CollectContainers(aS, aLSC);
866 // Check for user break
872 TopTools_ListOfShape aLCRes;
873 TopTools_MapOfShape aMInpFence;
874 aItLS.Initialize(aLSC);
875 for (; aItLS.More(); aItLS.Next()) {
876 const TopoDS_Shape& aSC = aItLS.Value();
879 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
882 for (; aIt.More(); aIt.Next()) {
883 const TopoDS_Shape& aS = aIt.Value();
884 if (myImages.IsBound(aS)) {
885 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
887 aItLSIm.Initialize(aLSIm);
888 for (; aItLSIm.More(); aItLSIm.Next()) {
889 const TopoDS_Shape& aSIm = aItLSIm.Value();
890 if (aMSRC.Contains(aSIm)) {
895 else if (aMSRC.Contains(aS)) {
900 aType = aSC.ShapeType();
919 BOPTools_AlgoTools::MakeConnexityBlocks(aRC, aT1, aT2, aLCB);
920 if (aLCB.IsEmpty()) {
924 aItLCB.Initialize(aLCB);
925 for (; aItLCB.More(); aItLCB.Next()) {
926 BOPTools_AlgoTools::MakeContainer(aType, aRCB);
928 const TopoDS_Shape& aCB = aItLCB.Value();
930 for (; aIt.More(); aIt.Next()) {
931 const TopoDS_Shape& aCBS = aIt.Value();
935 if (aType == TopAbs_WIRE) {
937 BOPTools_AlgoTools::OrientEdgesOnWire(aRCB);
939 else if (aType == TopAbs_SHELL) {
940 BOPTools_AlgoTools::OrientFacesOnShell(aRCB);
943 aRCB.Orientation(aSC.Orientation());
949 RemoveDuplicates(aLCRes);
951 // Check for user break
957 // add containers to result
958 TopoDS_Compound aResult;
959 aBB.MakeCompound(aResult);
961 aItLS.Initialize(aLCRes);
962 for (; aItLS.More(); aItLS.Next()) {
963 aBB.Add(aResult, aItLS.Value());
966 // create map of containers
967 TopTools_MapOfShape aMSResult;
968 TopExp::MapShapes(aResult, aMSResult);
970 // get input non-container shapes
971 TopTools_ListOfShape aLSNonCont;
972 for (i = 0; i < 2; ++i)
974 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
975 aItLS.Initialize(aLS);
976 for (; aItLS.More(); aItLS.Next())
978 const TopoDS_Shape& aS = aItLS.Value();
979 BOPTools_AlgoTools::TreatCompound(aS, aLSNonCont, &aMInpFence);
983 // put non-container shapes in the result
984 aItLS.Initialize(aLSNonCont);
985 for (; aItLS.More(); aItLS.Next())
987 const TopoDS_Shape& aS = aItLS.Value();
988 if (myImages.IsBound(aS))
990 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
991 aItLSIm.Initialize(aLSIm);
992 for (; aItLSIm.More(); aItLSIm.Next())
994 const TopoDS_Shape& aSIm = aItLSIm.Value();
995 if (aMSRC.Contains(aSIm) && aMSResult.Add(aSIm))
996 aBB.Add(aResult, aSIm);
999 else if (aMSRC.Contains(aS) && aMSResult.Add(aS))
1000 aBB.Add(aResult, aS);
1005 //=======================================================================
1006 //function : BuildSolid
1008 //=======================================================================
1009 void BOPAlgo_BOP::BuildSolid(const Message_ProgressRange& theRange)
1011 Message_ProgressScope aPS(theRange, NULL, 10.);
1013 TopTools_ListOfShape aLSC;
1015 TopTools_ListIteratorOfListOfShape aItLS;
1016 TopExp_Explorer aExp;
1019 // Get solids from input arguments
1020 TopTools_MapOfShape aMSA;
1021 // Map the arguments to find shared faces
1022 TopTools_IndexedDataMapOfShapeListOfShape aMFS;
1023 for (Standard_Integer i = 0; i < 2; ++i) {
1024 const TopTools_ListOfShape& aLSA = (i) ? myArguments : myTools;
1025 aItLS.Initialize(aLSA);
1026 for (; aItLS.More(); aItLS.Next()) {
1027 const TopoDS_Shape& aSA = aItLS.Value();
1028 aExp.Init(aSA, TopAbs_SOLID);
1029 for (; aExp.More(); aExp.Next()) {
1030 const TopoDS_Shape& aSol = aExp.Current();
1032 TopExp::MapShapesAndAncestors(aSol, TopAbs_FACE, TopAbs_SOLID, aMFS);
1035 // get Compsolids from input arguments
1036 CollectContainers(aSA, aLSC);
1039 // Check for user break
1045 // Find solids in input arguments sharing faces with other solids
1046 TopTools_MapOfShape aMTSols;
1047 Standard_Integer i, aNb = aMFS.Extent();
1048 for (i = 1; i < aNb; ++i) {
1049 const TopTools_ListOfShape& aLSols = aMFS(i);
1050 if (aLSols.Extent() > 1) {
1051 aItLS.Initialize(aLSols);
1052 for(; aItLS.More(); aItLS.Next()) {
1053 aMTSols.Add(aItLS.Value());
1058 // Possibly untouched solids - to be added to results as is
1059 TopTools_IndexedMapOfShape aMUSols;
1060 // Use map to chose the most outer faces to build result solids
1063 TopoDS_Iterator aIt(myRC);
1064 for (; aIt.More(); aIt.Next()) {
1065 const TopoDS_Shape& aSx = aIt.Value();
1066 if (aMSA.Contains(aSx)) {
1067 if (!aMTSols.Contains(aSx)) {
1073 MapFacesToBuildSolids(aSx, aMFS);
1074 } // for (; aIt.More(); aIt.Next()) {
1076 // Process possibly untouched solids.
1077 // Really untouched solids will be added into result as is.
1078 // Others will be processed by BuilderSolid.
1079 BOPTools_IndexedDataMapOfSetShape aDMSTS;
1081 aNb = aMUSols.Extent();
1082 for (i = 1; i <= aNb; ++i) {
1083 const TopoDS_Shape& aSx = aMUSols(i);
1085 aExp.Init(aSx, TopAbs_FACE);
1086 for (; aExp.More(); aExp.Next()) {
1087 if (aMFS.Contains(aExp.Current())) {
1093 MapFacesToBuildSolids(aSx, aMFS);
1097 aST.Add(aSx, TopAbs_FACE);
1098 if (!aDMSTS.Contains(aST)) {
1099 aDMSTS.Add(aST, aSx);
1103 // Check for user break
1109 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
1110 // Fill the list of faces to build the result solids
1111 TopTools_ListOfShape aSFS;
1112 aNb = aMFS.Extent();
1113 for (i = 1; i <= aNb; ++i) {
1114 const TopTools_ListOfShape& aLSx = aMFS(i);
1115 if (aLSx.Extent() == 1) {
1116 const TopoDS_Shape& aFx = aMFS.FindKey(i);
1117 TopExp::MapShapesAndAncestors(aFx, TopAbs_EDGE, TopAbs_FACE, aMEF);
1123 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
1124 if (aSFS.Extent()) {
1125 // Build solids from set of faces
1126 BOPAlgo_BuilderSolid aBS;
1127 aBS.SetContext(myContext);
1128 aBS.SetShapes(aSFS);
1129 aBS.SetAvoidInternalShapes (Standard_True);
1130 aBS.Perform(aPS.Next(8.));
1131 if (aBS.HasErrors()) {
1132 AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
1136 myReport->Merge(aBS.GetReport());
1139 const TopTools_ListOfShape& aLSR = aBS.Areas();
1141 // add new solids to result
1142 aItLS.Initialize(aLSR);
1143 for (; aItLS.More(); aItLS.Next()) {
1144 const TopoDS_Shape& aSR = aItLS.Value();
1149 // add untouched solids to result
1150 aNb = aDMSTS.Extent();
1151 for (i = 1; i <= aNb; ++i) {
1152 const TopoDS_Shape& aSx = aDMSTS(i);
1156 if (aLSC.IsEmpty()) {
1157 // no Compsolids in arguments
1162 // build new Compsolids from new solids containing splits
1163 // of faces from arguments of type Compsolid
1165 TopoDS_Shape aResult;
1166 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aResult);
1169 aIt.Initialize(aRC);
1171 // no solids in the result
1176 const TopoDS_Shape& aSol1 = aIt.Value();
1179 // optimization for one solid in the result
1182 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1183 aBB.Add(aCS, aSol1);
1185 aBB.Add(aResult, aCS);
1190 // get splits of faces of the Compsolid arguments
1191 TopTools_MapOfShape aMFCs;
1192 aItLS.Initialize(aLSC);
1193 for (; aItLS.More(); aItLS.Next()) {
1194 const TopoDS_Shape& aCs = aItLS.Value();
1195 aExp.Init(aCs, TopAbs_FACE);
1196 for (; aExp.More(); aExp.Next()) {
1197 const TopoDS_Shape& aF = aExp.Current();
1198 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
1203 TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
1204 for (; aItLFIm.More(); aItLFIm.Next()) {
1205 aMFCs.Add(aItLFIm.Value());
1211 // Check for user break
1216 // build connexity blocks from new solids
1217 TopTools_ListOfShape aLCBS;
1218 BOPTools_AlgoTools::MakeConnexityBlocks(aRC, TopAbs_FACE, TopAbs_SOLID, aLCBS);
1220 aItLS.Initialize(aLCBS);
1221 for (; aItLS.More(); aItLS.Next()) {
1222 const TopoDS_Shape& aCB = aItLS.Value();
1224 // check if the Compsolid should be created
1225 aExp.Init(aCB, TopAbs_FACE);
1226 for (; aExp.More(); aExp.Next()) {
1227 if (aMFCs.Contains(aExp.Current())) {
1233 // add solids directly into result as their origins are not Compsolids
1234 for (aIt.Initialize(aCB); aIt.More(); aIt.Next()) {
1235 aBB.Add(aResult, aIt.Value());
1242 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1244 aIt.Initialize(aCB);
1245 for (; aIt.More(); aIt.Next()) {
1246 aBB.Add(aCS, aIt.Value());
1249 aBB.Add(aResult, aCS);
1255 //=======================================================================
1256 //function : CheckArgsForOpenSolid
1258 //=======================================================================
1259 Standard_Boolean BOPAlgo_BOP::CheckArgsForOpenSolid()
1261 // Analyze the report to find if BuilderSolid has generated warnings
1262 // for any of the solids and collect these solids to check if they are open.
1263 TopTools_MapOfShape aFailedSolids;
1265 const Message_ListOfAlert& aList = myReport->GetAlerts(Message_Warning);
1266 for (Message_ListOfAlert::Iterator aIt(aList); aIt.More(); aIt.Next())
1268 const Handle(Standard_Type)& aType = aIt.Value()->DynamicType();
1269 if (aType != STANDARD_TYPE(BOPAlgo_AlertSolidBuilderUnusedFaces))
1272 Handle(TopoDS_AlertWithShape) aShapeAlert = Handle(TopoDS_AlertWithShape)::DownCast(aIt.Value());
1273 if (!aShapeAlert.IsNull())
1275 const TopoDS_Shape& aWarnShape = aShapeAlert->GetShape();
1276 if (!aWarnShape.IsNull())
1278 TopExp_Explorer expS(aWarnShape, TopAbs_SOLID);
1279 for (; expS.More(); expS.Next())
1280 aFailedSolids.Add(expS.Current());
1286 // Iterate on all solids from the arguments and check if any
1287 // of them are not closed.
1288 // At the same time, collect all internal faces of the input solids
1289 // to check if the splits of open solids did not acquire any new
1292 const Standard_Integer aNbS = myDS->NbSourceShapes();
1293 for (Standard_Integer i = 0; i < aNbS; ++i)
1295 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
1296 if (aSI.ShapeType() != TopAbs_SOLID)
1299 const TopoDS_Shape& aSolid = aSI.Shape();
1301 // Check that not INTERNAL faces create closed loops
1302 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
1303 // Collect all splits of internal faces
1304 TopTools_MapOfShape aMFInternal;
1306 for (TopoDS_Iterator itSh(aSolid); itSh.More(); itSh.Next())
1308 const TopoDS_Shape& aSh = itSh.Value();
1309 if (aSh.ShapeType() != TopAbs_SHELL)
1312 for (TopoDS_Iterator itF(aSh); itF.More(); itF.Next())
1314 const TopoDS_Shape& aF = itF.Value();
1315 if (aF.Orientation() == TopAbs_INTERNAL)
1317 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
1320 TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
1321 for (; itLFIm.More(); itLFIm.Next())
1322 aMFInternal.Add(itLFIm.Value());
1325 aMFInternal.Add(aF);
1328 TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
1332 // Analyze the Edge-Face connection map on free edges
1333 Standard_Boolean isClosed = Standard_True;
1334 const Standard_Integer aNbE = aMEF.Extent();
1335 for (Standard_Integer j = 1; j <= aNbE && isClosed; ++j)
1337 const TopoDS_Edge& aE = TopoDS::Edge(aMEF.FindKey(j));
1338 if (BRep_Tool::Degenerated(aE))
1339 // Skip degenerated edges
1342 isClosed = (aMEF(j).Extent() > 1);
1345 const TopoDS_Face& aF = TopoDS::Face(aMEF(j).First());
1346 isClosed = BRep_Tool::IsClosed(aE, aF); // Check for seam edges
1349 // Check if the edge is not internal in the face
1350 TopExp_Explorer expE(aF, TopAbs_EDGE);
1351 for (; expE.More(); expE.Next())
1353 if (expE.Current().IsSame(aE))
1355 isClosed = (expE.Current().Orientation() == TopAbs_INTERNAL);
1366 // Not closed solid is found
1368 if (aFailedSolids.Contains(aSolid))
1369 // Warning has been generated for this solid, return positive result right away.
1370 return Standard_True;
1373 // Check the splits not to acquire new INTERNAL faces
1374 const TopTools_ListOfShape *pLSIm = myImages.Seek(aSolid);
1378 TopTools_ListOfShape::Iterator itLSIm(*pLSIm);
1379 for (; itLSIm.More(); itLSIm.Next())
1381 const TopoDS_Shape& aSIm = itLSIm.Value();
1382 for (TopoDS_Iterator itSh(aSIm); itSh.More(); itSh.Next())
1384 const TopoDS_Shape& aSh = itSh.Value();
1385 if (aSh.ShapeType() != TopAbs_SHELL)
1388 for (TopoDS_Iterator itF(aSh); itF.More(); itF.Next())
1390 const TopoDS_Shape& aF = itF.Value();
1391 if (aF.Orientation() == TopAbs_INTERNAL)
1393 if (!aMFInternal.Contains(aF))
1394 // New internal face is found
1395 return Standard_True;
1402 return Standard_False;
1405 //=======================================================================
1406 //function : TypeToExplore
1408 //=======================================================================
1409 TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim)
1411 TopAbs_ShapeEnum aRet;
1432 //=======================================================================
1433 //function : CollectContainers
1435 //=======================================================================
1436 void CollectContainers(const TopoDS_Shape& theS,
1437 TopTools_ListOfShape& theLSC)
1439 TopAbs_ShapeEnum aType = theS.ShapeType();
1440 if (aType == TopAbs_WIRE ||
1441 aType == TopAbs_SHELL ||
1442 aType == TopAbs_COMPSOLID) {
1443 theLSC.Append(theS);
1447 if (aType != TopAbs_COMPOUND) {
1451 TopoDS_Iterator aIt(theS);
1452 for (; aIt.More(); aIt.Next()) {
1453 const TopoDS_Shape& aS = aIt.Value();
1454 CollectContainers(aS, theLSC);
1458 //=======================================================================
1459 //function : RemoveDuplicates
1460 //purpose : Filters the containers with identical contents
1461 //=======================================================================
1462 void RemoveDuplicates(TopTools_ListOfShape& theContainers)
1464 RemoveDuplicates(theContainers, TopAbs_WIRE);
1465 RemoveDuplicates(theContainers, TopAbs_SHELL);
1466 RemoveDuplicates(theContainers, TopAbs_COMPSOLID);
1469 //=======================================================================
1470 //function : RemoveDuplicates
1471 //purpose : Filters the containers of given type with identical contents
1472 //=======================================================================
1473 void RemoveDuplicates(TopTools_ListOfShape& theContainers,
1474 const TopAbs_ShapeEnum theType)
1476 // get containers of given type
1477 TopTools_ListOfShape aLC;
1478 TopTools_ListIteratorOfListOfShape aItLC(theContainers);
1479 for (; aItLC.More(); aItLC.Next()) {
1480 const TopoDS_Shape& aC = aItLC.Value();
1481 if (aC.ShapeType() == theType) {
1486 if (aLC.IsEmpty()) {
1490 // map containers to compare its contents
1491 NCollection_IndexedDataMap<TopoDS_Shape, TopTools_MapOfShape> aContents;
1493 aItLC.Initialize(aLC);
1494 for (; aItLC.More(); aItLC.Next()) {
1495 const TopoDS_Shape& aC = aItLC.Value();
1497 TopTools_MapOfShape& aMC = aContents(aContents.Add(aC, TopTools_MapOfShape()));
1499 TopoDS_Iterator aIt(aC);
1500 for (; aIt.More(); aIt.Next()) {
1501 aMC.Add(aIt.Value());
1505 // compare the contents of the containers and find duplicates
1506 TopTools_MapOfShape aDuplicates;
1508 Standard_Integer i, j, aNb = aContents.Extent();
1509 for (i = 1; i <= aNb; ++i) {
1510 const TopoDS_Shape& aCi = aContents.FindKey(i);
1511 if (aDuplicates.Contains(aCi)) {
1514 const TopTools_MapOfShape& aMi = aContents(i);
1515 Standard_Integer aNbi = aMi.Extent();
1517 for (j = i + 1; j <= aNb; ++j) {
1518 const TopoDS_Shape& aCj = aContents.FindKey(j);
1519 if (aDuplicates.Contains(aCj)) {
1522 const TopTools_MapOfShape& aMj = aContents(j);
1523 Standard_Integer aNbj = aMj.Extent();
1525 Standard_Integer aNbCommon = NbCommonItemsInMap(aMi, aMj);
1527 if (aNbj == aNbCommon) {
1528 aDuplicates.Add(aCj);
1532 if (aNbi == aNbCommon) {
1533 aDuplicates.Add(aCi);
1539 if (aDuplicates.IsEmpty()) {
1543 // remove duplicating containers
1544 aItLC.Initialize(theContainers);
1545 for (; aItLC.More(); ) {
1546 const TopoDS_Shape& aC = aItLC.Value();
1547 if (aDuplicates.Contains(aC)) {
1548 theContainers.Remove(aItLC);
1555 //=======================================================================
1556 //function : NbCommonItemsInMap
1557 //purpose : Counts the items contained in both maps
1558 //=======================================================================
1559 Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
1560 const TopTools_MapOfShape& theM2)
1562 const TopTools_MapOfShape* aMap1 = &theM1;
1563 const TopTools_MapOfShape* aMap2 = &theM2;
1565 if (theM2.Extent() < theM1.Extent()) {
1570 Standard_Integer iCommon = 0;
1571 for (TopTools_MapIteratorOfMapOfShape aIt(*aMap1); aIt.More(); aIt.Next()) {
1572 if (aMap2->Contains(aIt.Value())) {
1578 //=======================================================================
1579 //function : MapFacesToBuildSolids
1580 //purpose : Stores the faces of the given solid into outgoing maps:
1581 // <theMFS> - not internal faces with reference to solid.
1582 //=======================================================================
1583 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
1584 TopTools_IndexedDataMapOfShapeListOfShape& theMFS)
1586 TopExp_Explorer aExp(theSol, TopAbs_FACE);
1587 for (; aExp.More(); aExp.Next()) {
1588 const TopoDS_Shape& aF = aExp.Current();
1590 if (aF.Orientation() == TopAbs_INTERNAL) {
1594 TopTools_ListOfShape* pLSol = theMFS.ChangeSeek(aF);
1596 pLSol = &theMFS(theMFS.Add(aF, TopTools_ListOfShape()));
1597 pLSol->Append(theSol);
1600 const TopoDS_Shape& aF1 = theMFS.FindKey(theMFS.FindIndex(aF));
1601 if (aF1.Orientation() != aF.Orientation()) {
1602 pLSol->Append(theSol);