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.
19 #include <BOPAlgo_Builder.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPAlgo_BuilderSolid.hxx>
22 #include <BOPAlgo_PaveFiller.hxx>
23 #include <BOPAlgo_Tools.hxx>
24 #include <BOPDS_DS.hxx>
25 #include <BOPDS_ShapeInfo.hxx>
26 #include <BOPTools_AlgoTools.hxx>
27 #include <BRep_Builder.hxx>
28 #include <IntTools_Context.hxx>
29 #include <Standard_ErrorHandler.hxx>
30 #include <Standard_Failure.hxx>
32 #include <TopExp_Explorer.hxx>
34 #include <TopoDS_Compound.hxx>
35 #include <TopoDS_Solid.hxx>
36 #include <TopTools_IndexedMapOfShape.hxx>
37 #include <TopTools_MapOfOrientedShape.hxx>
40 //=======================================================================
43 //=======================================================================
44 BOPAlgo_Builder::BOPAlgo_Builder()
46 BOPAlgo_BuilderShape(),
47 myArguments(myAllocator),
48 myMapFence(100, myAllocator),
52 myImages(100, myAllocator),
53 myShapesSD(100, myAllocator),
54 myOrigins(100, myAllocator),
55 myInParts(100, myAllocator),
56 myNonDestructive(Standard_False),
57 myGlue(BOPAlgo_GlueOff),
58 myCheckInverted(Standard_True)
61 //=======================================================================
64 //=======================================================================
65 BOPAlgo_Builder::BOPAlgo_Builder
66 (const Handle(NCollection_BaseAllocator)& theAllocator)
68 BOPAlgo_BuilderShape(theAllocator),
69 myArguments(myAllocator),
70 myMapFence(100, myAllocator),
74 myImages(100, myAllocator),
75 myShapesSD(100, myAllocator),
76 myOrigins(100, myAllocator),
77 myInParts(100, myAllocator),
78 myNonDestructive(Standard_False),
79 myGlue(BOPAlgo_GlueOff),
80 myCheckInverted(Standard_True)
83 //=======================================================================
86 //=======================================================================
87 BOPAlgo_Builder::~BOPAlgo_Builder()
89 if (myEntryPoint==1) {
96 //=======================================================================
99 //=======================================================================
100 void BOPAlgo_Builder::Clear()
102 BOPAlgo_BuilderShape::Clear();
110 //=======================================================================
111 //function : AddArgument
113 //=======================================================================
114 void BOPAlgo_Builder::AddArgument(const TopoDS_Shape& theShape)
116 if (myMapFence.Add(theShape)) {
117 myArguments.Append(theShape);
120 //=======================================================================
121 //function : SetArguments
123 //=======================================================================
124 void BOPAlgo_Builder::SetArguments(const TopTools_ListOfShape& theShapes)
126 TopTools_ListIteratorOfListOfShape aIt;
130 aIt.Initialize(theShapes);
131 for (; aIt.More(); aIt.Next()) {
132 const TopoDS_Shape& aS = aIt.Value();
136 //=======================================================================
137 // function: CheckData
139 //=======================================================================
140 void BOPAlgo_Builder::CheckData()
142 Standard_Integer aNb = myArguments.Extent();
144 AddError (new BOPAlgo_AlertTooFewArguments); // too few arguments to process
150 //=======================================================================
151 // function: CheckFiller
153 //=======================================================================
154 void BOPAlgo_Builder::CheckFiller()
157 AddError (new BOPAlgo_AlertNoFiller);
160 GetReport()->Merge (myPaveFiller->GetReport());
163 //=======================================================================
166 //=======================================================================
167 void BOPAlgo_Builder::Prepare()
172 // 1. myShape is empty compound
173 aBB.MakeCompound(aC);
176 //=======================================================================
179 //=======================================================================
180 void BOPAlgo_Builder::Perform()
182 GetReport()->Clear();
184 if (myEntryPoint==1) {
191 Handle(NCollection_BaseAllocator) aAllocator=
192 NCollection_BaseAllocator::CommonBaseAllocator();
194 BOPAlgo_PaveFiller* pPF=new BOPAlgo_PaveFiller(aAllocator);
196 pPF->SetArguments(myArguments);
197 pPF->SetRunParallel(myRunParallel);
198 pPF->SetProgressIndicator(myProgressIndicator);
199 pPF->SetFuzzyValue(myFuzzyValue);
200 pPF->SetNonDestructive(myNonDestructive);
201 pPF->SetGlue(myGlue);
202 pPF->SetUseOBB(myUseOBB);
207 PerformInternal(*pPF);
209 //=======================================================================
210 //function : PerformWithFiller
212 //=======================================================================
213 void BOPAlgo_Builder::PerformWithFiller(const BOPAlgo_PaveFiller& theFiller)
215 GetReport()->Clear();
217 myNonDestructive = theFiller.NonDestructive();
218 myFuzzyValue = theFiller.FuzzyValue();
219 myGlue = theFiller.Glue();
220 myUseOBB = theFiller.UseOBB();
221 PerformInternal(theFiller);
223 //=======================================================================
224 //function : PerformInternal
226 //=======================================================================
227 void BOPAlgo_Builder::PerformInternal(const BOPAlgo_PaveFiller& theFiller)
229 GetReport()->Clear();
233 PerformInternal1(theFiller);
236 catch (Standard_Failure const&) {
237 AddError (new BOPAlgo_AlertBuilderFailed);
240 //=======================================================================
241 //function : PerformInternal1
243 //=======================================================================
244 void BOPAlgo_Builder::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
246 myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
247 myDS=myPaveFiller->PDS();
248 myContext=myPaveFiller->Context();
249 myFuzzyValue = myPaveFiller->FuzzyValue();
250 myNonDestructive = myPaveFiller->NonDestructive();
266 FillImagesVertices();
271 BuildResult(TopAbs_VERTEX);
281 BuildResult(TopAbs_EDGE);
287 FillImagesContainers(TopAbs_WIRE);
292 BuildResult(TopAbs_WIRE);
303 BuildResult(TopAbs_FACE);
308 FillImagesContainers(TopAbs_SHELL);
313 BuildResult(TopAbs_SHELL);
323 BuildResult(TopAbs_SOLID);
328 FillImagesContainers(TopAbs_COMPSOLID);
333 BuildResult(TopAbs_COMPSOLID);
339 FillImagesCompounds();
344 BuildResult(TopAbs_COMPOUND);
357 //=======================================================================
358 //function : PostTreat
360 //=======================================================================
361 void BOPAlgo_Builder::PostTreat()
363 Standard_Integer i, aNbS;
364 TopAbs_ShapeEnum aType;
365 TopTools_IndexedMapOfShape aMA;
366 if (myPaveFiller->NonDestructive()) {
368 aNbS=myDS->NbSourceShapes();
369 for (i=0; i<aNbS; ++i) {
370 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
371 aType=aSI.ShapeType();
372 if (aType==TopAbs_VERTEX ||
374 aType==TopAbs_FACE) {
375 const TopoDS_Shape& aS=aSI.Shape();
381 BOPTools_AlgoTools::CorrectTolerances(myShape, aMA, 0.05, myRunParallel);
382 BOPTools_AlgoTools::CorrectShapeTolerances(myShape, aMA, myRunParallel);
385 //=======================================================================
386 //function : BuildBOP
388 //=======================================================================
389 void BOPAlgo_Builder::BuildBOP(const TopTools_ListOfShape& theObjects,
390 const TopAbs_State theObjState,
391 const TopTools_ListOfShape& theTools,
392 const TopAbs_State theToolsState,
393 Handle(Message_Report) theReport)
398 // Report for the method
399 Handle(Message_Report) aReport = theReport.IsNull() ? myReport : theReport;
401 if (myArguments.IsEmpty() || myShape.IsNull())
403 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBuilderFailed());
407 // Check the input data
408 if ((theObjState != TopAbs_IN && theObjState != TopAbs_OUT) ||
409 (theToolsState != TopAbs_IN && theToolsState != TopAbs_OUT))
411 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBOPNotSet());
415 // Check input shapes
416 Standard_Boolean hasObjects = !theObjects.IsEmpty();
417 Standard_Boolean hasTools = !theTools .IsEmpty();
418 if (!hasObjects && !hasTools)
420 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertTooFewArguments());
424 // Check that all input solids are from the arguments
425 for (Standard_Integer i = 0; i < 2; ++i)
427 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
428 TopTools_ListOfShape::Iterator itLS(aList);
429 for (; itLS.More(); itLS.Next())
431 const TopoDS_Shape& aS = itLS.Value();
432 // Check if the shape belongs to the arguments of operation
433 if (myDS->Index(aS) < 0)
435 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnknownShape(aS));
439 // Check if the shape is a solid or collection of them
440 if (aS.ShapeType() != TopAbs_SOLID)
442 TopTools_ListOfShape aLS;
443 TopTools_MapOfShape aMFence;
444 BOPAlgo_Tools::TreatCompound(aS, aMFence, aLS);
446 TopTools_ListOfShape::Iterator it(aLS);
447 for (; it.More(); it.Next())
449 const TopoDS_Shape& aSx = it.Value();
450 if (aSx.ShapeType() != TopAbs_SOLID &&
451 aSx.ShapeType() != TopAbs_COMPSOLID)
453 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnsupportedType(aS));
461 // Classification of the faces relatively solids has been made
462 // on the stage of Solids splitting. All results are saved into
463 // myInParts map, which connects the solids with its IN faces from
464 // other arguments. All faces not contained in the list of IN faces
465 // will be considered as OUT.
467 // Prepare the maps of splits of solids faces with orientations
468 TopTools_IndexedMapOfOrientedShape aMObjFacesOri, aMToolFacesOri;
469 // Prepare the maps of splits of solids faces
470 TopTools_IndexedMapOfShape aMObjFaces, aMToolFaces;
471 // Copy the list of IN faces of the solids into map
472 TopTools_MapOfShape anINObjects, anINTools;
474 for (Standard_Integer i = 0; i < 2; ++i)
476 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
477 TopTools_IndexedMapOfOrientedShape& aMapOri = !i ? aMObjFacesOri : aMToolFacesOri;
478 TopTools_IndexedMapOfShape& aMap = !i ? aMObjFaces : aMToolFaces;
479 TopTools_ListOfShape::Iterator itLS(aList);
480 for (; itLS.More(); itLS.Next())
482 const TopoDS_Shape& aShape = itLS.Value();
483 TopExp_Explorer expS(aShape, TopAbs_SOLID);
484 for (; expS.More(); expS.Next())
486 const TopoDS_Shape& aS = expS.Current();
487 TopExp_Explorer expF(aS, TopAbs_FACE);
488 for (; expF.More(); expF.Next())
490 const TopoDS_Shape& aF = expF.Current();
491 if (aF.Orientation() != TopAbs_FORWARD &&
492 aF.Orientation() != TopAbs_REVERSED)
494 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
497 TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
498 for (; itLFIm.More(); itLFIm.Next())
500 TopoDS_Face aFIm = TopoDS::Face(itLFIm.Value());
501 if (BOPTools_AlgoTools::IsSplitToReverse(aFIm, aF, myContext))
514 // Copy the list of IN faces into a map
515 const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
518 TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
519 TopTools_ListOfShape::Iterator itLFIn(*pLFIN);
520 for (; itLFIn.More(); itLFIn.Next())
521 anINMap.Add(itLFIn.Value());
527 // Now we need to select all faces which will participate in
528 // building of the resulting solids. The final set of faces
529 // depends on the given states for the groups.
530 Standard_Boolean isObjectsIN = (theObjState == TopAbs_IN),
531 isToolsIN = (theToolsState == TopAbs_IN);
534 Standard_Boolean bAvoidIN = (!isObjectsIN && !isToolsIN), // avoid all in faces
535 bAvoidINforBoth = (isObjectsIN != isToolsIN); // avoid faces IN for both groups
537 // Choose which SD faces are needed to be taken - equally or differently oriented faces
538 Standard_Boolean isSameOriNeeded = (theObjState == theToolsState);
540 TopTools_IndexedMapOfOrientedShape aMResFacesOri;
541 TopTools_MapOfShape aMResFacesFence;
543 TopTools_MapOfShape aMFence, aMFToAvoid;
544 // Oriented fence map
545 TopTools_MapOfOrientedShape aMFenceOri;
547 for (Standard_Integer i = 0; i < 2; ++i)
549 const TopTools_IndexedMapOfOrientedShape& aMap = !i ? aMObjFacesOri : aMToolFacesOri;
550 const TopTools_IndexedMapOfShape& anOppositeMap = !i ? aMToolFaces : aMObjFaces;
551 const TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
552 const TopTools_MapOfShape& anOppositeINMap = !i ? anINTools : anINObjects;
553 const Standard_Boolean bTakeIN = !i ? isObjectsIN : isToolsIN;
555 const Standard_Integer aNbF = aMap.Extent();
556 for (Standard_Integer j = 1; j <= aNbF; ++j)
558 TopoDS_Shape aFIm = aMap(j);
560 Standard_Boolean isIN = anINMap.Contains(aFIm);
561 Standard_Boolean isINOpposite = anOppositeINMap.Contains(aFIm);
563 // Filtering for FUSE - avoid any IN faces
564 if (bAvoidIN && (isIN || isINOpposite))
567 // Filtering for CUT - avoid faces IN for both groups
568 if (bAvoidINforBoth && isIN && isINOpposite)
571 // Treatment of SD faces
572 if (!aMFence.Add(aFIm))
574 if (!anOppositeMap.Contains(aFIm))
576 // The face belongs to only one group
577 if (bTakeIN != isSameOriNeeded)
578 aMFToAvoid.Add(aFIm);
582 // The face belongs to both groups.
583 // Using its orientation decide if it is needed in the result or not.
584 Standard_Boolean isSameOri = !aMFenceOri.Add(aFIm);
585 if (isSameOriNeeded == isSameOri)
587 // Take the shape without classification
588 if (aMResFacesFence.Add(aFIm))
589 aMResFacesOri.Add(aFIm);
593 aMFToAvoid.Add(aFIm);
598 if (!aMFenceOri.Add(aFIm))
601 if (bTakeIN == isINOpposite)
605 aMResFacesOri.Add(aFIm);
606 aMResFacesOri.Add(aFIm.Reversed());
608 else if (bTakeIN && !isSameOriNeeded)
609 aMResFacesOri.Add(aFIm.Reversed());
611 aMResFacesOri.Add(aFIm);
612 aMResFacesFence.Add(aFIm);
617 // Remove the faces which has to be avoided
618 TopTools_ListOfShape aResFaces;
619 const Standard_Integer aNbRF = aMResFacesOri.Extent();
620 for (Standard_Integer i = 1; i <= aNbRF; ++i)
622 const TopoDS_Shape& aRF = aMResFacesOri(i);
623 if (!aMFToAvoid.Contains(aRF))
624 aResFaces.Append(aRF);
629 // Try to build closed solids from the faces
630 BOPAlgo_BuilderSolid aBS;
631 aBS.SetShapes(aResFaces);
632 aBS.SetRunParallel(myRunParallel);
633 aBS.SetContext(myContext);
634 aBS.SetFuzzyValue(myFuzzyValue);
635 aBS.SetProgressIndicator(myProgressIndicator);
639 TopTools_ListOfShape aResSolids;
642 if (!aBS.HasErrors())
644 // If any, add solids into resulting compound
645 TopTools_ListIteratorOfListOfShape itA(aBS.Areas());
646 for (; itA.More(); itA.Next())
648 const TopoDS_Shape& aSolid = itA.Value();
649 // The solid must contain at least one face
650 // from either of objects or tools
651 TopExp_Explorer expF(aSolid, TopAbs_FACE);
652 for (; expF.More(); expF.Next())
654 const TopoDS_Shape& aF = expF.Current();
655 if (aMObjFacesOri.Contains(aF) || aMToolFacesOri.Contains(aF))
660 aResSolids.Append(aSolid);
661 TopExp::MapShapes(aSolid, aMFence);
666 // Collect unused faces
667 TopoDS_Compound anUnUsedFaces;
668 aBB.MakeCompound(anUnUsedFaces);
670 TopTools_ListOfShape::Iterator itLF(aResFaces);
671 for (; itLF.More(); itLF.Next())
673 if (aMFence.Add(itLF.Value()))
674 aBB.Add(anUnUsedFaces, itLF.Value());
677 // Build blocks from the unused faces
678 TopTools_ListOfShape aLCB;
679 BOPTools_AlgoTools::MakeConnexityBlocks(anUnUsedFaces, TopAbs_EDGE, TopAbs_FACE, aLCB);
681 // Build solid from each block
682 TopTools_ListIteratorOfListOfShape itCB(aLCB);
683 for (; itCB.More(); itCB.Next())
685 const TopoDS_Shape& aCB = itCB.Value();
687 aBB.MakeShell(aShell);
688 // Add faces of the block to the shell
689 TopExp_Explorer anExpF(aCB, TopAbs_FACE);
690 for (; anExpF.More(); anExpF.Next())
691 aBB.Add(aShell, TopoDS::Face(anExpF.Current()));
693 BOPTools_AlgoTools::OrientFacesOnShell(aShell);
694 // Make solid out of the shell
696 aBB.MakeSolid(aSolid);
697 aBB.Add(aSolid, aShell);
698 // Add new solid to result
699 aResSolids.Append(aSolid);
704 // Fill solids with internal parts coming with the solids
705 TopTools_ListOfShape anInParts;
706 for (Standard_Integer i = 0; i < 2; ++i)
708 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
709 TopTools_ListOfShape::Iterator itLS(aList);
710 for (; itLS.More(); itLS.Next())
712 TopExp_Explorer expS(itLS.Value(), TopAbs_SOLID);
713 for (; expS.More(); expS.Next())
715 const TopoDS_Shape& aS = expS.Current(); // Solid
716 for (TopoDS_Iterator it(aS); it.More(); it.Next())
718 const TopoDS_Shape& aSInt = it.Value();
719 if (aSInt.Orientation() == TopAbs_INTERNAL)
720 anInParts.Append(aSInt); // vertex or edge
724 TopoDS_Iterator itInt(aSInt);
725 if (itInt.More() && itInt.Value().Orientation() == TopAbs_INTERNAL)
726 anInParts.Append(aSInt);
733 BOPAlgo_Tools::FillInternals(aResSolids, anInParts, myImages, myContext);
736 // Combine solids into compound
737 TopoDS_Shape aResult;
738 aBB.MakeCompound(TopoDS::Compound(aResult));
740 TopTools_ListOfShape::Iterator itLS(aResSolids);
741 for (; itLS.More(); itLS.Next())
742 aBB.Add(aResult, itLS.Value());