mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-03 17:56:21 +03:00
978 lines
31 KiB
C++
978 lines
31 KiB
C++
// Created on: 1996-11-08
|
|
// Created by: Jean Claude VAUTHIER
|
|
// Copyright (c) 1996-1999 Matra Datavision
|
|
// Copyright (c) 1999-2014 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
#include <GCPnts_TangentialDeflection.hxx>
|
|
|
|
#include <GCPnts_TCurveTypes.hxx>
|
|
|
|
#include <gp_Pnt.hxx>
|
|
#include <gp_Pnt2d.hxx>
|
|
#include <gp_Vec.hxx>
|
|
#include <gp_Vec2d.hxx>
|
|
#include <gp_XYZ.hxx>
|
|
#include <math_BrentMinimum.hxx>
|
|
#include <math_PSO.hxx>
|
|
#include <Precision.hxx>
|
|
#include <Standard_ConstructionError.hxx>
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
|
|
namespace
|
|
{
|
|
static const Standard_Real Us3 = 0.3333333333333333333333333333;
|
|
|
|
inline static void D0 (const Adaptor3d_Curve& C, const Standard_Real U, gp_Pnt& P)
|
|
{
|
|
C.D0 (U, P);
|
|
}
|
|
|
|
inline static void D2 (const Adaptor3d_Curve& C, const Standard_Real U,
|
|
gp_Pnt& P, gp_Vec& V1, gp_Vec& V2)
|
|
{
|
|
C.D2 (U, P, V1, V2);
|
|
}
|
|
|
|
static void D0 (const Adaptor2d_Curve2d& C, const Standard_Real U, gp_Pnt& PP)
|
|
{
|
|
Standard_Real X, Y;
|
|
gp_Pnt2d P;
|
|
C.D0 (U, P);
|
|
P.Coord (X, Y);
|
|
PP.SetCoord (X, Y, 0.0);
|
|
}
|
|
|
|
static void D2 (const Adaptor2d_Curve2d& C, const Standard_Real U,
|
|
gp_Pnt& PP, gp_Vec& VV1, gp_Vec& VV2)
|
|
{
|
|
Standard_Real X, Y;
|
|
gp_Pnt2d P;
|
|
gp_Vec2d V1,V2;
|
|
C.D2 (U, P, V1, V2);
|
|
P.Coord (X, Y);
|
|
PP.SetCoord (X, Y, 0.0);
|
|
V1.Coord (X, Y);
|
|
VV1.SetCoord (X, Y, 0.0);
|
|
V2.Coord (X, Y);
|
|
VV2.SetCoord (X, Y, 0.0);
|
|
}
|
|
|
|
static Standard_Real EstimAngl (const gp_Pnt& P1, const gp_Pnt& Pm, const gp_Pnt& P2)
|
|
{
|
|
gp_Vec V1(P1, Pm), V2(Pm, P2);
|
|
Standard_Real L = V1.Magnitude() * V2.Magnitude();
|
|
if (L > gp::Resolution())
|
|
{
|
|
return V1.CrossMagnitude(V2)/L;
|
|
}
|
|
else
|
|
{
|
|
return 0.;
|
|
}
|
|
}
|
|
|
|
// Return number of interval of continuity on which theParam is located.
|
|
// Last parameter is used to increase search speed.
|
|
static Standard_Integer getIntervalIdx(const Standard_Real theParam,
|
|
TColStd_Array1OfReal& theIntervs,
|
|
const Standard_Integer thePreviousIdx)
|
|
{
|
|
Standard_Integer anIdx;
|
|
for(anIdx = thePreviousIdx; anIdx < theIntervs.Upper(); anIdx++)
|
|
{
|
|
if (theParam >= theIntervs(anIdx) &&
|
|
theParam <= theIntervs(anIdx + 1)) // Inside of anIdx interval.
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return anIdx;
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GCPnts_TangentialDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
GCPnts_TangentialDeflection::GCPnts_TangentialDeflection()
|
|
: myAngularDeflection (0.0),
|
|
myCurvatureDeflection (0.0),
|
|
myUTol (0.0),
|
|
myMinNbPnts (0),
|
|
myMinLen(0.0),
|
|
myLastU (0.0),
|
|
myFirstu (0.0)
|
|
{
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GCPnts_TangentialDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (const Adaptor3d_Curve& theC,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
: myAngularDeflection (0.0),
|
|
myCurvatureDeflection (0.0),
|
|
myUTol (0.0),
|
|
myMinNbPnts (0),
|
|
myMinLen(0.0),
|
|
myLastU (0.0),
|
|
myFirstu (0.0)
|
|
{
|
|
Initialize (theC, theAngularDeflection, theCurvatureDeflection, theMinimumOfPoints, theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GCPnts_TangentialDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (const Adaptor3d_Curve& theC,
|
|
const Standard_Real theFirstParameter, const Standard_Real theLastParameter,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
: myAngularDeflection (0.0),
|
|
myCurvatureDeflection (0.0),
|
|
myUTol (0.0),
|
|
myMinNbPnts (0),
|
|
myMinLen(0.0),
|
|
myLastU (0.0),
|
|
myFirstu (0.0)
|
|
{
|
|
Initialize (theC, theFirstParameter, theLastParameter,
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GCPnts_TangentialDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (const Adaptor2d_Curve2d& theC,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
: myAngularDeflection (0.0),
|
|
myCurvatureDeflection (0.0),
|
|
myUTol (0.0),
|
|
myMinNbPnts (0),
|
|
myMinLen(0.0),
|
|
myLastU (0.0),
|
|
myFirstu (0.0)
|
|
{
|
|
Initialize (theC, theAngularDeflection, theCurvatureDeflection, theMinimumOfPoints, theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GCPnts_TangentialDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (const Adaptor2d_Curve2d& theC,
|
|
const Standard_Real theFirstParameter, const Standard_Real theLastParameter,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
: myAngularDeflection (0.0),
|
|
myCurvatureDeflection (0.0),
|
|
myUTol (0.0),
|
|
myMinNbPnts (0),
|
|
myMinLen(0.0),
|
|
myLastU (0.0),
|
|
myFirstu (0.0)
|
|
{
|
|
Initialize (theC, theFirstParameter, theLastParameter,
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
void GCPnts_TangentialDeflection::Initialize (const Adaptor3d_Curve& theC,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
{
|
|
Initialize (theC, theC.FirstParameter(), theC.LastParameter(),
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
void GCPnts_TangentialDeflection::Initialize (const Adaptor2d_Curve2d& theC,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
{
|
|
Initialize (theC, theC.FirstParameter(), theC.LastParameter(),
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol, theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
void GCPnts_TangentialDeflection::Initialize (const Adaptor3d_Curve& theC,
|
|
const Standard_Real theFirstParameter, const Standard_Real theLastParameter,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
{
|
|
initialize (theC, theFirstParameter, theLastParameter,
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol,
|
|
theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
void GCPnts_TangentialDeflection::Initialize (const Adaptor2d_Curve2d& theC,
|
|
const Standard_Real theFirstParameter, const Standard_Real theLastParameter,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
{
|
|
initialize (theC, theFirstParameter, theLastParameter,
|
|
theAngularDeflection, theCurvatureDeflection,
|
|
theMinimumOfPoints,
|
|
theUTol,
|
|
theMinLen);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : EvaluateDu
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::EvaluateDu (const TheCurve& theC,
|
|
const Standard_Real theU,
|
|
gp_Pnt& theP,
|
|
Standard_Real& theDu,
|
|
Standard_Boolean& theNotDone) const
|
|
{
|
|
gp_Vec T, N;
|
|
D2 (theC, theU, theP, T, N);
|
|
Standard_Real Lt = T.Magnitude();
|
|
constexpr Standard_Real LTol = Precision::Confusion();
|
|
if (Lt > LTol && N.Magnitude () > LTol)
|
|
{
|
|
Standard_Real Lc = N.CrossMagnitude (T);
|
|
Standard_Real Ln = Lc/Lt;
|
|
if (Ln > LTol)
|
|
{
|
|
theDu = sqrt (8.0 * Max (myCurvatureDeflection, myMinLen) / Ln);
|
|
theNotDone = Standard_False;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : PerformLinear
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::PerformLinear (const TheCurve& theC)
|
|
{
|
|
gp_Pnt P;
|
|
D0 (theC, myFirstu, P);
|
|
myParameters.Append (myFirstu);
|
|
myPoints .Append (P);
|
|
if (myMinNbPnts > 2)
|
|
{
|
|
Standard_Real Du = (myLastU - myFirstu) / myMinNbPnts;
|
|
Standard_Real U = myFirstu + Du;
|
|
for (Standard_Integer i = 2; i < myMinNbPnts; i++)
|
|
{
|
|
D0 (theC, U, P);
|
|
myParameters.Append (U);
|
|
myPoints .Append (P);
|
|
U += Du;
|
|
}
|
|
}
|
|
D0 (theC, myLastU, P);
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (P);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : PerformCircular
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::PerformCircular (const TheCurve& theC)
|
|
{
|
|
// akm 8/01/02 : check the radius before divide by it
|
|
Standard_Real dfR = theC.Circle().Radius();
|
|
Standard_Real Du = GCPnts_TangentialDeflection::ArcAngularStep (dfR, myCurvatureDeflection, myAngularDeflection, myMinLen);
|
|
|
|
const Standard_Real aDiff = myLastU - myFirstu;
|
|
// Round up number of points to satisfy curvatureDeflection more precisely
|
|
Standard_Integer NbPoints = (Standard_Integer)Min(Ceiling(aDiff / Du), 1.0e+6);
|
|
NbPoints = Max(NbPoints, myMinNbPnts - 1);
|
|
Du = aDiff / NbPoints;
|
|
|
|
gp_Pnt P;
|
|
Standard_Real U = myFirstu;
|
|
for (Standard_Integer i = 1; i <= NbPoints; i++)
|
|
{
|
|
D0 (theC, U, P);
|
|
myParameters.Append (U);
|
|
myPoints .Append (P);
|
|
U += Du;
|
|
}
|
|
|
|
D0 (theC, myLastU, P);
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (P);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::initialize (const TheCurve& theC,
|
|
const Standard_Real theFirstParameter, const Standard_Real theLastParameter,
|
|
const Standard_Real theAngularDeflection, const Standard_Real theCurvatureDeflection,
|
|
const Standard_Integer theMinimumOfPoints,
|
|
const Standard_Real theUTol,
|
|
const Standard_Real theMinLen)
|
|
{
|
|
Standard_ConstructionError_Raise_if (theCurvatureDeflection < Precision::Confusion() || theAngularDeflection < Precision::Angular(),
|
|
"GCPnts_TangentialDeflection::Initialize - Zero Deflection")
|
|
myParameters.Clear();
|
|
myPoints .Clear();
|
|
if (theFirstParameter < theLastParameter)
|
|
{
|
|
myFirstu = theFirstParameter;
|
|
myLastU = theLastParameter;
|
|
}
|
|
else
|
|
{
|
|
myLastU = theFirstParameter;
|
|
myFirstu = theLastParameter;
|
|
}
|
|
myUTol = theUTol;
|
|
myAngularDeflection = theAngularDeflection;
|
|
myCurvatureDeflection = theCurvatureDeflection;
|
|
myMinNbPnts = Max (theMinimumOfPoints, 2);
|
|
myMinLen = Max (theMinLen, Precision::Confusion());
|
|
|
|
switch (theC.GetType())
|
|
{
|
|
case GeomAbs_Line:
|
|
{
|
|
PerformLinear (theC);
|
|
break;
|
|
}
|
|
case GeomAbs_Circle:
|
|
{
|
|
PerformCircular (theC);
|
|
break;
|
|
}
|
|
case GeomAbs_BSplineCurve:
|
|
{
|
|
Handle(typename GCPnts_TCurveTypes<TheCurve>::BSplineCurve) aBS = theC.BSpline();
|
|
if (aBS->NbPoles() == 2) PerformLinear (theC);
|
|
else PerformCurve (theC);
|
|
break;
|
|
}
|
|
case GeomAbs_BezierCurve:
|
|
{
|
|
Handle(typename GCPnts_TCurveTypes<TheCurve>::BezierCurve) aBZ = theC.Bezier();
|
|
if (aBZ->NbPoles() == 2) PerformLinear (theC);
|
|
else PerformCurve (theC);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
PerformCurve (theC);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AddPoint
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Integer GCPnts_TangentialDeflection::AddPoint
|
|
(const gp_Pnt& thePnt,
|
|
const Standard_Real theParam,
|
|
const Standard_Boolean theIsReplace)
|
|
{
|
|
constexpr Standard_Real tol = Precision::PConfusion();
|
|
Standard_Integer index = -1;
|
|
const Standard_Integer nb = myParameters.Length();
|
|
for ( Standard_Integer i = 1; index == -1 && i <= nb; i++ )
|
|
{
|
|
Standard_Real dist = myParameters.Value( i ) - theParam;
|
|
if ( fabs( dist ) <= tol )
|
|
{
|
|
index = i;
|
|
if ( theIsReplace )
|
|
{
|
|
myPoints .ChangeValue (i) = thePnt;
|
|
myParameters.ChangeValue (i) = theParam;
|
|
}
|
|
}
|
|
else if ( dist > tol )
|
|
{
|
|
myPoints .InsertBefore (i, thePnt);
|
|
myParameters.InsertBefore (i, theParam);
|
|
index = i;
|
|
}
|
|
}
|
|
if (index == -1)
|
|
{
|
|
myPoints .Append (thePnt);
|
|
myParameters.Append (theParam);
|
|
index = myParameters.Length();
|
|
}
|
|
return index;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ArcAngularStep
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Real GCPnts_TangentialDeflection::ArcAngularStep(
|
|
const Standard_Real theRadius,
|
|
const Standard_Real theLinearDeflection,
|
|
const Standard_Real theAngularDeflection,
|
|
const Standard_Real theMinLength)
|
|
{
|
|
Standard_ConstructionError_Raise_if(theRadius < 0.0, "Negative radius");
|
|
|
|
constexpr Standard_Real aPrecision = Precision::Confusion();
|
|
|
|
Standard_Real Du = 0.0, aMinSizeAng = 0.0;
|
|
if (theRadius > aPrecision)
|
|
{
|
|
Du = Max(1.0 - (theLinearDeflection / theRadius), 0.0);
|
|
|
|
// It is not suitable to consider min size greater than 1/4 arc len.
|
|
if (theMinLength > aPrecision)
|
|
aMinSizeAng = Min(theMinLength / theRadius, M_PI_2);
|
|
}
|
|
Du = 2.0 * ACos(Du);
|
|
Du = Max(Min(Du, theAngularDeflection), aMinSizeAng);
|
|
return Du;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : PerformCurve
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::PerformCurve (const TheCurve& theC)
|
|
{
|
|
Standard_Integer i, j;
|
|
gp_XYZ V1, V2;
|
|
gp_Pnt MiddlePoint, CurrentPoint, LastPoint;
|
|
Standard_Real Du, Dusave, MiddleU, L1, L2;
|
|
|
|
Standard_Real U1 = myFirstu;
|
|
constexpr Standard_Real LTol = Precision::Confusion(); // protection longueur nulle
|
|
Standard_Real ATol = 1.e-2 * myAngularDeflection;
|
|
if (ATol > 1.e-2)
|
|
{
|
|
ATol = 1.e-2;
|
|
}
|
|
else if (ATol < 1.e-7)
|
|
{
|
|
ATol = 1.e-7;
|
|
}
|
|
|
|
D0 (theC, myLastU, LastPoint);
|
|
|
|
// Initialization du calcul
|
|
|
|
Standard_Boolean NotDone = Standard_True;
|
|
Dusave = (myLastU - myFirstu) * Us3;
|
|
Du = Dusave;
|
|
EvaluateDu (theC, U1, CurrentPoint, Du, NotDone);
|
|
myParameters.Append (U1);
|
|
myPoints .Append (CurrentPoint);
|
|
|
|
// Used to detect "isLine" current bspline and in Du computation in general handling.
|
|
const Standard_Integer NbInterv = theC.NbIntervals (GeomAbs_CN);
|
|
TColStd_Array1OfReal Intervs (1, NbInterv + 1);
|
|
theC.Intervals (Intervs, GeomAbs_CN);
|
|
|
|
if (NotDone || Du > 5. * Dusave)
|
|
{
|
|
//C'est soit une droite, soit une singularite :
|
|
V1 = (LastPoint.XYZ() - CurrentPoint.XYZ());
|
|
L1 = V1.Modulus ();
|
|
if (L1 > LTol)
|
|
{
|
|
// Si c'est une droite on verifie en calculant minNbPoints :
|
|
Standard_Boolean IsLine = Standard_True;
|
|
Standard_Integer NbPoints = (myMinNbPnts > 3) ? myMinNbPnts : 3;
|
|
switch (theC.GetType())
|
|
{
|
|
case GeomAbs_BSplineCurve:
|
|
{
|
|
Handle(typename GCPnts_TCurveTypes<TheCurve>::BSplineCurve) BS = theC.BSpline();
|
|
NbPoints = Max(BS->Degree() + 1, NbPoints);
|
|
break;
|
|
}
|
|
case GeomAbs_BezierCurve:
|
|
{
|
|
Handle(typename GCPnts_TCurveTypes<TheCurve>::BezierCurve) BZ = theC.Bezier();
|
|
NbPoints = Max(BZ->Degree() + 1, NbPoints);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
////
|
|
Standard_Real param = 0.;
|
|
for (i = 1; i <= NbInterv && IsLine; ++i)
|
|
{
|
|
// Avoid usage intervals out of [myFirstu, myLastU].
|
|
if ((Intervs(i + 1) < myFirstu)
|
|
|| (Intervs(i) > myLastU))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Fix border points in applicable intervals, to avoid be out of target interval.
|
|
if ((Intervs(i) < myFirstu)
|
|
&& (Intervs(i+1) > myFirstu))
|
|
{
|
|
Intervs(i) = myFirstu;
|
|
}
|
|
if ((Intervs(i) < myLastU)
|
|
&& (Intervs(i+1) > myLastU))
|
|
{
|
|
Intervs(i + 1) = myLastU;
|
|
}
|
|
|
|
const Standard_Real delta = (Intervs(i+1) - Intervs(i))/NbPoints;
|
|
for (j = 1; j <= NbPoints && IsLine; ++j)
|
|
{
|
|
param = Intervs(i) + j*delta;
|
|
D0 (theC, param, MiddlePoint);
|
|
V2 = (MiddlePoint.XYZ() - CurrentPoint.XYZ());
|
|
L2 = V2.Modulus ();
|
|
if (L2 > LTol)
|
|
{
|
|
const Standard_Real aAngle = V2.CrossMagnitude(V1)/(L1*L2);
|
|
IsLine = (aAngle < ATol);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsLine)
|
|
{
|
|
myParameters.Clear();
|
|
myPoints .Clear();
|
|
|
|
PerformLinear (theC);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// c'etait une singularite on continue:
|
|
//Du = Dusave;
|
|
EvaluateDu (theC, param, MiddlePoint, Du, NotDone);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Du = (myLastU - myFirstu) / 2.1;
|
|
MiddleU = myFirstu + Du;
|
|
D0 (theC, MiddleU, MiddlePoint);
|
|
V1 = (MiddlePoint.XYZ() - CurrentPoint.XYZ());
|
|
L1 = V1.Modulus ();
|
|
if (L1 < LTol)
|
|
{
|
|
// L1 < LTol C'est une courbe de longueur nulle, calcul termine :
|
|
// on renvoi un segment de 2 points (protection)
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (LastPoint);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Du > Dusave) Du = Dusave;
|
|
else Dusave = Du;
|
|
|
|
if (Du < myUTol)
|
|
{
|
|
Du = myLastU - myFirstu;
|
|
if (Du < myUTol)
|
|
{
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (LastPoint);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Traitement normal pour une courbe
|
|
Standard_Boolean MorePoints = Standard_True;
|
|
Standard_Real U2 = myFirstu;
|
|
Standard_Real AngleMax = myAngularDeflection * 0.5; // car on prend le point milieu
|
|
// Indexes of intervals of U1 and U2, used to handle non-uniform case.
|
|
Standard_Integer aIdx[2] = {Intervs.Lower(), Intervs.Lower()};
|
|
Standard_Boolean isNeedToCheck = Standard_False;
|
|
gp_Pnt aPrevPoint = myPoints.Last();
|
|
|
|
while (MorePoints)
|
|
{
|
|
aIdx[0] = getIntervalIdx(U1, Intervs, aIdx[0]);
|
|
U2 += Du;
|
|
|
|
if (U2 >= myLastU) // Bout de courbe
|
|
{
|
|
U2 = myLastU;
|
|
CurrentPoint = LastPoint;
|
|
Du = U2-U1;
|
|
Dusave = Du;
|
|
}
|
|
else
|
|
{
|
|
D0 (theC, U2, CurrentPoint); // Point suivant
|
|
}
|
|
|
|
Standard_Real Coef = 0.0, ACoef = 0., FCoef = 0.;
|
|
Standard_Boolean Correction, TooLarge, TooSmall;
|
|
TooLarge = Standard_False;
|
|
Correction = Standard_True;
|
|
TooSmall = Standard_False;
|
|
|
|
while (Correction) // Ajustement Du
|
|
{
|
|
if (isNeedToCheck)
|
|
{
|
|
aIdx[1] = getIntervalIdx(U2, Intervs, aIdx[0]);
|
|
if (aIdx[1] > aIdx[0]) // Jump to another polynom.
|
|
{
|
|
// Set Du to the smallest value and check deflection on it.
|
|
if (Du > (Intervs(aIdx[0] + 1) - Intervs(aIdx[0]) ) * Us3)
|
|
{
|
|
Du = (Intervs(aIdx[0] + 1) - Intervs(aIdx[0]) ) * Us3;
|
|
U2 = U1 + Du;
|
|
if (U2 > myLastU)
|
|
{
|
|
U2 = myLastU;
|
|
}
|
|
D0 (theC, U2, CurrentPoint);
|
|
}
|
|
}
|
|
}
|
|
MiddleU = (U1+U2)*0.5; // Verif / au point milieu
|
|
D0 (theC, MiddleU, MiddlePoint);
|
|
|
|
V1 = (CurrentPoint.XYZ() - aPrevPoint.XYZ()); // Critere de fleche
|
|
V2 = (MiddlePoint.XYZ() - aPrevPoint.XYZ());
|
|
L1 = V1.Modulus ();
|
|
|
|
FCoef = (L1 > myMinLen) ? V1.CrossMagnitude(V2) / (L1 * myCurvatureDeflection) : 0.0;
|
|
|
|
V1 = (CurrentPoint.XYZ() - MiddlePoint.XYZ()); // Critere d'angle
|
|
L1 = V1.Modulus ();
|
|
L2 = V2.Modulus ();
|
|
if (L1 > myMinLen && L2 > myMinLen)
|
|
{
|
|
Standard_Real angg = V1.CrossMagnitude(V2) / (L1 * L2);
|
|
ACoef = angg / AngleMax;
|
|
}
|
|
else
|
|
{
|
|
ACoef = 0.0;
|
|
}
|
|
|
|
// On retient le plus penalisant
|
|
Coef = Max (ACoef, FCoef);
|
|
|
|
if (isNeedToCheck && Coef < 0.55)
|
|
{
|
|
isNeedToCheck = Standard_False;
|
|
Du = Dusave;
|
|
U2 = U1 + Du;
|
|
if (U2 > myLastU)
|
|
{
|
|
U2 = myLastU;
|
|
}
|
|
D0 (theC, U2, CurrentPoint);
|
|
continue;
|
|
}
|
|
|
|
if (Coef <= 1.0)
|
|
{
|
|
if (Abs (myLastU - U2) < myUTol)
|
|
{
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (LastPoint);
|
|
MorePoints = Standard_False;
|
|
Correction = Standard_False;
|
|
}
|
|
else
|
|
{
|
|
if (Coef >= 0.55 || TooLarge)
|
|
{
|
|
myParameters.Append (U2);
|
|
myPoints .Append (CurrentPoint);
|
|
aPrevPoint = CurrentPoint;
|
|
Correction = Standard_False;
|
|
isNeedToCheck = Standard_True;
|
|
}
|
|
else if (TooSmall)
|
|
{
|
|
Correction = Standard_False;
|
|
aPrevPoint = CurrentPoint;
|
|
}
|
|
else
|
|
{
|
|
TooSmall = Standard_True;
|
|
//Standard_Real UUU2 = U2;
|
|
Du += Min((U2-U1)*(1.-Coef), Du*Us3);
|
|
|
|
U2 = U1 + Du;
|
|
if (U2 > myLastU)
|
|
{
|
|
U2 = myLastU;
|
|
}
|
|
D0 (theC, U2, CurrentPoint);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Coef >= 1.5)
|
|
{
|
|
if (!aPrevPoint.IsEqual (myPoints.Last(), Precision::Confusion()))
|
|
{
|
|
myParameters.Append (U1);
|
|
myPoints .Append (aPrevPoint);
|
|
}
|
|
U2 = MiddleU;
|
|
Du = U2-U1;
|
|
CurrentPoint = MiddlePoint;
|
|
}
|
|
else
|
|
{
|
|
Du*=0.9;
|
|
U2 = U1 + Du;
|
|
D0 (theC, U2, CurrentPoint);
|
|
TooLarge = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
|
|
Du = U2-U1;
|
|
|
|
if (MorePoints)
|
|
{
|
|
if (U1 > myFirstu)
|
|
{
|
|
if (FCoef > ACoef)
|
|
{
|
|
// La fleche est critere de decoupage
|
|
EvaluateDu (theC, U2, CurrentPoint, Du, NotDone);
|
|
if (NotDone)
|
|
{
|
|
Du += (Du-Dusave)*(Du/Dusave);
|
|
if (Du > 1.5 * Dusave) Du = 1.5 * Dusave;
|
|
if (Du < 0.75* Dusave) Du = 0.75 * Dusave;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//L'angle est le critere de decoupage
|
|
Du += (Du-Dusave)*(Du/Dusave);
|
|
if (Du > 1.5 * Dusave) Du = 1.5 * Dusave;
|
|
if (Du < 0.75* Dusave) Du = 0.75 * Dusave;
|
|
}
|
|
}
|
|
|
|
if (Du < myUTol)
|
|
{
|
|
Du = myLastU - U2;
|
|
if (Du < myUTol)
|
|
{
|
|
myParameters.Append (myLastU);
|
|
myPoints .Append (LastPoint);
|
|
MorePoints = Standard_False;
|
|
}
|
|
else if (Du*Us3 > myUTol)
|
|
{
|
|
Du*=Us3;
|
|
}
|
|
}
|
|
U1 = U2;
|
|
Dusave = Du;
|
|
}
|
|
}
|
|
// Recalage avant dernier point :
|
|
i = myPoints.Length() - 1;
|
|
// Real d = myPoints (i).Distance (myPoints (i+1));
|
|
// if (Abs(myParameters (i) - myParameters (i+1))<= 0.000001 || d < Precision::Confusion()) {
|
|
// cout<<"deux points confondus"<<endl;
|
|
// myParameters.Remove (i+1);
|
|
// myPoints.Remove (i+1);
|
|
// i--;
|
|
// }
|
|
if (i >= 2)
|
|
{
|
|
MiddleU = myParameters (i-1);
|
|
MiddleU = (myLastU + MiddleU)*0.5;
|
|
D0 (theC, MiddleU, MiddlePoint);
|
|
myParameters.SetValue (i, MiddleU);
|
|
myPoints .SetValue (i, MiddlePoint);
|
|
}
|
|
|
|
//-- On rajoute des points aux milieux des segments si le nombre
|
|
//-- mini de points n'est pas atteint
|
|
//--
|
|
Standard_Integer Nbp = myPoints.Length();
|
|
|
|
//std::cout << "GCPnts_TangentialDeflection: Number of Points (" << Nbp << " " << myMinNbPnts << " )" << std::endl;
|
|
|
|
while (Nbp < myMinNbPnts)
|
|
{
|
|
for (i = 2; i <= Nbp; i += 2)
|
|
{
|
|
MiddleU = (myParameters.Value(i-1) + myParameters.Value(i)) * 0.5;
|
|
D0 (theC, MiddleU, MiddlePoint);
|
|
myParameters.InsertBefore (i, MiddleU);
|
|
myPoints .InsertBefore (i, MiddlePoint);
|
|
Nbp++;
|
|
}
|
|
}
|
|
// Additional check for intervals
|
|
const Standard_Real MinLen2 = myMinLen * myMinLen;
|
|
const Standard_Integer MaxNbp = 10 * Nbp;
|
|
for (i = 1; i < Nbp; ++i)
|
|
{
|
|
U1 = myParameters (i);
|
|
U2 = myParameters (i + 1);
|
|
|
|
if (U2 - U1 <= myUTol)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check maximal deflection on interval;
|
|
Standard_Real dmax = 0.;
|
|
Standard_Real umax = 0.;
|
|
Standard_Real amax = 0.;
|
|
EstimDefl (theC, U1, U2, dmax, umax);
|
|
const gp_Pnt& P1 = myPoints (i);
|
|
const gp_Pnt& P2 = myPoints (i + 1);
|
|
D0 (theC, umax, MiddlePoint);
|
|
amax = EstimAngl(P1, MiddlePoint, P2);
|
|
if (dmax > myCurvatureDeflection || amax > AngleMax)
|
|
{
|
|
if (umax - U1 > myUTol && U2 - umax > myUTol)
|
|
{
|
|
if (P1.SquareDistance(MiddlePoint) > MinLen2
|
|
&& P2.SquareDistance(MiddlePoint) > MinLen2)
|
|
{
|
|
myParameters.InsertAfter (i, umax);
|
|
myPoints .InsertAfter (i, MiddlePoint);
|
|
++Nbp;
|
|
--i; //To compensate ++i in loop header: i must point to first part of split interval
|
|
if (Nbp > MaxNbp)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : EstimDefl
|
|
//purpose :
|
|
//=======================================================================
|
|
template<class TheCurve>
|
|
void GCPnts_TangentialDeflection::EstimDefl (const TheCurve& theC,
|
|
const Standard_Real theU1, const Standard_Real theU2,
|
|
Standard_Real& theMaxDefl, Standard_Real& theUMax)
|
|
{
|
|
const Standard_Real Du = (myLastU - myFirstu);
|
|
//
|
|
typename GCPnts_TCurveTypes<TheCurve>::DistFunction aFunc (theC, theU1, theU2);
|
|
//
|
|
const Standard_Integer aNbIter = 100;
|
|
const Standard_Real aRelTol = Max (1.e-3, 2. * myUTol / (Abs(theU1) + Abs(theU2)));
|
|
//
|
|
math_BrentMinimum anOptLoc (aRelTol, aNbIter, myUTol);
|
|
anOptLoc.Perform (aFunc, theU1, (theU1 + theU2) / 2., theU2);
|
|
if (anOptLoc.IsDone())
|
|
{
|
|
theMaxDefl = Sqrt(-anOptLoc.Minimum());
|
|
theUMax = anOptLoc.Location();
|
|
return;
|
|
}
|
|
//
|
|
math_Vector aLowBorder (1, 1), aUppBorder (1, 1), aSteps (1, 1);
|
|
aSteps (1) = Max (0.1 * Du, 100. * myUTol);
|
|
const Standard_Integer aNbParticles = Max(8, RealToInt(32 * (theU2 - theU1) / Du));
|
|
aLowBorder (1) = theU1;
|
|
aUppBorder (1) = theU2;
|
|
//
|
|
//
|
|
Standard_Real aValue = 0.0;
|
|
math_Vector aT (1, 1);
|
|
typename GCPnts_TCurveTypes<TheCurve>::DistFunctionMV aFuncMV(aFunc);
|
|
|
|
math_PSO aFinder (&aFuncMV, aLowBorder, aUppBorder, aSteps, aNbParticles);
|
|
aFinder.Perform (aSteps, aValue, aT);
|
|
//
|
|
anOptLoc.Perform (aFunc,
|
|
Max (aT(1) - aSteps(1), theU1),
|
|
aT (1),
|
|
Min (aT(1) + aSteps(1), theU2));
|
|
if (anOptLoc.IsDone())
|
|
{
|
|
theMaxDefl = Sqrt(-anOptLoc.Minimum());
|
|
theUMax = anOptLoc.Location();
|
|
return;
|
|
}
|
|
|
|
theMaxDefl = Sqrt(-aValue);
|
|
theUMax = aT (1);
|
|
}
|