1 // File: NMTAlgo_Splitter_1.cxx
2 // Created: Mon Feb 2 14:58:54 2004
3 // Author: Peter KURNEV
7 #include <NMTAlgo_Splitter.ixx>
8 #include <TopExp_Explorer.hxx>
9 #include <TopoDS_Shape.hxx>
10 #include <TopoDS_Compound.hxx>
11 #include <TopTools_MapOfShape.hxx>
12 #include <TopTools_DataMapOfShapeListOfShape.hxx>
13 #include <TopTools_MapIteratorOfMapOfShape.hxx>
14 #include <TopTools_ListOfShape.hxx>
15 #include <TopTools_ListIteratorOfListOfShape.hxx>
17 #include <TopoDS_Iterator.hxx>
18 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
20 #include <TopoDS_Edge.hxx>
21 #include <TopoDS_Face.hxx>
22 #include <NMTAlgo_Loop3d.hxx>
23 #include <Precision.hxx>
24 #include <BRep_Tool.hxx>
25 #include <BRepClass3d_SolidClassifier.hxx>
27 #include <TopoDS_Solid.hxx>
28 #include <NMTAlgo_Loop3d.hxx>
29 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
31 //=======================================================================
32 //function : ShellsAndSolids
34 //=======================================================================
35 void NMTAlgo_Splitter::ShellsAndSolids()
37 Standard_Boolean bMakeSolids;
38 TopAbs_ShapeEnum aType;
39 TopTools_ListIteratorOfListOfShape aItS;
40 TopTools_ListOfShape aLNS;
42 myAddedFacesMap.Clear();
43 bMakeSolids=(myLimit==TopAbs_SHAPE || myLimit<TopAbs_SHELL);
45 aItS.Initialize(myListShapes);
46 for ( ;aItS.More(); aItS.Next()) {
47 const TopoDS_Shape& aS=aItS.Value();
49 if (myToolShapes.Contains(aS)) {
54 if (aType > TopAbs_SHELL) {
55 continue;//face,wire,...
60 MakeShells (aS, aLNS);
62 if (bMakeSolids && aType==TopAbs_SOLID) {
66 TopTools_ListIteratorOfListOfShape it (aLNS);
67 for (; it.More(); it.Next()) {
68 myBuilder.Add (myShape, it.Value());
73 aItS.Initialize(myListShapes);
74 for ( ;aItS.More(); aItS.Next()) {
75 const TopoDS_Shape& aS=aItS.Value();
78 if (aType!=TopAbs_FACE || myMapTools.Contains(aS)) {
82 const TopoDS_Shape& aCSF=myImageShape.Image(aS).First();
83 TopoDS_Iterator itS(aCSF);
84 for (; itS.More(); itS.Next()){
85 const TopoDS_Shape& aF=itS.Value();
86 if (!myAddedFacesMap.Contains(aF)){
87 myBuilder.Add (myShape, aF);
92 //=======================================================================
93 //function : MakeShells
94 //purpose : split S into compound of shells
95 //=======================================================================
96 void NMTAlgo_Splitter::MakeShells(const TopoDS_Shape& aS,
97 TopTools_ListOfShape& aLNS)
99 NMTAlgo_Loop3d aShellMaker;
101 // get compound of split faces of aS
102 const TopoDS_Shape& aFC=myImageShape.Image(aS).First();
103 aShellMaker.AddConstFaces(aFC);
105 // add split faces inside aS
106 if (myClosedShapes.Contains(aS)) {
108 // internal faces compound
109 //modified by NIZNHY-PKV Thu Dec 23 16:34:05 2004 f
110 Standard_Integer aNbIF;
112 aNbIF=myInternalFaces.Extent();
113 //modified by NIZNHY-PKV Thu Dec 23 16:34:07 2004 t
114 TopoDS_Shape aIFC=FindFacesInside(aS, Standard_True);
115 aNbIF=myInternalFaces.Extent();
116 aShellMaker.AddSectionFaces(aIFC);
119 aLNS=aShellMaker.MakeShells(myAddedFacesMap);
121 // Add faces added to new shell to myAddedFacesMap:
122 // avoid rebuilding twice common part of 2 solids.
124 TopTools_ListIteratorOfListOfShape itS(aLNS);
125 TopExp_Explorer expF;
126 for (; itS.More(); itS.Next()) {
127 const TopoDS_Shape& aSh=itS.Value();
128 expF.Init (aSh, TopAbs_FACE);
129 for (; expF.More(); expF.Next()){
130 myAddedFacesMap.Add (expF.Current());
135 //=======================================================================
136 //function : MakeSolids
137 //purpose : make solids out of Shells
138 //=======================================================================
139 void NMTAlgo_Splitter::MakeSolids(const TopoDS_Shape& theSolid,
140 TopTools_ListOfShape& theShellList)
142 // for a solid wrapping other shells or solids without intersection,
143 // it is necessary to find shells making holes in it
144 Standard_Boolean isWrapping;
145 TopTools_ListOfShape aNewSolids; // result
146 TopTools_ListOfShape aHoleShells;
147 TopoDS_Shape anInfinitePointShape;
148 TopTools_DataMapOfShapeShape aInOutMap;
149 TopTools_ListIteratorOfListOfShape aShellIt, aSolisIt;
151 isWrapping = myWrappingSolid.Contains(theSolid);
152 if (!isWrapping && !theShellList.IsEmpty()) {
153 // check if theSolid initially has internal shells
154 TopoDS_Iterator aShellExp (theSolid);
156 isWrapping = aShellExp.More();
159 aShellIt.Initialize(theShellList);
160 for ( ; aShellIt.More(); aShellIt.Next()) {
161 const TopoDS_Shape & aShell = aShellIt.Value();
162 // check if a shell is a hole of theSolid
163 if (isWrapping && IsInside(anInfinitePointShape, aShell)){
164 aHoleShells.Append(aShell);
167 // make a solid from a shell
169 myBuilder.MakeSolid( Solid );
170 myBuilder.Add (Solid, aShell);
172 aNewSolids.Append (Solid);
176 // find outer a shell most close to each hole shell
177 aShellIt.Initialize(aHoleShells);
178 for (; aShellIt.More(); aShellIt.Next()){
179 const TopoDS_Shape & aHole = aShellIt.Value();
181 aSolisIt.Initialize(aNewSolids);
182 for ( ; aSolisIt.More(); aSolisIt.Next()) {
183 const TopoDS_Shape & aSolid = aSolisIt.Value();
185 if (! IsInside(aHole, aSolid)){
189 if ( aInOutMap.IsBound (aHole)){
190 const TopoDS_Shape & aSolid2 = aInOutMap( aHole );
191 if ( IsInside( aSolid, aSolid2 )) {
192 aInOutMap.UnBind( aHole );
193 aInOutMap.Bind ( aHole, aSolid );
197 aInOutMap.Bind (aHole, aSolid);
201 // add aHole to a solid
202 if (aInOutMap.IsBound( aHole )){
203 TopoDS_Shape & aSolid=aInOutMap(aHole);
204 myBuilder.Add (aSolid, aHole);
207 theShellList.Clear();
208 theShellList.Append( aNewSolids );
211 //=======================================================================
212 //function : FindFacesInside
213 //purpose : return compound of faces of other shapes that are
214 // inside <theShape>.
215 // <theShape> is an object shape.
216 // <CheckClosed> makes avoid faces that do not form a
218 // <All> makes return already added faces
219 //=======================================================================
220 TopoDS_Shape NMTAlgo_Splitter::FindFacesInside(const TopoDS_Shape& theShape,
221 const Standard_Boolean CheckClosed,
222 const Standard_Boolean All)
224 TopExp_Explorer expl;
226 // ================================================
227 // check if internal faces have been already found
228 // ================================================
229 if (myInternalFaces.IsBound(theShape)) {
230 TopoDS_Shape aIntFComp = myInternalFaces.Find (theShape);
231 TopoDS_Shape aIntRemFComp = myIntNotClFaces.Find (theShape);
233 expl.Init( aIntRemFComp, TopAbs_FACE);
234 if (CheckClosed || !expl.More()){
239 myBuilder.MakeCompound( C );
241 for (; expl.More(); expl.Next()){
242 myBuilder.Add( C, expl.Current() );
244 // add good internal faces
245 expl.Init( aIntFComp, TopAbs_FACE);
246 for (; expl.More(); expl.Next()) {
247 myBuilder.Add( C, expl.Current() );
253 // ===================================
254 // get data for internal faces search
255 // ===================================
257 TopTools_MapOfShape MSE, MFP;
258 TopTools_DataMapOfShapeListOfShape DMSEFP;
259 TopTools_IndexedDataMapOfShapeListOfShape DMEF;
260 TopTools_MapIteratorOfMapOfShape itm;
261 TopTools_ListOfShape EmptyL;
262 TopTools_ListIteratorOfListOfShape itl;
264 // compound of split faces of theShape
265 const TopoDS_Shape& CSF=myImageShape.Image(theShape).First();
266 // MSE filling: map of new section edges of CSF
267 expl.Init(CSF, TopAbs_EDGE);
268 for (; expl.More(); expl.Next()) {
269 const TopoDS_Shape& aE = expl.Current() ;
273 // DMEF: map edge of CSF - faces of CSF
274 TopExp::MapShapesAndAncestors(CSF, TopAbs_EDGE, TopAbs_FACE, DMEF);
277 // 1. MFP - a map of faces to process: map of resulting faces except
278 // those of theShape; we`ll add to C those of them which are inside CSF
279 // 2. DMSEFP - edge of MSE => faces of MFP
281 itl.Initialize(myListShapes);
282 for (;itl.More(); itl.Next()) {
283 const TopoDS_Shape& aShape = itl.Value();
285 if ( theShape.IsSame(aShape)) {
289 // iterate on split faces of aShape
290 const TopoDS_Shape& CSF1 = myImageShape.Image(aShape).First();
291 TopoDS_Iterator itF (CSF1);
292 for ( ; itF.More(); itF.Next()) {
293 const TopoDS_Shape& aF1 = itF.Value();
295 // iterate on edges of split faces of aShape,
296 // add to DMSEFP edges that are new
297 expl.Init(aF1, TopAbs_EDGE);
298 for (; expl.More(); expl.Next()) {
299 TopoDS_Shape aE1 = expl.Current();
300 if ( MSE.Contains(aE1)) {// section edge
301 if (!DMSEFP.IsBound(aE1)) {
302 DMSEFP.Bind(aE1, EmptyL);
304 DMSEFP(aE1).Append(aF1);
308 }//for (;itl.More(); itl.Next())
310 // ===========================
311 // find faces inside theShape
312 // ===========================
313 Standard_Boolean skipAlreadyAdded = Standard_False;
314 Standard_Boolean GoodOri, inside, sameDom1, sameDom2, isSectionE;
316 TopoDS_Face aFace1, anOrigFace, origF1, origF2; //, anOrigFace2;
317 TopTools_ListOfShape KeepFaces;
318 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Mapit;
320 // iterate on section edges, check faces of other shapes
321 // sharing section edges and put internal faces to KeepFaces
322 Mapit.Initialize(DMSEFP);
323 for (; Mapit.More() ; Mapit.Next() ) {
324 // a new edge of theShape
325 const TopoDS_Edge& E = TopoDS::Edge (Mapit.Key());
327 isSectionE=IsSectionEdge(E);
329 // split faces of other shapes sharing E
330 TopTools_ListOfShape& LSF = DMSEFP.ChangeFind(E);
332 itl.Initialize( LSF );
334 // a split faces of other shape
335 aFace1 = TopoDS::Face(itl.Value());
336 // remove aFace1 form DMSEFP and MFP
337 LSF.Remove( itl ); // == itl.Next();
338 if (!MFP.Remove( aFace1 ))
339 continue; // was not is MFP ( i.e already checked)
341 // check if aFace1 was already added to 2 shells
343 myAddedFacesMap.Contains(aFace1) &&
344 myAddedFacesMap.Contains(aFace1.Reversed())) {
345 skipAlreadyAdded = Standard_True;
348 // find another face which originates from the same face as aFace1:
349 // usually aFace2 is internal if aFace1 is not and vice versa
351 if (myImagesFaces.IsImage(aFace1)){
352 anOrigFace = TopoDS::Face(myImagesFaces.Root(aFace1));
355 //modified by NIZNHY-PKV Fri Dec 24 10:59:45 2004 f
360 while (itl.More()) { //#2
361 aFace2 = TopoDS::Face(itl.Value());
363 anOrigFace2 = aFace2;
364 if (myImagesFaces.IsImage(aFace2)) {
365 anOrigFace2 = TopoDS::Face(myImagesFaces.Root(aFace2));
368 if (!MFP.Contains( aFace2 )) {
373 if (anOrigFace.IsSame(anOrigFace2)) {
377 }// while (itl.More()) { #2
379 if (itl.More()) { // aFace2 found, remove it from maps
386 itl.Initialize( LSF );
387 } // if (!isSectionE) {
389 //modified by NIZNHY-PKV Fri Dec 24 10:59:52 2004 t
391 // check that anOrigFace is not same domain with CSF faces it intersects
393 //faces of CSF sharing E
395 const TopTools_ListOfShape& FL = DMEF.FindFromKey(E);
396 const TopoDS_Face& aFE1=TopoDS::Face(FL.First());
397 const TopoDS_Face& aFE2=TopoDS::Face(FL.Last());
400 if (myImagesFaces.IsImage(aFE1)) {
401 origF1=TopoDS::Face(myImagesFaces.Root(aFE1));
404 if (myImagesFaces.IsImage(aFE2)) {
405 origF2=TopoDS::Face(myImagesFaces.Root(aFE2));
408 sameDom1 = anOrigFace.IsSame( origF1 );
409 sameDom2 = anOrigFace.IsSame( origF2 );
411 if (!(sameDom1 || sameDom2) && HasSameDomainF(anOrigFace)) {
412 sameDom1 = IsSameDomainF(anOrigFace, origF1);
413 if (origF1 == origF2) {
418 if (sameDom1 && sameDom2){
422 if (sameDom1 || sameDom2) {
423 inside = NMTAlgo_Loop3d::IsInside (E, aFE1, aFE2, 1, dot, GoodOri);
424 if (inside || (dot + Precision::Angular() >= 1.0)) {
425 continue; // E is convex between origF1 and origF2 or they are tangent
429 // Keep one of found faces
431 //face of CSF sharing E
432 const TopoDS_Face& aShapeFace = sameDom1 ? aFE2 : aFE1;
433 // analyse aFace1 state
434 inside = NMTAlgo_Loop3d::IsInside (E, aShapeFace, aFace1, 1, dot, GoodOri);
435 if (inside) { //IFV 27.08.04
436 // aFace1 must be tested with both adjacent faces of CSF
437 const TopoDS_Face& aShapeFace2 = sameDom1 ? aFE1 : aFE2;
438 if (aShapeFace2 != aShapeFace){
440 NMTAlgo_Loop3d::IsInside(E, aShapeFace2, aFace1, 1, dot, GoodOri);
444 // store internal face
446 KeepFaces.Append(aFace1);
449 //modified by NIZNHY-PKV Fri Dec 24 11:02:55 2004 f
451 else if (!aFace2.IsNull()) {
452 if (dot + Precision::Angular() >= 1.0) {
453 // aFace2 state is not clear, it will be analysed alone, put it back to the maps
458 KeepFaces.Append(aFace2);
462 //modified by NIZNHY-PKV Fri Dec 24 11:03:03 2004 t
463 }// while (itl.More()) {
464 }// for (; Mapit.More() ; Mapit.Next() ) {
466 // ===================================================
467 // add not distributed faces connected with KeepFaces
468 // ===================================================
469 // ultimate list of internal faces
470 TopTools_ListOfShape KeptFaces;
473 KeptFaces.Append (KeepFaces);
475 while (!KeepFaces.IsEmpty()) {
476 // KeepEdges : map of edges of faces kept last time
477 TopTools_IndexedMapOfShape KeepEdges;
478 for ( itl.Initialize(KeepFaces); itl.More(); itl.Next() ) {
479 TopExp::MapShapes( itl.Value(), TopAbs_EDGE, KeepEdges);
480 KeptFaces.Append( itl.Value() );
485 // keep faces connected with already kept faces by KeepEdges
486 for ( itm.Initialize(MFP); itm.More(); itm.Next() ) {
487 const TopoDS_Shape& FP = itm.Key();
488 for (expl.Init(FP,TopAbs_EDGE); expl.More(); expl.Next()) {
489 const TopoDS_Shape& se = expl.Current();
490 if (!MSE.Contains(se) && KeepEdges.Contains(se) ) {
491 KeepFaces.Append(FP);
499 // ===============================================================
500 // here MFP contains faces outer of theShape and those of shapes
501 // which do not interfere with theShape at all and between which
502 // there may be those wrapped by theShape and whose faces may be
503 // needed to be returned as well
504 // ===============================================================
506 Standard_Boolean isSolid = (theShape.ShapeType() == TopAbs_SOLID);
507 if (All || isSolid) // All is for sub-result removal
509 for ( itm.Initialize( MFP ); itm.More(); itm.Next() ) {
510 TopoDS_Shape aFace = itm.Key();
512 // find a shape aFace originates from
513 TopoDS_Shape anOrigShape = GetOriginalShape( aFace );
515 // find out if all faces of anOrigShape are not in MFP
516 // and by the way remove them from MFP
517 Standard_Boolean isAllOut = Standard_True;
518 TopoDS_Shape aSplitFaces = anOrigShape;
519 if (myImageShape.HasImage(anOrigShape))
520 aSplitFaces = myImageShape.Image(anOrigShape).First();
522 TopTools_ListOfShape aSplitFaceL;
523 for (expl.Init( aSplitFaces, TopAbs_FACE ); expl.More(); expl.Next())
525 const TopoDS_Shape & aSpFace = expl.Current();
526 // a tool face which become object has image but the whole tool shape has not
527 if (myImageShape.HasImage( aSpFace ))
529 TopExp_Explorer exF (myImageShape.Image( aSpFace ).First(), TopAbs_FACE );
530 for ( ; exF.More(); exF.Next() )
532 aSplitFaceL.Append( exF.Current() );
533 if ( ! MFP.Remove( exF.Current() ))
534 isAllOut = Standard_False;
539 aSplitFaceL.Append( aSpFace );
540 if ( ! MFP.Remove( aSpFace ))
541 isAllOut = Standard_False;
544 itm.Initialize( MFP );
548 // classify anOrigShape against theShape
549 if (IsInside (anOrigShape, theShape)) {
550 if (isSolid && myClosedShapes.Contains(anOrigShape)) {
551 // to make a special care at solid reconstruction
552 myWrappingSolid.Add ( theShape );
554 // keep faces of an internal shape anOrigShape
555 KeptFaces.Append( aSplitFaceL );
560 // ====================================================
561 // check if kept faces form a shell without free edges
562 // ====================================================
564 DMEF.Clear(); // edge - kept faces
565 MFP.Clear(); // reuse it for wrong faces
567 for (itl.Initialize(KeptFaces); itl.More(); itl.Next() )
568 TopExp::MapShapesAndAncestors(itl.Value(), TopAbs_EDGE, TopAbs_FACE, DMEF);
570 Standard_Integer i, nb = DMEF.Extent();
571 Standard_Boolean isClosed = Standard_False;
573 isClosed = Standard_True;
574 for (i=1; isClosed && i<=nb; ++i) {
575 const TopoDS_Shape& E = DMEF.FindKey( i );
576 if (! BRep_Tool::Degenerated( TopoDS::Edge( E )) &&
578 isClosed = ( DMEF(i).Extent() != 1 );
581 const TopoDS_Shape& F = DMEF.FindFromIndex( i-1 ).First(); // bad face
583 // remove bad face from DMEF
584 for (expl.Init( F, TopAbs_EDGE); expl.More(); expl.Next()) {
585 const TopoDS_Shape& E = expl.Current();
586 TopTools_ListOfShape& FL = DMEF.ChangeFromKey( E );
587 for (itl.Initialize( FL ); itl.More(); itl.Next() ) {
588 if ( F.IsSame( itl.Value() )) {
603 // compound of removed internal faces
604 TopoDS_Compound CNotCl;
606 myBuilder.MakeCompound(C);
607 myBuilder.MakeCompound(CNotCl);
610 itl.Initialize(KeptFaces);
611 for (; itl.More(); itl.Next() ) {
612 TopoDS_Shape & aIntFace = itl.Value();
615 myAddedFacesMap.Contains(aIntFace) &&
616 myAddedFacesMap.Contains(aIntFace.Reversed())) {
620 if (! MFP.Contains( aIntFace )){
621 myBuilder.Add(C, aIntFace);
624 myBuilder.Add(CNotCl, aIntFace);
628 if (!skipAlreadyAdded && CheckClosed) {
629 myInternalFaces.Bind(theShape, C);
630 myIntNotClFaces.Bind(theShape, CNotCl);
634 if (!myMapSIFC.IsBound(theShape)) {
635 TopoDS_Compound aCIF;
636 myBuilder.MakeCompound(aCIF);
638 itl.Initialize(KeptFaces);
639 for (; itl.More(); itl.Next() ) {
640 TopoDS_Shape & aIntFace = itl.Value();
641 if (! MFP.Contains(aIntFace )){
642 myBuilder.Add(aCIF, aIntFace);
645 myMapSIFC.Bind(theShape, aCIF);
650 //=======================================================================
651 //function : IsInside
652 //purpose : Return True if the first vertex of S1 inside S2.
653 // If S1.IsNull(), check infinite point against S2.
654 //=======================================================================
655 Standard_Boolean NMTAlgo_Splitter::IsInside (const TopoDS_Shape& theS1,
656 const TopoDS_Shape& theS2)
658 BRepClass3d_SolidClassifier aClassifier( theS2 );
660 TopExp_Explorer expl(theS1, TopAbs_VERTEX);
663 aClassifier.PerformInfinitePoint( ::RealSmall());
666 const TopoDS_Vertex & aVertex = TopoDS::Vertex( expl.Current() );
667 aClassifier.Perform (BRep_Tool::Pnt( aVertex ),
668 BRep_Tool::Tolerance( aVertex ));
671 return ( aClassifier.State() == TopAbs_IN );
674 //=======================================================================
675 //function : GetOriginalShape
676 //purpose : Return the shape aShape originates from. aShape
677 // should be a face or more complex result shape
678 //=======================================================================
679 TopoDS_Shape NMTAlgo_Splitter::GetOriginalShape(const TopoDS_Shape& theShape) const
681 TopoDS_Shape anOrigShape;
683 TopExp_Explorer expl( theShape, TopAbs_FACE);
685 TopoDS_Shape aFace = expl.Current();
686 if (myImagesFaces.IsImage( aFace ))
687 aFace = myImagesFaces.Root( aFace );
688 anOrigShape = myFaceShapeMap.Find( aFace );