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 <BOPTools_SetMapHasher.hxx>
27 #include <BRep_Builder.hxx>
28 #include <BRep_Tool.hxx>
29 #include <NCollection_DataMap.hxx>
30 #include <TopAbs_ShapeEnum.hxx>
32 #include <TopExp_Explorer.hxx>
34 #include <TopoDS_Compound.hxx>
35 #include <TopoDS_Edge.hxx>
36 #include <TopoDS_Iterator.hxx>
37 #include <TopoDS_Shape.hxx>
38 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
39 #include <TopTools_IndexedMapOfShape.hxx>
40 #include <TopTools_ListOfShape.hxx>
41 #include <TopTools_MapOfShape.hxx>
44 TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim);
47 void CollectContainers(const TopoDS_Shape& theS,
48 TopTools_ListOfShape& theLSC);
51 void RemoveDuplicates(TopTools_ListOfShape& theContainers);
54 void RemoveDuplicates(TopTools_ListOfShape& theContainers,
55 const TopAbs_ShapeEnum theType);
58 Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
59 const TopTools_MapOfShape& theM2);
62 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
63 TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
64 TopTools_IndexedMapOfShape& theMFI);
66 //=======================================================================
69 //=======================================================================
70 BOPAlgo_BOP::BOPAlgo_BOP()
71 : BOPAlgo_ToolsProvider()
75 //=======================================================================
78 //=======================================================================
79 BOPAlgo_BOP::BOPAlgo_BOP(const Handle(NCollection_BaseAllocator)& theAllocator)
80 : BOPAlgo_ToolsProvider(theAllocator)
84 //=======================================================================
87 //=======================================================================
88 BOPAlgo_BOP::~BOPAlgo_BOP()
91 //=======================================================================
94 //=======================================================================
95 void BOPAlgo_BOP::Clear()
97 myOperation=BOPAlgo_UNKNOWN;
101 BOPAlgo_ToolsProvider::Clear();
103 //=======================================================================
104 //function : SetOperation
106 //=======================================================================
107 void BOPAlgo_BOP::SetOperation(const BOPAlgo_Operation theOperation)
109 myOperation=theOperation;
111 //=======================================================================
112 //function : Operation
114 //=======================================================================
115 BOPAlgo_Operation BOPAlgo_BOP::Operation()const
119 //=======================================================================
120 //function : CheckData
122 //=======================================================================
123 void BOPAlgo_BOP::CheckData()
125 Standard_Integer i, j, aNbArgs, aNbTools;
126 Standard_Boolean bFuse;
127 TopTools_ListIteratorOfListOfShape aItLS;
129 if (!(myOperation==BOPAlgo_COMMON ||
130 myOperation==BOPAlgo_FUSE ||
131 myOperation==BOPAlgo_CUT||
132 myOperation==BOPAlgo_CUT21)) {
133 // non-licit operation
134 AddError (new BOPAlgo_AlertBOPNotSet);
138 aNbArgs=myArguments.Extent();
140 // invalid number of Arguments
141 AddError (new BOPAlgo_AlertTooFewArguments);
145 aNbTools=myTools.Extent();
147 // invalid number of Tools
148 AddError (new BOPAlgo_AlertTooFewArguments);
157 bFuse = (myOperation == BOPAlgo_FUSE);
159 // The rules for different types of operations are the following:
160 // 1. FUSE: All arguments and tools should have the same dimension;
161 // 2. CUT: The MAXIMAL dimension of the ARGUMENTS should be less
162 // or equal to the MINIMAL dimension of the TOOLS;
163 // 3. CUT21: The MINIMAL dimension of ARGUMENTS should be grater
164 // or equal to the MAXIMAL dimension of the TOOLS;
165 // 4. COMMON: The arguments and tools could have any dimensions.
167 Standard_Integer iDimMin[2] = { 3, 3 },
168 iDimMax[2] = { 0, 0 };
169 Standard_Boolean bHasValid[2] = {Standard_False, Standard_False};
171 for (i=0; i<2; ++i) {
172 const TopTools_ListOfShape& aLS=(!i)? myArguments : myTools;
173 aItLS.Initialize(aLS);
174 for (j=0; aItLS.More(); aItLS.Next(), ++j) {
175 const TopoDS_Shape& aS=aItLS.Value();
176 Standard_Boolean bIsEmpty = BOPTools_AlgoTools3D::IsEmptyShape(aS);
179 AddWarning(new BOPAlgo_AlertEmptyShape (aS));
183 Standard_Integer iDMin, iDMax;
184 BOPTools_AlgoTools::Dimensions(aS, iDMin, iDMax);
186 if (iDMin < iDimMin[i])
188 if (iDMax > iDimMax[i])
191 if (bFuse && (iDimMin[i] != iDimMax[i]))
193 // non-homogeneous argument
194 AddError (new BOPAlgo_AlertBOPNotAllowed);
197 bHasValid[i] = Standard_True;
201 if (bHasValid[0] && bHasValid[1]) {
202 if (((myOperation == BOPAlgo_FUSE) && (iDimMax[0] != iDimMax[1])) ||
203 ((myOperation == BOPAlgo_CUT) && (iDimMax[0] > iDimMin[1])) ||
204 ((myOperation == BOPAlgo_CUT21) && (iDimMin[0] < iDimMax[1])) )
206 // non-licit operation for the arguments
207 AddError (new BOPAlgo_AlertBOPNotAllowed);
212 if (bHasValid[0] || bHasValid[1])
214 // In case of all empty shapes in one of the groups
215 // this group acquires the dimension of other group
216 myDims[0] = bHasValid[0] ? iDimMin[0] : iDimMin[1];
217 myDims[1] = bHasValid[1] ? iDimMin[1] : iDimMin[0];
220 //=======================================================================
221 //function : TreatEmtpyShape
223 //=======================================================================
224 Standard_Boolean BOPAlgo_BOP::TreatEmptyShape()
226 if (! GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
228 return Standard_False;
231 // Find non-empty objects
232 TopTools_ListOfShape aLValidObjs;
233 TopTools_ListIteratorOfListOfShape aItLS(myArguments);
234 for (; aItLS.More(); aItLS.Next()) {
235 if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
236 aLValidObjs.Append(aItLS.Value());
240 // Find non-empty tools
241 TopTools_ListOfShape aLValidTools;
242 aItLS.Initialize(myTools);
243 for (; aItLS.More() ; aItLS.Next()) {
244 if (!BOPTools_AlgoTools3D::IsEmptyShape(aItLS.Value())) {
245 aLValidTools.Append(aItLS.Value());
249 Standard_Boolean bHasValidObj = (aLValidObjs .Extent() > 0);
250 Standard_Boolean bHasValidTool = (aLValidTools.Extent() > 0);
252 if (bHasValidObj && bHasValidTool) {
253 // We need to continue the operation to obtain the result
254 return Standard_False;
257 if (!bHasValidObj && !bHasValidTool) {
258 // All shapes are empty shapes, the result will always be empty shape
259 return Standard_True;
262 // One of the groups of arguments consists of empty shapes only,
263 // so we can build the result of operation right away just by
264 // choosing the list of shapes to add to result, depending on
265 // the type of the operation.
266 // Although, if the group with valid shapes consists from more
267 // than just one shape, depending on the operation type we may need
268 // to split the shapes in this group before adding them into result.
270 TopTools_ListOfShape *pLResult = NULL;
272 switch (myOperation) {
275 if (aLValidObjs.Extent() + aLValidTools.Extent() > 1)
276 // The arguments must be split before adding into result
277 return Standard_False;
279 // Add not empty shapes into result
280 pLResult = bHasValidObj ? &aLValidObjs : &aLValidTools;
285 if (aLValidObjs.Extent() > 1)
286 // The objects must be split before adding into result
287 return Standard_False;
289 // Add objects into result
290 pLResult = &aLValidObjs;
295 if (aLValidTools.Extent() > 1)
296 // The tools must be split before adding into result
297 return Standard_False;
299 // Add tools into result
300 pLResult = &aLValidTools;
304 // Common will always be empty
311 aItLS.Initialize(*pLResult);
312 for (; aItLS.More(); aItLS.Next()) {
313 BRep_Builder().Add(myShape, aItLS.Value());
316 return Standard_True;
318 //=======================================================================
319 //function : BuildResult
321 //=======================================================================
322 void BOPAlgo_BOP::BuildResult(const TopAbs_ShapeEnum theType)
324 TopAbs_ShapeEnum aType;
326 TopTools_MapOfShape aM;
327 TopTools_ListIteratorOfListOfShape aIt, aItIm;
329 const TopTools_ListOfShape& aLA=myDS->Arguments();
331 for (; aIt.More(); aIt.Next()) {
332 const TopoDS_Shape& aS=aIt.Value();
333 aType=aS.ShapeType();
334 if (aType==theType) {
335 if (myImages.IsBound(aS)){
336 const TopTools_ListOfShape& aLSIm=myImages.Find(aS);
337 aItIm.Initialize(aLSIm);
338 for (; aItIm.More(); aItIm.Next()) {
339 const TopoDS_Shape& aSIm=aItIm.Value();
341 aBB.Add(myShape, aSIm);
347 aBB.Add(myShape, aS);
353 //=======================================================================
356 //=======================================================================
357 void BOPAlgo_BOP::Perform()
359 Handle(NCollection_BaseAllocator) aAllocator;
360 BOPAlgo_PaveFiller* pPF;
361 TopTools_ListIteratorOfListOfShape aItLS;
363 GetReport()->Clear();
365 if (myEntryPoint==1) {
373 NCollection_BaseAllocator::CommonBaseAllocator();
374 TopTools_ListOfShape aLS(aAllocator);
376 aItLS.Initialize(myArguments);
377 for (; aItLS.More(); aItLS.Next()) {
378 const TopoDS_Shape& aS=aItLS.Value();
382 aItLS.Initialize(myTools);
383 for (; aItLS.More(); aItLS.Next()) {
384 const TopoDS_Shape& aS=aItLS.Value();
388 pPF=new BOPAlgo_PaveFiller(aAllocator);
389 pPF->SetArguments(aLS);
390 pPF->SetRunParallel(myRunParallel);
391 pPF->SetProgressIndicator(myProgressIndicator);
392 pPF->SetFuzzyValue(myFuzzyValue);
393 pPF->SetNonDestructive(myNonDestructive);
394 pPF->SetGlue(myGlue);
395 pPF->SetUseOBB(myUseOBB);
400 PerformInternal(*pPF);
402 //=======================================================================
403 //function : PerformInternal1
405 //=======================================================================
406 void BOPAlgo_BOP::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
408 myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
409 myDS=myPaveFiller->PDS();
410 myContext=myPaveFiller->Context();
411 myFuzzyValue = myPaveFiller->FuzzyValue();
412 myNonDestructive = myPaveFiller->NonDestructive();
426 if (GetReport()->HasAlert (STANDARD_TYPE(BOPAlgo_AlertEmptyShape)))
428 Standard_Boolean bDone = TreatEmptyShape();
437 FillImagesVertices();
442 BuildResult(TopAbs_VERTEX);
452 BuildResult(TopAbs_EDGE);
458 FillImagesContainers(TopAbs_WIRE);
463 BuildResult(TopAbs_WIRE);
474 BuildResult(TopAbs_FACE);
480 FillImagesContainers(TopAbs_SHELL);
485 BuildResult(TopAbs_SHELL);
496 BuildResult(TopAbs_SOLID);
502 FillImagesContainers(TopAbs_COMPSOLID);
507 BuildResult(TopAbs_COMPSOLID);
513 FillImagesCompounds();
518 BuildResult(TopAbs_COMPOUND);
535 //=======================================================================
538 //=======================================================================
539 void BOPAlgo_BOP::BuildRC()
541 TopAbs_ShapeEnum aType;
545 aBB.MakeCompound(aC);
548 if (myOperation == BOPAlgo_FUSE) {
549 TopTools_MapOfShape aMFence;
550 aType = TypeToExplore(myDims[0]);
551 TopExp_Explorer aExp(myShape, aType);
552 for (; aExp.More(); aExp.Next()) {
553 const TopoDS_Shape& aS = aExp.Current();
554 if (aMFence.Add(aS)) {
562 // B. Common, Cut, Cut21
564 Standard_Integer i, j, aNb, iDim;
565 Standard_Boolean bCheckEdges, bContains, bCut21, bCommon;
566 TopTools_ListIteratorOfListOfShape aItLS;
568 // prepare the building elements of arguments to get its splits
569 TopTools_IndexedMapOfShape aMArgs, aMTools;
570 for (i = 0; i < 2; ++i) {
571 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
572 TopTools_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
573 aItLS.Initialize(aLS);
574 for (; aItLS.More(); aItLS.Next()) {
575 const TopoDS_Shape& aS = aItLS.Value();
576 TopTools_ListOfShape aList;
577 BOPTools_AlgoTools::TreatCompound (aS, aList);
578 for (TopTools_ListOfShape::Iterator itList (aList); itList.More(); itList.Next())
580 const TopoDS_Shape& aSS = itList.Value();
581 iDim = BOPTools_AlgoTools::Dimension (aSS);
584 aType = TypeToExplore (iDim);
585 TopExp::MapShapes (aSS, aType, aMS);
590 bCheckEdges = Standard_False;
592 // get splits of building elements
593 TopTools_IndexedMapOfShape aMArgsIm, aMToolsIm;
594 BOPTools_IndexedDataMapOfSetShape aMSetArgs, aMSetTools;
596 for (i = 0; i < 2; ++i) {
597 const TopTools_IndexedMapOfShape& aMS = !i ? aMArgs : aMTools;
598 TopTools_IndexedMapOfShape& aMSIm = !i ? aMArgsIm : aMToolsIm;
599 BOPTools_IndexedDataMapOfSetShape& aMSet = !i ? aMSetArgs : aMSetTools;
602 for (j = 1; j <= aNb; ++j) {
603 const TopoDS_Shape& aS = aMS(j);
604 aType = aS.ShapeType();
605 if (aType == TopAbs_EDGE) {
606 const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
607 bCheckEdges = Standard_True;
608 if (BRep_Tool::Degenerated(aE)) {
613 if (myImages.IsBound(aS)) {
614 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
615 aItLS.Initialize(aLSIm);
616 for (; aItLS.More(); aItLS.Next()) {
617 const TopoDS_Shape& aSIm = aItLS.Value();
623 if (aS.ShapeType() == TopAbs_SOLID) {
625 aST.Add(aS, TopAbs_FACE);
626 if (!aMSet.Contains(aST)) {
634 // compare the maps and make the result
636 Standard_Integer iDimMin, iDimMax;
638 iDimMin = Min(myDims[0], myDims[1]);
639 bCommon = (myOperation == BOPAlgo_COMMON);
640 bCut21 = (myOperation == BOPAlgo_CUT21);
642 const TopTools_IndexedMapOfShape& aMIt = bCut21 ? aMToolsIm : aMArgsIm;
643 const TopTools_IndexedMapOfShape& aMCheck = bCut21 ? aMArgsIm : aMToolsIm;
644 const BOPTools_IndexedDataMapOfSetShape& aMSetCheck = bCut21 ? aMSetArgs : aMSetTools;
646 TopTools_IndexedMapOfShape aMCheckExp, aMItExp;
650 for (i = 1; i <= aNb; ++i) {
651 const TopoDS_Shape& aS = aMIt(i);
652 iDimMax = BOPTools_AlgoTools::Dimension(aS);
653 for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
654 aType = TypeToExplore(iDim);
655 TopExp::MapShapes(aS, aType, aMItExp);
664 aNb = aMCheck.Extent();
665 for (i = 1; i <= aNb; ++i) {
666 const TopoDS_Shape& aS = aMCheck(i);
667 iDimMax = BOPTools_AlgoTools::Dimension(aS);
668 for (iDim = iDimMin; iDim < iDimMax; ++iDim) {
669 aType = TypeToExplore(iDim);
670 TopExp::MapShapes(aS, aType, aMCheckExp);
675 aNb = aMItExp.Extent();
676 for (i = 1; i <= aNb; ++i) {
677 const TopoDS_Shape& aS = aMItExp(i);
679 bContains = aMCheckExp.Contains(aS);
680 if (!bContains && aS.ShapeType() == TopAbs_SOLID) {
682 aST.Add(aS, TopAbs_FACE);
683 bContains = aMSetCheck.Contains(aST);
698 // filter result for COMMON operation
700 TopTools_MapOfShape aMFence;
701 TopExp_Explorer aExp;
703 aBB.MakeCompound(aCx);
705 for (iDim = 3; iDim >= iDimMin; --iDim) {
706 aType = TypeToExplore(iDim);
707 aExp.Init(aC, aType);
708 for (; aExp.More(); aExp.Next()) {
709 const TopoDS_Shape& aS = aExp.Current();
710 if (aMFence.Add(aS)) {
712 TopExp::MapShapes(aS, aMFence);
724 // The squats around degenerated edges
725 Standard_Integer nVD;
726 TopTools_IndexedMapOfShape aMVC;
729 TopExp::MapShapes(aC, TopAbs_VERTEX, aMVC);
732 aNb = myDS->NbSourceShapes();
733 for (i = 0; i < aNb; ++i) {
734 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
735 aType = aSI.ShapeType();
736 if (aType != TopAbs_EDGE) {
740 const TopoDS_Edge& aE = *((TopoDS_Edge*)&aSI.Shape());
741 if (!BRep_Tool::Degenerated(aE)) {
745 nVD = aSI.SubShapes().First();
746 const TopoDS_Shape& aVD = myDS->Shape(nVD);
748 if (!aMVC.Contains(aVD)) {
752 if (myDS->IsNewShape(nVD)) {
756 if (myDS->HasInterf(nVD)) {
765 //=======================================================================
766 //function : BuildShape
768 //=======================================================================
769 void BOPAlgo_BOP::BuildShape()
771 if (myDims[0] == 3 && myDims[1] == 3)
773 // For the Boolean operation on solids we need to check first
774 // if we are dealing with closed solids, because for open solids
775 // we cannot expect the BuilderSolid algorithm to produce good
776 // splits for them and have to try the alternative approach for
777 // building the result shape.
778 // This approach is not used by default as it will loose the
779 // modification history for solids, because the result solid
780 // will be built from scratch using the splits of faces.
781 Standard_Boolean hasNotClosedSolids = CheckArgsForOpenSolid();
782 if (hasNotClosedSolids)
784 Handle(Message_Report) aReport = new Message_Report();
785 BuildBOP(myArguments, myTools, myOperation, aReport);
786 if (aReport->GetAlerts(Message_Fail).IsEmpty())
788 // Success. Merge the report into the main report.
789 myReport->Merge(aReport);
795 // Build the result using splits of arguments.
799 if ((myOperation == BOPAlgo_FUSE) && (myDims[0] == 3)) {
805 TopAbs_ShapeEnum aType, aT1, aT2;
806 TopTools_ListOfShape aLSC, aLCB;
807 TopTools_ListIteratorOfListOfShape aItLS, aItLSIm, aItLCB;
810 TopoDS_Shape aRC, aRCB;
812 TopTools_MapOfShape aMSRC;
813 TopExp::MapShapes(myRC, aMSRC);
815 // collect images of containers
816 for (i = 0; i < 2; ++i) {
817 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
819 aItLS.Initialize(aLS);
820 for (; aItLS.More(); aItLS.Next()) {
821 const TopoDS_Shape& aS = aItLS.Value();
823 CollectContainers(aS, aLSC);
827 TopTools_ListOfShape aLCRes;
828 TopTools_MapOfShape aMInpFence;
829 aItLS.Initialize(aLSC);
830 for (; aItLS.More(); aItLS.Next()) {
831 const TopoDS_Shape& aSC = aItLS.Value();
834 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
837 for (; aIt.More(); aIt.Next()) {
838 const TopoDS_Shape& aS = aIt.Value();
839 if (myImages.IsBound(aS)) {
840 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
842 aItLSIm.Initialize(aLSIm);
843 for (; aItLSIm.More(); aItLSIm.Next()) {
844 const TopoDS_Shape& aSIm = aItLSIm.Value();
845 if (aMSRC.Contains(aSIm)) {
850 else if (aMSRC.Contains(aS)) {
855 aType = aSC.ShapeType();
874 BOPTools_AlgoTools::MakeConnexityBlocks(aRC, aT1, aT2, aLCB);
875 if (aLCB.IsEmpty()) {
879 aItLCB.Initialize(aLCB);
880 for (; aItLCB.More(); aItLCB.Next()) {
881 BOPTools_AlgoTools::MakeContainer(aType, aRCB);
883 const TopoDS_Shape& aCB = aItLCB.Value();
885 for (; aIt.More(); aIt.Next()) {
886 const TopoDS_Shape& aCBS = aIt.Value();
890 if (aType == TopAbs_WIRE) {
892 BOPTools_AlgoTools::OrientEdgesOnWire(aRCB);
894 else if (aType == TopAbs_SHELL) {
895 BOPTools_AlgoTools::OrientFacesOnShell(aRCB);
898 aRCB.Orientation(aSC.Orientation());
904 RemoveDuplicates(aLCRes);
906 // add containers to result
907 TopoDS_Compound aResult;
908 aBB.MakeCompound(aResult);
910 aItLS.Initialize(aLCRes);
911 for (; aItLS.More(); aItLS.Next()) {
912 aBB.Add(aResult, aItLS.Value());
915 // create map of containers
916 TopTools_MapOfShape aMSResult;
917 TopExp::MapShapes(aResult, aMSResult);
919 // get input non-container shapes
920 TopTools_ListOfShape aLSNonCont;
921 for (i = 0; i < 2; ++i)
923 const TopTools_ListOfShape& aLS = !i ? myArguments : myTools;
924 aItLS.Initialize(aLS);
925 for (; aItLS.More(); aItLS.Next())
927 const TopoDS_Shape& aS = aItLS.Value();
928 BOPTools_AlgoTools::TreatCompound(aS, aLSNonCont, &aMInpFence);
932 // put non-container shapes in the result
933 aItLS.Initialize(aLSNonCont);
934 for (; aItLS.More(); aItLS.Next())
936 const TopoDS_Shape& aS = aItLS.Value();
937 if (myImages.IsBound(aS))
939 const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
940 aItLSIm.Initialize(aLSIm);
941 for (; aItLSIm.More(); aItLSIm.Next())
943 const TopoDS_Shape& aSIm = aItLSIm.Value();
944 if (aMSRC.Contains(aSIm) && aMSResult.Add(aSIm))
945 aBB.Add(aResult, aSIm);
948 else if (aMSRC.Contains(aS) && aMSResult.Add(aS))
949 aBB.Add(aResult, aS);
954 //=======================================================================
955 //function : BuildSolid
957 //=======================================================================
958 void BOPAlgo_BOP::BuildSolid()
961 TopTools_ListOfShape aLSC;
963 TopTools_ListIteratorOfListOfShape aItLS;
964 TopExp_Explorer aExp;
967 // Get solids from input arguments
968 TopTools_MapOfShape aMSA;
969 // Map the arguments to find shared faces
970 TopTools_IndexedDataMapOfShapeListOfShape aMFS;
971 for (Standard_Integer i = 0; i < 2; ++i) {
972 const TopTools_ListOfShape& aLSA = (i) ? myArguments : myTools;
973 aItLS.Initialize(aLSA);
974 for (; aItLS.More(); aItLS.Next()) {
975 const TopoDS_Shape& aSA = aItLS.Value();
976 aExp.Init(aSA, TopAbs_SOLID);
977 for (; aExp.More(); aExp.Next()) {
978 const TopoDS_Shape& aSol = aExp.Current();
980 TopExp::MapShapesAndAncestors(aSol, TopAbs_FACE, TopAbs_SOLID, aMFS);
983 // get Compsolids from input arguments
984 CollectContainers(aSA, aLSC);
988 // Find solids in input arguments sharing faces with other solids
989 TopTools_MapOfShape aMTSols;
990 Standard_Integer i, aNb = aMFS.Extent();
991 for (i = 1; i < aNb; ++i) {
992 const TopTools_ListOfShape& aLSols = aMFS(i);
993 if (aLSols.Extent() > 1) {
994 aItLS.Initialize(aLSols);
995 for(; aItLS.More(); aItLS.Next()) {
996 aMTSols.Add(aItLS.Value());
1001 // Possibly untouched solids - to be added to results as is
1002 TopTools_IndexedMapOfShape aMUSols;
1003 // Use map to chose the most outer faces to build result solids
1006 TopTools_IndexedMapOfShape aMFI;
1008 TopoDS_Iterator aIt(myRC);
1009 for (; aIt.More(); aIt.Next()) {
1010 const TopoDS_Shape& aSx = aIt.Value();
1011 if (aMSA.Contains(aSx)) {
1012 if (!aMTSols.Contains(aSx)) {
1018 MapFacesToBuildSolids(aSx, aMFS, aMFI);
1019 } // for (; aIt.More(); aIt.Next()) {
1021 // Process possibly untouched solids.
1022 // Really untouched solids will be added into result as is.
1023 // Others will be processed by BuilderSolid.
1024 BOPTools_IndexedDataMapOfSetShape aDMSTS;
1026 aNb = aMUSols.Extent();
1027 for (i = 1; i <= aNb; ++i) {
1028 const TopoDS_Shape& aSx = aMUSols(i);
1030 aExp.Init(aSx, TopAbs_FACE);
1031 for (; aExp.More(); aExp.Next()) {
1032 if (aMFS.Contains(aExp.Current())) {
1038 MapFacesToBuildSolids(aSx, aMFS, aMFI);
1042 aST.Add(aSx, TopAbs_FACE);
1043 if (!aDMSTS.Contains(aST)) {
1044 aDMSTS.Add(aST, aSx);
1049 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
1050 // Fill the list of faces to build the result solids
1051 TopTools_ListOfShape aSFS;
1052 aNb = aMFS.Extent();
1053 for (i = 1; i <= aNb; ++i) {
1054 const TopTools_ListOfShape& aLSx = aMFS(i);
1055 if (aLSx.Extent() == 1) {
1056 const TopoDS_Shape& aFx = aMFS.FindKey(i);
1057 TopExp::MapShapesAndAncestors(aFx, TopAbs_EDGE, TopAbs_FACE, aMEF);
1062 aNb = aMFI.Extent();
1063 for (i = 1; i <= aNb; ++i) {
1064 TopoDS_Shape aFx = aMFI.FindKey(i);
1065 aSFS.Append(aFx.Oriented(TopAbs_FORWARD));
1066 aSFS.Append(aFx.Oriented(TopAbs_REVERSED));
1070 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
1071 if (aSFS.Extent()) {
1072 // Build solids from set of faces
1073 BOPAlgo_BuilderSolid aBS;
1074 aBS.SetContext(myContext);
1075 aBS.SetShapes(aSFS);
1077 if (aBS.HasErrors()) {
1078 AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
1082 myReport->Merge(aBS.GetReport());
1085 const TopTools_ListOfShape& aLSR = aBS.Areas();
1087 // add new solids to result
1088 aItLS.Initialize(aLSR);
1089 for (; aItLS.More(); aItLS.Next()) {
1090 const TopoDS_Shape& aSR = aItLS.Value();
1095 // add untouched solids to result
1096 aNb = aDMSTS.Extent();
1097 for (i = 1; i <= aNb; ++i) {
1098 const TopoDS_Shape& aSx = aDMSTS(i);
1102 if (aLSC.IsEmpty()) {
1103 // no Compsolids in arguments
1108 // build new Compsolids from new solids containing splits
1109 // of faces from arguments of type Compsolid
1111 TopoDS_Shape aResult;
1112 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aResult);
1114 aIt.Initialize(aRC);
1116 // no solids in the result
1121 const TopoDS_Shape& aSol1 = aIt.Value();
1124 // optimization for one solid in the result
1127 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1128 aBB.Add(aCS, aSol1);
1130 aBB.Add(aResult, aCS);
1135 // get splits of faces of the Compsolid arguments
1136 TopTools_MapOfShape aMFCs;
1137 aItLS.Initialize(aLSC);
1138 for (; aItLS.More(); aItLS.Next()) {
1139 const TopoDS_Shape& aCs = aItLS.Value();
1140 aExp.Init(aCs, TopAbs_FACE);
1141 for (; aExp.More(); aExp.Next()) {
1142 const TopoDS_Shape& aF = aExp.Current();
1143 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
1148 TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
1149 for (; aItLFIm.More(); aItLFIm.Next()) {
1150 aMFCs.Add(aItLFIm.Value());
1156 // build connexity blocks from new solids
1157 TopTools_ListOfShape aLCBS;
1158 BOPTools_AlgoTools::MakeConnexityBlocks(aRC, TopAbs_FACE, TopAbs_SOLID, aLCBS);
1160 aItLS.Initialize(aLCBS);
1161 for (; aItLS.More(); aItLS.Next()) {
1162 const TopoDS_Shape& aCB = aItLS.Value();
1164 // check if the Compsolid should be created
1165 aExp.Init(aCB, TopAbs_FACE);
1166 for (; aExp.More(); aExp.Next()) {
1167 if (aMFCs.Contains(aExp.Current())) {
1173 // add solids directly into result as their origins are not Compsolids
1174 for (aIt.Initialize(aCB); aIt.More(); aIt.Next()) {
1175 aBB.Add(aResult, aIt.Value());
1182 BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
1184 aIt.Initialize(aCB);
1185 for (; aIt.More(); aIt.Next()) {
1186 aBB.Add(aCS, aIt.Value());
1189 aBB.Add(aResult, aCS);
1195 //=======================================================================
1196 //function : CheckArgsForOpenSolid
1198 //=======================================================================
1199 Standard_Boolean BOPAlgo_BOP::CheckArgsForOpenSolid()
1201 // Analyze the report to find if BuilderSolid has generated warnings
1202 // for any of the solids and collect these solids to check if they are open.
1203 TopTools_MapOfShape aFailedSolids;
1205 const Message_ListOfAlert& aList = myReport->GetAlerts(Message_Warning);
1206 for (Message_ListOfAlert::Iterator aIt(aList); aIt.More(); aIt.Next())
1208 const Handle(Standard_Type)& aType = aIt.Value()->DynamicType();
1209 if (aType != STANDARD_TYPE(BOPAlgo_AlertSolidBuilderUnusedFaces))
1212 Handle(TopoDS_AlertWithShape) aShapeAlert = Handle(TopoDS_AlertWithShape)::DownCast(aIt.Value());
1213 if (!aShapeAlert.IsNull())
1215 const TopoDS_Shape& aWarnShape = aShapeAlert->GetShape();
1216 if (!aWarnShape.IsNull())
1218 TopExp_Explorer expS(aWarnShape, TopAbs_SOLID);
1219 for (; expS.More(); expS.Next())
1220 aFailedSolids.Add(expS.Current());
1226 // Iterate on all solids from the arguments and check if any
1227 // of them are not closed.
1228 // At the same time, collect all internal faces of the input solids
1229 // to check if the splits of open solids did not acquire any new
1232 const Standard_Integer aNbS = myDS->NbSourceShapes();
1233 for (Standard_Integer i = 0; i < aNbS; ++i)
1235 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
1236 if (aSI.ShapeType() != TopAbs_SOLID)
1239 const TopoDS_Shape& aSolid = aSI.Shape();
1241 // Check that not INTERNAL faces create closed loops
1242 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
1243 // Collect all splits of internal faces
1244 TopTools_MapOfShape aMFInternal;
1246 for (TopoDS_Iterator itSh(aSolid); itSh.More(); itSh.Next())
1248 const TopoDS_Shape& aSh = itSh.Value();
1249 if (aSh.ShapeType() != TopAbs_SHELL)
1252 for (TopoDS_Iterator itF(aSh); itF.More(); itF.Next())
1254 const TopoDS_Shape& aF = itF.Value();
1255 if (aF.Orientation() == TopAbs_INTERNAL)
1257 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
1260 TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
1261 for (; itLFIm.More(); itLFIm.Next())
1262 aMFInternal.Add(itLFIm.Value());
1265 aMFInternal.Add(aF);
1268 TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
1272 // Analyze the Edge-Face connection map on free edges
1273 Standard_Boolean isClosed = Standard_True;
1274 const Standard_Integer aNbE = aMEF.Extent();
1275 for (Standard_Integer j = 1; j <= aNbE && isClosed; ++j)
1277 const TopoDS_Edge& aE = TopoDS::Edge(aMEF.FindKey(j));
1278 if (BRep_Tool::Degenerated(aE))
1279 // Skip degenerated edges
1282 isClosed = (aMEF(j).Extent() > 1);
1285 const TopoDS_Face& aF = TopoDS::Face(aMEF(j).First());
1286 isClosed = BRep_Tool::IsClosed(aE, aF); // Check for seam edges
1289 // Check if the edge is not internal in the face
1290 TopExp_Explorer expE(aF, TopAbs_EDGE);
1291 for (; expE.More(); expE.Next())
1293 if (expE.Current().IsSame(aE))
1295 isClosed = (expE.Current().Orientation() == TopAbs_INTERNAL);
1306 // Not closed solid is found
1308 if (aFailedSolids.Contains(aSolid))
1309 // Warning has been generated for this solid, return positive result right away.
1310 return Standard_True;
1313 // Check the splits not to acquire new INTERNAL faces
1314 const TopTools_ListOfShape *pLSIm = myImages.Seek(aSolid);
1318 TopTools_ListOfShape::Iterator itLSIm(*pLSIm);
1319 for (; itLSIm.More(); itLSIm.Next())
1321 const TopoDS_Shape& aSIm = itLSIm.Value();
1322 for (TopoDS_Iterator itSh(aSIm); itSh.More(); itSh.Next())
1324 const TopoDS_Shape& aSh = itSh.Value();
1325 if (aSh.ShapeType() != TopAbs_SHELL)
1328 for (TopoDS_Iterator itF(aSh); itF.More(); itF.Next())
1330 const TopoDS_Shape& aF = itF.Value();
1331 if (aF.Orientation() == TopAbs_INTERNAL)
1333 if (!aMFInternal.Contains(aF))
1334 // New internal face is found
1335 return Standard_True;
1342 return Standard_False;
1345 //=======================================================================
1346 //function : TypeToExplore
1348 //=======================================================================
1349 TopAbs_ShapeEnum TypeToExplore(const Standard_Integer theDim)
1351 TopAbs_ShapeEnum aRet;
1372 //=======================================================================
1373 //function : CollectContainers
1375 //=======================================================================
1376 void CollectContainers(const TopoDS_Shape& theS,
1377 TopTools_ListOfShape& theLSC)
1379 TopAbs_ShapeEnum aType = theS.ShapeType();
1380 if (aType == TopAbs_WIRE ||
1381 aType == TopAbs_SHELL ||
1382 aType == TopAbs_COMPSOLID) {
1383 theLSC.Append(theS);
1387 if (aType != TopAbs_COMPOUND) {
1391 TopoDS_Iterator aIt(theS);
1392 for (; aIt.More(); aIt.Next()) {
1393 const TopoDS_Shape& aS = aIt.Value();
1394 CollectContainers(aS, theLSC);
1398 //=======================================================================
1399 //function : RemoveDuplicates
1400 //purpose : Filters the containers with identical contents
1401 //=======================================================================
1402 void RemoveDuplicates(TopTools_ListOfShape& theContainers)
1404 RemoveDuplicates(theContainers, TopAbs_WIRE);
1405 RemoveDuplicates(theContainers, TopAbs_SHELL);
1406 RemoveDuplicates(theContainers, TopAbs_COMPSOLID);
1409 //=======================================================================
1410 //function : RemoveDuplicates
1411 //purpose : Filters the containers of given type with identical contents
1412 //=======================================================================
1413 void RemoveDuplicates(TopTools_ListOfShape& theContainers,
1414 const TopAbs_ShapeEnum theType)
1416 // get containers of given type
1417 TopTools_ListOfShape aLC;
1418 TopTools_ListIteratorOfListOfShape aItLC(theContainers);
1419 for (; aItLC.More(); aItLC.Next()) {
1420 const TopoDS_Shape& aC = aItLC.Value();
1421 if (aC.ShapeType() == theType) {
1426 if (aLC.IsEmpty()) {
1430 // map containers to compare its contents
1431 NCollection_IndexedDataMap<TopoDS_Shape, TopTools_MapOfShape> aContents;
1433 aItLC.Initialize(aLC);
1434 for (; aItLC.More(); aItLC.Next()) {
1435 const TopoDS_Shape& aC = aItLC.Value();
1437 TopTools_MapOfShape& aMC = aContents(aContents.Add(aC, TopTools_MapOfShape()));
1439 TopoDS_Iterator aIt(aC);
1440 for (; aIt.More(); aIt.Next()) {
1441 aMC.Add(aIt.Value());
1445 // compare the contents of the containers and find duplicates
1446 TopTools_MapOfShape aDuplicates;
1448 Standard_Integer i, j, aNb = aContents.Extent();
1449 for (i = 1; i <= aNb; ++i) {
1450 const TopoDS_Shape& aCi = aContents.FindKey(i);
1451 if (aDuplicates.Contains(aCi)) {
1454 const TopTools_MapOfShape& aMi = aContents(i);
1455 Standard_Integer aNbi = aMi.Extent();
1457 for (j = i + 1; j <= aNb; ++j) {
1458 const TopoDS_Shape& aCj = aContents.FindKey(j);
1459 if (aDuplicates.Contains(aCj)) {
1462 const TopTools_MapOfShape& aMj = aContents(j);
1463 Standard_Integer aNbj = aMj.Extent();
1465 Standard_Integer aNbCommon = NbCommonItemsInMap(aMi, aMj);
1467 if (aNbj == aNbCommon) {
1468 aDuplicates.Add(aCj);
1472 if (aNbi == aNbCommon) {
1473 aDuplicates.Add(aCi);
1479 if (aDuplicates.IsEmpty()) {
1483 // remove duplicating containers
1484 aItLC.Initialize(theContainers);
1485 for (; aItLC.More(); ) {
1486 const TopoDS_Shape& aC = aItLC.Value();
1487 if (aDuplicates.Contains(aC)) {
1488 theContainers.Remove(aItLC);
1495 //=======================================================================
1496 //function : NbCommonItemsInMap
1497 //purpose : Counts the items contained in both maps
1498 //=======================================================================
1499 Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
1500 const TopTools_MapOfShape& theM2)
1502 const TopTools_MapOfShape* aMap1 = &theM1;
1503 const TopTools_MapOfShape* aMap2 = &theM2;
1505 if (theM2.Extent() < theM1.Extent()) {
1510 Standard_Integer iCommon = 0;
1511 for (TopTools_MapIteratorOfMapOfShape aIt(*aMap1); aIt.More(); aIt.Next()) {
1512 if (aMap2->Contains(aIt.Value())) {
1518 //=======================================================================
1519 //function : MapFacesToBuildSolids
1520 //purpose : Stores the faces of the given solid into outgoing maps:
1521 // <theMFS> - not internal faces with reference to solid;
1522 // <theMFI> - internal faces.
1523 //=======================================================================
1524 void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
1525 TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
1526 TopTools_IndexedMapOfShape& theMFI)
1528 TopExp_Explorer aExp(theSol, TopAbs_FACE);
1529 for (; aExp.More(); aExp.Next()) {
1530 const TopoDS_Shape& aF = aExp.Current();
1532 if (aF.Orientation() == TopAbs_INTERNAL) {
1537 TopTools_ListOfShape* pLSol = theMFS.ChangeSeek(aF);
1539 pLSol = &theMFS(theMFS.Add(aF, TopTools_ListOfShape()));
1540 pLSol->Append(theSol);
1543 const TopoDS_Shape& aF1 = theMFS.FindKey(theMFS.FindIndex(aF));
1544 if (aF1.Orientation() != aF.Orientation()) {
1545 pLSol->Append(theSol);