Loading files
// Created: 2009-01-21
//
// Copyright (c) 2009-2013 OPEN CASCADE SAS
//
// This file is part of commercial software by OPEN CASCADE SAS,
// furnished in accordance with the terms and conditions of the contract
// and with the inclusion of this copyright notice.
// This file or any part thereof may not be provided or otherwise
// made available to any third party.
//
// No ownership title to the software is transferred hereby.
//
// OPEN CASCADE SAS makes no representation or warranties with respect to the
// performance of this software, and specifically disclaims any responsibility
// for any damages, special or consequential, connected with its use.
#include <Geom2dConvert_ApproxArcsSegments.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <ElCLib.hxx>
#include <GC_MakeArcOfCircle2d.hxx>
#include <GC_MakeSegment2d.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <NCollection_IncAllocator.hxx>
#include <Precision.hxx>
#include <Standard_Version.hxx>
#include <gp.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Lin2d.hxx>
static const int MAXPOINTS = 100;
static const double MyCurvatureTolerance = 0.0001;
static bool checkContinuity(const occ::handle<Geom2d_Curve>& theCurve1,
const occ::handle<Geom2d_Curve>& theCurve2,
const double theAnglTol);
static Geom2dConvert_PPoint getParameter(const gp_XY& theXY1,
const double theFirstPar,
const double theLastPar,
const Adaptor2d_Curve2d& theCurve);
static bool isInflectionPoint(const double theParam, const Adaptor2d_Curve2d& theCurve);
static bool isInflectionPoint(const double theParam,
const Geom2dConvert_PPoint& theFirstInf,
const Adaptor2d_Curve2d& theCurve,
const double theAnglTol);
//=================================================================================================
Geom2dConvert_ApproxArcsSegments::Geom2dConvert_ApproxArcsSegments(
const Adaptor2d_Curve2d& theCurve,
const double theTolerance,
const double theAngleTol)
: myCurve(theCurve),
myAlloc(new NCollection_IncAllocator(4000)),
myTolerance(theTolerance),
myAngleTolerance(theAngleTol),
mySeqParams(myAlloc),
myStatus(StatusNotDone)
{
myExt[0] = Geom2dConvert_PPoint(myCurve.FirstParameter(), myCurve);
myExt[1] = Geom2dConvert_PPoint(myCurve.LastParameter(), myCurve);
switch (myCurve.GetType())
{
case GeomAbs_Line: {
// Create a single line segment.
const double aDist = myExt[0].Dist(myExt[1]);
if (aDist > Precision::Confusion())
{
const gp_Ax2d anAx2d(myExt[0].Point(), gp_Vec2d(myExt[0].Point(), myExt[1].Point()));
const occ::handle<Geom2d_Line> aLine = new Geom2d_Line(anAx2d);
mySeqCurves.Append(new Geom2d_TrimmedCurve(aLine, 0., aDist));
myStatus = StatusOK;
}
}
break;
case GeomAbs_Circle: {
// Create a couple of arcs of equal size.
const Geom2dConvert_PPoint aPP(.5 * (myExt[0].Parameter() + myExt[1].Parameter()), myCurve);
occ::handle<Geom2d_Curve> aCurve = makeCircle(myExt[0], aPP);
if (!aCurve.IsNull())
{
mySeqCurves.Append(aCurve);
aCurve = makeCircle(aPP, myExt[1]);
if (!aCurve.IsNull())
{
mySeqCurves.Append(aCurve);
}
}
}
break;
default:
makeFreeform();
}
// Check status of the calculation
if (myStatus == StatusNotDone)
{
if (!mySeqCurves.IsEmpty())
{
myStatus = StatusOK;
}
else
{
// std::cout << "GeomConv2d_Approx: no geometry converted." << std::endl;
myStatus = StatusError;
}
}
}
//=================================================================================================
occ::handle<Geom2d_Curve> Geom2dConvert_ApproxArcsSegments::makeCircle(
const Geom2dConvert_PPoint& theFirst,
const Geom2dConvert_PPoint& theLast) const
{
occ::handle<Geom2d_Curve> aResult;
gp_Pnt2d aPointM(0.0, 0.0);
const double aParaM = (theFirst.Parameter() + theLast.Parameter()) * .5;
myCurve.D0(aParaM, aPointM);
GC_MakeArcOfCircle2d aMakeArc1(theFirst.Point(), aPointM, theLast.Point());
if (aMakeArc1.IsDone())
{
aResult = aMakeArc1.Value();
}
// else
// std::cout << "makeCircle(): Circle not built" << std::endl;
return aResult;
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::makeArc(const Geom2dConvert_PPoint& theParam1,
Geom2dConvert_PPoint& theParam2,
const bool isFirst,
occ::handle<Geom2d_TrimmedCurve>& theCurve) const
{
const gp_XY aP1(theParam1.Point());
const gp_XY aP2(theParam2.Point());
const gp_XY aVec(isFirst ? theParam1.D1() : -theParam1.D1());
// Detect the sense (CCW means positive)
const gp_XY aDelta = aP2 - aP1;
double aSense = aVec ^ aDelta;
if (aSense > Precision::Angular())
{
aSense = 1.;
}
else if (aSense < -Precision::Angular())
{
aSense = -1.;
}
else
{
// std::cout << "makeArc(): Arc Not Built" << std::endl;
return false;
}
// Find the centre of the circle
const gp_XY aMiddle = (aP2 + aP1) * 0.5;
const double prodP1V = aP1 * aVec;
const double prodDeM = aDelta * aMiddle;
const double vprodVD = aVec ^ aDelta;
const double aResolution = gp::Resolution();
if (vprodVD < -aResolution || vprodVD > aResolution)
{
const gp_Pnt2d aCenter((prodP1V * aDelta.Y() - prodDeM * aVec.Y()) / vprodVD,
(prodDeM * aVec.X() - prodP1V * aDelta.X()) / vprodVD);
const double aRad = (aCenter.Distance(aP1) + aCenter.Distance(aP2)) * 0.5;
const gp_Ax22d ax22d(aCenter, gp_Dir2d(gp_Dir2d::D::X), gp_Dir2d(gp_Dir2d::D::Y));
const gp_Circ2d aCir(ax22d, aRad);
const occ::handle<Geom2d_Circle> Circ = new Geom2d_Circle(aCir);
// calculation parameters first and last points of arc.
double anAlpha1, anAlpha2;
if (isFirst)
{
anAlpha1 = ElCLib::Parameter(aCir, aP1);
anAlpha2 = ElCLib::Parameter(aCir, aP2);
}
else
{
anAlpha1 = ElCLib::Parameter(aCir, aP2);
anAlpha2 = ElCLib::Parameter(aCir, aP1);
aSense = -aSense;
}
if (fabs(anAlpha1 - anAlpha2) < 1e-100)
{
// very small value, just to avoid exact match
return false;
}
// Reverse the circle if the sense is negative
if (aSense < 0.)
{
anAlpha1 = Circ->ReversedParameter(anAlpha1);
anAlpha2 = Circ->ReversedParameter(anAlpha2);
Circ->Reverse();
}
theCurve = new Geom2d_TrimmedCurve(Circ, anAlpha1, anAlpha2);
// Correct the direction in the opposite point
const gp_XY aRadV = theParam2.Point() - aCenter.XY();
theParam2.SetD1(gp_XY(-aRadV.Y() * aSense, aRadV.X() * aSense));
return true;
}
// Algorithm failed, possibly because aVec is normal to the chorde
return false;
}
//=================================================================================================
occ::handle<Geom2d_TrimmedCurve> Geom2dConvert_ApproxArcsSegments::makeLine(
Geom2dConvert_PPoint& theFirst,
Geom2dConvert_PPoint& theLast,
const bool isCheck) const
{
occ::handle<Geom2d_TrimmedCurve> aResult;
gp_XY aSlope = theLast.Point() - theFirst.Point();
if (fabs(aSlope.SquareModulus()) < gp::Resolution())
{
return aResult;
}
gp_Dir2d aDirLine(aSlope);
if (isCheck)
{
if (theFirst.D1().SquareModulus() < gp::Resolution()
|| theLast.D1().SquareModulus() < gp::Resolution())
{
return aResult;
}
// Angular continuity (G1) is only checked when the end of the line is not
// on the extremity of the curve
double absAngle[2] = {0., 0.};
if (theFirst != myExt[0])
{
const double anAng = aDirLine.Angle(theFirst.D1());
absAngle[0] = (anAng > 0. ? anAng : -anAng);
}
if (theLast != myExt[1])
{
const double anAng = aDirLine.Angle(theLast.D1());
absAngle[1] = (anAng > 0. ? anAng : -anAng);
}
// if the derivatives in the end points differ from the derivative line
// more than value of the specified continuity tolerance
// then a biarc should be built instead of a line.
const double aContTolerance = std::max(myAngleTolerance, 0.01);
if (absAngle[0] > aContTolerance || absAngle[1] > aContTolerance)
{
// std::cout << "makeLine(): Line not built" << std::endl;
return aResult;
}
} // end if (isCheck)
// building segment of line
GC_MakeSegment2d aMakeSeg(theFirst.Point(), theLast.Point());
if (aMakeSeg.IsDone())
{
occ::handle<Geom2d_TrimmedCurve> aCurve = aMakeSeg.Value();
if (checkCurve(aCurve, theFirst.Parameter(), theLast.Parameter()))
{
aResult = aCurve;
// correct the derivatives fields in both arguments
const gp_XY aNewD1(theLast.Point() - theFirst.Point());
theFirst.SetD1(aNewD1);
theLast.SetD1(aNewD1);
}
}
// else
// std::cout << "makeLine(): Line not built" << std::endl;
return aResult;
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::makeFreeform()
{
NCollection_Sequence<Geom2dConvert_PPoint> seqParamPoints(myAlloc);
Geom2dConvert_PPoint* aPrevParam = &myExt[0];
// calculation of the inflection points.
getLinearParts(seqParamPoints);
const bool isNoInfPoints = seqParamPoints.IsEmpty();
NCollection_Sequence<occ::handle<Geom2d_Curve>> aSeqLinearParts;
bool isDone(true);
int i;
for (i = 1; i < seqParamPoints.Length(); i += 2)
{
occ::handle<Geom2d_Curve> aLineCurve;
Geom2dConvert_PPoint& aParam0 = seqParamPoints.ChangeValue(i);
Geom2dConvert_PPoint& aParam1 = seqParamPoints.ChangeValue(i + 1);
if (aParam0 != aParam1)
{
// linear part of the curve lies between odd and even values of i.
// parameters from parameter's sequence.
aLineCurve = makeLine(aParam0, aParam1, false);
}
aSeqLinearParts.Append(aLineCurve);
}
for (i = 1; i < seqParamPoints.Length(); i += 2)
{
// approximation for non-linear part preceding the linear part
if (seqParamPoints(i) != *aPrevParam)
{
const int aLastInd = mySeqCurves.Length();
isDone = makeApproximation(*aPrevParam, seqParamPoints(i));
if (isDone && aLastInd && mySeqCurves.Length() > aLastInd)
{
isDone = checkContinuity(mySeqCurves.Value(aLastInd),
mySeqCurves.Value(aLastInd + 1),
myAngleTolerance);
}
if (!isDone)
{
myStatus = StatusError;
break;
}
}
const occ::handle<Geom2d_Curve>& aCurve = aSeqLinearParts.Value((i + 1) / 2);
if (!aCurve.IsNull())
{
mySeqCurves.Append(aCurve);
}
else
{
Geom2dConvert_PPoint& aParam0 = seqParamPoints.ChangeValue(i);
Geom2dConvert_PPoint& aParam1 = seqParamPoints.ChangeValue(i + 1);
const int aLastInd = mySeqCurves.Length();
isDone = makeApproximation(aParam0, aParam1);
if (isDone && aLastInd && mySeqCurves.Length() > aLastInd)
{
isDone = checkContinuity(mySeqCurves.Value(aLastInd),
mySeqCurves.Value(aLastInd + 1),
myAngleTolerance);
}
if (!isDone)
{
myStatus = StatusError;
// std::cout << "makeOther: Line not built" << std::endl;
break;
}
}
aPrevParam = &seqParamPoints(i + 1);
}
// approximation for non-linear part following the last linear part
if (isDone && (*aPrevParam != myExt[1]))
{
// Case of a closed edge like an ellipse
if (isNoInfPoints && (myExt[0].Point() - myExt[1].Point()).Modulus() < myTolerance)
{
Geom2dConvert_PPoint aPPoint(0.5 * (myExt[0].Parameter() + myExt[1].Parameter()), myCurve);
isDone = makeApproximation(myExt[0], aPPoint);
if (isDone)
{
isDone = makeApproximation(aPPoint, myExt[1]);
}
}
else
{
isDone = makeApproximation(*aPrevParam, myExt[1]);
}
if (!isDone)
{
myStatus = StatusError;
// std::cout << "makeOther: Line not built" << std::endl;
}
}
return (mySeqCurves.Length() && myStatus != StatusError);
}
//=================================================================================================
void Geom2dConvert_ApproxArcsSegments::getLinearParts(
NCollection_Sequence<Geom2dConvert_PPoint>& theSeqPar)
{
int i;
// Fill the sequences with values along the curve
mySeqParams.Clear();
Adaptor2d_Curve2d& myCurveMut = const_cast<Adaptor2d_Curve2d&>(myCurve);
GCPnts_QuasiUniformDeflection aQUDefAlgo(myCurveMut, myTolerance * 0.5);
bool isUniformDone = aQUDefAlgo.IsDone();
gp_XY aLastPnt(myExt[0].Point());
if (isUniformDone)
{
for (i = 1; i <= aQUDefAlgo.NbPoints(); i++)
{
const Geom2dConvert_PPoint aPP(aQUDefAlgo.Parameter(i), myCurve);
mySeqParams.Append(aPP);
aLastPnt = aPP.Point();
}
}
else
{
const double aParamStep = (myExt[1].Parameter() - myExt[0].Parameter()) / MAXPOINTS;
for (i = 1; i <= MAXPOINTS; i++)
{
const double aParam = myExt[0].Parameter() + aParamStep * i;
const Geom2dConvert_PPoint aPP(aParam, myCurve);
mySeqParams.Append(aPP);
aLastPnt = aPP.Point();
}
}
// check if the curve may be linearised
gp_XY aDir = myExt[1].Point() - myExt[0].Point();
const double aMod2 = aDir.SquareModulus();
if (aMod2 > Precision::Confusion())
{
bool isLinear = true;
aDir /= sqrt(aMod2);
for (i = 1; i <= mySeqParams.Length(); i++)
{
// Distance from point "i" to the segment between two extremities
const double aDist = aDir ^ (mySeqParams(i).Point() - myExt[0].Point());
if (aDist > myTolerance * 0.5 || aDist < -myTolerance * 0.5)
{
isLinear = false;
break;
}
}
if (isLinear)
{
theSeqPar.Append(myExt[0]);
theSeqPar.Append(myExt[1]);
return;
}
}
// check if point for First Parameter is inflection point.
int indStartLinear(0);
Geom2dConvert_PPoint aLastInflParam = myExt[0];
Geom2dConvert_PPoint aFirstInflParam = myExt[0];
// Getting further inflection points with step by parameter.
// The point with index 1 is the same as myExt[0]
for (i = 1; i <= mySeqParams.Length(); i++)
{
const Geom2dConvert_PPoint& aCurParam = mySeqParams(i);
if (indStartLinear)
{
bool isStillInflectionFirst =
isInflectionPoint(aFirstInflParam.Parameter(), aCurParam, myCurve, myAngleTolerance);
if (isInflectionPoint(aCurParam.Parameter(), aFirstInflParam, myCurve, myAngleTolerance))
{
aLastInflParam = mySeqParams(i);
while (!isStillInflectionFirst)
{
if (++indStartLinear >= i)
{
indStartLinear = 0;
break;
}
aFirstInflParam = mySeqParams(indStartLinear);
isStillInflectionFirst =
isInflectionPoint(aFirstInflParam.Parameter(), aCurParam, myCurve, myAngleTolerance);
}
}
else
{
// Add the interval in the output sequence
// The interval is added only if it is more than 10 times the tolerance
aLastInflParam = findInflection(aLastInflParam, aCurParam);
if (!isInflectionPoint(aFirstInflParam.Parameter(),
aLastInflParam,
myCurve,
myAngleTolerance))
{
aFirstInflParam = findInflection(aLastInflParam, aFirstInflParam);
}
const double aDist((aFirstInflParam.Point() - aLastInflParam.Point()).Modulus());
if (aFirstInflParam.Parameter() < aLastInflParam.Parameter() && aDist > 10 * myTolerance)
{
theSeqPar.Append(aFirstInflParam);
theSeqPar.Append(aLastInflParam);
}
indStartLinear = 0;
}
}
else if (isInflectionPoint(aCurParam.Parameter(), myCurve))
{
aLastInflParam = aCurParam;
if (i > 1)
{
aFirstInflParam = findInflection(aCurParam, mySeqParams(i - 1));
}
indStartLinear = i;
}
}
const double aDist((aFirstInflParam.Point() - myExt[1].Point()).Modulus());
if (indStartLinear && aDist > 10 * myTolerance)
{
theSeqPar.Append(aFirstInflParam);
theSeqPar.Append(myExt[1]);
}
}
//=================================================================================================
Geom2dConvert_PPoint Geom2dConvert_ApproxArcsSegments::findInflection(
const Geom2dConvert_PPoint& theParamIsInfl,
const Geom2dConvert_PPoint& theParamNoInfl) const
{
double aLower(theParamIsInfl.Parameter());
double anUpper(theParamNoInfl.Parameter());
double aTest(0.);
for (int i = 0; i < 3; i++)
{ // 3 iterations
aTest = (aLower + anUpper) * 0.5;
if (isInflectionPoint(aTest, theParamIsInfl, myCurve, myAngleTolerance))
{
aLower = aTest;
}
else
{
anUpper = aTest;
}
}
return Geom2dConvert_PPoint(aTest, myCurve);
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::makeApproximation(Geom2dConvert_PPoint& theFirstParam,
Geom2dConvert_PPoint& theLastParam)
{
// if difference between parameters is less than Precision::PConfusion
// approximation was not made.
bool isDone = false;
if (theLastParam != theFirstParam)
{
const double aDistance = (theFirstParam.Point() - theLastParam.Point()).Modulus();
if (aDistance < myTolerance)
{
const occ::handle<Geom2d_Curve> aCurve = makeLine(theFirstParam, theLastParam, true);
isDone = !aCurve.IsNull();
if (isDone && mySeqCurves.Length())
{
isDone = checkContinuity(mySeqCurves.Last(), aCurve, myAngleTolerance);
}
if (isDone || aDistance < Precision::Confusion())
{
mySeqCurves.Append(aCurve);
return isDone;
}
}
// calculate biarc
isDone = calculateBiArcs(theFirstParam, theLastParam);
// if biarc was not calculated calculation is repeated on half the interval.
if (!isDone)
{
Geom2dConvert_PPoint aParaM(theFirstParam.Parameter()
+ (theLastParam.Parameter() - theFirstParam.Parameter()) * 0.55,
myCurve);
isDone = makeApproximation(theFirstParam, aParaM);
if (isDone)
{
isDone = makeApproximation(aParaM, theLastParam);
}
}
}
return isDone;
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::calculateBiArcs(Geom2dConvert_PPoint& theFirstParam,
Geom2dConvert_PPoint& theLastParam)
{
const double aResolution = gp::Resolution();
if (theFirstParam.D1().SquareModulus() < aResolution
|| theLastParam.D1().SquareModulus() < aResolution)
{
// std::cout << "calculateBiArcs(): bad initial data" << std::endl;
return false;
}
const gp_XY aPnt[2] = {theFirstParam.Point(), theLastParam.Point()};
gp_Dir2d aDir[2] = {theFirstParam.D1(), theLastParam.D1()};
// Try to approximate the curve by a single arc. The criterion for that is
// more rigid if the curve is the entire input curve
// (possible pb. connecting with other boundaries)
const gp_Vec2d aDelta(aPnt[1] - aPnt[0]);
double anAngle1 = aDelta.Angle(gp_Vec2d(aDir[0]));
if (anAngle1 < 0.)
{
anAngle1 = -anAngle1;
}
double anAngle2 = aDelta.Angle(gp_Vec2d(aDir[1]));
if (anAngle2 < 0.)
{
anAngle2 = -anAngle2;
}
// in the case when two angles are equal one arc can be built.
double anAngleThreshold(Precision::Angular() * 10.);
if (theFirstParam != myExt[0] || theLastParam != myExt[1])
{
anAngleThreshold = myAngleTolerance * 0.1;
}
if (fabs(anAngle1 - anAngle2) < anAngleThreshold)
{
occ::handle<Geom2d_TrimmedCurve> aCurve;
// protect the theLastParam from modification of D1, when
// the created arc is rejected.
Geom2dConvert_PPoint aLastParam(theLastParam);
if (!makeArc(theFirstParam, aLastParam, true, aCurve))
{
return false;
}
if (checkCurve(aCurve, theFirstParam.Parameter(), aLastParam.Parameter()))
{
theLastParam = aLastParam;
mySeqCurves.Append(aCurve);
return true;
}
}
// if one arc was not built or for other cases biarc will be built
// method for building biarc was taken from article Ahmad H. Nasri et al.
// "A Recursive Subdivision Algorithm for Piecewise Circular Spline",
// Computer Graphics Forum, 2001.
// definition of point of intersection two tangent directions in the points
// corresponding FirstParameter and LastParameter.
aDir[1].Reverse();
// Direct calculation of intersection point, replaces a class call below
const double aProd[3] = {aPnt[0] ^ aDir[0].XY(), aPnt[1] ^ aDir[1].XY(), aDir[1] ^ aDir[0].XY()};
gp_XY aIntPoint((aProd[0] * aDir[1].X() - aProd[1] * aDir[0].X()) / aProd[2],
(aProd[0] * aDir[1].Y() - aProd[1] * aDir[0].Y()) / aProd[2]);
const gp_XY aDiff[2] = {aIntPoint - aPnt[0], aIntPoint - aPnt[1]};
if (aDiff[0] * aDir[0].XY() < 0. || aDiff[1] * aDir[1].XY() < 0.)
{
return false;
}
// calculation middle point for building biarc.
const double ad1 = aDiff[0].Modulus();
const double ad2 = aDiff[1].Modulus();
const double ad12 = aDelta.Magnitude();
const double aB1 = ad1 / (ad1 + ad2);
if (fabs(aB1 - 0.5) < 0.0001)
{
return false;
}
gp_XY aXY[2] = {aPnt[0] + aDir[0].XY() * ad12 * ad1 / (ad12 + ad1 + ad2),
aPnt[1] + aDir[1].XY() * ad12 * ad2 / (ad12 + ad1 + ad2)};
const gp_XY aXYmidArc(aXY[0] + aB1 * (aXY[1] - aXY[0]));
Geom2dConvert_PPoint aParamMidArc =
getParameter(aXYmidArc, theFirstParam.Parameter(), theLastParam.Parameter(), myCurve);
// building first arc from biarc.
occ::handle<Geom2d_TrimmedCurve> aCurve1, aCurve2;
if (!makeArc(theFirstParam, aParamMidArc, true, aCurve1))
{
return false;
}
if (!checkCurve(aCurve1, theFirstParam.Parameter(), aParamMidArc.Parameter()))
{
return false;
}
// building second arc from biarc.
if (makeArc(theLastParam, aParamMidArc, false, aCurve2))
{
if (checkCurve(aCurve2, aParamMidArc.Parameter(), theLastParam.Parameter()))
{
mySeqCurves.Append(aCurve1);
mySeqCurves.Append(aCurve2);
return true;
}
}
return false;
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::calculateLines(Geom2dConvert_PPoint& theFirstParam,
Geom2dConvert_PPoint& theLastParam)
{
Geom2dConvert_PPoint* aPrevParam = &theFirstParam;
for (int i = 1; i <= mySeqParams.Length(); i++)
{
Geom2dConvert_PPoint& aCurParam = mySeqParams.ChangeValue(i);
if (aCurParam.Parameter() < (*aPrevParam).Parameter())
{
continue;
}
if (aCurParam.Parameter() > theLastParam.Parameter())
{
break;
}
// build line segment
if (aCurParam != *aPrevParam)
{
const double aDistance = (aCurParam.Point() - (*aPrevParam).Point()).Modulus();
if (aDistance > myTolerance)
{
const occ::handle<Geom2d_Curve> aCurve = makeLine(*aPrevParam, aCurParam, false);
if (aCurve.IsNull())
{
return false;
}
mySeqCurves.Append(aCurve);
aPrevParam = &mySeqParams(i);
}
}
}
return true;
}
//=================================================================================================
bool Geom2dConvert_ApproxArcsSegments::checkCurve(const occ::handle<Geom2d_Curve>& aCurve,
const double theFirstParam,
const double theLastParam) const
{
if (aCurve.IsNull())
{
return false; // check fails on empty input
}
bool isUniformDone = !mySeqParams.IsEmpty();
// calculation sequence of the parameters or step by parameter.
int aNbPnts = (isUniformDone ? mySeqParams.Length() : MAXPOINTS);
double aParamStep = (theLastParam - theFirstParam) / MAXPOINTS;
occ::handle<Geom2d_Curve> aCurve1 = aCurve;
occ::handle<Geom2d_TrimmedCurve> aTrCurve = occ::down_cast<Geom2d_TrimmedCurve>(aCurve);
if (!aTrCurve.IsNull())
{
aCurve1 = aTrCurve->BasisCurve();
}
gp_Lin2d aLin2d;
gp_Circ2d aCirc2d;
occ::handle<Geom2d_Line> aGeomLine = occ::down_cast<Geom2d_Line>(aCurve1);
bool isLine = (!aGeomLine.IsNull());
bool isCircle = (!isLine);
if (isLine)
{
aLin2d = aGeomLine->Lin2d();
}
else
{
occ::handle<Geom2d_Circle> aGeomCircle = occ::down_cast<Geom2d_Circle>(aCurve1);
isCircle = (!aGeomCircle.IsNull());
if (isCircle)
{
aCirc2d = aGeomCircle->Circ2d();
}
else
{
return false;
}
}
// calculation of the max deflection points from CurveAdaptor from Geom curve.
bool isLess = true;
int i = 1;
for (; i <= aNbPnts && isLess; i++)
{
double aParam =
(isUniformDone ? mySeqParams.Value(i).Parameter() : (theFirstParam + i * aParamStep));
if (aParam < (theFirstParam - Precision::PConfusion())
|| aParam > (theLastParam + Precision::PConfusion()))
{
continue;
}
// getting point from adaptor curve by specified parameter.
gp_Pnt2d aPointAdaptor(0., 0.);
gp_Pnt2d aProjPoint(0., 0.);
myCurve.D0(aParam, aPointAdaptor);
double aParameterCurve = 0.0;
// getting point from geom curve by specified parameter.
if (isLine)
{
aParameterCurve = ElCLib::Parameter(aLin2d, aPointAdaptor);
aProjPoint = ElCLib::Value(aParameterCurve, aLin2d);
}
else if (isCircle)
{
aParameterCurve = ElCLib::Parameter(aCirc2d, aPointAdaptor);
aProjPoint = ElCLib::Value(aParameterCurve, aCirc2d);
}
isLess = (aProjPoint.Distance(aPointAdaptor) < myTolerance + Precision::PConfusion());
}
return isLess;
}
//=================================================================================================
bool checkContinuity(const occ::handle<Geom2d_Curve>& theCurve1,
const occ::handle<Geom2d_Curve>& theCurve2,
const double theAngleTol)
{
gp_Vec2d v11, v21;
gp_Pnt2d p1, p2;
theCurve1->D1(theCurve1->LastParameter(), p1, v11);
theCurve2->D1(theCurve2->FirstParameter(), p2, v21);
// check continuity with the specified tolerance.
return (v11.IsParallel(v21, theAngleTol));
}
//=================================================================================================
Geom2dConvert_PPoint getParameter(const gp_XY& theXY1,
const double theFirstParam,
const double theLastParam,
const Adaptor2d_Curve2d& theCurve)
{
Geom2dConvert_PPoint aResult;
double prevParam = theFirstParam;
double af1 = theFirstParam;
double af2 = theLastParam;
// for finding nearest point use method half division.
double aMinDist = RealLast();
int i = 1;
for (; i <= MAXPOINTS; i++)
{
aResult = Geom2dConvert_PPoint(af1, theCurve);
double adist1 = (theXY1 - aResult.Point()).Modulus();
if (adist1 < Precision::Confusion())
{
return aResult;
}
aResult = Geom2dConvert_PPoint(af2, theCurve);
double adist2 = (theXY1 - aResult.Point()).Modulus();
if (adist2 < Precision::Confusion())
{
return aResult;
}
if (aMinDist <= adist2 - Precision::Confusion() && aMinDist <= adist1 - Precision::Confusion())
{
break;
}
if (adist1 < adist2 - Precision::Confusion())
{
prevParam = af1;
aMinDist = adist1;
af2 = (af1 + af2) * 0.5;
}
else
{
prevParam = af2;
aMinDist = adist2;
af1 = (af1 + af2) * 0.5;
}
}
aResult = Geom2dConvert_PPoint(prevParam, theCurve);
return aResult;
}
//=================================================================================================
bool isInflectionPoint(const double theParam, const Adaptor2d_Curve2d& theCurve)
{
gp_Pnt2d aP1;
gp_Vec2d aD1, aD2;
theCurve.D2(theParam, aP1, aD1, aD2);
const double aSqMod = aD1.XY().SquareModulus();
const double aCurvature = fabs(aD1.XY() ^ aD2.XY()) / (aSqMod * sqrt(aSqMod));
return (aCurvature < MyCurvatureTolerance);
}
//=================================================================================================
bool isInflectionPoint(const double theParam,
const Geom2dConvert_PPoint& theFirstInfl,
const Adaptor2d_Curve2d& theCurve,
const double theAngleTol)
{
gp_Pnt2d aP1;
gp_Vec2d aD1, aD2;
theCurve.D2(theParam, aP1, aD1, aD2);
const double aSqMod = aD1.XY().SquareModulus();
const double aCurvature = fabs(aD1.XY() ^ aD2.XY()) / (aSqMod * sqrt(aSqMod));
double aContAngle = fabs(gp_Vec2d(aP1.XY() - theFirstInfl.Point()).Angle(aD1));
aContAngle = std::min(aContAngle, fabs(M_PI - aContAngle));
return (aCurvature < MyCurvatureTolerance && aContAngle < theAngleTol);
}
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.