1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-29 14:00:49 +03:00

Analyzer for surface normals is added

This commit is contained in:
ifv
2014-10-23 16:13:26 +04:00
committed by gka
parent 95ee0712bc
commit 75ee56f2df
4 changed files with 488 additions and 0 deletions

View File

@@ -0,0 +1,342 @@
#include <BRepCheck_SurfNormAnalyzer.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomAdaptor_HSurface.hxx>
#include <Adaptor3d_TopolTool.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <gp_VectorWithNullMagnitude.hxx>
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;
}

View File

@@ -0,0 +1,84 @@
#ifndef _BRepCheck_SurfNormAnalyzer_HeaderFile
#define _BRepCheck_SurfNormAnalyzer_HeaderFile
#ifndef _Standard_HeaderFile
#include <Standard.hxx>
#endif
#ifndef _Standard_DefineAlloc_HeaderFile
#include <Standard_DefineAlloc.hxx>
#endif
#ifndef _Standard_Macro_HeaderFile
#include <Standard_Macro.hxx>
#endif
#ifndef _TopoDS_Shape_HeaderFile
#include <TopoDS_Shape.hxx>
#endif
#ifndef _Standard_Boolean_HeaderFile
#include <Standard_Boolean.hxx>
#endif
#ifndef _TopAbs_ShapeEnum_HeaderFile
#include <TopAbs_ShapeEnum.hxx>
#endif
#include <TopTools_ListOfShape.hxx>
class Handle_Geom_Surface;
//! A class to check the problems with calculations<br>
//! 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<br>
//! dS/du || dS/dv N is poor defined. It can cause problems in intersection<br>
//! and other algoritms.<br>
//! This class diagnoses whether the area on the surface where angle between dS/du<br>
//! and dS/dv less then given angular tolerance. <br>
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

1
src/BRepCheck/FILES Normal file
View File

@@ -0,0 +1 @@
BRepCheck_SurfNormAnalyzer.hxx

View File

@@ -23,6 +23,7 @@
#include <BRepCheck_Analyzer.hxx>
#include <BRepCheck_Result.hxx>
#include <BRepCheck_ListIteratorOfListOfStatus.hxx>
#include <BRepCheck_SurfNormAnalyzer.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
@@ -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);
}