1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0022598: Approximation of p-curve by 2D line

Check whether p-curve being projected can be approximated by straight line is made before full-scale projection, to improve performance.
If straight, pcurve is created as Line only if this will lead to the same range parameterization as 3d curve, otherwise BSpline of degree 1 is created.
Re-approximation of line pcurves by bsplines removed from ShapeFix_Edge.

Test case updating to new behavior.

Added "static" keyword to the  fixPeriodictyTroubles() function.

Update of test-cases according new behavior
This commit is contained in:
aml
2015-02-05 17:57:20 +03:00
committed by bugmaster
parent 9ccea0c628
commit 15b54261a3
275 changed files with 696 additions and 543 deletions

View File

@@ -210,6 +210,18 @@ is
pout : out Array1OfReal from TColStd)
returns Boolean is private;
getLine(me ; points : Array1OfPnt from TColgp;
params : Array1OfReal from TColStd;
points2d: out Array1OfPnt2d from TColgp;
theTol : Real;
IsRecompute: in out Boolean) returns Curve from Geom2d is protected;
---Purpose: Try to approximate 3D curve by Geom2d_Line
-- or Geom2d_BsplineCurve with degree 1 with specified tolerance.
-- points - points obtained from 3d curve.
-- params - parameters corresponding points on 3d curves
-- points2d - 2d points lies on line in parametric space
-- theTol - tolerance used for compare initial points 3d and
-- 3d points obtained from line lying in parameric space of surface
fields

View File

@@ -307,7 +307,6 @@ Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::Perform (Handle(Geom_Curv
c2d = InterpolatePCurve (nbPini, thePnts2d, theParams2d, c3d);
// c2d = ApproximatePCurve (nbPini, thePnts2d, theParams2d, c3d);
// Faut-il aussi reprendre la C3D ?
myStatus |= ShapeExtend::EncodeStatus (c2d.IsNull() ? ShapeExtend_FAIL1 : ShapeExtend_DONE2);
return Status (ShapeExtend_DONE);
}
@@ -463,19 +462,211 @@ Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::PerformAdvanced (Handle(G
return result;
}
//! Fix possible period jump and handle walking period parameter.
static Standard_Boolean fixPeriodictyTroubles(gp_Pnt2d *thePnt, // pointer to gp_Pnt2d[4] beginning
Standard_Integer theIdx, // Index of objective coord: 1 ~ X, 2 ~ Y
Standard_Real thePeriod) // Period on objective coord
{
Standard_Integer i;
Standard_Boolean isNeedToFix = Standard_True;
for (i = 0; i < 3; i++)
{
Standard_Real aDiff = Abs (thePnt[i].Coord(theIdx) - thePnt[i + 1].Coord(theIdx));
if ( aDiff > Precision::PConfusion() &&
aDiff < thePeriod - Precision::PConfusion())
{
// Walk over period coord -> not walking on another isoline in parameter space.
isNeedToFix = Standard_False;
}
}
if (isNeedToFix)
{
// Walking on isoline on another parameter. Fix period paramter to obtained minimum.
Standard_Real aFixParam = Min (thePnt[0].Coord(theIdx), thePnt[3].Coord(theIdx));
for(i = 0; i < 4; i++)
thePnt[i].SetCoord(theIdx, aFixParam);
}
// Fix possible period jump on first point.
if ( Abs(thePnt[0].Coord(theIdx) - thePnt[1].Coord(theIdx) ) > thePeriod / 2.01)
{
Standard_Real aMult = thePnt[0].Coord(theIdx) < thePnt[1].Coord(theIdx) ? 1.0 : -1.0;
Standard_Real aNewParam = thePnt[0].Coord(theIdx) + aMult * thePeriod;
thePnt[0].SetCoord(theIdx, aNewParam);
return Standard_False;
}
// Fix possible period jump on last point.
if ( Abs(thePnt[2].Coord(theIdx) - thePnt[3].Coord(theIdx) ) > thePeriod / 2.01)
{
Standard_Real aMult = thePnt[3].Coord(theIdx) < thePnt[2].Coord(theIdx) ? 1.0 : -1.0;
Standard_Real aNewParam = thePnt[3].Coord(theIdx) + aMult * thePeriod;
thePnt[3].SetCoord(theIdx, aNewParam);
return Standard_False;
}
return Standard_True;
}
//=======================================================================
//function : getLine
//purpose :
//=======================================================================
Handle(Geom2d_Curve) ShapeConstruct_ProjectCurveOnSurface::getLine(
const TColgp_Array1OfPnt& thepoints,
const TColStd_Array1OfReal& theparams,
TColgp_Array1OfPnt2d& thePnt2ds,
Standard_Real theTol,
Standard_Boolean &isRecompute) const
{
Standard_Integer nb = thepoints.Length();
gp_Pnt aP[4];
aP[0] = thepoints(1);
aP[1] = thepoints(2);
aP[2] = thepoints(nb - 1);
aP[3] = thepoints(nb);
gp_Pnt2d aP2d[4];
Standard_Integer i = 0;
Standard_Real aTol2 = theTol * theTol;
Standard_Boolean isPeriodicU = mySurf->Surface()->IsUPeriodic();
Standard_Boolean isPeriodicV = mySurf->Surface()->IsVPeriodic();
// Workaround:
// Protection against bad "tolerance" shapes.
if (aTol2 > 1.0)
{
theTol = Precision::Confusion();
aTol2 = theTol * theTol;
}
Standard_Real anOldTol2 = aTol2;
// project first and last points
for( ; i < 4; i +=3)
{
Standard_Integer j;
for ( j=0; j < myNbCashe; j++ )
if ( myCashe3d[j].SquareDistance (aP[i] ) < aTol2)
{
aP2d[i] = mySurf->NextValueOfUV (myCashe2d[j], aP[i], theTol,
theTol);
break;
}
if ( j >= myNbCashe )
aP2d[i] = mySurf->ValueOfUV(aP[i], theTol);
Standard_Real aDist = mySurf->Gap();
Standard_Real aCurDist = aDist * aDist;
if( aTol2 < aDist * aDist)
aTol2 = aCurDist;
}
if ( isPeriodicU || isPeriodicV )
{
// Compute second and last but one c2d points.
for(i = 1; i < 3; i++)
{
Standard_Integer j;
for ( j=0; j < myNbCashe; j++ )
if ( myCashe3d[j].SquareDistance (aP[i] ) < aTol2)
{
aP2d[i] = mySurf->NextValueOfUV (myCashe2d[j], aP[i], theTol, theTol);
break;
}
if ( j >= myNbCashe )
aP2d[i] = mySurf->ValueOfUV(aP[i], theTol);
Standard_Real aDist = mySurf->Gap();
Standard_Real aCurDist = aDist * aDist;
if( aTol2 < aDist * aDist)
aTol2 = aCurDist;
}
if (isPeriodicU)
{
isRecompute = fixPeriodictyTroubles(&aP2d[0], 1 /* X Coord */, mySurf->Surface()->UPeriod());
}
if (isPeriodicV)
{
isRecompute = fixPeriodictyTroubles(&aP2d[0], 2 /* Y Coord */, mySurf->Surface()->VPeriod());
}
}
thePnt2ds.SetValue(1, aP2d[0]);
thePnt2ds.SetValue(nb, aP2d[3]);
// Restore old tolerance in 2d space to avoid big gap cases.
aTol2 = anOldTol2;
// Check that straight line in 2d with parameterisation as in 3d will fit
// fit 3d curve at all points.
Standard_Real dPar = theparams(nb) - theparams(1);
if ( Abs(dPar) < Precision::PConfusion() )
return 0;
gp_Vec2d aVec0 (aP2d[0], aP2d[3]);
gp_Vec2d aVec = aVec0 / dPar;
Standard_Real aFirstPointDist = mySurf->Surface()->Value(aP2d[0].X(), aP2d[0].Y()).
SquareDistance(thepoints(1));
for(i = 2; i < nb; i++)
{
gp_XY aCurPoint = aP2d[0].XY() + aVec.XY() * (theparams(i) - theparams(1));
gp_Pnt aCurP;
mySurf->Surface()->D0(aCurPoint.X(), aCurPoint.Y(), aCurP);
Standard_Real aDist1 = aCurP.SquareDistance(thepoints(i));
if(Abs (aFirstPointDist - aDist1) > aTol2)
return 0;
}
// check if pcurve can be represented by Geom2d_Line (parameterised by length)
Standard_Real aLLength = aVec0.Magnitude();
if ( Abs (aLLength - dPar) <= Precision::PConfusion() )
{
gp_XY aDirL = aVec0.XY() / aLLength;
gp_Pnt2d aPL (aP2d[0].XY() - theparams(1) * aDirL);
return new Geom2d_Line (aPL, gp_Dir2d(aDirL));
}
// create straight bspline
TColgp_Array1OfPnt2d aPoles(1, 2);
aPoles(1) = aP2d[0];
aPoles(2) = aP2d[3];
TColStd_Array1OfReal aKnots(1,2);
aKnots(1) = theparams(1);
aKnots(2) = theparams(theparams.Length());
TColStd_Array1OfInteger aMults(1,2);
aMults(1) = 2;
aMults(2) = 2;
Standard_Integer aDegree = 1;
Handle(Geom2d_BSplineCurve) abspl2d =
new Geom2d_BSplineCurve (aPoles, aKnots, aMults, aDegree);
return abspl2d;
}
//=======================================================================
//function : ApproxPCurve
//purpose :
//=======================================================================
Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::ApproxPCurve(const Standard_Integer nbrPnt,
Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::ApproxPCurve(const Standard_Integer nbrPnt,
const TColgp_Array1OfPnt& points,
const TColStd_Array1OfReal& params,
TColgp_Array1OfPnt2d& pnt2d,
Handle(Geom2d_Curve)& c2d)
{
Standard_Boolean isDone = Standard_True;
// for performance, first try to handle typical case when pcurve is straight
Standard_Boolean isRecompute = Standard_False;
c2d = getLine(points, params, pnt2d, myPreci, isRecompute);
if(!c2d.IsNull())
{
return Standard_True;
}
Standard_Boolean isDone = Standard_True;
// test if the curve 3d is a boundary of the surface
// (only for Bezier or BSpline surface)
@@ -628,17 +819,29 @@ Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::PerformAdvanced (Handle(G
if ( (i == 1) && p1OnIso) p2d = valueP1;
else if( (i == nbrPnt) && p2OnIso) p2d = valueP2;
else {// general case (not an iso) mais attention aux singularites !
if ( ii==1 ) {
//:q9 abv 23 Mar 99: use cashe as 1st approach
Standard_Integer j; // svv #1
for ( j=0; j < myNbCashe; j++ )
if ( myCashe3d[j].SquareDistance ( p3d ) < myPreci*myPreci ) {
p2d = mySurf->NextValueOfUV (myCashe2d[j], p3d, myPreci,
Precision::Confusion()+gap);
break;
}
if ( j >= myNbCashe ) p2d = mySurf->ValueOfUV(p3d, myPreci);
}
// first and last points are already computed by getLine()
if ( (i == 1 || i == nbrPnt))
{
if (!isRecompute)
{
p2d = pnt2d(i);
gap = mySurf->Gap();
continue;
}
else
{
//:q9 abv 23 Mar 99: use cashe as 1st approach
Standard_Integer j; // svv #1
for ( j=0; j < myNbCashe; j++ )
if ( myCashe3d[j].SquareDistance ( p3d ) < myPreci*myPreci )
{
p2d = mySurf->NextValueOfUV (myCashe2d[j], p3d, myPreci,
Precision::Confusion()+gap);
break;
}
if ( j >= myNbCashe ) p2d = mySurf->ValueOfUV(p3d, myPreci);
}
}
else {
p2d = mySurf->NextValueOfUV (p2d, p3d, myPreci, //:S4030: optimizing
Precision::Confusion()+1000*gap); //:q1
@@ -964,21 +1167,6 @@ Standard_Boolean ShapeConstruct_ProjectCurveOnSurface::PerformAdvanced (Handle(G
myCashe2d[1] = pnt2d(1);
myCashe2d[0] = pnt2d(nbrPnt);
}
if (isoParam && isoPar2d3d) {
// create directly isoparametrics (PCurve)
gp_Vec2d aVec2d(valueP1, valueP2);
gp_Dir2d aDir2d(aVec2d);
gp_Pnt2d P0;
if (isoTypeU) P0.SetCoord(valueP1.X(), valueP1.Y() - params(1)*aDir2d.Y());
else P0.SetCoord(valueP1.X() - params(1)*aDir2d.X(), valueP1.Y());
c2d = new Geom2d_Line(P0, aDir2d);
}
return isDone;
}
@@ -1432,7 +1620,7 @@ Handle(Geom_Curve) ShapeConstruct_ProjectCurveOnSurface::InterpolateCurve3d(cons
if (mp[0] > 0 &&
( ! p1OnIso || currd2[0] < mind2[0] ) ) {
p1OnIso = Standard_True;
mind2[0] = currd2[0];
mind2[0] = currd2[0]; // LP2.stp #105899: FLT_INVALID_OPERATION on Windows 7 VC 9 Release mode on the whole file
if (isoU) valueP1.SetCoord(isoVal, tp[0]);
else valueP1.SetCoord(tp[0], isoVal);
}