1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
18 #include <ShapeFix_Solid.ixx>
20 #include <Standard_ErrorHandler.hxx>
21 #include <Standard_Failure.hxx>
23 #include <BRep_Builder.hxx>
24 #include <BRepClass3d_SolidClassifier.hxx>
25 #include <Precision.hxx>
26 #include <TopoDS_Shape.hxx>
27 #include <ShapeBuild_ReShape.hxx>
28 #include <TopoDS_Iterator.hxx>
30 #include <ShapeExtend.hxx>
31 #include <ShapeAnalysis_Edge.hxx>
32 #include <ShapeAnalysis_Curve.hxx>
33 #include <TopoDS_Wire.hxx>
34 #include <ShapeExtend_WireData.hxx>
35 #include <TopTools_MapIteratorOfMapOfShape.hxx>
36 #include <TopoDS_Iterator.hxx>
37 #include <TopTools_MapOfShape.hxx>
38 #include <TopTools_DataMapOfShapeListOfShape.hxx>
39 #include <TopTools_SequenceOfShape.hxx>
40 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
42 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
44 #include <Bnd_Box2d.hxx>
45 #include <ShapeAnalysis.hxx>
46 #include <TopoDS_Edge.hxx>
47 #include <BRep_Tool.hxx>
48 #include <Geom_Surface.hxx>
49 #include <TopTools_ListOfShape.hxx>
50 #include <Precision.hxx>
52 #include <TopTools_ListIteratorOfListOfShape.hxx>
53 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <TopoDS_Solid.hxx>
56 #include <BRep_Builder.hxx>
57 #include <TopoDS_CompSolid.hxx>
58 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
60 #include <BRep_Tool.hxx>
61 #include <TopTools_IndexedMapOfShape.hxx>
62 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
63 #include <Message_Msg.hxx>
64 #include <Message_ProgressSentry.hxx>
65 #include <TopoDS_Vertex.hxx>
66 #include <TopTools_IndexedMapOfShape.hxx>
68 #include <TopTools_DataMapOfShapeInteger.hxx>
69 #include <Geom_Curve.hxx>
70 #include <ShapeAnalysis_FreeBounds.hxx>
72 //======================================================
73 //function : ShapeFix_Solid
75 //=======================================================================
77 ShapeFix_Solid::ShapeFix_Solid()
79 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
81 myFixShell = new ShapeFix_Shell;
82 myCreateOpenSolidMode = Standard_False;
85 //=======================================================================
86 //function : ShapeFix_Solid
88 //=======================================================================
90 ShapeFix_Solid::ShapeFix_Solid(const TopoDS_Solid& solid)
92 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
94 myFixShell = new ShapeFix_Shell;
95 myCreateOpenSolidMode = Standard_False;
99 //=======================================================================
102 //=======================================================================
104 void ShapeFix_Solid::Init(const TopoDS_Solid& solid)
107 //mySolid = TopoDS::Solid(shape.EmptyCopied());
109 // for( TopoDS_Iterator iter(solid); iter.More(); iter.Next())
110 // B.Add(mySolid,TopoDS::Shell(iter.Value()));
113 #ifdef DEB_GET_MIDDLE_POINT
114 //=======================================================================
115 //function : GetMiddlePoint
117 //=======================================================================
118 static void GetMiddlePoint(const TopoDS_Shape& aShape, gp_Pnt& pmid)
120 TopExp_Explorer aExp(aShape,TopAbs_EDGE);
121 gp_XYZ center(0.0,0.0,0.0);
122 Standard_Integer numpoints =0;
123 for( ; aExp.More(); aExp.Next()) {
124 TopoDS_Edge e1 = TopoDS::Edge(aExp.Current());
126 Handle(Geom_Curve) c3d = BRep_Tool::Curve(e1,f,l);
128 for(Standard_Integer i =1 ; i <=5; i++) {
129 Standard_Real param = f+(l-f)/4*(i-1);
142 //=======================================================================
143 //function : CollectSolids
145 //=======================================================================
146 static void CollectSolids(const TopTools_SequenceOfShape& aSeqShells ,
147 TopTools_DataMapOfShapeListOfShape& aMapShellHoles,
148 TopTools_DataMapOfShapeInteger& theMapStatus)
150 TopTools_MapOfShape aMapHoles;
151 for ( Standard_Integer i1 = 1; i1 <= aSeqShells.Length(); i1++ ) {
152 TopoDS_Shell aShell1 = TopoDS::Shell(aSeqShells.Value(i1));
153 TopTools_ListOfShape lshells;
154 aMapShellHoles.Bind(aShell1,lshells);
156 //Finds roots shells and hole shells.
157 for ( Standard_Integer i = 1; i <= aSeqShells.Length(); i++ ) {
158 TopoDS_Shell aShell1 = TopoDS::Shell(aSeqShells.Value(i));
159 TopExp_Explorer aExpEdges(aShell1,TopAbs_EDGE);
160 if(!BRep_Tool::IsClosed(aShell1) || !aExpEdges.More()) continue;
164 B.Add (solid,aShell1);
167 TopAbs_State infinstatus = TopAbs_UNKNOWN;
168 BRepClass3d_SolidClassifier bsc3d (solid);
169 Standard_Integer st = 0;
170 if(!theMapStatus.IsBound(aShell1)) {
172 bsc3d.PerformInfinitePoint(Precision::Confusion());
173 infinstatus = bsc3d.State();
175 if(infinstatus != TopAbs_UNKNOWN && infinstatus !=TopAbs_ON)
176 st = (infinstatus == TopAbs_IN ? 1 :2);
177 theMapStatus.Bind(aShell1,st);
182 st = theMapStatus.Find(aShell1);
184 infinstatus = (theMapStatus.Find(aShell1) == 1 ? TopAbs_IN : TopAbs_OUT);
187 for ( Standard_Integer j = 1; j <= aSeqShells.Length(); j++ ) {
189 TopoDS_Shape aShell2 = aSeqShells.Value(j);
190 if(!BRep_Tool::IsClosed(aShell2)) continue;
191 if(aMapHoles.Contains(aShell2)) continue;
192 if(aMapShellHoles.IsBound(aShell2)) {
193 Standard_Boolean isAnalysis = Standard_False;
194 const TopTools_ListOfShape& ls = aMapShellHoles.Find(aShell2);
195 for(TopTools_ListIteratorOfListOfShape li(ls); li.More() && !isAnalysis; li.Next())
196 isAnalysis = li.Value().IsSame(aShell1);
197 if(isAnalysis) continue;
199 TopAbs_State pointstatus = TopAbs_UNKNOWN;
200 Standard_Integer numon =0;
201 TopTools_IndexedMapOfShape amapVert;
202 for(TopExp_Explorer aExpVert(aShell2,TopAbs_VERTEX); aExpVert.More() && amapVert.Extent() < 10; aExpVert.Next())
203 amapVert.Add(aExpVert.Current());
204 for(Standard_Integer k = 1; k <= amapVert.Extent() &&
205 (pointstatus ==TopAbs_UNKNOWN || (pointstatus ==TopAbs_ON && numon < 3)); k++) {
206 TopoDS_Vertex aV = TopoDS::Vertex(amapVert.FindKey(k));
207 gp_Pnt aPf = BRep_Tool::Pnt(aV);
208 bsc3d.Perform(aPf,Precision::Confusion());
209 pointstatus =bsc3d.State();
210 if(pointstatus ==TopAbs_ON) numon++;
213 if(numon == 3 && pointstatus ==TopAbs_ON) {
214 #ifdef DEB_GET_MIDDLE_POINT
216 GetMiddlePoint(aShell2,pmid);
217 bsc3d.Perform(pmid,Precision::Confusion());
219 pointstatus = /*(bsc3d.State() == TopAbs_IN ? TopAbs_IN :*/TopAbs_OUT;
221 if(pointstatus != infinstatus) {
222 aMapShellHoles.ChangeFind(aShell1).Append(aShell2);
223 if( aMapHoles.Contains(aShell2))
224 aMapHoles.Remove(aShell2);
225 else aMapHoles.Add(aShell2);
229 catch(Standard_Failure) {
231 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
232 Standard_Failure::Caught()->Print(cout); cout << endl;
237 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItShellHoles( aMapShellHoles);
238 for(; aItShellHoles.More();aItShellHoles.Next()) {
239 if(aMapHoles.Contains(aItShellHoles.Key())) continue;
240 const TopTools_ListOfShape& lHoles =aItShellHoles.Value();
241 if(lHoles.IsEmpty()) continue;
242 for(TopTools_ListIteratorOfListOfShape lItHoles(lHoles);lItHoles.More(); lItHoles.Next()) {
243 if(aMapHoles.Contains(lItHoles.Value())) {
244 const TopTools_ListOfShape& lUnHoles = aMapShellHoles.Find(lItHoles.Value());
245 for(TopTools_ListIteratorOfListOfShape lItUnHoles(lUnHoles);lItUnHoles.More(); lItUnHoles.Next())
246 aMapHoles.Remove(lItUnHoles.Value());
250 for(TopTools_MapIteratorOfMapOfShape aIterHoles(aMapHoles);aIterHoles.More(); aIterHoles.Next())
251 aMapShellHoles.UnBind(aIterHoles.Key());
254 //=======================================================================
255 //function : CreateSolids
257 //=======================================================================
259 static Standard_Boolean CreateSolids(const TopoDS_Shape aShape,TopTools_IndexedMapOfShape& aMapSolids)
261 TopTools_SequenceOfShape aSeqShells;
262 Standard_Boolean isDone = Standard_False;
264 for(TopExp_Explorer aExpShell(aShape,TopAbs_SHELL); aExpShell.More(); aExpShell.Next()) {
265 aSeqShells.Append(aExpShell.Current());
267 TopTools_DataMapOfShapeListOfShape aMapShellHoles;
268 TopTools_DataMapOfShapeInteger aMapStatus;
269 CollectSolids(aSeqShells,aMapShellHoles,aMapStatus);
270 TopTools_IndexedDataMapOfShapeShape ShellSolid;
271 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItShellHoles( aMapShellHoles);
272 //Defines correct orientation of shells
273 for(; aItShellHoles.More();aItShellHoles.Next()) {
274 TopoDS_Shell aShell = TopoDS::Shell(aItShellHoles.Key());
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) {
302 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
303 Standard_Failure::Caught()->Print(cout); cout << endl;
305 ShellSolid.Add(aShell,aSolid);
309 if (infinstatus == TopAbs_IN) {
310 isDone = Standard_True;
312 TopoDS_Solid aTmpSolid;
313 B.MakeSolid (aTmpSolid);
314 B.Add (aTmpSolid,aShell);
318 const TopTools_ListOfShape& lHoles = aItShellHoles.Value();
319 for(TopTools_ListIteratorOfListOfShape lItHoles(lHoles); lItHoles.More();lItHoles.Next()) {
320 TopoDS_Shell aShellHole = TopoDS::Shell(lItHoles.Value());
321 if(aMapStatus.IsBound(aShellHole)) {
322 infinstatus = (aMapStatus.Find(aShellHole) == 1 ? TopAbs_IN : TopAbs_OUT);
327 B.Add (solid,aShellHole);
328 BRepClass3d_SolidClassifier bsc3dHol (solid);
329 bsc3dHol.PerformInfinitePoint(Precision::Confusion());
330 infinstatus = bsc3dHol.State();
332 if (infinstatus == TopAbs_OUT) {
333 aShellHole.Reverse();
334 isDone = Standard_True;
336 B.Add(aSolid,aShellHole);
338 ShellSolid.Add(aShell,aSolid);
340 //Creation of compsolid from shells containing shared faces.
341 TopTools_IndexedDataMapOfShapeListOfShape aMapFaceShells;
342 TopExp::MapShapesAndAncestors(aShape,TopAbs_FACE,TopAbs_SHELL,aMapFaceShells);
343 for(Standard_Integer i =1; i <= aMapFaceShells.Extent(); i++) {
344 const TopTools_ListOfShape& lshells = aMapFaceShells.FindFromIndex(i);
345 if(lshells.Extent() <2) continue;
346 TopoDS_CompSolid aCompSolid;
348 aB.MakeCompSolid(aCompSolid);
349 isDone = (aShape.ShapeType() != TopAbs_COMPSOLID || isDone);
350 for(TopTools_ListIteratorOfListOfShape lItSh(lshells);lItSh.More(); lItSh.Next()) {
351 if(ShellSolid.Contains(lItSh.Value())) {
352 for(TopExp_Explorer aExpSol(ShellSolid.FindFromKey(lItSh.Value()),TopAbs_SOLID);aExpSol.More(); aExpSol.Next())
353 aB.Add(aCompSolid,aExpSol.Current());
354 ShellSolid.ChangeFromKey(lItSh.Value()) = aCompSolid;
358 for(Standard_Integer kk =1 ; kk <= ShellSolid.Extent();kk++)
359 if(!aMapSolids.Contains(ShellSolid.FindFromIndex(kk)))
360 aMapSolids.Add(ShellSolid.FindFromIndex(kk));
361 isDone = (aMapSolids.Extent() >1 || isDone);
364 //=======================================================================
367 //=======================================================================
369 Standard_Boolean ShapeFix_Solid::Perform(const Handle(Message_ProgressIndicator)& theProgress)
372 Standard_Boolean status = Standard_False;
373 if ( Context().IsNull() )
374 SetContext ( new ShapeBuild_ReShape );
375 myFixShell->SetContext(Context());
377 Standard_Integer NbShells = 0;
378 TopoDS_Shape S = Context()->Apply ( myShape );
380 // Calculate number of underlying shells
381 Standard_Integer aNbShells = 0;
382 for ( TopExp_Explorer aExpSh(S, TopAbs_SHELL); aExpSh.More(); aExpSh.Next() )
385 // Start progress scope (no need to check if progress exists -- it is safe)
386 Message_ProgressSentry aPSentry(theProgress, "Fixing solid stage", 0, 2, 1);
388 if ( NeedFix(myFixShellMode) )
390 // Start progress scope (no need to check if progress exists -- it is safe)
391 Message_ProgressSentry aPSentry(theProgress, "Fixing shell", 0, aNbShells, 1);
393 // Fix shell by shell using ShapeFix_Shell tool
394 for ( TopExp_Explorer aExpSh(S, TopAbs_SHELL); aExpSh.More() && aPSentry.More(); aExpSh.Next(), aPSentry.Next() )
396 TopoDS_Shape sh = aExpSh.Current();
398 myFixShell->Init( TopoDS::Shell(sh) );
399 if ( myFixShell->Perform(theProgress) )
401 status = Standard_True;
402 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
404 NbShells+= myFixShell->NbShells();
407 // Halt algorithm in case of user's abort
408 if ( !aPSentry.More() )
409 return Standard_False;
413 NbShells = aNbShells;
416 // Switch to the second stage
420 TopoDS_Shape tmpShape = Context()->Apply(myShape);
421 TopExp_Explorer aExp(tmpShape,TopAbs_SHELL);
422 Standard_Boolean isClosed = Standard_False;
424 TopoDS_Shell aShtmp = TopoDS::Shell(aExp.Current());
425 ShapeAnalysis_FreeBounds sfb(aShtmp);
426 TopoDS_Compound aC1 = sfb.GetClosedWires();
427 TopoDS_Compound aC2 = sfb.GetOpenWires();
428 Standard_Integer numedge =0;
429 TopExp_Explorer aExp1(aC1,TopAbs_EDGE);
430 for( ; aExp1.More(); aExp1.Next())
432 for(aExp1.Init(aC2,TopAbs_EDGE) ; aExp1.More(); aExp1.Next())
434 isClosed = (!numedge);
435 aShtmp.Closed(isClosed);
438 if(isClosed || myCreateOpenSolidMode) {
439 if(BRep_Tool::IsClosed(tmpShape)) {
440 TopoDS_Iterator itersh(tmpShape);
442 if(itersh.More() && itersh.Value().ShapeType() == TopAbs_SHELL)
443 aShell = TopoDS::Shell(itersh.Value());
444 if(!aShell.IsNull()) {
445 TopoDS_Solid aSol = SolidFromShell(aShell);
446 if(ShapeExtend::DecodeStatus(myStatus,ShapeExtend_DONE2)) {
447 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG20"));// Orientaion of shell was corrected.
448 Context()->Replace(tmpShape,aSol);
453 mySolid = TopoDS::Solid(tmpShape);
456 TopoDS_Iterator aIt(tmpShape,Standard_False);
457 Context()->Replace(tmpShape,aIt.Value());
458 SendFail (Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
462 TopoDS_Shape aResShape = Context()->Apply(myShape);
463 TopTools_SequenceOfShape aSeqShells;
464 TopTools_IndexedMapOfShape aMapSolids;
465 if(CreateSolids(aResShape,aMapSolids)) {
466 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG20"));// Orientaion of shell was corrected..
467 if(aMapSolids.Extent() ==1) {
468 TopoDS_Shape aResSol = aMapSolids.FindKey(1);
469 if(aResShape.ShapeType() == TopAbs_SHELL && myCreateOpenSolidMode) {
473 B.Add (solid,aResSol);
478 if(aResSol.ShapeType() == TopAbs_SHELL)
479 SendFail (Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
481 Context()->Replace(aResShape,mySolid);
483 else if(aMapSolids.Extent() >1) {
484 SendWarning (Message_Msg ("FixAdvSolid.FixOrientation.MSG30"));// Bad connected solid a few solids were created.
486 TopoDS_Compound aComp;
487 aB.MakeCompound(aComp);
488 Message_ProgressSentry aPSentry(theProgress, "Creating solid",
489 0, aMapSolids.Extent(), 1);
490 for(Standard_Integer i =1; (i <= aMapSolids.Extent()) && (aPSentry.More());
491 i++, aPSentry.Next())
493 TopoDS_Shape aResSh =aMapSolids.FindKey(i);
494 if(aResShape.ShapeType() == TopAbs_SHELL && myCreateOpenSolidMode) {
495 aResSh.Closed(Standard_False);
499 B.Add (solid,aResSh);
502 else if (aResShape.ShapeType() == TopAbs_SHELL)
503 SendFail(Message_Msg ("FixAdvSolid.FixShell.MSG10")); // Solid can not be created from open shell.
504 aB.Add(aComp,aResSh);
507 if ( !aPSentry.More() )
508 return Standard_False; // aborted execution
509 Context()->Replace(aResShape,aComp);
513 myShape = Context()->Apply(myShape);
516 //=======================================================================
519 //=======================================================================
521 TopoDS_Shape ShapeFix_Solid::Shape()
525 //=======================================================================
526 //function : SolidFromShell
528 //=======================================================================
530 TopoDS_Solid ShapeFix_Solid::SolidFromShell (const TopoDS_Shell& shell)
532 TopoDS_Shell sh = shell;
533 if (!sh.Free ()) sh.Free(Standard_True);
539 // Pas encore fini : il faut une bonne orientation
542 BRepClass3d_SolidClassifier bsc3d (solid);
543 Standard_Real t = Precision::Confusion(); // tolerance moyenne
544 bsc3d.PerformInfinitePoint(t);
546 if (bsc3d.State() == TopAbs_IN) {
547 // Ensuite, inverser C-A-D REPRENDRE LES SHELLS
548 // (l inversion du solide n est pas bien prise en compte)
550 if (!sh.Free ()) sh.Free(Standard_True);
552 B.MakeSolid (soli2); // on recommence
556 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
559 catch(Standard_Failure) {
561 cout << "Warning: ShapeFix_Solid::SolidFromShell: Exception: ";
562 Standard_Failure::Caught()->Print(cout); cout << endl;
569 //=======================================================================
572 //=======================================================================
574 Standard_Boolean ShapeFix_Solid::Status(const ShapeExtend_Status /*status*/) const
579 //=======================================================================
582 //=======================================================================
584 TopoDS_Shape ShapeFix_Solid::Solid() const
589 //=======================================================================
590 //function : SetMsgRegistrator
592 //=======================================================================
594 void ShapeFix_Solid::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
596 ShapeFix_Root::SetMsgRegistrator ( msgreg );
597 myFixShell->SetMsgRegistrator ( msgreg );
600 //=======================================================================
601 //function : SetPrecision
603 //=======================================================================
605 void ShapeFix_Solid::SetPrecision (const Standard_Real preci)
607 ShapeFix_Root::SetPrecision ( preci );
608 myFixShell->SetPrecision ( preci );
611 //=======================================================================
612 //function : SetMinTolerance
614 //=======================================================================
616 void ShapeFix_Solid::SetMinTolerance (const Standard_Real mintol)
618 ShapeFix_Root::SetMinTolerance ( mintol );
619 myFixShell->SetMinTolerance ( mintol );
622 //=======================================================================
623 //function : SetMaxTolerance
625 //=======================================================================
627 void ShapeFix_Solid::SetMaxTolerance (const Standard_Real maxtol)
629 ShapeFix_Root::SetMaxTolerance ( maxtol );
630 myFixShell->SetMaxTolerance ( maxtol );