1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
3 // Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
4 // Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
5 // EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 // This file is part of Open CASCADE Technology software library.
9 // This library is free software; you can redistribute it and/or modify it under
10 // the terms of the GNU Lesser General Public License version 2.1 as published
11 // by the Free Software Foundation, with special exception defined in the file
12 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 // distribution for complete text of the license and disclaimer of any warranty.
15 // Alternatively, this file may be used under the terms of Open CASCADE
16 // commercial license or contractual agreement.
18 #include <BOPAlgo_Builder.hxx>
21 #include <TopAbs_State.hxx>
24 #include <TopoDS_AlertWithShape.hxx>
25 #include <TopoDS_Shape.hxx>
28 #include <TopExp_Explorer.hxx>
30 #include <BRep_Builder.hxx>
32 #include <BOPAlgo_BuilderSolid.hxx>
34 #include <IntTools_Context.hxx>
36 #include <BOPDS_DS.hxx>
37 #include <BOPDS_ShapeInfo.hxx>
39 #include <BOPTools_AlgoTools.hxx>
40 #include <BOPTools_MapOfSet.hxx>
41 #include <BOPTools_Set.hxx>
42 #include <BOPTools_Parallel.hxx>
44 #include <BOPAlgo_Tools.hxx>
45 #include <NCollection_IncAllocator.hxx>
46 #include <NCollection_Vector.hxx>
48 #include <TopTools_IndexedMapOfShape.hxx>
49 #include <TopTools_MapOfShape.hxx>
50 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
51 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
52 #include <TopTools_ListOfShape.hxx>
57 void OwnInternalShapes(const TopoDS_Shape& ,
58 TopTools_IndexedMapOfShape& );
61 //=======================================================================
62 //function : FillImagesSolids
64 //=======================================================================
65 void BOPAlgo_Builder::FillImagesSolids(const Message_ProgressRange& theRange)
67 Standard_Integer i = 0, aNbS = myDS->NbSourceShapes();
68 for (i = 0; i < aNbS; ++i) {
69 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
70 if (aSI.ShapeType() == TopAbs_SOLID)
79 Message_ProgressScope aPS(theRange, "Building splits of solids", 10);
81 TopTools_DataMapOfShapeShape aDraftSolids;
82 // Find all IN faces for all IN faces
83 FillIn3DParts(aDraftSolids, aPS.Next(4));
88 // Build split of the solids
89 BuildSplitSolids(aDraftSolids, aPS.Next(5));
94 // Fill solids with internal parts
95 FillInternalShapes(aPS.Next());
97 //=======================================================================
98 //function : FillIn3DParts
100 //=======================================================================
101 void BOPAlgo_Builder::FillIn3DParts(TopTools_DataMapOfShapeShape& theDraftSolids,
102 const Message_ProgressRange& theRange)
104 Message_ProgressScope aPS(theRange, NULL, 2);
106 Handle(NCollection_BaseAllocator) anAlloc = new NCollection_IncAllocator;
108 // Find all faces that are IN solids
110 // Store boxes of the shapes into a map
111 TopTools_DataMapOfShapeBox aShapeBoxMap(1, anAlloc);
114 TopTools_MapOfShape aMFence(1, anAlloc);
117 TopTools_ListOfShape aLFaces(anAlloc);
119 Standard_Integer i, aNbS = myDS->NbSourceShapes();
120 for (i = 0; i < aNbS; ++i)
122 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
123 if (aSI.ShapeType() != TopAbs_FACE)
131 const TopoDS_Shape& aS = aSI.Shape();
132 const TopTools_ListOfShape* pLSIm = myImages.Seek(aS);
136 TopTools_ListIteratorOfListOfShape aItLSIm(*pLSIm);
137 for (; aItLSIm.More(); aItLSIm.Next())
139 const TopoDS_Shape& aSIm = aItLSIm.Value();
140 if (aMFence.Add(aSIm))
141 aLFaces.Append(aSIm);
147 aShapeBoxMap.Bind(aS, aSI.Box());
154 TopTools_ListOfShape aLSolids(anAlloc);
155 // Keep INTERNAL faces of the solids
156 TopTools_DataMapOfShapeListOfShape aSolidsIF(1, anAlloc);
158 TopTools_IndexedDataMapOfShapeShape aDraftSolid(1, anAlloc);
160 for (i = 0; i < aNbS; ++i)
162 BOPDS_ShapeInfo& aSI = myDS->ChangeShapeInfo(i);
163 if (aSI.ShapeType() != TopAbs_SOLID)
171 const TopoDS_Shape& aS = aSI.Shape();
172 const TopoDS_Solid& aSolid = (*(TopoDS_Solid*)(&aS));
174 // Bounding box for the solid aS
175 Bnd_Box& aBoxS = aSI.ChangeBox();
177 myDS->BuildBndBoxSolid(i, aBoxS, myCheckInverted);
180 TopTools_ListOfShape aLIF;
183 BuildDraftSolid(aSolid, aSD, aLIF);
185 aLSolids.Append(aSD);
186 aSolidsIF.Bind(aSD, aLIF);
187 aShapeBoxMap.Bind(aSD, aBoxS);
188 aDraftSolid.Add(aS, aSD);
191 // Perform classification of the faces
192 TopTools_IndexedDataMapOfShapeListOfShape anInParts;
194 BOPAlgo_Tools::ClassifyFaces(aLFaces, aLSolids, myRunParallel,
195 myContext, anInParts, aShapeBoxMap,
196 aSolidsIF, aPS.Next());
198 // Analyze the results of classification
199 Standard_Integer aNbSol = aDraftSolid.Extent();
200 for (i = 1; i <= aNbSol; ++i)
206 const TopoDS_Solid& aSolid = TopoDS::Solid(aDraftSolid.FindKey(i));
207 const TopoDS_Solid& aSDraft = TopoDS::Solid(aDraftSolid(i));
208 const TopTools_ListOfShape& aLInFaces = anInParts.FindFromKey(aSDraft);
209 const TopTools_ListOfShape& aLInternal = aSolidsIF.Find(aSDraft);
211 Standard_Integer aNbIN = aLInFaces.Extent();
215 Standard_Boolean bHasImage = Standard_False;
216 // Check if the shells of the solid have image
217 for (TopoDS_Iterator it(aSolid); it.More() && !bHasImage; it.Next())
218 bHasImage = myImages.IsBound(it.Value());
221 // no need to split the solid
225 theDraftSolids.Bind(aSolid, aSDraft);
227 Standard_Integer aNbInt = aLInternal.Extent();
231 TopTools_ListOfShape *pLIN = myInParts.Bound(aSolid, TopTools_ListOfShape());
233 TopTools_ListIteratorOfListOfShape aItLS(aLInFaces);
234 for (; aItLS.More(); aItLS.Next())
235 pLIN->Append(aItLS.Value());
237 aItLS.Initialize(aLInternal);
238 for (; aItLS.More(); aItLS.Next())
239 pLIN->Append(aItLS.Value());
243 //=======================================================================
244 //function : BuildDraftSolid
246 //=======================================================================
247 void BOPAlgo_Builder::BuildDraftSolid(const TopoDS_Shape& theSolid,
248 TopoDS_Shape& theDraftSolid,
249 TopTools_ListOfShape& theLIF)
251 Standard_Boolean bToReverse;
252 Standard_Integer iFlag;
253 TopAbs_Orientation aOrF, aOrSh, aOrSd;
254 TopoDS_Iterator aIt1, aIt2;
258 TopTools_ListIteratorOfListOfShape aItS;
260 aOrSd=theSolid.Orientation();
261 theDraftSolid.Orientation(aOrSd);
263 aIt1.Initialize(theSolid);
264 for (; aIt1.More(); aIt1.Next()) {
265 const TopoDS_Shape& aSh=aIt1.Value();
266 if(aSh.ShapeType()!=TopAbs_SHELL) {
267 continue; // mb internal edges,vertices
270 aOrSh=aSh.Orientation();
272 aShD.Orientation(aOrSh);
275 aIt2.Initialize(aSh);
276 for (; aIt2.More(); aIt2.Next()) {
277 const TopoDS_Shape& aF=aIt2.Value();
278 aOrF=aF.Orientation();
280 if (myImages.IsBound(aF)) {
281 const TopTools_ListOfShape& aLSp=myImages.Find(aF);
282 aItS.Initialize(aLSp);
283 for (; aItS.More(); aItS.Next()) {
286 if (myShapesSD.IsBound(aFx)) {
288 if (aOrF==TopAbs_INTERNAL) {
289 aFx.Orientation(aOrF);
293 bToReverse=BOPTools_AlgoTools::IsSplitToReverseWithWarn
294 (aFx, aF, myContext, myReport);
302 }//if (myShapesSD.IsBound(aFx)) {
304 aFx.Orientation(aOrF);
305 if (aOrF==TopAbs_INTERNAL) {
314 } // if (myImages.IsBound(aF)) {
317 if (aOrF==TopAbs_INTERNAL) {
325 } //for (; aIt2.More(); aIt2.Next()) {
328 aShD.Closed (BRep_Tool::IsClosed (aShD));
329 aBB.Add(theDraftSolid, aShD);
331 } //for (; aIt1.More(); aIt1.Next()) {
334 //=======================================================================
336 //=======================================================================
337 //class : BOPAlgo_SplitSolid
338 //purpose : Auxiliary class to extend the BOPAlgo_BuilderSolid with the solid to split
339 //=======================================================================
340 class BOPAlgo_SplitSolid : public BOPAlgo_BuilderSolid
344 void SetSolid(const TopoDS_Solid& theSolid) { mySolid = theSolid; }
346 //! Returns the solid
347 const TopoDS_Solid& Solid() const { return mySolid; }
349 //! Sets progress range
350 void SetProgressRange(const Message_ProgressRange& theRange)
355 // New perform method, using own progress range
358 Message_ProgressScope aPS(myRange, NULL, 1);
363 BOPAlgo_BuilderSolid::Perform(aPS.Next());
367 //! Disable the range enabled method
368 virtual void Perform(const Message_ProgressRange&/* theRange*/) {}
371 TopoDS_Solid mySolid; //!< Solid to split
372 Message_ProgressRange myRange;
375 // Vector of Solid Builders
376 typedef NCollection_Vector<BOPAlgo_SplitSolid> BOPAlgo_VectorOfBuilderSolid;
378 //=======================================================================
379 //function : BuildSplitSolids
381 //=======================================================================
382 void BOPAlgo_Builder::BuildSplitSolids(TopTools_DataMapOfShapeShape& theDraftSolids,
383 const Message_ProgressRange& theRange)
385 Standard_Boolean bFlagSD;
386 Standard_Integer i, aNbS;
387 TopExp_Explorer aExp;
388 TopTools_ListIteratorOfListOfShape aIt;
390 Handle(NCollection_BaseAllocator) aAlr0;
391 aAlr0=NCollection_BaseAllocator::CommonBaseAllocator();
393 TopTools_ListOfShape aSFS(aAlr0), aLSEmpty(aAlr0);
394 TopTools_MapOfShape aMFence(100, aAlr0);
395 BOPTools_MapOfSet aMST(100, aAlr0);
396 BOPAlgo_VectorOfBuilderSolid aVBS;
398 Message_ProgressScope aPSOuter (theRange, NULL, 10);
399 // 0. Find same domain solids for non-interfered solids
400 aNbS=myDS->NbSourceShapes();
401 for (i=0; i<aNbS; ++i) {
402 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
404 if (aSI.ShapeType()!=TopAbs_SOLID) {
407 if (UserBreak(aPSOuter))
412 const TopoDS_Shape& aS=aSI.Shape();
413 if (!aMFence.Add(aS)) {
416 if(theDraftSolids.IsBound(aS)) {
422 aST.Add(aS, TopAbs_FACE);
425 } //for (i=1; i<=aNbS; ++i)
427 // Build temporary map of solids images to avoid rebuilding
428 // of the solids without internal faces
429 TopTools_IndexedDataMapOfShapeListOfShape aSolidsIm;
430 // 1. Build solids for interfered source solids
431 for (i = 0; i < aNbS; ++i) {
432 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
433 if (aSI.ShapeType() != TopAbs_SOLID)
436 const TopoDS_Shape& aS = aSI.Shape();
437 const TopoDS_Solid& aSolid=(*(TopoDS_Solid*)(&aS));
438 if (!theDraftSolids.IsBound(aS))
441 const TopoDS_Shape& aSD = theDraftSolids.Find(aS);
442 const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
443 if (!pLFIN || pLFIN->IsEmpty())
445 aSolidsIm(aSolidsIm.Add(aS, TopTools_ListOfShape())).Append(aSD);
451 // 1.1 Fill Shell Faces Set
452 aExp.Init(aSD, TopAbs_FACE);
453 for (; aExp.More(); aExp.Next()) {
454 const TopoDS_Shape& aF = aExp.Current();
458 // 1.2 Fill internal faces
459 aIt.Initialize(*pLFIN);
460 for (; aIt.More(); aIt.Next()) {
461 TopoDS_Shape aF = aIt.Value();
463 aF.Orientation(TopAbs_FORWARD);
465 aF.Orientation(TopAbs_REVERSED);
469 // 1.3 Build new solids
470 BOPAlgo_SplitSolid& aBS=aVBS.Appended();
471 aBS.SetSolid(aSolid);
473 aBS.SetRunParallel(myRunParallel);
474 }//for (i=0; i<aNbS; ++i) {
476 Standard_Integer k, aNbBS;
479 // Set progress range for each task to be run in parallel
480 Message_ProgressScope aPSParallel(aPSOuter.Next(9), "Splitting solids", aNbBS);
481 for (Standard_Integer iS = 0; iS < aNbBS; iS++)
483 BOPAlgo_SplitSolid& aSplitSolid = aVBS.ChangeValue(iS);
484 aSplitSolid.SetProgressRange(aPSParallel.Next());
487 //===================================================
488 BOPTools_Parallel::Perform (myRunParallel, aVBS);
489 //===================================================
490 if (UserBreak(aPSOuter))
495 for (k = 0; k < aNbBS; ++k)
497 BOPAlgo_SplitSolid& aBS = aVBS(k);
498 aSolidsIm.Add(aBS.Solid(), aBS.Areas());
500 // Merge BuilderSolid's report into main report,
501 // assigning the solid with the warnings/errors which
502 // have been generated for it.
503 // Convert all errors of BuilderSolid into warnings for main report.
504 const Handle(Message_Report)& aBSReport = aBS.GetReport();
505 Message_Gravity anAlertTypes[2] = { Message_Warning, Message_Fail };
506 for (Standard_Integer iGravity = 0; iGravity < 2; iGravity++)
508 const Message_ListOfAlert& anLAlerts = aBSReport->GetAlerts(anAlertTypes[iGravity]);
509 for (Message_ListOfAlert::Iterator itA(anLAlerts); itA.More(); itA.Next())
511 Handle(Message_Alert) anAlert = itA.Value();
513 Handle(TopoDS_AlertWithShape) anAlertWithShape = Handle(TopoDS_AlertWithShape)::DownCast(itA.Value());
514 if (!anAlertWithShape.IsNull())
516 TopoDS_Shape aWarnShape;
517 BRep_Builder().MakeCompound(TopoDS::Compound(aWarnShape));
518 BRep_Builder().Add(aWarnShape, aBS.Solid());
519 BRep_Builder().Add(aWarnShape, anAlertWithShape->GetShape());
521 anAlertWithShape->SetShape(aWarnShape);
522 AddWarning(anAlertWithShape);
530 // Add new solids to images map
531 aNbBS = aSolidsIm.Extent();
532 for (k = 1; k <= aNbBS; ++k)
534 const TopoDS_Shape& aS = aSolidsIm.FindKey(k);
535 const TopTools_ListOfShape& aLSR = aSolidsIm(k);
537 if (!myImages.IsBound(aS)) {
538 TopTools_ListOfShape* pLSx = myImages.Bound(aS, TopTools_ListOfShape());
540 aIt.Initialize(aLSR);
541 for (; aIt.More(); aIt.Next()) {
544 const TopoDS_Shape& aSR=aIt.Value();
545 aST.Add(aSR, TopAbs_FACE);
547 bFlagSD=aMST.Contains(aST);
549 const BOPTools_Set& aSTx=aMST.Added(aST);
550 const TopoDS_Shape& aSx=aSTx.Shape();
553 TopTools_ListOfShape* pLOr = myOrigins.ChangeSeek(aSx);
555 pLOr = myOrigins.Bound(aSx, TopTools_ListOfShape());
560 myShapesSD.Bind(aSR, aSx);
566 //=======================================================================
567 //function :FillInternalShapes
569 //=======================================================================
570 void BOPAlgo_Builder::FillInternalShapes(const Message_ProgressRange& theRange)
572 Standard_Integer i, j, aNbS, aNbSI, aNbSx;
573 TopAbs_ShapeEnum aType;
575 TopoDS_Iterator aItS;
577 TopTools_ListIteratorOfListOfShape aIt, aIt1;
579 Handle(NCollection_BaseAllocator) aAllocator;
580 //-----------------------------------------------------scope f
581 aAllocator=NCollection_BaseAllocator::CommonBaseAllocator();
583 TopTools_IndexedDataMapOfShapeListOfShape aMSx(100, aAllocator);
584 TopTools_IndexedMapOfShape aMx(100, aAllocator);
585 TopTools_IndexedMapOfShape aMSI(100, aAllocator);
586 TopTools_MapOfShape aMFence(100, aAllocator);
587 TopTools_MapOfShape aMSOr(100, aAllocator);
588 TopTools_ListOfShape aLSd(aAllocator);
589 TopTools_ListOfShape aLArgs(aAllocator);
590 TopTools_ListOfShape aLSC(aAllocator);
591 TopTools_ListOfShape aLSI(aAllocator);
593 Message_ProgressScope aPS(theRange, NULL, 10);
595 // 1. Shapes to process
597 // 1.1 Shapes from pure arguments aMSI
598 // 1.1.1 vertex, edge, wire
600 const TopTools_ListOfShape& aArguments=myDS->Arguments();
601 aIt.Initialize(aArguments);
602 for (; aIt.More(); aIt.Next()) {
603 const TopoDS_Shape& aS=aIt.Value();
604 BOPTools_AlgoTools::TreatCompound(aS, aLSC, &aMFence);
606 aIt.Initialize(aLSC);
607 for (; aIt.More(); aIt.Next()) {
608 const TopoDS_Shape& aS=aIt.Value();
609 aType=aS.ShapeType();
610 if (aType==TopAbs_WIRE) {
612 for(; aItS.More(); aItS.Next()) {
613 const TopoDS_Shape& aE=aItS.Value();
614 if (aMFence.Add(aE)) {
619 else if (aType==TopAbs_VERTEX || aType==TopAbs_EDGE){
625 aIt.Initialize(aLArgs);
626 for (; aIt.More(); aIt.Next()) {
627 const TopoDS_Shape& aS=aIt.Value();
628 aType=aS.ShapeType();
629 if (aType==TopAbs_VERTEX ||
630 aType==TopAbs_EDGE ||
631 aType==TopAbs_WIRE) {
632 if (aMFence.Add(aS)) {
633 if (myImages.IsBound(aS)) {
634 const TopTools_ListOfShape &aLSp=myImages.Find(aS);
635 aIt1.Initialize(aLSp);
636 for (; aIt1.More(); aIt1.Next()) {
637 const TopoDS_Shape& aSp=aIt1.Value();
654 // 2. Internal vertices, edges from source solids
658 aNbS=myDS->NbSourceShapes();
659 for (i=0; i<aNbS; ++i) {
660 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
662 if (aSI.ShapeType()!=TopAbs_SOLID) {
670 const TopoDS_Shape& aS=aSI.Shape();
673 OwnInternalShapes(aS, aMx);
676 for (j=1; j<=aNbSx; ++j) {
677 const TopoDS_Shape& aSi=aMx(j);
678 if (myImages.IsBound(aSi)) {
679 const TopTools_ListOfShape &aLSp=myImages.Find(aSi);
680 aIt1.Initialize(aLSp);
681 for (; aIt1.More(); aIt1.Next()) {
682 const TopoDS_Shape& aSp=aIt1.Value();
691 // build aux map from splits of solids
692 if (myImages.IsBound(aS)) {
693 const TopTools_ListOfShape &aLSp=myImages.Find(aS);
694 aIt.Initialize(aLSp);
695 for (; aIt.More(); aIt.Next()) {
696 const TopoDS_Shape& aSp=aIt.Value();
697 if (aMFence.Add(aSp)) {
698 TopExp::MapShapesAndAncestors(aSp, TopAbs_VERTEX, TopAbs_EDGE, aMSx);
699 TopExp::MapShapesAndAncestors(aSp, TopAbs_VERTEX, TopAbs_FACE, aMSx);
700 TopExp::MapShapesAndAncestors(aSp, TopAbs_EDGE , TopAbs_FACE, aMSx);
706 if (aMFence.Add(aS)) {
707 TopExp::MapShapesAndAncestors(aS, TopAbs_VERTEX, TopAbs_EDGE, aMSx);
708 TopExp::MapShapesAndAncestors(aS, TopAbs_VERTEX, TopAbs_FACE, aMSx);
709 TopExp::MapShapesAndAncestors(aS, TopAbs_EDGE , TopAbs_FACE, aMSx);
714 }// for (i=0; i<aNbS; ++i) {
716 // 3. Some shapes of aMSI can be already tied with faces of
718 aNbSI = aMSI.Extent();
719 for (i = 1; i <= aNbSI; ++i) {
720 const TopoDS_Shape& aSI = aMSI(i);
721 if (aMSx.Contains(aSI)) {
722 const TopTools_ListOfShape &aLSx=aMSx.FindFromKey(aSI);
723 aNbSx = aLSx.Extent();
734 aNbSI = aLSI.Extent();
741 // 5 Settle internal vertices and edges into solids
744 Message_ProgressScope aPSLoop(aPS.Next(9), "Looking for internal shapes", aLSd.Size());
746 aIt.Initialize(aLSd);
747 for (; aIt.More(); aIt.Next(), aPSLoop.Next()) {
748 TopoDS_Solid aSd=TopoDS::Solid(aIt.Value());
750 aIt1.Initialize(aLSI);
751 for (; aIt1.More();) {
752 TopoDS_Shape aSI = aIt1.Value();
753 aSI.Orientation(TopAbs_INTERNAL);
755 aState=BOPTools_AlgoTools::ComputeStateByOnePoint
756 (aSI, aSd, 1.e-11, myContext);
758 if (aState != TopAbs_IN) {
763 if (aMSOr.Contains(aSd)) {
768 aItS.Initialize(aSd);
769 for (; aItS.More(); aItS.Next()) {
770 const TopoDS_Shape& aSh=aItS.Value();
776 // no need to check for images of aSd as aMSOr contains only original solids
777 TopTools_ListOfShape* pLS = myImages.Bound(aSd, TopTools_ListOfShape());
780 TopTools_ListOfShape* pLOr = myOrigins.Bound(aSdx, TopTools_ListOfShape());
791 }//for (; aIt1.More();) {
792 }//for (; aIt.More(); aIt.Next()) {
794 //-----------------------------------------------------scope t
803 //=======================================================================
804 //function : OwnInternalShapes
806 //=======================================================================
807 void OwnInternalShapes(const TopoDS_Shape& theS,
808 TopTools_IndexedMapOfShape& theMx)
812 aIt.Initialize(theS);
813 for (; aIt.More(); aIt.Next()) {
814 const TopoDS_Shape& aSx=aIt.Value();
815 if (aSx.ShapeType()!=TopAbs_SHELL) {