1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-02 17:46:22 +03:00

0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface

When collecting the points to build plane use the points on the curve instead of poles (in case of BSpline and Bezier curves).

Side effect changes:
Changes in Geom2dHatch_Elements are to increase the chance of correct 2d classification (by the means of Geom2dHatch_Classifier) by taking more than just one point on the edge to construct the classification ray and by checking if this ray is not tangent to the edge itself.
This commit is contained in:
emv 2019-09-26 14:50:10 +03:00 committed by apn
parent 97e0059b05
commit 5646c90e87
7 changed files with 246 additions and 198 deletions

View File

@ -55,6 +55,7 @@
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <NCollection_Vector.hxx>
//=======================================================================
//function : Controle
@ -174,6 +175,70 @@ BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape& S,
{
Init(S,Tol,OnlyPlane,OnlyClosed);
}
namespace
{
static void fillParams (const TColStd_Array1OfReal& theKnots,
Standard_Integer theDegree,
Standard_Real theParMin,
Standard_Real theParMax,
NCollection_Vector<Standard_Real>& theParams)
{
Standard_Real aPrevPar = theParMin;
theParams.Append (aPrevPar);
Standard_Integer aNbP = Max (theDegree, 1);
for (Standard_Integer i = 1;
(i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i)
{
if (theKnots (i + 1) < theParMin + Precision::PConfusion())
continue;
Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP;
for (Standard_Integer k = 1; k <= aNbP ; ++k)
{
Standard_Real aPar = theKnots (i) + k * aStep;
if (aPar > theParMax - Precision::PConfusion())
break;
if (aPar > aPrevPar + Precision::PConfusion())
{
theParams.Append (aPar);
aPrevPar = aPar;
}
}
}
theParams.Append (theParMax);
}
static void fillPoints (const BRepAdaptor_Curve& theCurve,
const NCollection_Vector<Standard_Real> theParams,
TColgp_SequenceOfPnt& thePoints,
TColStd_SequenceOfReal& theWeights)
{
Standard_Real aDistPrev = 0., aDistNext;
gp_Pnt aPPrev (theCurve.Value (theParams (0))), aPNext;
for (Standard_Integer iP = 1; iP <= theParams.Length(); ++iP)
{
if (iP < theParams.Length())
{
Standard_Real aParam = theParams (iP);
aPNext = theCurve.Value (aParam);
aDistNext = aPPrev.Distance (aPNext);
}
else
aDistNext = 0.0;
thePoints.Append (aPPrev);
theWeights.Append (aDistPrev + aDistNext);
aDistPrev = aDistNext;
aPPrev = aPNext;
}
}
}
//=======================================================================
//function : Init
//purpose :
@ -282,117 +347,57 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape& S,
}
Standard_Integer iNbPoints=0;
// Add the points with weights to the sequences
// Fill the parameters of the sampling points
NCollection_Vector<Standard_Real> aParams;
switch (c.GetType())
{
case GeomAbs_BezierCurve:
case GeomAbs_BezierCurve:
{
// Put all poles for bezier
Handle(Geom_BezierCurve) GC = c.Bezier();
Standard_Integer iNbPol = GC->NbPoles();
Standard_Real tf = GC->FirstParameter();
Standard_Real tl = GC->LastParameter();
Standard_Real r = (dfUl - dfUf) / (tl - tf);
r *= iNbPol;
if ( iNbPol < 2 || r < 1.)
// Degenerate
continue;
else
{
Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol);
GC->Poles(aPoles->ChangeArray1());
gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext;
Standard_Real dfDistPrev = 0., dfDistNext;
for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++)
{
if (iPol<iNbPol)
{
aPoleNext = aPoles->Value(iPol+1);
dfDistNext = aPolePrev.Distance(aPoleNext);
}
else
dfDistNext = 0.;
aPoints.Append (aPolePrev);
aWeight.Append (dfDistPrev+dfDistNext);
dfDistPrev = dfDistNext;
aPolePrev = aPoleNext;
}
}
}
break;
case GeomAbs_BSplineCurve:
{
// Put all poles for bspline
Handle(Geom_BSplineCurve) GC = c.BSpline();
Standard_Integer iNbPol = GC->NbPoles();
Standard_Real tf = GC->FirstParameter();
Standard_Real tl = GC->LastParameter();
Standard_Real r = (dfUl - dfUf) / (tl - tf);
r *= iNbPol;
if ( iNbPol < 2 || r < 1.)
// Degenerate
continue;
else
{
Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol);
GC->Poles(aPoles->ChangeArray1());
gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext;
Standard_Real dfDistPrev = 0., dfDistNext;
for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++)
{
if (iPol<iNbPol)
{
aPoleNext = aPoles->Value(iPol+1);
dfDistNext = aPolePrev.Distance(aPoleNext);
}
else
dfDistNext = 0.;
aPoints.Append (aPolePrev);
aWeight.Append (dfDistPrev+dfDistNext);
dfDistPrev = dfDistNext;
aPolePrev = aPoleNext;
}
}
}
break;
TColStd_Array1OfReal aKnots (1, 2);
aKnots.SetValue (1, GC->FirstParameter());
aKnots.SetValue (2, GC->LastParameter());
case GeomAbs_Line:
case GeomAbs_Circle:
case GeomAbs_Ellipse:
case GeomAbs_Hyperbola:
case GeomAbs_Parabola:
// Two points on straight segment, Four points on otheranalitical curves
iNbPoints = (c.GetType() == GeomAbs_Line ? 2 : 4);
Standard_FALLTHROUGH
default:
fillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
break;
}
case GeomAbs_BSplineCurve:
{
Handle(Geom_BSplineCurve) GC = c.BSpline();
fillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
break;
}
case GeomAbs_Line:
{
// Two points on a straight segment
aParams.Append (dfUf);
aParams.Append (dfUl);
break;
}
case GeomAbs_Circle:
case GeomAbs_Ellipse:
case GeomAbs_Hyperbola:
case GeomAbs_Parabola:
// Four points on other analytical curves
iNbPoints = 4;
Standard_FALLTHROUGH
default:
{
// Put some points on other curves
if (iNbPoints==0)
iNbPoints = 15 + c.NbIntervals(GeomAbs_C3);
Standard_Real dfDelta = (dfUl-dfUf)/(iNbPoints-1);
Standard_Integer iPoint;
Standard_Real dfU;
gp_Pnt aPointPrev = c.Value(dfUf), aPointNext;
Standard_Real dfDistPrev = 0., dfDistNext;
for (iPoint=1, dfU=dfUf+dfDelta;
iPoint<=iNbPoints;
iPoint++, dfU+=dfDelta)
{
if (iPoint<iNbPoints)
{
aPointNext = c.Value(dfU);
dfDistNext = aPointPrev.Distance(aPointNext);
}
else
dfDistNext = 0.;
aPoints.Append (aPointPrev);
aWeight.Append (dfDistPrev+dfDistNext);
dfDistPrev = dfDistNext;
aPointPrev = aPointNext;
}
} // default:
} // switch (c.GetType()) ...
} // for (ex.Init(S,TopAbs_EDGE); ex.More() && control; ex.Next()) ...
if (iNbPoints == 0)
iNbPoints = 15 + c.NbIntervals (GeomAbs_C3);
TColStd_Array1OfReal aBounds (1, 2);
aBounds.SetValue (1, dfUf);
aBounds.SetValue (2, dfUl);
fillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
}
}
// Add the points with weights to the sequences
fillPoints (c, aParams, aPoints, aWeight);
}
if (aPoints.Length() < 3) {
return;
@ -505,79 +510,33 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape& S,
}
}
}
//
// let us be more tolerant (occ415)
Standard_Real dfDist = RealLast();
Handle(Geom_Plane) aPlane;
//
if (isSolved) {
//Plane normal can have two directions, direction is chosen
//according to direction of eigenvector
gp_Vec anN(aVec(1), aVec(2), aVec(3));
aPlane = new Geom_Plane(aBaryCenter,anN);
dfDist = Controle (aPoints, aPlane);
}
//
if (!isSolved || myTolerance < dfDist) {
gp_Pnt aFirstPnt=aPoints(1);
for (iPoint=2; iPoint<=aPoints.Length(); iPoint++) {
gp_Vec aDir(aFirstPnt,aPoints(iPoint));
Standard_Real dfSide=aDir.Magnitude();
if (dfSide<myTolerance) {
continue; // degeneration
}
for (Standard_Integer iP1=iPoint+1; iP1<=aPoints.Length(); iP1++) {
gp_Vec aCross = gp_Vec(aFirstPnt,aPoints(iP1)) ^ aDir ;
if (!isSolved)
return;
if (aCross.Magnitude() > dfSide*myTolerance) {
Handle(Geom_Plane) aPlane2 = new Geom_Plane(aBaryCenter, aCross);
Standard_Real dfDist2 = Controle (aPoints, aPlane2);
if (dfDist2 < myTolerance) {
myTolReached = dfDist2;
mySurface = aPlane2;
return;
}
if (dfDist2 < dfDist) {
dfDist = dfDist2;
aPlane = aPlane2;
}
}
}
}
}
//
//XXf
//static Standard_Real weakness = 5.0;
Standard_Real weakness = 5.0;
//XXf
if(dfDist <= myTolerance || (dfDist < myTolerance*weakness && Tol<0)) {
//XXf
//myTolReached = dfDist;
//XXt
gp_Vec aN (aVec (1), aVec (2), aVec (3));
Handle(Geom_Plane) aPlane = new Geom_Plane (aBaryCenter, aN);
myTolReached = Controle (aPoints, aPlane);
const Standard_Real aWeakness = 5.0;
if (myTolReached <= myTolerance || (Tol < 0 && myTolReached < myTolerance * aWeakness))
{
mySurface = aPlane;
//If S is wire, try to orient surface according to orientation of wire.
if(S.ShapeType() == TopAbs_WIRE && S.Closed())
if (S.ShapeType() == TopAbs_WIRE && S.Closed())
{
//
TopoDS_Wire aW = TopoDS::Wire(S);
TopoDS_Face aTmpFace = BRepLib_MakeFace(mySurface, Precision::Confusion());
TopoDS_Wire aW = TopoDS::Wire (S);
TopoDS_Face aTmpFace = BRepLib_MakeFace (mySurface, Precision::Confusion());
BRep_Builder BB;
BB.Add(aTmpFace, aW);
BRepTopAdaptor_FClass2d FClass(aTmpFace, 0.);
if ( FClass.PerformInfinitePoint() == TopAbs_IN )
BB.Add (aTmpFace, aW);
BRepTopAdaptor_FClass2d FClass (aTmpFace, 0.);
if (FClass.PerformInfinitePoint() == TopAbs_IN)
{
gp_Dir aN = aPlane->Position().Direction();
aN.Reverse();
mySurface = new Geom_Plane(aPlane->Position().Location(), aN);
gp_Dir aNorm = aPlane->Position().Direction();
aNorm.Reverse();
mySurface = new Geom_Plane (aPlane->Position().Location(), aNorm);
}
}
}
//XXf
myTolReached = dfDist;
//XXt
}
//=======================================================================
//function : Found

View File

@ -28,6 +28,11 @@
#include <Standard_NoSuchObject.hxx>
#include <TColStd_MapIntegerHasher.hxx>
#include <TopAbs_Orientation.hxx>
#include <Precision.hxx>
static const Standard_Real Probing_Start = 0.123;
static const Standard_Real Probing_End = 0.8;
static const Standard_Real Probing_Step = 0.2111;
Geom2dHatch_Elements::Geom2dHatch_Elements(const Geom2dHatch_Elements& )
{
@ -41,6 +46,7 @@ Geom2dHatch_Elements::Geom2dHatch_Elements()
NumWire = 0;
NumEdge = 0;
myCurEdge = 1;
myCurEdgePar = Probing_Start;
}
void Geom2dHatch_Elements::Clear()
@ -102,7 +108,7 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P,
Standard_Real& Par)
{
myCurEdge = 1;
myCurEdgePar = Probing_Start;
return OtherSegment(P, L, Par);
}
@ -111,43 +117,91 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P,
//purpose :
//=======================================================================
Standard_Boolean Geom2dHatch_Elements::OtherSegment(const gp_Pnt2d& P,
gp_Lin2d& L,
Standard_Real& Par)
Standard_Boolean Geom2dHatch_Elements::OtherSegment (const gp_Pnt2d& P,
gp_Lin2d& L,
Standard_Real& Par)
{
Geom2dHatch_DataMapIteratorOfMapOfElements Itertemp;
Standard_Integer i;
for( Itertemp.Initialize(myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++) {
for (Itertemp.Initialize (myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++)
{
if (i < myCurEdge)
continue;
void *ptrmyMap = (void *)(&myMap);
Geom2dHatch_Element& Item=((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind(Itertemp.Key());
Geom2dHatch_Element& Item = ((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind (Itertemp.Key());
Geom2dAdaptor_Curve& E = Item.ChangeCurve();
TopAbs_Orientation Or= Item.Orientation();
gp_Pnt2d P2 = E.Value
((E.FirstParameter() + E.LastParameter()) *0.5);
if ((Or == TopAbs_FORWARD) ||
(Or == TopAbs_REVERSED)) {
gp_Vec2d V(P,P2);
Par = V.Magnitude();
if (Par >= gp::Resolution()) {
L = gp_Lin2d(P,V);
myCurEdge++;
return Standard_True;
TopAbs_Orientation Or = Item.Orientation();
if (Or == TopAbs_FORWARD || Or == TopAbs_REVERSED)
{
Standard_Real aFPar = E.FirstParameter(), aLPar = E.LastParameter();
if (Precision::IsNegativeInfinite (aFPar))
{
if (Precision::IsPositiveInfinite (aLPar))
{
aFPar = -1.;
aLPar = 1.;
}
else
aFPar = aLPar - 1.;
}
else if (Precision::IsPositiveInfinite (aLPar))
aLPar = aFPar + 1.;
for (; myCurEdgePar < Probing_End; myCurEdgePar += Probing_Step)
{
Standard_Real aParam = myCurEdgePar * aFPar + (1. - myCurEdgePar) * aLPar;
gp_Vec2d aTanVec;
gp_Pnt2d aPOnC;
E.D1 (aParam, aPOnC, aTanVec);
gp_Vec2d aLinVec (P, aPOnC);
Par = aLinVec.SquareMagnitude();
if (Par > Precision::SquarePConfusion())
{
gp_Dir2d aLinDir (aLinVec);
Standard_Real aTanMod = aTanVec.SquareMagnitude();
if (aTanMod < Precision::SquarePConfusion())
continue;
aTanVec /= Sqrt (aTanMod);
Standard_Real aSinA = aTanVec.Crossed (aLinDir);
if (Abs (aSinA) < 0.001)
{
// too small angle - line and edge may be considered
// as tangent which is bad for classifier
if (myCurEdgePar + Probing_Step < Probing_End)
continue;
}
L = gp_Lin2d (P, aLinDir);
aPOnC = E.Value (aFPar);
if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion())
{
aPOnC = E.Value (aLPar);
if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion())
{
myCurEdgePar += Probing_Step;
if (myCurEdgePar >= Probing_End)
{
myCurEdge++;
myCurEdgePar = Probing_Start;
}
Par = Sqrt (Par);
return Standard_True;
}
}
}
}
}
}
if (i == myCurEdge + 1) {
Par = RealLast();
L = gp_Lin2d(P,gp_Dir2d(1,0));
myCurEdge++;
return Standard_True;
myCurEdgePar = Probing_Start;
}
Par = RealLast();
L = gp_Lin2d (P, gp_Dir2d (1, 0));
return Standard_False;
}

View File

@ -114,7 +114,7 @@ private:
Standard_Integer NumWire;
Standard_Integer NumEdge;
Standard_Integer myCurEdge;
Standard_Real myCurEdgePar;
};

View File

@ -0,0 +1,22 @@
puts "============="
puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface"
puts "============="
brestore [locate_data_file bug30878_wire.brep] w
# build the face on the original wire
mkplane result w 1
checkprops result -s 69458.1
# reduce the tolerance
settolerance w 0.7
# build face again
mkplane result w 1
checkprops result -s 69458.1
set MaxFTol 0.7
set MaxETol 0.7
set MaxVTol 0.7

View File

@ -0,0 +1,11 @@
puts "REQUIRED ALL: Error. mkplane has been finished with \"Not Planar\" status."
puts "REQUIRED ALL: Error : The mkface can not be built."
puts "============="
puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface"
puts "============="
brestore [locate_data_file bug30878_wire2.brep] w
mkplane result w 1

View File

@ -1,9 +1,9 @@
puts "TODO OCC23068 ALL: Error : big tolerance of shape result"
puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2"
#puts "TODO OCC24255 ALL: An exception was caught"
#puts "TODO OCC24255 ALL: Error: Offset is not done."
#puts "TODO OCC24255 ALL: Error : The offset cannot be built."
#puts "TODO OCC23068 ALL: Error : big tolerance of shape result"
#puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2"
#puts "TODO OCC23068 ALL: Error : The resulting shape is WRONG"
puts "TODO OCC31005 ALL: Error: Offset is not done"
puts "TODO OCC31005 ALL: Error: The command cannot be built"
puts "TODO OCC31005 ALL: Error : The offset cannot be built"
restore [locate_data_file offset_wire_041.brep] s

View File

@ -1,4 +1,6 @@
puts "TODO OCC25109 ALL: Faulty shapes in variables"
puts "TODO OCC31005 ALL: Faulty shapes in variables"
puts "TODO OCC31005 ALL: Error : The length of result shape is"
puts "TODO OCC31005 ALL: Error : The resulting shape is WRONG"
restore [locate_data_file case_3_wire2.brep] s