Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1993-12-14
// Created by: Christophe MARION
// Copyright (c) 1993-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.
#ifndef _Extrema_GLocateExtPC_HeaderFile
#define _Extrema_GLocateExtPC_HeaderFile
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <GeomAbs_CurveType.hxx>
#include <Precision.hxx>
#include <Standard_DomainError.hxx>
#include <StdFail_NotDone.hxx>
#include <NCollection_Array1.hxx>
#include <cmath>
//! Template class for locating extremum of distance between a point and a curve.
//! Calculates the distance with a close point. The close point is defined by
//! the parameter value U0. The function F(u)=distance(P,C(u)) has an extremum
//! when g(u)=dF/du=0. The algorithm searches a zero near the close point.
//!
//! @tparam TheCurve Curve type (e.g., Adaptor3d_Curve, Adaptor2d_Curve2d)
//! @tparam TheCurveTool Tool for curve operations
//! @tparam ThePoint Point type (e.g., gp_Pnt, gp_Pnt2d)
//! @tparam TheVector Vector type (e.g., gp_Vec, gp_Vec2d)
//! @tparam ThePOnC Point on curve type
//! @tparam TheELPC Extended local projection curve type
//! @tparam TheLocEPC Local extremum point curve type
template <typename TheCurve,
typename TheCurveTool,
typename ThePoint,
typename TheVector,
typename ThePOnC,
typename TheELPC,
typename TheLocEPC>
class Extrema_GLocateExtPC
{
public:
DEFINE_STANDARD_ALLOC
//! Default constructor.
Extrema_GLocateExtPC()
: myC(nullptr),
mydist2(0.0),
myismin(false),
myDone(false),
myumin(0.0),
myusup(0.0),
mytol(0.0),
type(GeomAbs_OtherCurve),
numberext(0)
{
}
//! Calculates the distance with a close point.
//! The close point is defined by the parameter value U0.
//! TolF is used to decide to stop the iterations.
//! At the nth iteration, the criteria is: abs(Un - Un-1) < TolF.
Extrema_GLocateExtPC(const ThePoint& theP,
const TheCurve& theC,
const double theU0,
const double theTolF)
{
Initialize(theC,
TheCurveTool::FirstParameter(theC),
TheCurveTool::LastParameter(theC),
theTolF);
Perform(theP, theU0);
}
//! Calculates the distance with a close point.
//! The close point is defined by the parameter value U0.
//! Zeros are searched between Umin and Usup.
//! TolF is used to decide to stop the iterations.
//! At the nth iteration, the criteria is: abs(Un - Un-1) < TolF.
Extrema_GLocateExtPC(const ThePoint& theP,
const TheCurve& theC,
const double theU0,
const double theUmin,
const double theUsup,
const double theTolF)
{
Initialize(theC, theUmin, theUsup, theTolF);
Perform(theP, theU0);
}
//! Sets the fields of the algorithm.
void Initialize(const TheCurve& theC,
const double theUmin,
const double theUsup,
const double theTolF)
{
myC = const_cast<TheCurve*>(&theC);
mytol = theTolF;
myumin = theUmin;
myusup = theUsup;
type = TheCurveTool::GetType(theC);
double tolu = TheCurveTool::Resolution(theC, Precision::Confusion());
if ((type == GeomAbs_BSplineCurve) || (type == GeomAbs_BezierCurve)
|| (type == GeomAbs_OffsetCurve) || (type == GeomAbs_OtherCurve))
{
myLocExtPC.Initialize(theC, theUmin, theUsup, tolu);
}
else
{
myExtremPC.Initialize(theC, theUmin, theUsup, tolu);
}
}
//! Performs the algorithm with point P and initial parameter U0.
void Perform(const ThePoint& theP, const double theU0)
{
int i, i1, i2, inter;
double Par, valU, valU2 = RealLast(), local_u0;
double myintuinf = 0, myintusup = 0;
local_u0 = theU0;
switch (type)
{
case GeomAbs_OtherCurve:
case GeomAbs_OffsetCurve:
case GeomAbs_BSplineCurve: {
// Search for extremum is done interval by continuous C2 interval
int n = TheCurveTool::NbIntervals(*myC, GeomAbs_C2);
NCollection_Array1<double> theInter(1, n + 1);
TheCurveTool::Intervals(*myC, theInter, GeomAbs_C2);
//
// be gentle with the caller
//
if (local_u0 < myumin)
{
local_u0 = myumin;
}
else if (local_u0 > myusup)
{
local_u0 = myusup;
}
// Search for interval containing U0
bool found = false;
inter = 1;
while (!found && inter <= n)
{
myintuinf = std::max(theInter(inter), myumin);
myintusup = std::min(theInter(inter + 1), myusup);
if ((local_u0 >= myintuinf) && (local_u0 < myintusup))
found = true;
inter++;
}
if (found)
inter--; // IFV 16.06.00 - inter is increased after found!
// Try on found interval
myLocExtPC.Initialize(*myC, myintuinf, myintusup, mytol);
myLocExtPC.Perform(theP, local_u0);
myDone = myLocExtPC.IsDone();
if (myDone)
{
mypp = myLocExtPC.Point();
myismin = myLocExtPC.IsMin();
mydist2 = myLocExtPC.SquareDistance();
}
else
{
int k = 1;
// Try on neighboring intervals:
i1 = inter;
i2 = inter;
double s1inf, s2inf, s1sup, s2sup;
ThePoint P1;
TheVector V1;
TheCurveTool::D1(*myC, myintuinf, P1, V1);
s2inf = (TheVector(theP, P1) * V1);
TheCurveTool::D1(*myC, myintusup, P1, V1);
s1sup = (TheVector(theP, P1) * V1);
while (!myDone && (i2 > 0) && (i1 <= n))
{
i1 = inter + k;
i2 = inter - k;
if (i1 <= n)
{
myintuinf = std::max(theInter(i1), myumin);
myintusup = std::min(theInter(i1 + 1), myusup);
if (myintuinf < myintusup)
{
TheCurveTool::D1(*myC, myintuinf, P1, V1);
s2sup = (TheVector(theP, P1) * V1);
if (Precision::IsInfinite(s2sup) || Precision::IsInfinite(s1sup))
{
break;
}
if (s1sup * s2sup <= RealEpsilon())
{
// extremum:
myDone = true;
mypp.SetValues(myintuinf, P1);
myismin = (s1sup <= 0.0);
mydist2 = theP.SquareDistance(P1);
break;
}
TheCurveTool::D1(*myC, myintusup, P1, V1);
s1sup = (TheVector(theP, P1) * V1);
myLocExtPC.Initialize(*myC, myintuinf, myintusup, mytol);
myLocExtPC.Perform(theP, (myintuinf + myintusup) * 0.5);
myDone = myLocExtPC.IsDone();
if (myDone)
{
mypp = myLocExtPC.Point();
myismin = myLocExtPC.IsMin();
mydist2 = myLocExtPC.SquareDistance();
break;
}
}
}
if (i2 > 0)
{
myintuinf = std::max(theInter(i2), myumin);
myintusup = std::min(theInter(i2 + 1), myusup);
if (myintuinf < myintusup)
{
TheCurveTool::D1(*myC, myintusup, P1, V1);
s1inf = (TheVector(theP, P1) * V1);
if (Precision::IsInfinite(s2inf) || Precision::IsInfinite(s1inf))
{
break;
}
if (s1inf * s2inf <= RealEpsilon())
{
// extremum:
myDone = true;
mypp.SetValues(myintusup, P1);
myismin = (s1inf <= 0.0);
mydist2 = theP.SquareDistance(P1);
break;
}
TheCurveTool::D1(*myC, myintuinf, P1, V1);
s2inf = (TheVector(theP, P1) * V1);
myLocExtPC.Initialize(*myC, myintuinf, myintusup, mytol);
myLocExtPC.Perform(theP, (myintuinf + myintusup) * 0.5);
myDone = myLocExtPC.IsDone();
if (myDone)
{
mypp = myLocExtPC.Point();
myismin = myLocExtPC.IsMin();
mydist2 = myLocExtPC.SquareDistance();
break;
}
}
}
k++;
}
}
}
break;
case GeomAbs_BezierCurve: {
myLocExtPC.Perform(theP, theU0);
myDone = myLocExtPC.IsDone();
}
break;
default: {
myExtremPC.Perform(theP);
numberext = 0;
if (myExtremPC.IsDone())
{
for (i = 1; i <= myExtremPC.NbExt(); i++)
{
Par = myExtremPC.Point(i).Parameter();
valU = std::abs(Par - theU0);
if (valU <= valU2)
{
valU2 = valU;
numberext = i;
myDone = true;
}
}
}
if (numberext == 0)
myDone = false;
break;
}
}
}
//! Returns True if the distance is found.
bool IsDone() const { return myDone; }
//! Returns the value of the extremum square distance.
double SquareDistance() const
{
if (!IsDone())
{
throw StdFail_NotDone();
}
double d = 0;
if ((type == GeomAbs_BezierCurve))
{
d = myLocExtPC.SquareDistance();
}
else if (type == GeomAbs_BSplineCurve || type == GeomAbs_OffsetCurve
|| type == GeomAbs_OtherCurve)
{
d = mydist2;
}
else
{
if (numberext != 0)
{
d = myExtremPC.SquareDistance(numberext);
}
}
return d;
}
//! Returns True if the extremum distance is a minimum.
bool IsMin() const
{
if (!IsDone())
{
throw StdFail_NotDone();
}
bool b = false;
if ((type == GeomAbs_BezierCurve))
{
b = myLocExtPC.IsMin();
}
else if (type == GeomAbs_BSplineCurve || type == GeomAbs_OffsetCurve
|| type == GeomAbs_OtherCurve)
{
b = myismin;
}
else
{
if (numberext != 0)
{
b = myExtremPC.IsMin(numberext);
}
}
return b;
}
//! Returns the point of the extremum distance.
const ThePOnC& Point() const
{
if (!IsDone())
{
throw StdFail_NotDone();
}
if (type == GeomAbs_BezierCurve)
{
return myLocExtPC.Point();
}
else if (type == GeomAbs_BSplineCurve || type == GeomAbs_OffsetCurve
|| type == GeomAbs_OtherCurve)
{
return mypp;
}
return myExtremPC.Point(numberext);
}
private:
ThePOnC mypp;
TheCurve* myC;
double mydist2;
bool myismin;
bool myDone;
double myumin;
double myusup;
double mytol;
TheLocEPC myLocExtPC;
TheELPC myExtremPC;
GeomAbs_CurveType type;
int numberext;
};
#endif // _Extrema_GLocateExtPC_HeaderFile