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>
20 #include <Precision.hxx>
22 #include <Bnd_Box.hxx>
23 #include <TopAbs_State.hxx>
26 #include <TopoDS_AlertWithShape.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopoDS_Solid.hxx>
29 #include <TopoDS_Shape.hxx>
30 #include <TopoDS_Face.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Solid.hxx>
33 #include <TopoDS_Shell.hxx>
34 #include <TopoDS_Compound.hxx>
37 #include <TopExp_Explorer.hxx>
39 #include <BRep_Builder.hxx>
41 #include <BOPAlgo_Tools.hxx>
42 #include <BOPAlgo_BuilderSolid.hxx>
44 #include <IntTools_Context.hxx>
46 #include <BOPDS_DS.hxx>
47 #include <BOPDS_ShapeInfo.hxx>
49 #include <BOPTools_AlgoTools.hxx>
50 #include <BOPTools_MapOfSet.hxx>
51 #include <BOPTools_Set.hxx>
52 #include <BOPTools_Parallel.hxx>
54 #include <BOPAlgo_Tools.hxx>
55 #include <NCollection_Array1.hxx>
56 #include <NCollection_IncAllocator.hxx>
57 #include <NCollection_Vector.hxx>
59 #include <TopTools_IndexedMapOfShape.hxx>
60 #include <TopTools_MapOfShape.hxx>
61 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
62 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
63 #include <TopTools_ListOfShape.hxx>
68 void OwnInternalShapes(const TopoDS_Shape& ,
69 TopTools_IndexedMapOfShape& );
72 //=======================================================================
73 //function : FillImagesSolids
75 //=======================================================================
76 void BOPAlgo_Builder::FillImagesSolids()
78 Standard_Boolean bHasSolids;
79 Standard_Integer i, aNbS;
81 bHasSolids=Standard_False;
82 aNbS=myDS->NbSourceShapes();
83 for (i=0; i<aNbS; ++i) {
84 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
85 if (aSI.ShapeType()==TopAbs_SOLID) {
86 bHasSolids=!bHasSolids;
96 TopTools_DataMapOfShapeShape aDraftSolids;
97 // Find all IN faces for all IN faces
98 FillIn3DParts(aDraftSolids);
99 // Build split of the solids
100 BuildSplitSolids(aDraftSolids);
101 // Fill solids with internal parts
102 FillInternalShapes();
104 //=======================================================================
105 //function : FillIn3DParts
107 //=======================================================================
108 void BOPAlgo_Builder::FillIn3DParts(TopTools_DataMapOfShapeShape& theDraftSolids)
110 Handle(NCollection_BaseAllocator) anAlloc = new NCollection_IncAllocator;
112 // Find all faces that are IN solids
114 // Store boxes of the shapes into a map
115 TopTools_DataMapOfShapeBox aShapeBoxMap(1, anAlloc);
118 TopTools_MapOfShape aMFence(1, anAlloc);
121 TopTools_ListOfShape aLFaces(anAlloc);
123 Standard_Integer i, aNbS = myDS->NbSourceShapes();
124 for (i = 0; i < aNbS; ++i)
126 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
127 if (aSI.ShapeType() != TopAbs_FACE)
130 const TopoDS_Shape& aS = aSI.Shape();
131 const TopTools_ListOfShape* pLSIm = myImages.Seek(aS);
135 TopTools_ListIteratorOfListOfShape aItLSIm(*pLSIm);
136 for (; aItLSIm.More(); aItLSIm.Next())
138 const TopoDS_Shape& aSIm = aItLSIm.Value();
139 if (aMFence.Add(aSIm))
140 aLFaces.Append(aSIm);
146 aShapeBoxMap.Bind(aS, aSI.Box());
153 TopTools_ListOfShape aLSolids(anAlloc);
154 // Keep INTERNAL faces of the solids
155 TopTools_DataMapOfShapeListOfShape aSolidsIF(1, anAlloc);
157 TopTools_IndexedDataMapOfShapeShape aDraftSolid(1, anAlloc);
159 for (i = 0; i < aNbS; ++i)
161 BOPDS_ShapeInfo& aSI = myDS->ChangeShapeInfo(i);
162 if (aSI.ShapeType() != TopAbs_SOLID)
165 const TopoDS_Shape& aS = aSI.Shape();
166 const TopoDS_Solid& aSolid = (*(TopoDS_Solid*)(&aS));
168 // Bounding box for the solid aS
169 Bnd_Box& aBoxS = aSI.ChangeBox();
171 myDS->BuildBndBoxSolid(i, aBoxS, myCheckInverted);
174 TopTools_ListOfShape aLIF;
177 BuildDraftSolid(aSolid, aSD, aLIF);
179 aLSolids.Append(aSD);
180 aSolidsIF.Bind(aSD, aLIF);
181 aShapeBoxMap.Bind(aSD, aBoxS);
182 aDraftSolid.Add(aS, aSD);
185 // Perform classification of the faces
186 TopTools_IndexedDataMapOfShapeListOfShape anInParts;
188 BOPAlgo_Tools::ClassifyFaces(aLFaces, aLSolids, myRunParallel,
189 myContext, anInParts, aShapeBoxMap, aSolidsIF);
191 // Analyze the results of classification
192 Standard_Integer aNbSol = aDraftSolid.Extent();
193 for (i = 1; i <= aNbSol; ++i)
195 const TopoDS_Solid& aSolid = TopoDS::Solid(aDraftSolid.FindKey(i));
196 const TopoDS_Solid& aSDraft = TopoDS::Solid(aDraftSolid(i));
197 const TopTools_ListOfShape& aLInFaces = anInParts.FindFromKey(aSDraft);
198 const TopTools_ListOfShape& aLInternal = aSolidsIF.Find(aSDraft);
200 Standard_Integer aNbIN = aLInFaces.Extent();
204 Standard_Boolean bHasImage = Standard_False;
205 // Check if the shells of the solid have image
206 for (TopoDS_Iterator it(aSolid); it.More() && !bHasImage; it.Next())
207 bHasImage = myImages.IsBound(it.Value());
210 // no need to split the solid
214 theDraftSolids.Bind(aSolid, aSDraft);
216 Standard_Integer aNbInt = aLInternal.Extent();
220 TopTools_ListOfShape *pLIN = myInParts.Bound(aSolid, TopTools_ListOfShape());
222 TopTools_ListIteratorOfListOfShape aItLS(aLInFaces);
223 for (; aItLS.More(); aItLS.Next())
224 pLIN->Append(aItLS.Value());
226 aItLS.Initialize(aLInternal);
227 for (; aItLS.More(); aItLS.Next())
228 pLIN->Append(aItLS.Value());
232 //=======================================================================
233 //function : BuildDraftSolid
235 //=======================================================================
236 void BOPAlgo_Builder::BuildDraftSolid(const TopoDS_Shape& theSolid,
237 TopoDS_Shape& theDraftSolid,
238 TopTools_ListOfShape& theLIF)
240 Standard_Boolean bToReverse;
241 Standard_Integer iFlag;
242 TopAbs_Orientation aOrF, aOrSh, aOrSd;
243 TopoDS_Iterator aIt1, aIt2;
247 TopTools_ListIteratorOfListOfShape aItS;
249 aOrSd=theSolid.Orientation();
250 theDraftSolid.Orientation(aOrSd);
252 aIt1.Initialize(theSolid);
253 for (; aIt1.More(); aIt1.Next()) {
254 const TopoDS_Shape& aSh=aIt1.Value();
255 if(aSh.ShapeType()!=TopAbs_SHELL) {
256 continue; // mb internal edges,vertices
259 aOrSh=aSh.Orientation();
261 aShD.Orientation(aOrSh);
264 aIt2.Initialize(aSh);
265 for (; aIt2.More(); aIt2.Next()) {
266 const TopoDS_Shape& aF=aIt2.Value();
267 aOrF=aF.Orientation();
269 if (myImages.IsBound(aF)) {
270 const TopTools_ListOfShape& aLSp=myImages.Find(aF);
271 aItS.Initialize(aLSp);
272 for (; aItS.More(); aItS.Next()) {
275 if (myShapesSD.IsBound(aFx)) {
277 if (aOrF==TopAbs_INTERNAL) {
278 aFx.Orientation(aOrF);
282 bToReverse=BOPTools_AlgoTools::IsSplitToReverseWithWarn
283 (aFx, aF, myContext, myReport);
291 }//if (myShapesSD.IsBound(aFx)) {
293 aFx.Orientation(aOrF);
294 if (aOrF==TopAbs_INTERNAL) {
303 } // if (myImages.IsBound(aF)) {
306 if (aOrF==TopAbs_INTERNAL) {
314 } //for (; aIt2.More(); aIt2.Next()) {
317 aShD.Closed (BRep_Tool::IsClosed (aShD));
318 aBB.Add(theDraftSolid, aShD);
320 } //for (; aIt1.More(); aIt1.Next()) {
323 //=======================================================================
325 //=======================================================================
326 //class : BOPAlgo_SplitSolid
327 //purpose : Auxiliary class to extend the BOPAlgo_BuilderSolid with the solid to split
328 //=======================================================================
329 class BOPAlgo_SplitSolid : public BOPAlgo_BuilderSolid
333 void SetSolid(const TopoDS_Solid& theSolid) { mySolid = theSolid; }
335 //! Returns the solid
336 const TopoDS_Solid& Solid() const { return mySolid; }
339 TopoDS_Solid mySolid; //!< Solid to split
342 // Vector of Solid Builders
343 typedef NCollection_Vector<BOPAlgo_SplitSolid> BOPAlgo_VectorOfBuilderSolid;
344 // Functors to split solids
345 typedef BOPTools_Functor<BOPAlgo_SplitSolid,
346 BOPAlgo_VectorOfBuilderSolid> BOPAlgo_BuilderSolidFunctor;
348 typedef BOPTools_Cnt<BOPAlgo_BuilderSolidFunctor,
349 BOPAlgo_VectorOfBuilderSolid> BOPAlgo_BuilderSolidCnt;
350 //=======================================================================
352 //=======================================================================
353 //function : BuildSplitSolids
355 //=======================================================================
356 void BOPAlgo_Builder::BuildSplitSolids(TopTools_DataMapOfShapeShape& theDraftSolids)
358 Standard_Boolean bFlagSD;
359 Standard_Integer i, aNbS;
360 TopExp_Explorer aExp;
361 TopTools_ListIteratorOfListOfShape aIt;
363 Handle(NCollection_BaseAllocator) aAlr0;
364 aAlr0=NCollection_BaseAllocator::CommonBaseAllocator();
366 TopTools_ListOfShape aSFS(aAlr0), aLSEmpty(aAlr0);
367 TopTools_MapOfShape aMFence(100, aAlr0);
368 BOPTools_MapOfSet aMST(100, aAlr0);
369 BOPAlgo_VectorOfBuilderSolid aVBS;
371 // 0. Find same domain solids for non-interfered solids
372 aNbS=myDS->NbSourceShapes();
373 for (i=0; i<aNbS; ++i) {
374 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
376 if (aSI.ShapeType()!=TopAbs_SOLID) {
380 const TopoDS_Shape& aS=aSI.Shape();
381 if (!aMFence.Add(aS)) {
384 if(theDraftSolids.IsBound(aS)) {
390 aST.Add(aS, TopAbs_FACE);
393 } //for (i=1; i<=aNbS; ++i)
395 // Build temporary map of solids images to avoid rebuilding
396 // of the solids without internal faces
397 TopTools_IndexedDataMapOfShapeListOfShape aSolidsIm;
398 // 1. Build solids for interfered source solids
399 for (i = 0; i < aNbS; ++i) {
400 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
401 if (aSI.ShapeType() != TopAbs_SOLID)
404 const TopoDS_Shape& aS = aSI.Shape();
405 const TopoDS_Solid& aSolid=(*(TopoDS_Solid*)(&aS));
406 if (!theDraftSolids.IsBound(aS))
409 const TopoDS_Shape& aSD = theDraftSolids.Find(aS);
410 const TopTools_ListOfShape* pLFIN = myInParts.Seek(aS);
411 if (!pLFIN || pLFIN->IsEmpty())
413 aSolidsIm(aSolidsIm.Add(aS, TopTools_ListOfShape())).Append(aSD);
419 // 1.1 Fill Shell Faces Set
420 aExp.Init(aSD, TopAbs_FACE);
421 for (; aExp.More(); aExp.Next()) {
422 const TopoDS_Shape& aF = aExp.Current();
426 // 1.2 Fill internal faces
427 aIt.Initialize(*pLFIN);
428 for (; aIt.More(); aIt.Next()) {
429 TopoDS_Shape aF = aIt.Value();
431 aF.Orientation(TopAbs_FORWARD);
433 aF.Orientation(TopAbs_REVERSED);
437 // 1.3 Build new solids
438 BOPAlgo_SplitSolid& aBS=aVBS.Appended();
439 aBS.SetSolid(aSolid);
441 aBS.SetRunParallel(myRunParallel);
442 aBS.SetProgressIndicator(myProgressIndicator);
443 }//for (i=0; i<aNbS; ++i) {
445 Standard_Integer k, aNbBS;
449 //===================================================
450 BOPAlgo_BuilderSolidCnt::Perform(myRunParallel, aVBS);
451 //===================================================
453 for (k = 0; k < aNbBS; ++k)
455 BOPAlgo_SplitSolid& aBS = aVBS(k);
456 aSolidsIm.Add(aBS.Solid(), aBS.Areas());
458 // Merge BuilderSolid's report into main report,
459 // assigning the solid with the warnings/errors which
460 // have been generated for it.
461 // Convert all errors of BuilderSolid into warnings for main report.
462 const Handle(Message_Report)& aBSReport = aBS.GetReport();
463 Message_Gravity anAlertTypes[2] = { Message_Warning, Message_Fail };
464 for (Standard_Integer iGravity = 0; iGravity < 2; iGravity++)
466 const Message_ListOfAlert& anLAlerts = aBSReport->GetAlerts(anAlertTypes[iGravity]);
467 for (Message_ListOfAlert::Iterator itA(anLAlerts); itA.More(); itA.Next())
469 Handle(Message_Alert) anAlert = itA.Value();
471 Handle(TopoDS_AlertWithShape) anAlertWithShape = Handle(TopoDS_AlertWithShape)::DownCast(itA.Value());
472 if (!anAlertWithShape.IsNull())
474 TopoDS_Shape aWarnShape;
475 BRep_Builder().MakeCompound(TopoDS::Compound(aWarnShape));
476 BRep_Builder().Add(aWarnShape, aBS.Solid());
477 BRep_Builder().Add(aWarnShape, anAlertWithShape->GetShape());
479 anAlertWithShape->SetShape(aWarnShape);
480 AddWarning(anAlertWithShape);
488 // Add new solids to images map
489 aNbBS = aSolidsIm.Extent();
490 for (k = 1; k <= aNbBS; ++k)
492 const TopoDS_Shape& aS = aSolidsIm.FindKey(k);
493 const TopTools_ListOfShape& aLSR = aSolidsIm(k);
495 if (!myImages.IsBound(aS)) {
496 TopTools_ListOfShape* pLSx = myImages.Bound(aS, TopTools_ListOfShape());
498 aIt.Initialize(aLSR);
499 for (; aIt.More(); aIt.Next()) {
502 const TopoDS_Shape& aSR=aIt.Value();
503 aST.Add(aSR, TopAbs_FACE);
505 bFlagSD=aMST.Contains(aST);
507 const BOPTools_Set& aSTx=aMST.Added(aST);
508 const TopoDS_Shape& aSx=aSTx.Shape();
511 TopTools_ListOfShape* pLOr = myOrigins.ChangeSeek(aSx);
513 pLOr = myOrigins.Bound(aSx, TopTools_ListOfShape());
518 myShapesSD.Bind(aSR, aSx);
524 //=======================================================================
525 //function :FillInternalShapes
527 //=======================================================================
528 void BOPAlgo_Builder::FillInternalShapes()
530 Standard_Integer i, j, aNbS, aNbSI, aNbSx;
531 TopAbs_ShapeEnum aType;
533 TopoDS_Iterator aItS;
535 TopTools_ListIteratorOfListOfShape aIt, aIt1;
537 Handle(NCollection_BaseAllocator) aAllocator;
538 //-----------------------------------------------------scope f
539 aAllocator=NCollection_BaseAllocator::CommonBaseAllocator();
541 TopTools_IndexedDataMapOfShapeListOfShape aMSx(100, aAllocator);
542 TopTools_IndexedMapOfShape aMx(100, aAllocator);
543 TopTools_IndexedMapOfShape aMSI(100, aAllocator);
544 TopTools_MapOfShape aMFence(100, aAllocator);
545 TopTools_MapOfShape aMSOr(100, aAllocator);
546 TopTools_ListOfShape aLSd(aAllocator);
547 TopTools_ListOfShape aLArgs(aAllocator);
548 TopTools_ListOfShape aLSC(aAllocator);
549 TopTools_ListOfShape aLSI(aAllocator);
551 // 1. Shapes to process
553 // 1.1 Shapes from pure arguments aMSI
554 // 1.1.1 vertex, edge, wire
556 const TopTools_ListOfShape& aArguments=myDS->Arguments();
557 aIt.Initialize(aArguments);
558 for (; aIt.More(); aIt.Next()) {
559 const TopoDS_Shape& aS=aIt.Value();
560 BOPAlgo_Tools::TreatCompound(aS, aMFence, aLSC);
562 aIt.Initialize(aLSC);
563 for (; aIt.More(); aIt.Next()) {
564 const TopoDS_Shape& aS=aIt.Value();
565 aType=aS.ShapeType();
566 if (aType==TopAbs_WIRE) {
568 for(; aItS.More(); aItS.Next()) {
569 const TopoDS_Shape& aE=aItS.Value();
570 if (aMFence.Add(aE)) {
575 else if (aType==TopAbs_VERTEX || aType==TopAbs_EDGE){
581 aIt.Initialize(aLArgs);
582 for (; aIt.More(); aIt.Next()) {
583 const TopoDS_Shape& aS=aIt.Value();
584 aType=aS.ShapeType();
585 if (aType==TopAbs_VERTEX ||
586 aType==TopAbs_EDGE ||
587 aType==TopAbs_WIRE) {
588 if (aMFence.Add(aS)) {
589 if (myImages.IsBound(aS)) {
590 const TopTools_ListOfShape &aLSp=myImages.Find(aS);
591 aIt1.Initialize(aLSp);
592 for (; aIt1.More(); aIt1.Next()) {
593 const TopoDS_Shape& aSp=aIt1.Value();
606 // 2. Internal vertices, edges from source solids
610 aNbS=myDS->NbSourceShapes();
611 for (i=0; i<aNbS; ++i) {
612 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
614 if (aSI.ShapeType()!=TopAbs_SOLID) {
620 const TopoDS_Shape& aS=aSI.Shape();
623 OwnInternalShapes(aS, aMx);
626 for (j=1; j<=aNbSx; ++j) {
627 const TopoDS_Shape& aSi=aMx(j);
628 if (myImages.IsBound(aSi)) {
629 const TopTools_ListOfShape &aLSp=myImages.Find(aSi);
630 aIt1.Initialize(aLSp);
631 for (; aIt1.More(); aIt1.Next()) {
632 const TopoDS_Shape& aSp=aIt1.Value();
641 // build aux map from splits of solids
642 if (myImages.IsBound(aS)) {
643 const TopTools_ListOfShape &aLSp=myImages.Find(aS);
644 aIt.Initialize(aLSp);
645 for (; aIt.More(); aIt.Next()) {
646 const TopoDS_Shape& aSp=aIt.Value();
647 if (aMFence.Add(aSp)) {
648 TopExp::MapShapesAndAncestors(aSp, TopAbs_VERTEX, TopAbs_EDGE, aMSx);
649 TopExp::MapShapesAndAncestors(aSp, TopAbs_VERTEX, TopAbs_FACE, aMSx);
650 TopExp::MapShapesAndAncestors(aSp, TopAbs_EDGE , TopAbs_FACE, aMSx);
656 if (aMFence.Add(aS)) {
657 TopExp::MapShapesAndAncestors(aS, TopAbs_VERTEX, TopAbs_EDGE, aMSx);
658 TopExp::MapShapesAndAncestors(aS, TopAbs_VERTEX, TopAbs_FACE, aMSx);
659 TopExp::MapShapesAndAncestors(aS, TopAbs_EDGE , TopAbs_FACE, aMSx);
664 }// for (i=0; i<aNbS; ++i) {
666 // 3. Some shapes of aMSI can be already tied with faces of
668 aNbSI = aMSI.Extent();
669 for (i = 1; i <= aNbSI; ++i) {
670 const TopoDS_Shape& aSI = aMSI(i);
671 if (aMSx.Contains(aSI)) {
672 const TopTools_ListOfShape &aLSx=aMSx.FindFromKey(aSI);
673 aNbSx = aLSx.Extent();
684 aNbSI = aLSI.Extent();
689 // 5 Settle internal vertices and edges into solids
691 aIt.Initialize(aLSd);
692 for (; aIt.More(); aIt.Next()) {
693 TopoDS_Solid aSd=TopoDS::Solid(aIt.Value());
695 aIt1.Initialize(aLSI);
696 for (; aIt1.More();) {
697 TopoDS_Shape aSI = aIt1.Value();
698 aSI.Orientation(TopAbs_INTERNAL);
700 aState=BOPTools_AlgoTools::ComputeStateByOnePoint
701 (aSI, aSd, 1.e-11, myContext);
703 if (aState != TopAbs_IN) {
708 if (aMSOr.Contains(aSd)) {
713 aItS.Initialize(aSd);
714 for (; aItS.More(); aItS.Next()) {
715 const TopoDS_Shape& aSh=aItS.Value();
721 // no need to check for images of aSd as aMSOr contains only original solids
722 TopTools_ListOfShape* pLS = myImages.Bound(aSd, TopTools_ListOfShape());
725 TopTools_ListOfShape* pLOr = myOrigins.Bound(aSdx, TopTools_ListOfShape());
736 }//for (; aIt1.More();) {
737 }//for (; aIt.More(); aIt.Next()) {
739 //-----------------------------------------------------scope t
748 //=======================================================================
749 //function : OwnInternalShapes
751 //=======================================================================
752 void OwnInternalShapes(const TopoDS_Shape& theS,
753 TopTools_IndexedMapOfShape& theMx)
757 aIt.Initialize(theS);
758 for (; aIt.More(); aIt.Next()) {
759 const TopoDS_Shape& aSx=aIt.Value();
760 if (aSx.ShapeType()!=TopAbs_SHELL) {