From 75ee56f2dfedde283df9b1afcb209bdbcb7f9d94 Mon Sep 17 00:00:00 2001 From: ifv Date: Thu, 23 Oct 2014 16:13:26 +0400 Subject: [PATCH] Analyzer for surface normals is added --- src/BRepCheck/BRepCheck_SurfNormAnalyzer.cxx | 342 +++++++++++++++++++ src/BRepCheck/BRepCheck_SurfNormAnalyzer.hxx | 84 +++++ src/BRepCheck/FILES | 1 + src/BRepTest/BRepTest_CheckCommands.cxx | 61 ++++ 4 files changed, 488 insertions(+) create mode 100644 src/BRepCheck/BRepCheck_SurfNormAnalyzer.cxx create mode 100644 src/BRepCheck/BRepCheck_SurfNormAnalyzer.hxx create mode 100644 src/BRepCheck/FILES diff --git a/src/BRepCheck/BRepCheck_SurfNormAnalyzer.cxx b/src/BRepCheck/BRepCheck_SurfNormAnalyzer.cxx new file mode 100644 index 0000000000..3fcbd5067b --- /dev/null +++ b/src/BRepCheck/BRepCheck_SurfNormAnalyzer.cxx @@ -0,0 +1,342 @@ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static Standard_Real AdjustExtr(const Adaptor3d_Surface& S, + const Standard_Real UMin, + const Standard_Real UMax, + const Standard_Real VMin, + const Standard_Real VMax, + const Standard_Real Extr0, + const Standard_Real Tol, + Standard_Real& uextr, + Standard_Real& vextr ); + + + +//======================================================================= +//function : BRepCheck_Analyzer +//purpose : +//======================================================================= + +BRepCheck_SurfNormAnalyzer::BRepCheck_SurfNormAnalyzer (): +myAngTol(0.01) +{ + +} + + +//======================================================================= +//function : BRepCheck_Analyzer +//purpose : +//======================================================================= + +BRepCheck_SurfNormAnalyzer::BRepCheck_SurfNormAnalyzer + (const TopoDS_Shape& theS, + const Standard_Real theAngTol): +myShape(theS), myAngTol(theAngTol) +{ + +} + + + +//======================================================================= +//function : IsValid +//purpose : +//======================================================================= + +Standard_Boolean BRepCheck_SurfNormAnalyzer::IsValid() +{ + TopLoc_Location anL; + myBadFaces.Clear(); + Standard_Real umin, umax, vmin, vmax; + TopExp_Explorer anEx(myShape, TopAbs_FACE); + for(; anEx.More(); anEx.Next()) + { + TopoDS_Face aF = TopoDS::Face(anEx.Current()); + BRepTools::UVBounds(aF, umin, umax, vmin, vmax); + const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aF, anL); + if(IsProblemSurf(aSurf, umin, umax, vmin, vmax, myAngTol)) + { + myBadFaces.Append(aF); + } + } + + + return myBadFaces.IsEmpty(); +} +//======================================================================= +//function : BadFaces +//purpose : +//======================================================================= +const TopTools_ListOfShape& BRepCheck_SurfNormAnalyzer::BadFaces() const +{ + return myBadFaces; +} +//======================================================================= +//function : SetShape +//purpose : +//======================================================================= + +void BRepCheck_SurfNormAnalyzer::SetShape(const TopoDS_Shape& theShape) +{ + myBadFaces.Clear(); + myShape = theShape; +} +//======================================================================= +//function : SetTolerance +//purpose : +//======================================================================= + +void BRepCheck_SurfNormAnalyzer::SetTolerance(const Standard_Real theAngTol) +{ + myBadFaces.Clear(); + myAngTol = theAngTol; +} +//======================================================================= +//function : GetShape +//purpose : +//======================================================================= + +const TopoDS_Shape& BRepCheck_SurfNormAnalyzer::GetShape() const +{ + return myShape; +} +//======================================================================= +//function : GetTolerance +//purpose : +//======================================================================= + +Standard_Real BRepCheck_SurfNormAnalyzer::GetTolerance() const +{ + return myAngTol; +} +//======================================================================= +//function : IsProblemSurf +//purpose : +//======================================================================= + +Standard_Boolean +BRepCheck_SurfNormAnalyzer::IsProblemSurf(const Handle_Geom_Surface& theSurf, + const Standard_Real theUMin, + const Standard_Real theUMax, + const Standard_Real theVMin, + const Standard_Real theVMax, + const Standard_Real theAngTol) +{ + Standard_Boolean aStatus = Standard_False; + GeomAdaptor_Surface aGAS(theSurf, theUMin, theUMax, theVMin, theVMax); + GeomAbs_SurfaceType aSType = aGAS.GetType(); + // + if(aSType <= GeomAbs_Torus) + { + return aStatus; + } + // + Handle(GeomAdaptor_HSurface) aGAHS = new GeomAdaptor_HSurface(aGAS); + Handle(Adaptor3d_TopolTool) aTT = new Adaptor3d_TopolTool(aGAHS); + if(aTT->DomainIsInfinite()) + { + return aStatus; + } + // + Standard_Real aDefl = 0.1; //the same as for intersection default + Standard_Integer aNbMinU = 10, aNbMinV = 10; + aTT->SamplePnts(aDefl, aNbMinU, aNbMinV); + Standard_Integer aNbU = aTT->NbSamplesU(); + Standard_Integer aNbV = aTT->NbSamplesV(); + TColStd_Array1OfReal anUPars(1, aNbU), aVPars(1, aNbV); + aTT->UParameters(anUPars); + aTT->VParameters(aVPars); + // + gp_Pnt aP; + gp_Vec aDU, aDV; + Standard_Real u, v, ang; + TColStd_Array2OfReal aTabN(1, aNbU, 1, aNbV); + Standard_Integer i, j; + //Check singular point on boundary + for(j = 1; j <= aNbV; j += aNbV-1) + { + aP = theSurf->Value(anUPars(1), aVPars(j)); + Standard_Real length = 0.; + for(i = 2; i <= aNbU; ++i) + { + gp_Pnt aPcur = theSurf->Value(anUPars(i), aVPars(j)); + length += aPcur.Distance(aP); + if(length > Precision::Confusion()) + { + break; + } + aP = aPcur; + } + if(length <= Precision::Confusion()) + { + if(j == 1) + { + aVPars(j) += (aVPars(2)-aVPars(1)) / 10.; + } + else + { + aVPars(aNbV) -= (aVPars(aNbV)-aVPars(aNbV-1)) / 10.; + } + } + } + for(j = 1; j <= aNbU; j += aNbU-1) + { + aP = theSurf->Value(anUPars(j), aVPars(1)); + Standard_Real length = 0.; + for(i = 2; i <= aNbV; ++i) + { + gp_Pnt aPcur = theSurf->Value(anUPars(j), aVPars(i)); + length += aPcur.Distance(aP); + if(length > Precision::Confusion()) + { + break; + } + aP = aPcur; + } + if(length <= Precision::Confusion()) + { + if(j == 1) + { + anUPars(j) += (anUPars(2)-anUPars(1)) / 10.; + } + else + { + anUPars(aNbU) -= (anUPars(aNbU)-anUPars(aNbU-1)) / 10.; + } + } + } + // + for(i = 1; i <= aNbU; ++i) + { + u = anUPars(i); + for(j = 1; j <= aNbV; ++j) + { + v = aVPars(j); + theSurf->D1(u, v, aP, aDU, aDV); + try + { + ang = aDU.Angle(aDV); + if(ang > M_PI/2.) + { + ang = M_PI - ang; + } + } + catch (gp_VectorWithNullMagnitude) + { + ang = 0.; + } + + aTabN(i, j) = ang; + } + } + // + Standard_Real min = RealLast(); + Standard_Integer imin = 0, jmin = 0; + for(i = 1; i <= aNbU; ++i) + { + for(j = 1; j <= aNbV; ++j) + { + if(aTabN(i, j) < theAngTol) + { + return Standard_True; + } + else + { + if(aTabN(i, j) < min) + { + min = aTabN(i, j); + imin = i; + jmin = j; + } + } + } + } + // + Standard_Real umin = anUPars(Max(1, imin-1)); + Standard_Real umax = anUPars(Min(aNbU, imin+1)); + Standard_Real vmin = aVPars(Max(1, jmin-1)); + Standard_Real vmax = aVPars(Min(aNbV, jmin+1)); + // + Standard_Real min0 = min, uextr = anUPars(imin), vextr = aVPars(jmin); + min = AdjustExtr(aGAS, umin, umax, vmin, vmax, + min0, theAngTol / 10., uextr, vextr ); + + if(min < theAngTol) + { + aStatus = Standard_True; + } + return aStatus; +} +Standard_Real AdjustExtr(const Adaptor3d_Surface& S, + const Standard_Real UMin, + const Standard_Real UMax, + const Standard_Real VMin, + const Standard_Real VMax, + const Standard_Real Extr0, + const Standard_Real Tol, + Standard_Real& uextr, + Standard_Real& vextr ) +{ + Standard_Integer Nu = 5, Nv = 5; + gp_Pnt P; + gp_Vec DU, DV; + Standard_Integer i, j; + Standard_Real du = (UMax-UMin)/(Nu-1); + Standard_Real dv = (VMax-VMin)/(Nv-1); + Standard_Real extr = Extr0; + Standard_Real u, v, ang; + for (i = 1, u = UMin; i <= Nu; i++, u += du){ + for (j = 1, v = VMin;j <= Nv; j++, v += dv){ + S.D1(u,v,P,DU,DV); + try + { + ang = DU.Angle(DV); + if(ang > M_PI/2.) + { + ang = M_PI - ang; + } + } + catch (gp_VectorWithNullMagnitude) + { + ang = 0.; + } + // + if(extr > ang) + { + extr = ang; + uextr = u; + vextr = v; + } + } + } + + if(Abs(extr - Extr0) > Tol) + { + Standard_Real umin, umax, vmin, vmax; + umin = Max(UMin, uextr - du); + umax = Min(UMax, uextr + du); + vmin = Max(VMin, vextr - dv); + vmax = Min(VMax, vextr + dv); + Standard_Real extr0 = extr; + extr = AdjustExtr(S, umin, umax, vmin, vmax, + extr0, Tol, uextr, vextr); + } + return extr; +} \ No newline at end of file diff --git a/src/BRepCheck/BRepCheck_SurfNormAnalyzer.hxx b/src/BRepCheck/BRepCheck_SurfNormAnalyzer.hxx new file mode 100644 index 0000000000..2076992ae6 --- /dev/null +++ b/src/BRepCheck/BRepCheck_SurfNormAnalyzer.hxx @@ -0,0 +1,84 @@ + +#ifndef _BRepCheck_SurfNormAnalyzer_HeaderFile +#define _BRepCheck_SurfNormAnalyzer_HeaderFile + +#ifndef _Standard_HeaderFile +#include +#endif +#ifndef _Standard_DefineAlloc_HeaderFile +#include +#endif +#ifndef _Standard_Macro_HeaderFile +#include +#endif + +#ifndef _TopoDS_Shape_HeaderFile +#include +#endif + +#ifndef _Standard_Boolean_HeaderFile +#include +#endif + +#ifndef _TopAbs_ShapeEnum_HeaderFile +#include +#endif + +#include + +class Handle_Geom_Surface; + + +//! A class to check the problems with calculations
+//! of normals of face surfaces when dS/du and dS/dv are almost parallel: +//! normal to surface is calculated as N = dS/du^dS/dv and when
+//! dS/du || dS/dv N is poor defined. It can cause problems in intersection
+//! and other algoritms.
+//! This class diagnoses whether the area on the surface where angle between dS/du
+//! and dS/dv less then given angular tolerance.
+class BRepCheck_SurfNormAnalyzer { +public: + + DEFINE_STANDARD_ALLOC + // + Standard_EXPORT BRepCheck_SurfNormAnalyzer(); + Standard_EXPORT BRepCheck_SurfNormAnalyzer(const TopoDS_Shape& theS, const Standard_Real theAngTol); + // + Standard_EXPORT void SetShape(const TopoDS_Shape& theS); + Standard_EXPORT void SetTolerance(const Standard_Real theAngTol); + // + Standard_EXPORT Standard_Boolean IsValid(); + // + Standard_EXPORT const TopoDS_Shape& GetShape() const; + Standard_EXPORT Standard_Real GetTolerance() const; + // + Standard_EXPORT const TopTools_ListOfShape& BadFaces() const; + // + Standard_EXPORT static Standard_Boolean + IsProblemSurf(const Handle_Geom_Surface& theSurf, + const Standard_Real theUMin, + const Standard_Real theUMax, + const Standard_Real theVMin, + const Standard_Real theVMax, + const Standard_Real theAngTol); + + +protected: + + + + + +private: + + +TopoDS_Shape myShape; +TopTools_ListOfShape myBadFaces; +Standard_Real myAngTol; + + +}; + + + +#endif diff --git a/src/BRepCheck/FILES b/src/BRepCheck/FILES new file mode 100644 index 0000000000..23f46ec3c5 --- /dev/null +++ b/src/BRepCheck/FILES @@ -0,0 +1 @@ +BRepCheck_SurfNormAnalyzer.hxx diff --git a/src/BRepTest/BRepTest_CheckCommands.cxx b/src/BRepTest/BRepTest_CheckCommands.cxx index 03cc77f022..dcc1bfeb57 100644 --- a/src/BRepTest/BRepTest_CheckCommands.cxx +++ b/src/BRepTest/BRepTest_CheckCommands.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,60 @@ static void Print(Standard_OStream& OS, } +// +//======================================================================= +//function : checknorm +//purpose : Checks the normals of faces +//======================================================================= +static Standard_Integer checknorm(Draw_Interpretor& di, + Standard_Integer narg, const char** a) +{ + if (narg < 3) { + return 1; + } + Standard_Real tol = 1.e-2; + TopoDS_Shape S = DBRep::Get(a[2]); + if(S.IsNull()) + { + di << "Null shape \n"; + return 1; + } + TopExp_Explorer anExp(S, TopAbs_FACE); + if(!anExp.More()) + { + di << "There are no faces in shape /n"; + return 1; + } + // + if(narg > 3) + { + tol = atof(a[3]); + } + // + BRepCheck_SurfNormAnalyzer aNormChecker(S, tol); + if(aNormChecker.IsValid()) + { + di << "All faces seem to be valid \n" ; + return 0; + } + + const TopTools_ListOfShape& aBadFaces = aNormChecker.BadFaces(); + + // + di << " number of problematic faces : " << aBadFaces.Extent() << "\n"; + // + char Name[32]; + Standard_Integer ipp=0; + TopTools_ListIteratorOfListOfShape itf; + for (itf.Initialize(aBadFaces); itf.More(); itf.Next()) { + ipp++; + Sprintf(Name,"%s_%d",a[1], ipp); + DBRep::Set(Name, itf.Value()); + di << Name << " " ; + } + di << "\n"; + return 0; +} //======================================================================= //function : computetolerance //purpose : @@ -1677,5 +1732,11 @@ theCommands.Add("listfuseedge", "listfuseedge shape", __FILE__, listfuseedge,g); + +theCommands.Add("checknorm", + "checknorm name shape tol", + __FILE__, + checknorm,g); + } -- 2.39.5