1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
15 #include <Bnd_Box2d.hxx>
16 #include <BRep_Builder.hxx>
17 #include <BRep_Tool.hxx>
18 #include <BRepClass3d_SolidClassifier.hxx>
19 #include <Geom_Curve.hxx>
20 #include <Geom_Surface.hxx>
22 #include <Message_Msg.hxx>
23 #include <Message_ProgressIndicator.hxx>
24 #include <Message_ProgressSentry.hxx>
25 #include <Precision.hxx>
26 #include <ShapeAnalysis.hxx>
27 #include <ShapeAnalysis_Curve.hxx>
28 #include <ShapeAnalysis_Edge.hxx>
29 #include <ShapeAnalysis_FreeBounds.hxx>
30 #include <ShapeBuild_ReShape.hxx>
31 #include <ShapeExtend.hxx>
32 #include <ShapeExtend_BasicMsgRegistrator.hxx>
33 #include <ShapeExtend_WireData.hxx>
34 #include <ShapeFix_Shell.hxx>
35 #include <ShapeFix_Solid.hxx>
36 #include <Standard_ErrorHandler.hxx>
37 #include <Standard_Failure.hxx>
38 #include <Standard_Type.hxx>
42 #include <TopoDS_CompSolid.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Iterator.hxx>
45 #include <TopoDS_Shape.hxx>
46 #include <TopoDS_Shell.hxx>
47 #include <TopoDS_Solid.hxx>
48 #include <TopoDS_Vertex.hxx>
49 #include <TopoDS_Wire.hxx>
50 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
51 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
52 #include <TopTools_DataMapOfShapeInteger.hxx>
53 #include <TopTools_DataMapOfShapeListOfShape.hxx>
54 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
55 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
56 #include <TopTools_IndexedMapOfShape.hxx>
57 #include <TopTools_ListIteratorOfListOfShape.hxx>
58 #include <TopTools_ListOfShape.hxx>
59 #include <TopTools_MapIteratorOfMapOfShape.hxx>
60 #include <TopTools_MapOfShape.hxx>
61 #include <TopTools_SequenceOfShape.hxx>
63 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Solid,ShapeFix_Root)
65 //======================================================
66 //function : ShapeFix_Solid
68 //=======================================================================
69 ShapeFix_Solid::ShapeFix_Solid()
71 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
73 myFixShell = new ShapeFix_Shell;
74 myCreateOpenSolidMode = Standard_False;
77 //=======================================================================
78 //function : ShapeFix_Solid
80 //=======================================================================
82 ShapeFix_Solid::ShapeFix_Solid(const TopoDS_Solid& solid)
84 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
86 myFixShell = new ShapeFix_Shell;
87 myCreateOpenSolidMode = Standard_False;
91 //=======================================================================
94 //=======================================================================
96 void ShapeFix_Solid::Init(const TopoDS_Solid& solid)
99 //mySolid = TopoDS::Solid(shape.EmptyCopied());
101 // for( TopoDS_Iterator iter(solid); iter.More(); iter.Next())
102 // B.Add(mySolid,TopoDS::Shell(iter.Value()));
105 #ifdef OCCT_DEBUG_GET_MIDDLE_POINT
106 //=======================================================================
107 //function : GetMiddlePoint
109 //=======================================================================
110 static void GetMiddlePoint(const TopoDS_Shape& aShape, gp_Pnt& pmid)
112 TopExp_Explorer aExp(aShape,TopAbs_EDGE);
113 gp_XYZ center(0.0,0.0,0.0);
114 Standard_Integer numpoints =0;
115 for( ; aExp.More(); aExp.Next()) {
116 TopoDS_Edge e1 = TopoDS::Edge(aExp.Current());
118 Handle(Geom_Curve) c3d = BRep_Tool::Curve(e1,f,l);
120 for(Standard_Integer i =1 ; i <=5; i++) {
121 Standard_Real param = f+(l-f)/4*(i-1);
134 //=======================================================================
135 //function : CollectSolids
137 //=======================================================================
138 static void CollectSolids(const TopTools_SequenceOfShape& aSeqShells ,
139 TopTools_IndexedDataMapOfShapeListOfShape& anIndexedMapShellHoles,
140 TopTools_DataMapOfShapeInteger& theMapStatus)
142 TopTools_MapOfShape aMapHoles;
143 TopTools_DataMapOfShapeListOfShape aMapShellHoles;
144 for ( Standard_Integer i1 = 1; i1 <= aSeqShells.Length(); i1++ ) {
145 TopoDS_Shell aShell1 = TopoDS::Shell(aSeqShells.Value(i1));
146 TopTools_ListOfShape lshells;
147 aMapShellHoles.Bind(aShell1,lshells);
149 //Finds roots shells and hole shells.
150 for ( Standard_Integer i = 1; i <= aSeqShells.Length(); i++ ) {
151 TopoDS_Shell aShell1 = TopoDS::Shell(aSeqShells.Value(i));
152 TopExp_Explorer aExpEdges(aShell1,TopAbs_EDGE);
153 if(!BRep_Tool::IsClosed(aShell1) || !aExpEdges.More()) continue;
157 B.Add (solid,aShell1);
160 TopAbs_State infinstatus = TopAbs_UNKNOWN;
161 BRepClass3d_SolidClassifier bsc3d (solid);
162 Standard_Integer st = 0;
163 if(!theMapStatus.IsBound(aShell1)) {
165 bsc3d.PerformInfinitePoint(Precision::Confusion());
166 infinstatus = bsc3d.State();
168 if(infinstatus != TopAbs_UNKNOWN && infinstatus !=TopAbs_ON)
169 st = (infinstatus == TopAbs_IN ? 1 :2);
170 theMapStatus.Bind(aShell1,st);
175 st = theMapStatus.Find(aShell1);
177 infinstatus = (theMapStatus.Find(aShell1) == 1 ? TopAbs_IN : TopAbs_OUT);
180 for ( Standard_Integer j = 1; j <= aSeqShells.Length(); j++ ) {
182 TopoDS_Shape aShell2 = aSeqShells.Value(j);
183 if(!BRep_Tool::IsClosed(aShell2)) continue;
184 if(aMapHoles.Contains(aShell2)) continue;
185 if(aMapShellHoles.IsBound(aShell2)) {
186 Standard_Boolean isAnalysis = Standard_False;
187 const TopTools_ListOfShape& ls = aMapShellHoles.Find(aShell2);
188 for(TopTools_ListIteratorOfListOfShape li(ls); li.More() && !isAnalysis; li.Next())
189 isAnalysis = li.Value().IsSame(aShell1);
190 if(isAnalysis) continue;
192 TopAbs_State pointstatus = TopAbs_UNKNOWN;
193 Standard_Integer numon =0;
194 TopTools_IndexedMapOfShape amapVert;
195 for(TopExp_Explorer aExpVert(aShell2,TopAbs_VERTEX); aExpVert.More() && amapVert.Extent() < 10; aExpVert.Next())
196 amapVert.Add(aExpVert.Current());
197 for(Standard_Integer k = 1; k <= amapVert.Extent() &&
198 (pointstatus ==TopAbs_UNKNOWN || (pointstatus ==TopAbs_ON && numon < 3)); k++) {
199 TopoDS_Vertex aV = TopoDS::Vertex(amapVert.FindKey(k));
200 gp_Pnt aPf = BRep_Tool::Pnt(aV);
201 bsc3d.Perform(aPf,Precision::Confusion());
202 pointstatus =bsc3d.State();
203 if(pointstatus ==TopAbs_ON) numon++;
206 if(numon == 3 && pointstatus ==TopAbs_ON) {
207 #ifdef OCCT_DEBUG_GET_MIDDLE_POINT
209 GetMiddlePoint(aShell2,pmid);
210 bsc3d.Perform(pmid,Precision::Confusion());
212 pointstatus = /*(bsc3d.State() == TopAbs_IN ? TopAbs_IN :*/TopAbs_OUT;
214 if(pointstatus != infinstatus) {
215 aMapShellHoles.ChangeFind(aShell1).Append(aShell2);
216 if( aMapHoles.Contains(aShell2))
217 aMapHoles.Remove(aShell2);
218 else aMapHoles.Add(aShell2);
222 catch(Standard_Failure const& anException) {
224 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
225 anException.Print(cout); cout << endl;
231 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItShellHoles( aMapShellHoles);
232 for(; aItShellHoles.More();aItShellHoles.Next()) {
233 if(aMapHoles.Contains(aItShellHoles.Key())) continue;
234 const TopTools_ListOfShape& lHoles =aItShellHoles.Value();
235 if(lHoles.IsEmpty()) continue;
236 for(TopTools_ListIteratorOfListOfShape lItHoles(lHoles);lItHoles.More(); lItHoles.Next()) {
237 if(aMapHoles.Contains(lItHoles.Value())) {
238 const TopTools_ListOfShape& lUnHoles = aMapShellHoles.Find(lItHoles.Value());
239 for(TopTools_ListIteratorOfListOfShape lItUnHoles(lUnHoles);lItUnHoles.More(); lItUnHoles.Next())
240 aMapHoles.Remove(lItUnHoles.Value());
244 for(TopTools_MapIteratorOfMapOfShape aIterHoles(aMapHoles);aIterHoles.More(); aIterHoles.Next())
245 aMapShellHoles.UnBind (aIterHoles.Key());
247 for (Standard_Integer i = 1; i <= aSeqShells.Length(); ++i) {
248 const TopoDS_Shape& aShell1 = aSeqShells.Value (i);
249 if (aMapShellHoles.IsBound (aShell1)) {
250 const TopTools_ListOfShape& ls = aMapShellHoles.Find (aShell1);
251 anIndexedMapShellHoles.Add (aShell1, ls);
255 //=======================================================================
256 //function : CreateSolids
258 //=======================================================================
260 static Standard_Boolean CreateSolids(const TopoDS_Shape theShape,TopTools_IndexedMapOfShape& aMapSolids)
262 TopTools_SequenceOfShape aSeqShells;
263 Standard_Boolean isDone = Standard_False;
265 for(TopExp_Explorer aExpShell(theShape,TopAbs_SHELL); aExpShell.More(); aExpShell.Next()) {
266 aSeqShells.Append(aExpShell.Current());
268 TopTools_IndexedDataMapOfShapeListOfShape aMapShellHoles;
269 TopTools_DataMapOfShapeInteger aMapStatus;
270 CollectSolids(aSeqShells,aMapShellHoles,aMapStatus);
271 TopTools_IndexedDataMapOfShapeShape ShellSolid;
272 //Defines correct orientation of shells
273 for (Standard_Integer i = 1; i <= aMapShellHoles.Extent(); ++i) {
274 TopoDS_Shell aShell = TopoDS::Shell(aMapShellHoles.FindKey(i));
275 TopExp_Explorer aExpEdges(aShell,TopAbs_EDGE);
276 if(!BRep_Tool::IsClosed(aShell) || !aExpEdges.More()) {
277 ShellSolid.Add(aShell,aShell);
278 isDone = Standard_True;
282 TopAbs_State infinstatus = TopAbs_UNKNOWN;
284 B.MakeSolid (aSolid);
285 B.Add (aSolid,aShell);
286 if(aMapStatus.IsBound(aShell)) {
287 Standard_Integer st = aMapStatus.Find(aShell);
289 infinstatus = (aMapStatus.Find(aShell) == 1 ? TopAbs_IN : TopAbs_OUT);
296 BRepClass3d_SolidClassifier bsc3d (aSolid);
297 bsc3d.PerformInfinitePoint(Precision::Confusion());
298 infinstatus = bsc3d.State();
300 catch(Standard_Failure const& anException) {
302 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
303 anException.Print(cout); cout << endl;
306 ShellSolid.Add(aShell,aSolid);
310 if (infinstatus == TopAbs_IN) {
311 isDone = Standard_True;
313 TopoDS_Solid aTmpSolid;
314 B.MakeSolid (aTmpSolid);
315 B.Add (aTmpSolid,aShell);
319 const TopTools_ListOfShape& lHoles = aMapShellHoles (i);
320 for(TopTools_ListIteratorOfListOfShape lItHoles(lHoles); lItHoles.More();lItHoles.Next()) {
321 TopoDS_Shell aShellHole = TopoDS::Shell(lItHoles.Value());
322 if(aMapStatus.IsBound(aShellHole)) {
323 infinstatus = (aMapStatus.Find(aShellHole) == 1 ? TopAbs_IN : TopAbs_OUT);
328 B.Add (solid,aShellHole);
329 BRepClass3d_SolidClassifier bsc3dHol (solid);
330 bsc3dHol.PerformInfinitePoint(Precision::Confusion());
331 infinstatus = bsc3dHol.State();
333 if (infinstatus == TopAbs_OUT) {
334 aShellHole.Reverse();
335 isDone = Standard_True;
337 B.Add(aSolid,aShellHole);
339 ShellSolid.Add(aShell,aSolid);
341 //Creation of compsolid from shells containing shared faces.
342 TopTools_IndexedDataMapOfShapeListOfShape aMapFaceShells;
343 TopExp::MapShapesAndAncestors(theShape,TopAbs_FACE,TopAbs_SHELL,aMapFaceShells);
344 for(Standard_Integer i =1; i <= aMapFaceShells.Extent(); i++) {
345 const TopTools_ListOfShape& lshells = aMapFaceShells.FindFromIndex(i);
346 if(lshells.Extent() <2) continue;
347 TopoDS_CompSolid aCompSolid;
349 aB.MakeCompSolid(aCompSolid);
350 isDone = (theShape.ShapeType() != TopAbs_COMPSOLID || isDone);
351 Standard_Integer nbSol = 0;
353 for(TopTools_ListIteratorOfListOfShape lItSh(lshells);lItSh.More(); lItSh.Next()) {
354 if(ShellSolid.Contains(lItSh.Value())) {
355 const TopoDS_Shape& aShape = ShellSolid.FindFromKey(lItSh.Value());
356 TopExp_Explorer aExpSol(aShape, TopAbs_SOLID);
358 for(;aExpSol.More(); aExpSol.Next())
360 aB.Add(aCompSolid,aExpSol.Current());
368 for(TopTools_ListIteratorOfListOfShape lItSh1(lshells);lItSh1.More(); lItSh1.Next())
370 if(ShellSolid.Contains(lItSh1.Value()))
371 ShellSolid.ChangeFromKey(lItSh1.Value()) = aCompSolid;
376 for(Standard_Integer kk =1 ; kk <= ShellSolid.Extent();kk++)
377 if(!aMapSolids.Contains(ShellSolid.FindFromIndex(kk)))
378 aMapSolids.Add(ShellSolid.FindFromIndex(kk));
379 isDone = (aMapSolids.Extent() >1 || isDone);
382 //=======================================================================
385 //=======================================================================
387 Standard_Boolean ShapeFix_Solid::Perform(const Handle(Message_ProgressIndicator)& theProgress)
390 Standard_Boolean status = Standard_False;
391 if ( Context().IsNull() )
392 SetContext ( new ShapeBuild_ReShape );
393 myFixShell->SetContext(Context());
395 Standard_Integer NbShells = 0;
396 TopoDS_Shape S = Context()->Apply ( myShape );
398 // Calculate number of underlying shells
399 Standard_Integer aNbShells = 0;
400 for ( TopExp_Explorer aExpSh(S, TopAbs_SHELL); aExpSh.More(); aExpSh.Next() )
403 // Start progress scope (no need to check if progress exists -- it is safe)
404 Message_ProgressSentry aPSentry(theProgress, "Fixing solid stage", 0, 2, 1);
406 if ( NeedFix(myFixShellMode) )
408 // Start progress scope (no need to check if progress exists -- it is safe)
409 Message_ProgressSentry aPSentryFixShell(theProgress, "Fixing shell", 0, aNbShells, 1);
411 // Fix shell by shell using ShapeFix_Shell tool
412 for ( TopExp_Explorer aExpSh(S, TopAbs_SHELL); aExpSh.More() && aPSentryFixShell.More(); aExpSh.Next(), aPSentryFixShell.Next() )
414 TopoDS_Shape sh = aExpSh.Current();
416 myFixShell->Init( TopoDS::Shell(sh) );
417 if ( myFixShell->Perform(theProgress) )
419 status = Standard_True;
420 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
422 NbShells+= myFixShell->NbShells();
425 // Halt algorithm in case of user's abort
426 if ( !aPSentryFixShell.More() )
427 return Standard_False;
431 NbShells = aNbShells;
434 // Switch to the second stage
438 TopoDS_Shape tmpShape = Context()->Apply(myShape);
439 TopExp_Explorer aExp(tmpShape,TopAbs_SHELL);
440 Standard_Boolean isClosed = Standard_False;
442 TopoDS_Shell aShtmp = TopoDS::Shell(aExp.Current());
443 ShapeAnalysis_FreeBounds sfb(aShtmp);
444 TopoDS_Compound aC1 = sfb.GetClosedWires();
445 TopoDS_Compound aC2 = sfb.GetOpenWires();
446 Standard_Integer numedge =0;
447 TopExp_Explorer aExp1(aC1,TopAbs_EDGE);
448 for( ; aExp1.More(); aExp1.Next())
450 for(aExp1.Init(aC2,TopAbs_EDGE) ; aExp1.More(); aExp1.Next())
452 isClosed = (!numedge);
453 aShtmp.Closed(isClosed);
456 if(isClosed || myCreateOpenSolidMode) {
457 TopoDS_Iterator itersh(tmpShape);
459 if(itersh.More() && itersh.Value().ShapeType() == TopAbs_SHELL)
460 aShell = TopoDS::Shell(itersh.Value());
461 if(!aShell.IsNull()) {
462 TopoDS_Solid aSol = SolidFromShell(aShell);
463 if(ShapeExtend::DecodeStatus(myStatus,ShapeExtend_DONE2)) {
464 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG20"));// Orientaion of shell was corrected.
465 Context()->Replace(tmpShape,aSol);
469 mySolid = TopoDS::Solid(tmpShape);
472 status = Standard_True;
473 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
474 TopoDS_Iterator aIt(tmpShape,Standard_False);
475 Context()->Replace(tmpShape,aIt.Value());
476 SendFail (Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
480 TopoDS_Shape aResShape = Context()->Apply(myShape);
481 TopTools_SequenceOfShape aSeqShells;
482 TopTools_IndexedMapOfShape aMapSolids;
483 if(CreateSolids(aResShape,aMapSolids)) {
484 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG20"));// Orientaion of shell was corrected..
485 if(aMapSolids.Extent() ==1) {
486 TopoDS_Shape aResSol = aMapSolids.FindKey(1);
487 if(aResShape.ShapeType() == TopAbs_SHELL && myCreateOpenSolidMode) {
491 B.Add (solid,aResSol);
496 if(aResSol.ShapeType() == TopAbs_SHELL)
497 SendFail (Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
499 Context()->Replace(aResShape,mySolid);
501 else if(aMapSolids.Extent() >1) {
502 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG30"));// Bad connected solid a few solids were created.
504 TopoDS_Compound aComp;
505 aB.MakeCompound(aComp);
506 Message_ProgressSentry aPSentryCreatingSolid(theProgress, "Creating solid",
507 0, aMapSolids.Extent(), 1);
508 for(Standard_Integer i =1; (i <= aMapSolids.Extent()) && (aPSentryCreatingSolid.More());
509 i++, aPSentryCreatingSolid.Next())
511 TopoDS_Shape aResSh =aMapSolids.FindKey(i);
512 if(aResShape.ShapeType() == TopAbs_SHELL && myCreateOpenSolidMode) {
513 aResSh.Closed(Standard_False);
517 B.Add (solid,aResSh);
520 else if (aResShape.ShapeType() == TopAbs_SHELL)
521 SendFail(Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
522 aB.Add(aComp,aResSh);
525 if ( !aPSentryCreatingSolid.More() )
526 return Standard_False; // aborted execution
527 Context()->Replace(aResShape,aComp);
531 myShape = Context()->Apply(myShape);
534 //=======================================================================
537 //=======================================================================
539 TopoDS_Shape ShapeFix_Solid::Shape()
543 //=======================================================================
544 //function : SolidFromShell
546 //=======================================================================
548 TopoDS_Solid ShapeFix_Solid::SolidFromShell (const TopoDS_Shell& shell)
550 TopoDS_Shell sh = shell;
551 if (!sh.Free ()) sh.Free(Standard_True);
557 // Pas encore fini : il faut une bonne orientation
560 BRepClass3d_SolidClassifier bsc3d (solid);
561 Standard_Real t = Precision::Confusion(); // tolerance moyenne
562 bsc3d.PerformInfinitePoint(t);
564 if (bsc3d.State() == TopAbs_IN) {
565 // Ensuite, inverser C-A-D REPRENDRE LES SHELLS
566 // (l inversion du solide n est pas bien prise en compte)
568 if (!sh.Free ()) sh.Free(Standard_True);
570 B.MakeSolid (soli2); // on recommence
574 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
577 catch(Standard_Failure const& anException) {
579 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
580 anException.Print(cout); cout << endl;
588 //=======================================================================
591 //=======================================================================
593 Standard_Boolean ShapeFix_Solid::Status (const ShapeExtend_Status theStatus) const
595 return ShapeExtend::DecodeStatus (myStatus, theStatus);
598 //=======================================================================
601 //=======================================================================
603 TopoDS_Shape ShapeFix_Solid::Solid() const
608 //=======================================================================
609 //function : SetMsgRegistrator
611 //=======================================================================
613 void ShapeFix_Solid::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
615 ShapeFix_Root::SetMsgRegistrator ( msgreg );
616 myFixShell->SetMsgRegistrator ( msgreg );
619 //=======================================================================
620 //function : SetPrecision
622 //=======================================================================
624 void ShapeFix_Solid::SetPrecision (const Standard_Real preci)
626 ShapeFix_Root::SetPrecision ( preci );
627 myFixShell->SetPrecision ( preci );
630 //=======================================================================
631 //function : SetMinTolerance
633 //=======================================================================
635 void ShapeFix_Solid::SetMinTolerance (const Standard_Real mintol)
637 ShapeFix_Root::SetMinTolerance ( mintol );
638 myFixShell->SetMinTolerance ( mintol );
641 //=======================================================================
642 //function : SetMaxTolerance
644 //=======================================================================
646 void ShapeFix_Solid::SetMaxTolerance (const Standard_Real maxtol)
648 ShapeFix_Root::SetMaxTolerance ( maxtol );
649 myFixShell->SetMaxTolerance ( maxtol );