0022746: Progress indicator in ShapeHealing
[occt.git] / src / ShapeFix / ShapeFix_Shell.cxx
CommitLineData
7fd59977 1// File: ShapeFix_Shell.cxx
2// Created: Wed Aug 12 11:07:12 1998
3// Author: Galina KULIKOVA
4// <gka@nnov.matra-dtv.fr>
5// pdn 17.12.98 ie_exhaust-A.stp
6
7#include <ShapeFix_Shell.ixx>
8
9#include <Precision.hxx>
10#include <TopAbs.hxx>
11#include <TopoDS_Iterator.hxx>
12#include <TopoDS_Shape.hxx>
13#include <TopoDS_Face.hxx>
14#include <TopoDS_Edge.hxx>
15#include <TopoDS_Shell.hxx>
16#include <TopoDS.hxx>
17#include <TopExp_Explorer.hxx>
18#include <TopExp.hxx>
19
20#include <TColStd_SequenceOfInteger.hxx>
21#include <TopTools_SequenceOfShape.hxx>
22#include <TopTools_MapOfShape.hxx>
23#include <TopTools_MapIteratorOfMapOfShape.hxx>
24#include <TopTools_IndexedMapOfShape.hxx>
25#include <TopTools_DataMapOfShapeShape.hxx>
26#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
27#include <TopTools_ListOfShape.hxx>
28#include <TopTools_ListIteratorOfListOfShape.hxx>
29
30#include <BRep_Builder.hxx>
31#include <BRep_Tool.hxx>
32
33#include <ShapeExtend.hxx>
34#include <ShapeBuild_ReShape.hxx>
35#include <Message_Msg.hxx>
b485ee79 36#include <Message_ProgressSentry.hxx>
7fd59977 37#include <TopTools_DataMapOfShapeInteger.hxx>
38#include <TopTools_DataMapOfShapeInteger.hxx>
39#include <TopTools_DataMapOfShapeInteger.hxx>
40#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
41#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
42#include <TColStd_DataMapOfIntegerListOfInteger.hxx>
43#include <Bnd_Box.hxx>
44#include <BRepBndLib.hxx>
45#include <Bnd_Array1OfBox.hxx>
46#include <TColStd_MapOfInteger.hxx>
47#include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
48#include <TopoDS_Iterator.hxx>
49#include <TopTools_IndexedMapOfShape.hxx>
50#include <TopTools_IndexedDataMapOfShapeShape.hxx>
51
52//=======================================================================
53//function : ShapeFix_Shell
54//purpose :
55//=======================================================================
56
57ShapeFix_Shell::ShapeFix_Shell()
58{
59 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
60 myFixFaceMode = -1;
61 myFixOrientationMode = -1;
62 myFixFace = new ShapeFix_Face;
63 myNbShells =0;
64}
65
66//=======================================================================
67//function : ShapeFix_Shell
68//purpose :
69//=======================================================================
70
71ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape)
72{
73 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
74 myFixFaceMode = -1;
75 myFixOrientationMode = -1;
76 myFixFace = new ShapeFix_Face;
77 Init(shape);
78}
79
80//=======================================================================
81//function : Init
82//purpose :
83//=======================================================================
84
85void ShapeFix_Shell::Init(const TopoDS_Shell& shell)
86{
87 myShape = shell;
88 myShell = shell;
89 myNbShells =0;
90}
91
92//=======================================================================
93//function : Perform
94//purpose :
95//=======================================================================
96
b485ee79 97Standard_Boolean ShapeFix_Shell::Perform(const Handle(Message_ProgressIndicator)& theProgress)
7fd59977 98{
99 Standard_Boolean status = Standard_False;
b485ee79
KD
100 if ( Context().IsNull() )
101 SetContext(new ShapeBuild_ReShape);
7fd59977 102 myFixFace->SetContext(Context());
b485ee79
KD
103
104 if ( NeedFix(myFixFaceMode) )
105 {
106 TopoDS_Shape S = Context()->Apply(myShell);
107
108 // Get the number of faces for progress indication
109 Standard_Integer aNbFaces = 0;
110 for ( TopExp_Explorer aFaceExp(S, TopAbs_FACE); aFaceExp.More(); aFaceExp.Next() )
111 ++aNbFaces;
112
113 // Start progress scope (no need to check if progress exists -- it is safe)
114 Message_ProgressSentry aPSentry(theProgress, "Fixing face", 0, aNbFaces, 1);
115
116 for( TopoDS_Iterator iter(S); iter.More() && aPSentry.More(); iter.Next(), aPSentry.Next() )
117 {
7fd59977 118 TopoDS_Shape sh = iter.Value();
119 TopoDS_Face tmpFace = TopoDS::Face(sh);
120 myFixFace->Init(tmpFace);
b485ee79
KD
121 if ( myFixFace->Perform() )
122 {
123 status = Standard_True;
124 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
7fd59977 125 }
126 }
b485ee79
KD
127
128 // Halt algorithm in case of user's abort
129 if ( !aPSentry.More() )
130 return Standard_False;
7fd59977 131 }
132 TopoDS_Shape newsh = Context()->Apply(myShell);
133 if ( NeedFix ( myFixOrientationMode) )
134 FixFaceOrientation(TopoDS::Shell(newsh));
135 if ( status )
136 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
137 if(Status(ShapeExtend_DONE2))
138 status = Standard_True;
139 return status;
140}
141
142//=======================================================================
143// function : GetFreeEdges
144// purpose :
145//=======================================================================
146static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape,TopTools_MapOfShape& MapEdges)
147{
148 for(TopExp_Explorer aExpF(aShape,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
149 for(TopExp_Explorer aExpE(aExpF.Current(),TopAbs_EDGE); aExpE.More(); aExpE.Next()) {
150 TopoDS_Edge edge = TopoDS::Edge(aExpE.Current());
151 if(!MapEdges.Contains(edge))
152 MapEdges.Add(edge);
153 else MapEdges.Remove(edge);
154 }
155 }
156 return (MapEdges.Extent());
157}
158//=======================================================================
159// function : GetShells
160// purpose : If mode isMultiConnex = Standard_True gets max possible shell for
161// exception of multiconnexity parts.
162// Else if this mode is equal to Standard_False maximum possible
163// shell will be created without taking account of multiconnexity.
164// In this function map face - shell and sequence of mebius faces is formed.
165//=======================================================================
166static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface,
167 const TopTools_MapOfShape& aMapMultiConnectEdges,
168 TopTools_SequenceOfShape& aSeqShells,
169 TopTools_DataMapOfShapeShape& aMapFaceShells,
170 TopTools_SequenceOfShape& ErrFaces)
171{
172 Standard_Boolean done = Standard_False;
173 if(!Lface.Length()) return Standard_False;
174 TopoDS_Shell nshell;
175 TopTools_MapOfShape dire, reve;
176 BRep_Builder B;
177 B.MakeShell(nshell);
178 Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty();
179 Standard_Integer i=1, j=1;
180 TopTools_SequenceOfShape aSeqUnconnectFaces;
181 for( ; i<=Lface.Length(); i++) {
182 TopTools_MapOfShape dtemp, rtemp;
183 Standard_Integer nbbe=0, nbe = 0;
184 TopoDS_Face F1 = TopoDS::Face(Lface.Value(i));
185 for(TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) {
186 TopoDS_Edge edge = TopoDS::Edge(expe.Current());
187
188 // if multiconnexity mode is equal to Standard_True faces contains
189 // the same multiconnexity edges are not added to one shell.
190 if(isMultiConnex && aMapMultiConnectEdges.Contains(edge))
191 continue;
192
193 if((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge))
194 || (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge)))
195 nbbe++;
196 else if((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge))
197 || (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge)))
198 nbe++;
199
200 if(dire.Contains(edge)) dire.Remove(edge);
201 else
202 if(reve.Contains(edge)) reve.Remove(edge);
203 else {
204 if(edge.Orientation() == TopAbs_FORWARD) dtemp.Add(edge);
205 if(edge.Orientation() == TopAbs_REVERSED) rtemp.Add(edge);
206 }
207 }
208 if(!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty())
209 continue;
210
211 // if face can not be added to shell it added to sequence of error faces.
212
213 if( nbe != 0 && nbbe != 0) {
214 ErrFaces.Append(F1);
215 Lface.Remove(i);
216 j++;
217 continue;
218 }
219
220 // Addition of face to shell. In the dependance of orientation faces in the shell
221 // added face can be reversed.
222
223 if((nbe != 0 || nbbe != 0) || j == 1) {
224 if(nbbe != 0) {
225 F1.Reverse();
226 for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
227 reve.Add(ite.Key());
228 for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
229 dire.Add(ite1.Key());
230 done = Standard_True;
231 }
232 else {
233 for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
234 dire.Add(ite.Key());
235 for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
236 reve.Add(ite1.Key());
237 }
238 j++;
239 B.Add(nshell,F1);
240 aMapFaceShells.Bind(F1,nshell);
241 Lface.Remove(i);
242
243 // if closed shell is obtained it adds to sequence of shells and new shell begin to construct.
244 if(isMultiConnex && BRep_Tool::IsClosed(nshell)) {
245 aSeqShells.Append(nshell);
246 TopoDS_Shell nshellnext;
247 B.MakeShell(nshellnext);
248 nshell = nshellnext;
249 j=1;
250 }
251
252 i=0;
253 }
254 //if shell contains of one face. This face is added to sequence of faces.
255 // This shell is removed.
256 if(Lface.Length() && i == Lface.Length() && j <=2) {
257 TopoDS_Iterator aItf(nshell,Standard_False);
258 if(aItf.More()) {
259 aSeqUnconnectFaces.Append(aItf.Value());
260 aMapFaceShells.UnBind(aItf.Value());
261 }
262 TopoDS_Shell nshellnext;
263 B.MakeShell(nshellnext);
264 nshell = nshellnext;
265 i=0;
266 j=1;
267 }
268 }
269 Standard_Boolean isContains = Standard_False;
270 for(Standard_Integer k =1 ; k <= aSeqShells.Length() && !isContains; k++)
271 isContains = nshell.IsSame(aSeqShells.Value(k));
272 if(!isContains) {
273 Standard_Integer numFace =0;
274 TopoDS_Shape aFace;
275 for(TopoDS_Iterator aItf(nshell,Standard_False) ; aItf.More(); aItf.Next()) {
276 aFace = aItf.Value();
277 numFace++;
278 }
279 if(numFace >1)
280 aSeqShells.Append(nshell);
281 else if(numFace == 1) {
282 if(aMapFaceShells.IsBound(aFace))
283 aMapFaceShells.UnBind(aFace);
284 Lface.Append(aFace);
285 }
286 }
287
288 //Sequence of faces Lface contains faces which can not be added to obtained shells.
289 for(Standard_Integer j1 =1; j1 <= aSeqUnconnectFaces.Length(); j1++) {
290 Lface.Append(aSeqUnconnectFaces);
291 }
292
293 return done;
294}
295//=======================================================================
296// function : AddMultiConexityFaces
297// purpose : In this function faces have only of multiconnexity boundary
298// are added to shells having free boundary contains the same
299// multiconnexity edges as faces.
300//=======================================================================
301static Standard_Boolean AddMultiConexityFaces(TopTools_SequenceOfShape& Lface,
302 const TopTools_MapOfShape& aMapMultiConnectEdges,
303 TopTools_SequenceOfShape& SeqShells,
304 const TopTools_DataMapOfShapeShape& aMapFaceShells,
305 const TopTools_IndexedDataMapOfShapeListOfShape& aMapEdgeFaces,
306 TopTools_SequenceOfShape& ErrFaces,
307 const Standard_Boolean NonManifold)
308{
309 Standard_Boolean done = Standard_False;
310// BRep_Builder aB;
311 TopTools_SequenceOfShape llPosibleShells;
312 TopTools_SequenceOfShape AddShapes;
313 for(Standard_Integer i1 = 1 ; i1<=Lface.Length();i1++ ) {
314
315 TopoDS_Shape aShape = Lface.Value(i1);
316
317 Standard_Integer aNbMultEdges =0;
318
319 //Finds faces having only multiconnexity boundary.
320 for(TopoDS_Iterator aItWires(aShape,Standard_False); aItWires.More(); aItWires.Next()) {
321 Standard_Integer aNbEdges =0;
322 for(TopoDS_Iterator aItEdges(aItWires.Value(),Standard_False); aItEdges.More(); aItEdges.Next(),aNbEdges++) {
323 TopoDS_Shape edge = aItEdges.Value();
324 if(!aMapMultiConnectEdges.Contains(edge)) continue;
325 aNbMultEdges++;
326 }
327 if(!aNbMultEdges) continue;
328
329 if(aNbMultEdges == aNbEdges)
330 AddShapes.Append(aShape);
331 else llPosibleShells.Append(aShape);
332 }
333 }
334
335 // Attemp to create shell from unconnected which have not only multiconnexity boundary.
336 TopTools_SequenceOfShape aTmpShells;
337 if(!llPosibleShells.IsEmpty()) {
338 TopTools_MapOfShape aMap;
339 TopTools_SequenceOfShape aTmp;
340 TopTools_DataMapOfShapeShape aTmpFaceShell;
341 if(GetShells(llPosibleShells,aMap,aTmpShells,aTmpFaceShell,aTmp)) {
342 for(Standard_Integer kk =1; kk <= aTmpShells.Length(); kk++) {
343 TopoDS_Shape aSh = aTmpShells.Value(kk);
344 TopTools_MapOfShape mapEdges;
345 if(GetFreeEdges(aSh,mapEdges)) {
346 Standard_Integer nbedge =0;
347 for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
348 if( aMapMultiConnectEdges.Contains(amapIter.Key()))
349 nbedge++;
350 }
351 if(nbedge && nbedge == mapEdges.Extent())
352 AddShapes.Append(aSh);
353 }
354 }
355 }
356 }
357
358 //Add choosen faces to shells.
359 for(Standard_Integer k1 =1; k1 <= AddShapes.Length(); k1++) {
360 TopTools_DataMapOfShapeInteger MapOtherShells;
361 TopTools_MapOfShape dire,reve;
362 TopoDS_Shape aSh = AddShapes.Value(k1);
363 TopTools_MapOfShape mapEdges;
364 if(!GetFreeEdges(aSh,mapEdges)) continue;
365 TopTools_ListOfShape lfaces;
366
367 //Fill MapOtherShells which will contain shells with orientation in which selected shape aSh will be add.
368
369 for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
370 if(!aMapMultiConnectEdges.Contains(amapIter.Key())) continue;
371 TopoDS_Edge edge = TopoDS::Edge(amapIter.Key());
372 if( edge.Orientation() == TopAbs_FORWARD) dire.Add(edge);
373 else reve.Add(edge);
374 TopTools_ListOfShape lf;
375 lf = aMapEdgeFaces.FindFromKey(edge);
376 lfaces.Append(lf);
377 }
378 for(TopTools_ListIteratorOfListOfShape aItl(lfaces) ; aItl.More(); aItl.Next()) {
379 TopoDS_Shape aF = aItl.Value();
380 if(!aMapFaceShells.IsBound( aF)) continue;
381
382 TopoDS_Shape aOthershell;
383 aOthershell = aMapFaceShells.Find(aF);
384 if(MapOtherShells.IsBound(aOthershell)) continue;
385 if(!NonManifold && BRep_Tool::IsClosed(aOthershell))
386 continue;
387
388 TopTools_MapOfShape mapShellEdges;
389 GetFreeEdges(aOthershell,mapShellEdges);
390 Standard_Boolean isAdd = Standard_True;
391 for(TopTools_MapIteratorOfMapOfShape amapIter1(mapEdges);amapIter1.More() && isAdd ; amapIter1.Next())
392 isAdd = mapShellEdges.Contains(amapIter1.Key());
393
394 if(!isAdd) continue;
395 Standard_Integer nbdir =0, nbrev=0;
396
397 //add only free face whome all edges contains in the shell as open boundary.
398 for(TopTools_MapIteratorOfMapOfShape aIte( mapShellEdges);aIte.More() ;aIte.Next()) {
399 TopoDS_Edge edgeS = TopoDS::Edge(aIte.Key());
400 if(!aMapMultiConnectEdges.Contains(edgeS)) continue;
401 if( (edgeS.Orientation() == TopAbs_FORWARD && dire.Contains(edgeS)) || (edgeS.Orientation() == TopAbs_REVERSED && reve.Contains(edgeS))) nbrev++;
402 else if((edgeS.Orientation() == TopAbs_FORWARD && reve.Contains(edgeS))
403 || (edgeS.Orientation() == TopAbs_REVERSED && dire.Contains(edgeS))) nbdir++;
404 }
405 if(nbdir && nbrev) {
406 ErrFaces.Append(aSh);
407 continue;
408 }
409 if(nbdir || nbrev) {
410 Standard_Integer isReverse =(nbrev ? 1: 0);
411 MapOtherShells.Bind(aOthershell,isReverse);
412 }
413
414 }
415 if(MapOtherShells.IsEmpty()) {
416// i1++;
417 continue;
418 }
419
420 //Adds face to open shells containg the same multishared edges.
421 //For nonmanifold mode creation ine shell from face and shells containing the same multishared edges.
422 // If one face can be added to a few shells (case of compsolid) face will be added to each shell.
423 done = Standard_True;
424 Standard_Integer FirstRev = 0,FirstInd =0;
425 Standard_Integer ind =0;
426 for(Standard_Integer l =1; l <= SeqShells.Length(); l++) {
427 if(!MapOtherShells.IsBound(SeqShells.Value(l))) continue;
428 ind++;
429 Standard_Integer isRev = MapOtherShells.Find(SeqShells.Value(l));
430 TopoDS_Shape anewShape = (isRev ? aSh.Reversed() :aSh);
431
432 BRep_Builder aB1;
433 TopoDS_Shape aShell = SeqShells.Value(l);
434 if(ind ==1 || !NonManifold) {
435 if(ind ==1) {
436 FirstRev = isRev;
437 FirstInd = l;
438 }
439 for(TopExp_Explorer aE(anewShape,TopAbs_FACE); aE.More(); aE.Next())
440 aB1.Add(aShell,aE.Current());
441 SeqShells.ChangeValue(l) = aShell;
442 }
443 else if(NonManifold) {
444 Standard_Boolean isReversed = !((!(isRev) && !FirstRev) || ((isRev) && FirstRev));
445 aShell = SeqShells.Value(FirstInd);
446 for(TopoDS_Iterator aItF(SeqShells.Value(l),Standard_False); aItF.More(); aItF.Next()) {
447 TopoDS_Shape nF = ( isReversed ? aItF.Value().Reversed() : aItF.Value());
448 aB1.Add(aShell,nF);
449 }
450 SeqShells.ChangeValue(FirstInd) = aShell;
451 SeqShells.Remove(l--);
452 }
453 }
454
455 dire.Clear();
456 reve.Clear();
457 for(TopExp_Explorer aEt(aSh,TopAbs_FACE); aEt.More(); aEt.Next()) {
458 for(Standard_Integer kk =1 ; kk <= Lface.Length(); kk++) {
459 if(aEt.Current().IsSame(Lface.Value(kk)))
460 Lface.Remove(kk--);
461 }
462 }
463 }
464 return done;
465}
466
467//=======================================================================
468// function : BoxIn
469// purpose : Check if one face contains inside other.
470//=======================================================================
471static Standard_Integer BoxIn(const Bnd_Box& theBox1,const Bnd_Box& theBox2)
472{
473 Standard_Integer aNumIn = 0;
474 Standard_Real aXmin1,aYmin1,aXmax1,aYmax1,aXmin2,aYmin2,aXmax2,aYmax2,aZmin1,aZmax1,aZmin2,aZmax2;
475 theBox1.Get(aXmin1,aYmin1,aZmin1,aXmax1,aYmax1,aZmax1);
476 theBox2.Get(aXmin2,aYmin2,aZmin2,aXmax2,aYmax2,aZmax2);
477 if(aXmin1 == aXmin2 && aXmax1 == aXmax2 && aYmin1 == aYmin2 && aYmax1 == aYmax2 &&
478 aZmin1 == aZmin2 && aZmax1 == aZmax2)
479 aNumIn = 0;
480 else if( aXmin1 >= aXmin2 && aXmax1 <= aXmax2 && aYmin1 >= aYmin2 && aYmax1 <= aYmax2 &&
481 aZmin1 >= aZmin2 && aZmax1 <= aZmax2)
482 aNumIn = 1;
483 else if( aXmin1 <= aXmin2 && aXmax1 >= aXmax2 && aYmin1 <= aYmin2 && aYmax1 >= aYmax2 && aZmin1 <= aZmin2 && aZmax1 >= aZmax2)
484 aNumIn = 2;
485 return aNumIn;
486}
487//=======================================================================
488// function : GetClosedShells
489// purpose : Check if one shell is a part from other shell.
490// For case of compsolid when afew shells are created from
491// the same set of faces.
492//=======================================================================
493static void GetClosedShells(TopTools_SequenceOfShape& Shells, TopTools_SequenceOfShape& aRemainShells)
494{
495 Bnd_Array1OfBox aBoxes(1,Shells.Length());
496 for(Standard_Integer i =1; i <= Shells.Length(); i++) {
497 Bnd_Box Box;
498 BRepBndLib::AddClose(Shells.Value(i),Box);
499 aBoxes.SetValue(i,Box);
500 }
501 TColStd_MapOfInteger aMapNum;
502 for(Standard_Integer j = 1; j <= aBoxes.Length(); j++) {
503 for(Standard_Integer k = j+1; k <= aBoxes.Length(); k++) {
504 Standard_Integer NumIn = BoxIn(aBoxes.Value(j),aBoxes.Value(k));
505 switch(NumIn) {
506 case 1:aMapNum.Add(k); break;
507 case 2: aMapNum.Add(j); break;
508 default : break;
509 }
510 }
511 }
512 for(Standard_Integer i1 =1; i1 <= Shells.Length(); i1++) {
513 if(!aMapNum.Contains(i1))
514 aRemainShells.Append(Shells.Value(i1));
515 }
516
517}
518//=======================================================================
519// function : GlueClosedCandidate
520// purpose :Attemt firstly to create closed shells from sequence of open shells.
521//=======================================================================
522static void GlueClosedCandidate(TopTools_SequenceOfShape& OpenShells,
523 const TopTools_MapOfShape& aMapMultiConnectEdges,
524 TopTools_SequenceOfShape& aSeqNewShells)
525
526{
527 // Creating new shells if some open shells contain the same free boundary.
528 for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
529 TopoDS_Shape aShell = OpenShells.Value(i);
530 TopTools_MapOfShape mapEdges1;
531 TopTools_MapOfShape dire,reve;
532 if(!GetFreeEdges(aShell,mapEdges1)) continue;
533
534 for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
535 TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
536 if(!aMapMultiConnectEdges.Contains(edge1)) break;
537 if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
538 else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
539 }
540 if(mapEdges1.Extent() >(dire.Extent() + reve.Extent())) continue;
541
542 //Filling map MapOtherShells which contains candidate to creation of closed shell
543 // with aShell.
544
545 TopTools_DataMapOfShapeInteger MapOtherShells;
546
547 for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
548 Standard_Boolean isAddShell = Standard_True;
549 Standard_Boolean isReversed = Standard_False;
550 Standard_Integer nbedge =0;
551 TopTools_MapOfShape mapEdges2;
552 TopoDS_Shape aShell2 = OpenShells.Value(j);
553 if(!GetFreeEdges(aShell2,mapEdges2)) continue;
554 for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() && isAddShell;aIte2.Next()) {
555 TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
556 if(!aMapMultiConnectEdges.Contains(edge2)) {
557 isAddShell = Standard_False;
558 break;
559 //continue;
560 }
561 isAddShell = (dire.Contains(edge2) || reve.Contains(edge2));
562 if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
563 || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
564 isReversed = Standard_True;
565 nbedge++;
566 }
567
568 if(!isAddShell) continue;
569 MapOtherShells.Bind(OpenShells.Value(j),isReversed);
570 }
571 if(!MapOtherShells.Extent()) continue;
572
573
574 if(MapOtherShells.Extent() >1) {
575
576 // Case of compsolid when more than two shells have the same free boundary.
577 TopTools_SequenceOfShape aSeqCandidate;
578 aSeqCandidate.Append(OpenShells.Value(i));
579
580 for(TopTools_DataMapIteratorOfDataMapOfShapeInteger aIt(MapOtherShells); aIt.More(); aIt.Next())
581 aSeqCandidate.Append(aIt.Key());
582
583 //Creation all possibly shells from choosen candidate.And
584 // addition of them to temporary sequence.
585
586 TopTools_SequenceOfShape aTmpSeq;
587 for(Standard_Integer k =1; k <= aSeqCandidate.Length(); k++) {
588
589 for(Standard_Integer l = k+1; l <= aSeqCandidate.Length(); l++) {
590 TopoDS_Shell aNewSh;
591 BRep_Builder aB;
592 aB.MakeShell(aNewSh);
593 for(TopoDS_Iterator aIt1(aSeqCandidate.Value(k),Standard_False); aIt1.More(); aIt1.Next())
594 aB.Add(aNewSh,aIt1.Value());
595 Standard_Integer isRev = MapOtherShells.Find(aSeqCandidate.Value(l));
596 if(k !=1) {
597 isRev = ((isRev == MapOtherShells.Find(aSeqCandidate.Value(k))) ? 1 : 0);
598 }
599 for(TopExp_Explorer aExp(aSeqCandidate.Value(l),TopAbs_FACE); aExp.More(); aExp.Next()) {
600 TopoDS_Shape aFace = (isRev ? aExp.Current().Reversed(): aExp.Current());
601 aB.Add(aNewSh,aFace);
602 }
603 aTmpSeq.Append(aNewSh);
604 }
605 }
606
607 //Choice from temporary sequence shells contains different set of faces (case of compsolid)
608 TopTools_SequenceOfShape aRemainShells;
609 GetClosedShells(aTmpSeq,aRemainShells);
610 aSeqNewShells.Append(aRemainShells);
611
612 for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ ) {
613 if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
614 OpenShells.Remove(j1--);
615 }
616
617 }
618 else {
619 BRep_Builder aB;
620 TopoDS_Shape aNewShell = aShell;
621 TopoDS_Shape addShell;
622 Standard_Boolean isReversed = Standard_False;
623 for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ ) {
624 if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
625 addShell = OpenShells.Value(j1);
626 isReversed = MapOtherShells.Find(addShell);
627 OpenShells.Remove(j1);
628 break;
629 }
630
631 for(TopExp_Explorer aExpF(addShell,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
632 TopoDS_Shape aFace = aExpF.Current();
633 if(isReversed)
634 aFace.Reverse();
635 aB.Add(aNewShell,aFace);
636 }
637 aSeqNewShells.Append(aNewShell);
638 }
639
640 //OpenShells.ChangeValue(i) = aShell;
641 OpenShells.Remove(i--);
642 }
643}
644//=======================================================================
645// function : CreateNonManifoldShells
646// purpose : Attempt to create max possible shells from open shells.
647//=======================================================================
648
649static void CreateNonManifoldShells(TopTools_SequenceOfShape& SeqShells,
650 const TopTools_MapOfShape& aMapMultiConnectEdges)
651{
652 TopTools_IndexedDataMapOfShapeListOfShape aMap;
653 for(Standard_Integer i =1 ; i <= SeqShells.Length(); i++) {
654 TopoDS_Shape aShell = SeqShells.Value(i);
655 TopTools_IndexedMapOfShape medeg;
656 TopExp::MapShapes(aShell,TopAbs_EDGE,medeg);
657 for(TopTools_MapIteratorOfMapOfShape mit(aMapMultiConnectEdges); mit.More(); mit.Next()) {
658 //for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) {
659 //TopoDS_Shape ae = aExp.Current();
660 TopoDS_Shape ae =mit.Key();
661 //if( aMapMultiConnectEdges.Contains(aExp.Current())) {
662 if(medeg.Contains(ae)) {
663 if(aMap.Contains(ae))
664 aMap.ChangeFromKey(ae).Append(aShell);
665 else {
666 TopTools_ListOfShape al;
667 al.Append(aShell);
668 aMap.Add(ae,al);
669 }
670 }
671 }
672 }
673 TopTools_IndexedDataMapOfShapeShape aMapShells;
674 for(Standard_Integer j =1; j <= aMap.Extent(); j++) {
675 const TopTools_ListOfShape& LShells = aMap.FindFromIndex(j);
676 TopoDS_Shell aNewShell;
677 BRep_Builder aB;
678 aB.MakeShell(aNewShell);
679 TopTools_MapOfShape mapmerge;
680 Standard_Boolean ismerged = Standard_False;
681 Standard_Integer num = 1;
682 for(TopTools_ListIteratorOfListOfShape alit(LShells); alit.More();alit.Next(),num++) {
683 if(!aMapShells.Contains(alit.Value())) {
684 for(TopExp_Explorer aEf(alit.Value(),TopAbs_FACE); aEf.More(); aEf.Next()) {
685 aB.Add(aNewShell,aEf.Current());
686 }
687 ismerged = Standard_True;
688 mapmerge.Add(alit.Value());
689 }
690 else if(ismerged) {
691 TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
692 while(aMapShells.Contains(arshell)){
693 TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
694 if(ss.IsSame(arshell)) break;
695 arshell = ss;
696 }
697
698 if(!mapmerge.Contains(arshell)) {
699 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
700 aB.Add(aNewShell,aEf.Current());
701 }
702 mapmerge.Add(arshell);
703 }
704 }
705 else {
706 TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
707 while(aMapShells.Contains(arshell)) {
708 TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
709 if(ss.IsSame(arshell)) break;
710 arshell = ss;
711 }
712 if(num == 1) {
713 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next())
714 aB.Add(aNewShell,aEf.Current());
715
716 mapmerge.Add(arshell);
717 }
718 else if(!mapmerge.Contains(arshell)) {
719 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
720 aB.Add(aNewShell,aEf.Current());
721 }
722 mapmerge.Add(arshell);
723 }
724 }
725 }
726 if(mapmerge.Extent() >1 || ismerged) {
727 for(TopTools_MapIteratorOfMapOfShape alit1(mapmerge); alit1.More();alit1.Next()) {
728 TopoDS_Shape oldShell = alit1.Key();
729 //while(aMapShells.Contains(oldShell)) {
730 // TopoDS_Shape ss = aMapShells.FindFromKey(oldShell);
731 // if(ss.IsSame(oldShell)) break;
732 // oldShell = ss;
733 //}
734 aMapShells.Add(oldShell,aNewShell);
735 }
736 }
737 }
738 TopTools_IndexedMapOfShape MapNewShells;
739 for(Standard_Integer nn = 1;nn <= SeqShells.Length(); nn++) {
740 if(aMapShells.Contains(SeqShells.Value(nn))) {
741 TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn));
742 while(aMapShells.Contains(aNewShell)) {
743 TopoDS_Shape ss = aMapShells.FindFromKey(aNewShell);
744 if(ss.IsSame(aNewShell)) break;
745 aNewShell = ss;
746 }
747 MapNewShells.Add(aNewShell);
748
749 SeqShells.Remove(nn--);
750 }
751
752 }
753 for(Standard_Integer ii =1; ii <= MapNewShells.Extent(); ii++)
754 SeqShells.Append(MapNewShells.FindKey(ii));
755}
756//=======================================================================
757// function : CreateClosedShell
758// purpose : Attempt to create max possible shells from open shells.
759//=======================================================================
760
761static void CreateClosedShell(TopTools_SequenceOfShape& OpenShells,
762 const TopTools_MapOfShape& aMapMultiConnectEdges)
763{
764 TopTools_SequenceOfShape aNewShells;
765 //Attemt firstly to create closed shells.
766 GlueClosedCandidate(OpenShells,aMapMultiConnectEdges,aNewShells);
767
768 // Creating new shells if some open shells contain the multishared same edges.
769 for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
770 Standard_Boolean isAddShell = Standard_False;
771 TopoDS_Shape aShell = OpenShells.Value(i);
772 Standard_Boolean isReversed = Standard_False;
773 for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
774 TopTools_MapOfShape mapEdges1;
775 TopTools_MapOfShape dire,reve;
776 if(!GetFreeEdges(aShell,mapEdges1)) break;
777 for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
778 TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
779 if(!aMapMultiConnectEdges.Contains(edge1)) continue;
780 if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
781 else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
782 }
783 if(dire.IsEmpty() && reve.IsEmpty()) break;
784 TopTools_MapOfShape mapEdges2;
785 TopoDS_Shape aShell2 = OpenShells.Value(j);
786 if(!GetFreeEdges(aShell2,mapEdges2)) continue;
787 for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() ;aIte2.Next()) {
788 TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
789 if(!aMapMultiConnectEdges.Contains(edge2)) continue;
790 if(!dire.Contains(edge2) && !reve.Contains(edge2)) continue;
791 isAddShell = Standard_True;
792 if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
793 || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
794 isReversed = Standard_True;
795 }
796
797 if(!isAddShell) continue;
798 BRep_Builder aB;
799
800 for(TopExp_Explorer aExpF21(OpenShells.Value(j),TopAbs_FACE); aExpF21.More(); aExpF21.Next()) {
801 TopoDS_Shape aFace = aExpF21.Current();
802 if(isReversed)
803 aFace.Reverse();
804 aB.Add( aShell,aFace);
805 }
806
807 OpenShells.ChangeValue(i) = aShell;
808 OpenShells.Remove(j--);
809 }
810 }
811
812 OpenShells.Append(aNewShells);
813
814}
815
816
817//=======================================================================
818// function : FixFaceOrientation
819// purpose :
820//=======================================================================
821
822Standard_Boolean ShapeFix_Shell::FixFaceOrientation(const TopoDS_Shell& shell,const Standard_Boolean isAccountMultiConex,const Standard_Boolean NonManifold)
823{
824 //myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
825 Standard_Boolean done = Standard_False;
826 TopTools_SequenceOfShape aSeqShells;
827 TopTools_SequenceOfShape aErrFaces; // Compound of faces like to Mebiuce leaf.
828 TopTools_SequenceOfShape Lface;
829 TopTools_DataMapOfShapeShape aMapFaceShells;
830 myShell = shell;
831 myShape = shell;
832 Standard_Integer aNumMultShell =0;
833 for (TopoDS_Iterator iter(shell); iter.More(); iter.Next())
834 Lface.Append(iter.Value());
835 TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
836 TopExp::MapShapesAndAncestors(myShell,TopAbs_EDGE,TopAbs_FACE,aMapEdgeFaces);
837 TopTools_MapOfShape aMapMultiConnectEdges;
838 if(isAccountMultiConex) {
839 //Finds multishared edges
840 for(Standard_Integer k = 1; k <= aMapEdgeFaces.Extent(); k++) {
841 if(aMapEdgeFaces.FindFromIndex(k).Extent() >2)
842 aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k));
843 }
844 }
845 Standard_Boolean isGetShells = Standard_True;
846 //Gets possible shells with taking in account of multiconnexity.
847 while(isGetShells && Lface.Length()) {
848 TopTools_SequenceOfShape aTmpSeqShells;
849 if(GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells,aMapFaceShells,aErrFaces)) {
850 done = Standard_True;
851 }
852 isGetShells = !aTmpSeqShells.IsEmpty();
853 if(isGetShells)
854 aSeqShells.Append(aTmpSeqShells);
855 }
856 if(!done)
857 done = (aSeqShells.Length() >1);
858 Standard_Boolean aIsDone = Standard_False;
859 if(Lface.Length() > 0 && aSeqShells.Length()) {
860 for(Standard_Integer jj =1; jj <= Lface.Length(); jj++) {
861 if(aMapFaceShells.IsBound(Lface.Value(jj)))
862 aMapFaceShells.UnBind(Lface.Value(jj));
863 }
864
865 //Addition of faces having only multiconnexity boundary to shells having holes
866 // containing only the multiconnexity edges
867 aIsDone = AddMultiConexityFaces(Lface,aMapMultiConnectEdges,aSeqShells,aMapFaceShells,
868 aMapEdgeFaces,aErrFaces,NonManifold);
869 }
870 aNumMultShell = aSeqShells.Length();
871 if (!aErrFaces.IsEmpty()) {
872
873 //if Shell contains of Mebius faces one shell will be created from each those face.
874 BRep_Builder B;
875 B.MakeCompound(myErrFaces);
876 TopoDS_Compound aCompShells;
877 B.MakeCompound(aCompShells);
878 for(Standard_Integer n =1; n <= aErrFaces.Length(); n++)
879 B.Add(myErrFaces,aErrFaces.Value(n));
880 if(aNumMultShell) {
881 if(aNumMultShell == 1) {
882 B.Add(aCompShells,aSeqShells.Value(1));
883 for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
884 TopoDS_Shell aSh;
885 B.MakeShell(aSh);
886 B.Add(aSh,aErrFaces.Value(n1));
887 B.Add(aCompShells,aSh);
888 }
889 myShape = aCompShells;
890 }
891 else {
892 for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
893 B.Add(aCompShells,aSeqShells.Value(i));
894 for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
895 TopoDS_Shell aSh;
896 B.MakeShell(aSh);
897 B.Add(aSh,aErrFaces.Value(n1));
898 B.Add(aCompShells,aSh);
899 }
900 myShape = aCompShells;
901 }
902 }
903
904 done = Standard_True;
905 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL);
906 SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG20"));//Faces were incorrectly oriented in the shell, a few shells were created;
907 return Standard_True;
908 }
909 if(aNumMultShell >1) {
910 TopTools_SequenceOfShape OpenShells;
911 for(Standard_Integer i1 =1; i1 <= aSeqShells.Length(); i1++) {
912 TopoDS_Shape aShell = aSeqShells.Value(i1);
913 if(!BRep_Tool::IsClosed(aShell)) {
914 OpenShells.Append(aShell);
915 aSeqShells.Remove(i1--);
916 }
917 }
918 if(OpenShells.Length() >1)
919 //Attempt of creation closed shell from open shells with taking into account multiconnexity.
920 CreateClosedShell(OpenShells,aMapMultiConnectEdges);
921 aSeqShells.Append(OpenShells);
922
923 }
924
925 // In the case if NonManifold is equal to Standard_True one non-manifold shell will be created.
926 //Else compound from shells will be created if length of sequence of shape >1.
927 if(Lface.Length()) {
928
929 for(Standard_Integer i = 1; i <= Lface.Length();i++) {
930 BRep_Builder aB;
931 TopoDS_Shell OneShell;
932 aB.MakeShell(OneShell);
933 aB.Add(OneShell, Lface.Value(i));
934 aSeqShells.Append(OneShell);
935 }
936
937 }
938 if(NonManifold && aSeqShells.Length() >1 ) {
939 CreateNonManifoldShells(aSeqShells,aMapMultiConnectEdges);
940 }
941 if(!done)
942 done = (aSeqShells.Length() >1 || aIsDone);
943 if(aSeqShells.Length() == 1) {
944 myShell = TopoDS::Shell(aSeqShells.Value(1));
945 myShape =myShell;
946 myNbShells =1;
947 }
948 else {
949 BRep_Builder B;
950 TopoDS_Compound aCompShells;
951 B.MakeCompound(aCompShells);
952 for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
953 B.Add(aCompShells,aSeqShells.Value(i));
954 myShape = aCompShells;
955 myNbShells = aSeqShells.Length();
956 }
957 if(done) {
958 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
959 if(!Context().IsNull())
960 Context()->Replace(shell, myShape);
961 if( myNbShells == 1)
962 SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG0"));//Faces were incorrectly oriented in the shell, corrected
963 else
964 SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG30"));//Bad connected shell ,a few shells were created.
965 return Standard_True;
966 }
967 else return Standard_False;
968}
969
970//=======================================================================
971//function : Status
972//purpose :
973//=======================================================================
974
975Standard_Boolean ShapeFix_Shell::Status(const ShapeExtend_Status status) const
976{
977 return ShapeExtend::DecodeStatus (myStatus, status);
978}
979
980//=======================================================================
981//function : Shell
982//purpose :
983//=======================================================================
984
985TopoDS_Shell ShapeFix_Shell::Shell()
986{
987 return myShell;
988}
989//=======================================================================
990//function : Shell
991//purpose :
992//=======================================================================
993
994TopoDS_Shape ShapeFix_Shell::Shape()
995{
996 return myShape;
997}
998
999//=======================================================================
1000//function : ErrorFaces
1001//purpose :
1002//=======================================================================
1003
1004TopoDS_Compound ShapeFix_Shell::ErrorFaces() const
1005{
1006 return myErrFaces;
1007}
1008
1009//=======================================================================
1010//function : SetMsgRegistrator
1011//purpose :
1012//=======================================================================
1013
1014void ShapeFix_Shell::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
1015{
1016 ShapeFix_Root::SetMsgRegistrator ( msgreg );
1017 myFixFace->SetMsgRegistrator ( msgreg );
1018}
1019
1020//=======================================================================
1021//function : SetPrecision
1022//purpose :
1023//=======================================================================
1024
1025void ShapeFix_Shell::SetPrecision (const Standard_Real preci)
1026{
1027 ShapeFix_Root::SetPrecision ( preci );
1028 myFixFace->SetPrecision ( preci );
1029}
1030
1031//=======================================================================
1032//function : SetMinTolerance
1033//purpose :
1034//=======================================================================
1035
1036void ShapeFix_Shell::SetMinTolerance (const Standard_Real mintol)
1037{
1038 ShapeFix_Root::SetMinTolerance ( mintol );
1039 myFixFace->SetMinTolerance ( mintol );
1040}
1041
1042//=======================================================================
1043//function : SetMaxTolerance
1044//purpose :
1045//=======================================================================
1046
1047void ShapeFix_Shell::SetMaxTolerance (const Standard_Real maxtol)
1048{
1049 ShapeFix_Root::SetMaxTolerance ( maxtol );
1050 myFixFace->SetMaxTolerance ( maxtol );
1051}
1052//=======================================================================
1053//function : NbShells
1054//purpose :
1055//=======================================================================
1056
1057Standard_Integer ShapeFix_Shell::NbShells() const
1058{
1059 return myNbShells;
1060}