From 98a4340017efe352ca177d30440af50c7bae3a74 Mon Sep 17 00:00:00 2001 From: aml Date: Thu, 22 Oct 2015 14:54:59 +0300 Subject: [PATCH] 0026620: Shape healing unreasonably downgrades tolerance of a face Added face support in SameParameter in classes ShapeAnalysis_Edge, ShapeFix_Edge. Test case for issue CR26620 Minor correction. --- src/ShapeAnalysis/ShapeAnalysis_Edge.cxx | 46 ++++++++++++++++++++---- src/ShapeAnalysis/ShapeAnalysis_Edge.hxx | 9 +++++ src/ShapeFix/ShapeFix.cxx | 19 +++++++++- src/ShapeFix/ShapeFix_Edge.cxx | 43 ++++++++++++++++------ src/ShapeFix/ShapeFix_Edge.hxx | 37 +++++++++++++++++++ src/ShapeFix/ShapeFix_Face.cxx | 2 +- src/ShapeFix/ShapeFix_Shape.cxx | 12 ++++--- src/ShapeFix/ShapeFix_Wire.cxx | 8 ++--- tests/bugs/heal/bug26620 | 26 ++++++++++++++ 9 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 tests/bugs/heal/bug26620 diff --git a/src/ShapeAnalysis/ShapeAnalysis_Edge.cxx b/src/ShapeAnalysis/ShapeAnalysis_Edge.cxx index 45b4bc350a..1cde3aa9b0 100644 --- a/src/ShapeAnalysis/ShapeAnalysis_Edge.cxx +++ b/src/ShapeAnalysis/ShapeAnalysis_Edge.cxx @@ -772,6 +772,19 @@ Standard_Boolean ShapeAnalysis_Edge::ComputeDeviation (const Adaptor3d_Curve& CR return OK; } +//======================================================================= +//function : CheckSameParameter +//purpose : +//======================================================================= + +Standard_Boolean ShapeAnalysis_Edge::CheckSameParameter (const TopoDS_Edge& edge, + Standard_Real& maxdev, + const Standard_Integer NbControl) +{ + TopoDS_Face anEmptyFace; + return CheckSameParameter(edge, anEmptyFace, maxdev, NbControl); +} + //======================================================================= //function : CheckSameParameter @@ -779,8 +792,9 @@ Standard_Boolean ShapeAnalysis_Edge::ComputeDeviation (const Adaptor3d_Curve& CR //======================================================================= Standard_Boolean ShapeAnalysis_Edge::CheckSameParameter (const TopoDS_Edge& edge, - Standard_Real& maxdev, - const Standard_Integer NbControl) + const TopoDS_Face& face, + Standard_Real& maxdev, + const Standard_Integer NbControl) { myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK ); if (BRep_Tool::Degenerated (edge)) return Standard_False; @@ -814,12 +828,27 @@ Standard_Boolean ShapeAnalysis_Edge::CheckSameParameter (const TopoDS_Edge& edge return Standard_False; } + Handle(Geom_Surface) aFaceSurf; + TopLoc_Location L; + if ( !face.IsNull() ) + { + aFaceSurf = BRep_Tool::Surface(face, L); + } + // iterate on pcurves itcr.Initialize ( TE->Curves() ); - for ( ; itcr.More(); itcr.Next() ) { + for ( ; itcr.More(); itcr.Next() ) + { Handle(BRep_GCurve) GC = Handle(BRep_GCurve)::DownCast(itcr.Value()); if ( GC.IsNull() || ! GC->IsCurveOnSurface() ) continue; + if ( !(face.IsNull()) ) // Face is not null. + { + // Check for different surface. + if (!GC->IsCurveOnSurface(aFaceSurf, GC->Location())) + continue; + } + Standard_Real f, l; GC->Range ( f, l ); Handle(Geom_Surface) Su = GC->Surface(); @@ -833,15 +862,18 @@ Standard_Boolean ShapeAnalysis_Edge::CheckSameParameter (const TopoDS_Edge& edge //Adaptor3d_CurveOnSurface ACS(GHPC,GAHS); Adaptor3d_CurveOnSurface ACS; ACS.Load(GHPC, GAHS); - if ( ! ComputeDeviation ( AC3d, ACS, SameParameter, maxdev, NbControl-1 ) ) { + if ( ! ComputeDeviation ( AC3d, ACS, SameParameter, maxdev, NbControl-1 ) ) + { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 ); } - if ( GC->IsCurveOnClosedSurface() ) { + if ( GC->IsCurveOnClosedSurface() ) + { GHPC->ChangeCurve2d().Load ( GC->PCurve2(), f, l ); // same bounds ACS.Load(GHPC, GAHS); // sans doute inutile - if ( ! ComputeDeviation ( AC3d, ACS, SameParameter, maxdev, NbControl-1 ) ) { - myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 ); + if ( ! ComputeDeviation ( AC3d, ACS, SameParameter, maxdev, NbControl-1 ) ) + { + myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 ); } } } diff --git a/src/ShapeAnalysis/ShapeAnalysis_Edge.hxx b/src/ShapeAnalysis/ShapeAnalysis_Edge.hxx index 1c0b556712..1022a0e1b4 100644 --- a/src/ShapeAnalysis/ShapeAnalysis_Edge.hxx +++ b/src/ShapeAnalysis/ShapeAnalysis_Edge.hxx @@ -157,6 +157,15 @@ public: //! If deviation is greater than tolerance of the edge (i.e. //! incorrect flag) returns False, else returns True. Standard_EXPORT Standard_Boolean CheckSameParameter (const TopoDS_Edge& edge, Standard_Real& maxdev, const Standard_Integer NbControl = 23); + + //! Checks the edge to be SameParameter. + //! Calculates the maximal deviation between 3d curve and each + //! pcurve of the edge on equidistant points (the same + //! algorithm as in BRepCheck; default value is 23 as in BRepCheck). + //! This deviation is returned in parameter. + //! If deviation is greater than tolerance of the edge (i.e. + //! incorrect flag) returns False, else returns True. + Standard_EXPORT Standard_Boolean CheckSameParameter (const TopoDS_Edge& theEdge, const TopoDS_Face& theFace, Standard_Real& theMaxdev, const Standard_Integer theNbControl = 23); //! Computes the maximal deviation between the two curve //! representations. diff --git a/src/ShapeFix/ShapeFix.cxx b/src/ShapeFix/ShapeFix.cxx index d4a3b8efa2..4a4c4c855b 100644 --- a/src/ShapeFix/ShapeFix.cxx +++ b/src/ShapeFix/ShapeFix.cxx @@ -93,6 +93,9 @@ Standard_Boolean ShapeFix::SameParameter(const TopoDS_Shape& shape, for ( TopExp_Explorer anEdgeExp(shape, TopAbs_FACE); anEdgeExp.More(); anEdgeExp.Next() ) ++aNbFaces; + TopTools_IndexedDataMapOfShapeListOfShape aMapEF; + TopExp::MapShapesAndAncestors(shape, TopAbs_EDGE, TopAbs_FACE, aMapEF); + BRep_Builder B; //Standard_Integer nbexcp = 0; Standard_Integer nbfail = 0, numedge = 0; @@ -129,7 +132,21 @@ Standard_Boolean ShapeFix::SameParameter(const TopoDS_Shape& shape, B.SameParameter (E,Standard_False); } - sfe->FixSameParameter (E); // K2-SEP97 + TopTools_ListOfShape aListOfFaces; + aMapEF.FindFromKey(E, aListOfFaces); + if (aListOfFaces.Extent() != 0) + { + TopTools_ListOfShape::Iterator aListOfFacesIt(aListOfFaces); + for ( ; aListOfFacesIt.More() ; aListOfFacesIt.Next()) + { + TopoDS_Face aF = TopoDS::Face( aListOfFacesIt.Value() ); + sfe->FixSameParameter (E, aF); + } + } + else + { + sfe->FixSameParameter (E); // K2-SEP97 + } if (!BRep_Tool::SameParameter (E)) { ierr = 1; nbfail ++; } diff --git a/src/ShapeFix/ShapeFix_Edge.cxx b/src/ShapeFix/ShapeFix_Edge.cxx index 55f80718c2..2723c57f1e 100644 --- a/src/ShapeFix/ShapeFix_Edge.cxx +++ b/src/ShapeFix/ShapeFix_Edge.cxx @@ -576,7 +576,7 @@ Standard_Boolean ShapeFix_Edge::FixAddPCurve (const TopoDS_Edge& edge, //purpose : //======================================================================= - Standard_Boolean ShapeFix_Edge::FixVertexTolerance(const TopoDS_Edge& edge, +Standard_Boolean ShapeFix_Edge::FixVertexTolerance(const TopoDS_Edge& edge, const TopoDS_Face& face) { myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK ); @@ -699,7 +699,6 @@ Standard_Boolean ShapeFix_Edge::FixReversed2d (const TopoDS_Edge& edge, return Standard_True; } - //======================================================================= //function : FixSameParameter //purpose : @@ -708,8 +707,21 @@ Standard_Boolean ShapeFix_Edge::FixReversed2d (const TopoDS_Edge& edge, Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, const Standard_Real tolerance) { - myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK ); + TopoDS_Face anEmptyFace; + return FixSameParameter(edge, anEmptyFace, tolerance); +} +//======================================================================= +//function : FixSameParameter +//purpose : +//======================================================================= + +Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, + const TopoDS_Face& face, + const Standard_Real tolerance) +{ + myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK ); + if ( BRep_Tool::Degenerated ( edge ) ) { BRep_Builder B; @@ -726,10 +738,10 @@ Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, TopoDS_Edge copyedge; TopoDS_Vertex V1 = sae.FirstVertex (edge); TopoDS_Vertex V2 = sae.LastVertex (edge); - Standard_Real TolFV = ( V1.IsNull() ? 0. : BRep_Tool::Tolerance ( V1 ) ); - Standard_Real TolLV = ( V2.IsNull() ? 0. : BRep_Tool::Tolerance ( V2 ) ); + Standard_Real TolFV = ( V1.IsNull() ? 0.0 : BRep_Tool::Tolerance ( V1 ) ); + Standard_Real TolLV = ( V2.IsNull() ? 0.0 : BRep_Tool::Tolerance ( V2 ) ); Standard_Real tol = BRep_Tool::Tolerance (edge); - + Standard_Boolean wasSP = BRep_Tool::SameParameter ( edge ), SP = Standard_False; { try @@ -764,14 +776,23 @@ Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 ); } } - + // compute deviation on the original pcurves Standard_Real maxdev; B.SameParameter ( edge, Standard_True ); - sae.CheckSameParameter ( edge, maxdev ); + + // Should check all pcurves in case of non-sameparametrization input. + TopoDS_Face aFace = face; + if (!wasSP) + { + TopoDS_Face anEmptyFace; + aFace = anEmptyFace; + } + + sae.CheckSameParameter ( edge, aFace, maxdev ); if ( sae.Status ( ShapeExtend_FAIL2 ) ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 ); - + // if BRepLib was OK, compare and select the best variant if ( SP ) { @@ -779,7 +800,7 @@ Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, sae.CheckSameParameter ( copyedge, BRLDev ); myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 ); if ( BRLTol < BRLDev ) BRLTol = BRLDev; - + //chose the best result if ( BRLTol < maxdev ) { @@ -796,7 +817,7 @@ Standard_Boolean ShapeFix_Edge::FixSameParameter(const TopoDS_Edge& edge, //restore tolerances because they could be modified by BRepLib if ( ! V1.IsNull() ) SFST.SetTolerance ( V1, Max (maxdev, TolFV), TopAbs_VERTEX); if ( ! V2.IsNull() ) SFST.SetTolerance ( V2, Max (maxdev, TolLV), TopAbs_VERTEX); - + if ( maxdev > tol ) { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 ); diff --git a/src/ShapeFix/ShapeFix_Edge.hxx b/src/ShapeFix/ShapeFix_Edge.hxx index d5c052aa18..ba1a759759 100644 --- a/src/ShapeFix/ShapeFix_Edge.hxx +++ b/src/ShapeFix/ShapeFix_Edge.hxx @@ -173,6 +173,43 @@ public: //! DONE5 - if the edge resulting from BRepLib has been chosen, i.e. variant b. above //! (only for edges with not set SameParameter) Standard_EXPORT Standard_Boolean FixSameParameter (const TopoDS_Edge& edge, const Standard_Real tolerance = 0.0); + + //! Tries to make edge SameParameter and sets corresponding + //! tolerance and SameParameter flag. + //! First, it makes edge same range if SameRange flag is not set. + //! + //! If flag SameParameter is set, this method calls the + //! function ShapeAnalysis_Edge::CheckSameParameter() that + //! calculates the maximal deviation of pcurves of the edge from + //! its 3d curve. If deviation > tolerance, the tolerance of edge + //! is increased to a value of deviation. If deviation < tolerance + //! nothing happens. + //! + //! If flag SameParameter is not set, this method chooses the best + //! variant (one that has minimal tolerance), either + //! a. only after computing deviation (as above) or + //! b. after calling standard procedure BRepLib::SameParameter + //! and computing deviation (as above). If > 0, it is + //! used as parameter for BRepLib::SameParameter, otherwise, + //! tolerance of the edge is used. + //! + //! Use : Is to be called after all pcurves and 3d curve of the edge are + //! correctly computed + //! Remark : SameParameter flag is always set to True after this method + //! Returns: True, if something done, else False + //! Status : OK - edge was initially SameParameter, nothing is done + //! FAIL1 - computation of deviation of pcurves from 3d curve has failed + //! FAIL2 - BRepLib::SameParameter() has failed + //! DONE1 - tolerance of the edge was increased + //! DONE2 - flag SameParameter was set to True (only if + //! BRepLib::SameParameter() did not set it) + //! DONE3 - edge was modified by BRepLib::SameParameter() to SameParameter + //! DONE4 - not used anymore + //! DONE5 - if the edge resulting from BRepLib has been chosen, i.e. variant b. above + //! (only for edges with not set SameParameter) + Standard_EXPORT Standard_Boolean FixSameParameter (const TopoDS_Edge& edge, + const TopoDS_Face& face, + const Standard_Real tolerance = 0.0); //! Returns the status (in the form of True/False) of last Fix Standard_EXPORT Standard_Boolean Status (const ShapeExtend_Status status) const; diff --git a/src/ShapeFix/ShapeFix_Face.cxx b/src/ShapeFix/ShapeFix_Face.cxx index b40cc52aca..dd4762265e 100644 --- a/src/ShapeFix/ShapeFix_Face.cxx +++ b/src/ShapeFix/ShapeFix_Face.cxx @@ -842,7 +842,7 @@ Standard_Boolean ShapeFix_Face::FixAddNaturalBound() Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool(); for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) { TopoDS_Edge edg = TopoDS::Edge (Eed.Current()); - sfe->FixVertexTolerance(edg); + sfe->FixVertexTolerance(edg, myFace); } // B.UpdateFace (myFace,myPrecision); diff --git a/src/ShapeFix/ShapeFix_Shape.cxx b/src/ShapeFix/ShapeFix_Shape.cxx index 459bc81e9f..cca527e530 100644 --- a/src/ShapeFix/ShapeFix_Shape.cxx +++ b/src/ShapeFix/ShapeFix_Shape.cxx @@ -257,11 +257,15 @@ Standard_Boolean ShapeFix_Shape::Perform(const Handle(Message_ProgressIndicator) // for case when vertex belong to the different faces it is necessary to check vertices tolerances //after all fixes. //This fix it should be performed for example for case when cutting edge was performed. - Handle(ShapeFix_Edge) sfe = FixEdgeTool(); - TopExp_Explorer anExpE (myResult, TopAbs_EDGE); - for ( ; anExpE.More(); anExpE.Next()) - sfe->FixVertexTolerance( TopoDS::Edge (anExpE.Current())); + TopExp_Explorer anExpF (myResult, TopAbs_FACE); + for ( ; anExpF.More(); anExpF.Next()) + { + TopoDS_Face aF = TopoDS::Face(anExpF.Current()); + TopExp_Explorer anExpE (aF, TopAbs_EDGE); + for ( ; anExpE.More(); anExpE.Next()) + sfe->FixVertexTolerance( TopoDS::Edge (anExpE.Current()), aF); + } } } myResult = Context()->Apply(myResult); diff --git a/src/ShapeFix/ShapeFix_Wire.cxx b/src/ShapeFix/ShapeFix_Wire.cxx index af37d9085e..7ae6c98e15 100644 --- a/src/ShapeFix/ShapeFix_Wire.cxx +++ b/src/ShapeFix/ShapeFix_Wire.cxx @@ -416,7 +416,7 @@ Standard_Boolean ShapeFix_Wire::Perform() // TEMPORARILY without special mode !!! Handle(ShapeExtend_WireData) sbwd = WireData(); for (Standard_Integer iedge = 1; iedge <= sbwd->NbEdges(); iedge++) - if ( myFixEdge->FixVertexTolerance (sbwd->Edge (iedge)) ) + if ( myFixEdge->FixVertexTolerance (sbwd->Edge (iedge), Face()) ) { Fixed = Standard_True; } @@ -800,7 +800,7 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves() } } } - myFixEdge->FixSameParameter ( sbwd->Edge(i) ); + myFixEdge->FixSameParameter ( sbwd->Edge(i), Face()); if ( myFixEdge->Status ( ShapeExtend_DONE ) ) myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 ); if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) @@ -814,7 +814,7 @@ Standard_Boolean ShapeFix_Wire::FixEdgeCurves() { for ( i=1; i <= nb; i++) { - myFixEdge->FixVertexTolerance (sbwd->Edge (i), face); + myFixEdge->FixVertexTolerance (sbwd->Edge (i), Face()); if ( myFixEdge->Status ( ShapeExtend_DONE ) ) myStatusEdgeCurves |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 ); if ( myFixEdge->Status ( ShapeExtend_FAIL ) ) @@ -1778,7 +1778,7 @@ static Standard_Boolean TryNewPCurve (const TopoDS_Edge &E, const TopoDS_Face &f // no call to BRepLib: B.SameParameter ( edge, Standard_False ); Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge; - sfe->FixSameParameter ( edge ); + sfe->FixSameParameter ( edge, face ); c2d = BRep_Tool::CurveOnSurface ( edge, face, first, last ); tol = BRep_Tool::Tolerance ( edge ); return Standard_True; diff --git a/tests/bugs/heal/bug26620 b/tests/bugs/heal/bug26620 new file mode 100644 index 0000000000..0c33f3dfa7 --- /dev/null +++ b/tests/bugs/heal/bug26620 @@ -0,0 +1,26 @@ +puts "REQUIRED ALL: Faulty shapes in variables faulty_1 to" + +puts "============" +puts "OCC26620" +puts "============" +puts "" +####################################################################### +## Shape healing unreasonably downgrades tolerance of a face +####################################################################### + +restore [locate_data_file bug26620_ff.brep] ff + +puts "\nBefore shape healing" +checkshape ff +tolerance ff + +fixshape r ff + +puts "\nAfter shape healing" +checkshape r +regexp {Tolerance +MAX=([-0-9.+eE]+)} [tolerance r] full MaxTol + +set expected_MaxTolerance 0.1 +set tol_abs_MaxTolerance 0.5 +set tol_rel_MaxTolerance 0.5 +checkreal "MaxTolerance" ${MaxTol} ${expected_MaxTolerance} ${tol_abs_MaxTolerance} ${tol_rel_MaxTolerance}