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 if (myProgressScope != NULL)
200 pPF->SetProgressIndicator(*myProgressScope);
202 pPF->SetFuzzyValue(myFuzzyValue);
203 pPF->SetNonDestructive(myNonDestructive);
204 pPF->SetGlue(myGlue);
205 pPF->SetUseOBB(myUseOBB);
210 PerformInternal(*pPF);
212 //=======================================================================
213 //function : PerformWithFiller
215 //=======================================================================
216 void BOPAlgo_Builder::PerformWithFiller(const BOPAlgo_PaveFiller& theFiller)
218 GetReport()->Clear();
220 myNonDestructive = theFiller.NonDestructive();
221 myFuzzyValue = theFiller.FuzzyValue();
222 myGlue = theFiller.Glue();
223 myUseOBB = theFiller.UseOBB();
224 PerformInternal(theFiller);
226 //=======================================================================
227 //function : PerformInternal
229 //=======================================================================
230 void BOPAlgo_Builder::PerformInternal(const BOPAlgo_PaveFiller& theFiller)
232 GetReport()->Clear();
236 PerformInternal1(theFiller);
239 catch (Standard_Failure const&) {
240 AddError (new BOPAlgo_AlertBuilderFailed);
243 //=======================================================================
244 //function : PerformInternal1
246 //=======================================================================
247 void BOPAlgo_Builder::PerformInternal1(const BOPAlgo_PaveFiller& theFiller)
249 myPaveFiller=(BOPAlgo_PaveFiller*)&theFiller;
250 myDS=myPaveFiller->PDS();
251 myContext=myPaveFiller->Context();
252 myFuzzyValue = myPaveFiller->FuzzyValue();
253 myNonDestructive = myPaveFiller->NonDestructive();
269 FillImagesVertices();
274 BuildResult(TopAbs_VERTEX);
284 BuildResult(TopAbs_EDGE);
290 FillImagesContainers(TopAbs_WIRE);
295 BuildResult(TopAbs_WIRE);
306 BuildResult(TopAbs_FACE);
311 FillImagesContainers(TopAbs_SHELL);
316 BuildResult(TopAbs_SHELL);
326 BuildResult(TopAbs_SOLID);
331 FillImagesContainers(TopAbs_COMPSOLID);
336 BuildResult(TopAbs_COMPSOLID);
342 FillImagesCompounds();
347 BuildResult(TopAbs_COMPOUND);
360 //=======================================================================
361 //function : PostTreat
363 //=======================================================================
364 void BOPAlgo_Builder::PostTreat()
366 Standard_Integer i, aNbS;
367 TopAbs_ShapeEnum aType;
368 TopTools_IndexedMapOfShape aMA;
369 if (myPaveFiller->NonDestructive()) {
371 aNbS=myDS->NbSourceShapes();
372 for (i=0; i<aNbS; ++i) {
373 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
374 aType=aSI.ShapeType();
375 if (aType==TopAbs_VERTEX ||
377 aType==TopAbs_FACE) {
378 const TopoDS_Shape& aS=aSI.Shape();
384 BOPTools_AlgoTools::CorrectTolerances(myShape, aMA, 0.05, myRunParallel);
385 BOPTools_AlgoTools::CorrectShapeTolerances(myShape, aMA, myRunParallel);
388 //=======================================================================
389 //function : BuildBOP
391 //=======================================================================
392 void BOPAlgo_Builder::BuildBOP(const TopTools_ListOfShape& theObjects,
393 const TopAbs_State theObjState,
394 const TopTools_ListOfShape& theTools,
395 const TopAbs_State theToolsState,
396 Handle(Message_Report) theReport)
401 // Report for the method
402 Handle(Message_Report) aReport = theReport.IsNull() ? myReport : theReport;
404 if (myArguments.IsEmpty() || myShape.IsNull())
406 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBuilderFailed());
410 // Check the input data
411 if ((theObjState != TopAbs_IN && theObjState != TopAbs_OUT) ||
412 (theToolsState != TopAbs_IN && theToolsState != TopAbs_OUT))
414 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertBOPNotSet());
418 // Check input shapes
419 Standard_Boolean hasObjects = !theObjects.IsEmpty();
420 Standard_Boolean hasTools = !theTools .IsEmpty();
421 if (!hasObjects && !hasTools)
423 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertTooFewArguments());
427 // Check that all input solids are from the arguments
428 for (Standard_Integer i = 0; i < 2; ++i)
430 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
431 TopTools_ListOfShape::Iterator itLS(aList);
432 for (; itLS.More(); itLS.Next())
434 const TopoDS_Shape& aS = itLS.Value();
435 // Check if the shape belongs to the arguments of operation
436 if (myDS->Index(aS) < 0)
438 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnknownShape(aS));
442 // Check if the shape is a solid or collection of them
443 if (aS.ShapeType() != TopAbs_SOLID)
445 TopTools_ListOfShape aLS;
446 TopTools_MapOfShape aMFence;
447 BOPTools_AlgoTools::TreatCompound(aS, aLS, &aMFence);
449 TopTools_ListOfShape::Iterator it(aLS);
450 for (; it.More(); it.Next())
452 const TopoDS_Shape& aSx = it.Value();
453 if (aSx.ShapeType() != TopAbs_SOLID &&
454 aSx.ShapeType() != TopAbs_COMPSOLID)
456 aReport->AddAlert(Message_Fail, new BOPAlgo_AlertUnsupportedType(aS));
464 // Classification of the faces relatively solids has been made
465 // on the stage of Solids splitting. All results are saved into
466 // myInParts map, which connects the solids with its IN faces from
467 // other arguments. All faces not contained in the list of IN faces
468 // will be considered as OUT.
470 // Prepare the maps of splits of solids faces with orientations
471 TopTools_IndexedMapOfOrientedShape aMObjFacesOri, aMToolFacesOri;
472 // Prepare the maps of splits of solids faces
473 TopTools_IndexedMapOfShape aMObjFaces, aMToolFaces;
474 // Copy the list of IN faces of the solids into map
475 TopTools_MapOfShape anINObjects, anINTools;
477 for (Standard_Integer i = 0; i < 2; ++i)
479 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
480 TopTools_IndexedMapOfOrientedShape& aMapOri = !i ? aMObjFacesOri : aMToolFacesOri;
481 TopTools_IndexedMapOfShape& aMap = !i ? aMObjFaces : aMToolFaces;
482 TopTools_ListOfShape::Iterator itLS(aList);
483 for (; itLS.More(); itLS.Next())
485 const TopoDS_Shape& aShape = itLS.Value();
486 TopExp_Explorer expS(aShape, TopAbs_SOLID);
487 for (; expS.More(); expS.Next())
489 const TopoDS_Shape& aS = expS.Current();
490 TopExp_Explorer expF(aS, TopAbs_FACE);
491 for (; expF.More(); expF.Next())
493 const TopoDS_Shape& aF = expF.Current();
494 if (aF.Orientation() != TopAbs_FORWARD &&
495 aF.Orientation() != TopAbs_REVERSED)
497 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
500 TopTools_ListOfShape::Iterator itLFIm(*pLFIm);
501 for (; itLFIm.More(); itLFIm.Next())
503 TopoDS_Face aFIm = TopoDS::Face(itLFIm.Value());
504 if (BOPTools_AlgoTools::IsSplitToReverse(aFIm, aF, myContext))
517 // Copy the list of IN faces into a map
518 const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
521 TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
522 TopTools_ListOfShape::Iterator itLFIn(*pLFIN);
523 for (; itLFIn.More(); itLFIn.Next())
524 anINMap.Add(itLFIn.Value());
530 // Now we need to select all faces which will participate in
531 // building of the resulting solids. The final set of faces
532 // depends on the given states for the groups.
533 Standard_Boolean isObjectsIN = (theObjState == TopAbs_IN),
534 isToolsIN = (theToolsState == TopAbs_IN);
537 Standard_Boolean bAvoidIN = (!isObjectsIN && !isToolsIN), // avoid all in faces
538 bAvoidINforBoth = (isObjectsIN != isToolsIN); // avoid faces IN for both groups
540 // Choose which SD faces are needed to be taken - equally or differently oriented faces
541 Standard_Boolean isSameOriNeeded = (theObjState == theToolsState);
543 TopTools_IndexedMapOfOrientedShape aMResFacesOri;
544 TopTools_MapOfShape aMResFacesFence;
546 TopTools_MapOfShape aMFence, aMFToAvoid;
547 // Oriented fence map
548 TopTools_MapOfOrientedShape aMFenceOri;
550 for (Standard_Integer i = 0; i < 2; ++i)
552 const TopTools_IndexedMapOfOrientedShape& aMap = !i ? aMObjFacesOri : aMToolFacesOri;
553 const TopTools_IndexedMapOfShape& anOppositeMap = !i ? aMToolFaces : aMObjFaces;
554 const TopTools_MapOfShape& anINMap = !i ? anINObjects : anINTools;
555 const TopTools_MapOfShape& anOppositeINMap = !i ? anINTools : anINObjects;
556 const Standard_Boolean bTakeIN = !i ? isObjectsIN : isToolsIN;
558 const Standard_Integer aNbF = aMap.Extent();
559 for (Standard_Integer j = 1; j <= aNbF; ++j)
561 TopoDS_Shape aFIm = aMap(j);
563 Standard_Boolean isIN = anINMap.Contains(aFIm);
564 Standard_Boolean isINOpposite = anOppositeINMap.Contains(aFIm);
566 // Filtering for FUSE - avoid any IN faces
567 if (bAvoidIN && (isIN || isINOpposite))
570 // Filtering for CUT - avoid faces IN for both groups
571 if (bAvoidINforBoth && isIN && isINOpposite)
574 // Treatment of SD faces
575 if (!aMFence.Add(aFIm))
577 if (!anOppositeMap.Contains(aFIm))
579 // The face belongs to only one group
580 if (bTakeIN != isSameOriNeeded)
581 aMFToAvoid.Add(aFIm);
585 // The face belongs to both groups.
586 // Using its orientation decide if it is needed in the result or not.
587 Standard_Boolean isSameOri = !aMFenceOri.Add(aFIm);
588 if (isSameOriNeeded == isSameOri)
590 // Take the shape without classification
591 if (aMResFacesFence.Add(aFIm))
592 aMResFacesOri.Add(aFIm);
596 aMFToAvoid.Add(aFIm);
601 if (!aMFenceOri.Add(aFIm))
604 if (bTakeIN == isINOpposite)
608 aMResFacesOri.Add(aFIm);
609 aMResFacesOri.Add(aFIm.Reversed());
611 else if (bTakeIN && !isSameOriNeeded)
612 aMResFacesOri.Add(aFIm.Reversed());
614 aMResFacesOri.Add(aFIm);
615 aMResFacesFence.Add(aFIm);
620 // Remove the faces which has to be avoided
621 TopTools_ListOfShape aResFaces;
622 const Standard_Integer aNbRF = aMResFacesOri.Extent();
623 for (Standard_Integer i = 1; i <= aNbRF; ++i)
625 const TopoDS_Shape& aRF = aMResFacesOri(i);
626 if (!aMFToAvoid.Contains(aRF))
627 aResFaces.Append(aRF);
632 // Try to build closed solids from the faces
633 BOPAlgo_BuilderSolid aBS;
634 aBS.SetShapes(aResFaces);
635 aBS.SetRunParallel(myRunParallel);
636 aBS.SetContext(myContext);
637 aBS.SetFuzzyValue(myFuzzyValue);
638 if (myProgressScope != NULL)
640 aBS.SetProgressIndicator(*myProgressScope);
645 TopTools_ListOfShape aResSolids;
648 if (!aBS.HasErrors())
650 // If any, add solids into resulting compound
651 TopTools_ListIteratorOfListOfShape itA(aBS.Areas());
652 for (; itA.More(); itA.Next())
654 const TopoDS_Shape& aSolid = itA.Value();
655 // The solid must contain at least one face
656 // from either of objects or tools
657 TopExp_Explorer expF(aSolid, TopAbs_FACE);
658 for (; expF.More(); expF.Next())
660 const TopoDS_Shape& aF = expF.Current();
661 if (aMObjFacesOri.Contains(aF) || aMToolFacesOri.Contains(aF))
666 aResSolids.Append(aSolid);
667 TopExp::MapShapes(aSolid, aMFence);
672 // Collect unused faces
673 TopoDS_Compound anUnUsedFaces;
674 aBB.MakeCompound(anUnUsedFaces);
676 TopTools_ListOfShape::Iterator itLF(aResFaces);
677 for (; itLF.More(); itLF.Next())
679 if (aMFence.Add(itLF.Value()))
680 aBB.Add(anUnUsedFaces, itLF.Value());
683 // Build blocks from the unused faces
684 TopTools_ListOfShape aLCB;
685 BOPTools_AlgoTools::MakeConnexityBlocks(anUnUsedFaces, TopAbs_EDGE, TopAbs_FACE, aLCB);
687 // Build solid from each block
688 TopTools_ListIteratorOfListOfShape itCB(aLCB);
689 for (; itCB.More(); itCB.Next())
691 const TopoDS_Shape& aCB = itCB.Value();
693 aBB.MakeShell(aShell);
694 // Add faces of the block to the shell
695 TopExp_Explorer anExpF(aCB, TopAbs_FACE);
696 for (; anExpF.More(); anExpF.Next())
697 aBB.Add(aShell, TopoDS::Face(anExpF.Current()));
699 BOPTools_AlgoTools::OrientFacesOnShell(aShell);
700 // Make solid out of the shell
702 aBB.MakeSolid(aSolid);
703 aBB.Add(aSolid, aShell);
704 // Add new solid to result
705 aResSolids.Append(aSolid);
710 // Fill solids with internal parts coming with the solids
711 TopTools_ListOfShape anInParts;
712 for (Standard_Integer i = 0; i < 2; ++i)
714 const TopTools_ListOfShape& aList = !i ? theObjects : theTools;
715 TopTools_ListOfShape::Iterator itLS(aList);
716 for (; itLS.More(); itLS.Next())
718 TopExp_Explorer expS(itLS.Value(), TopAbs_SOLID);
719 for (; expS.More(); expS.Next())
721 const TopoDS_Shape& aS = expS.Current(); // Solid
722 for (TopoDS_Iterator it(aS); it.More(); it.Next())
724 const TopoDS_Shape& aSInt = it.Value();
725 if (aSInt.Orientation() == TopAbs_INTERNAL)
726 anInParts.Append(aSInt); // vertex or edge
730 TopoDS_Iterator itInt(aSInt);
731 if (itInt.More() && itInt.Value().Orientation() == TopAbs_INTERNAL)
732 anInParts.Append(aSInt);
739 BOPAlgo_Tools::FillInternals(aResSolids, anInParts, myImages, myContext);
742 // Combine solids into compound
743 TopoDS_Shape aResult;
744 aBB.MakeCompound(TopoDS::Compound(aResult));
746 TopTools_ListOfShape::Iterator itLS(aResSolids);
747 for (; itLS.More(); itLS.Next())
748 aBB.Add(aResult, itLS.Value());