Program Listing for File G2lib.cc¶
↰ Return to documentation for file (G2lib.cc)
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2017 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Industriale |
| Universita` degli Studi di Trento |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
#include "Clothoids.hh"
#include "PolynomialRoots.hh"
#include <algorithm>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif
namespace G2lib {
using std::numeric_limits;
using std::fpclassify;
using std::lower_bound;
using std::abs;
using std::sqrt;
using std::sin;
using std::cos;
using std::tan;
using std::atan;
using std::asin;
using std::acos;
real_type const m_1_sqrt_pi = 0.564189583547756286948079451561; // 1/sqrt(pi)
real_type const machepsi = numeric_limits<real_type>::epsilon();
real_type const machepsi10 = 10*machepsi;
real_type const machepsi100 = 100*machepsi;
real_type const machepsi1000 = 1000*machepsi;
real_type const sqrtMachepsi = sqrt(machepsi);
bool intersect_with_AABBtree = true;
#ifdef G2LIB_COMPATIBILITY_MODE
bool use_ISO = true;
#endif
char const *CurveType_name[] = {
"LINE",
"POLYLINE",
"CIRCLE",
"BIARC",
"BIARC_LIST",
"CLOTHOID",
"CLOTHOID_LIST"
};
void
rangeSymm( real_type & ang ) {
ang = fmod( ang, Utils::m_2pi );
while ( ang < -Utils::m_pi ) ang += Utils::m_2pi;
while ( ang > Utils::m_pi ) ang -= Utils::m_2pi;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static inline real_type power2( real_type a ) { return a*a; }
static inline real_type power3( real_type a ) { return a*a*a; }
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
// sin(x)/x
*/
real_type
Sinc( real_type x ) {
if ( abs(x) < 0.02 ) {
real_type x2 = x*x;
return 1-(x2/6)*(1-(x2/20)*(1-x2/42));
} else {
return sin(x)/x;
}
}
real_type
Sinc_D( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.04 ) return -(x/3)*(1-(x2/10)*(1-(x2/28)*(1-(x2/54))));
else return (cos(x)-sin(x)/x)/x;
}
real_type
Sinc_DD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.02 ) return -1./3.+x2*(0.1-x2*((1.0/168.0)-(x2/6480)));
else return ((2/x2-1)*sin(x)-2*cos(x)/x)/x;
}
real_type
Sinc_DDD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.009 ) return (1.0/5.0+(-1.0/42.0+(1.0/1080.0)*x2)*x2)*x;
else return ((6/x2-1)*cos(x)+(3-6/x2)*sin(x)/x)/x;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
// (1-cos(x))/x
*/
real_type
Cosc( real_type x ) {
if ( abs(x) < 0.04 ) {
real_type x2 = x*x;
return (x/2)*(1-(x2/12)*(1-(x2/30)*(1-x2/56)));
} else {
return (1-cos(x))/x;
}
}
real_type
Cosc_D( real_type x ) {
if ( abs(x) < 0.02 ) {
real_type x2 = x*x;
return 0.5*(1-(x2/4)*(1-(x2/18)*(1-(x2/40))));
} else {
return (sin(x)+(cos(x)-1)/x)/x;
}
}
real_type
Cosc_DD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.04 )
return -(x/4)*(1-(x2/9)*(1-((3.0/80.0)*x2)*(1-((2.0/105.0)*x2))));
else
return ((1-2/x2)*cos(x)+(2/x-sin(x))/x)/x;
}
real_type
Cosc_DDD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.02 )
return -(1-(x2/3)*(1-(x2/16)*(1-(2.0/75.0)*x2)))/4.0;
else
return ((6/x2-1)*sin(x)+((6/x2-3)*cos(x)-6/x2)/x)/x;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
// atan(x)/x
*/
real_type
Atanc( real_type x ) {
if ( abs(x) < 0.03 ) {
real_type x2 = x*x;
return 1-x2*((1./3.)-x2*((1./5.)-x2*((1./7.)-x2*((1./9.)-(x2/11)))));
} else {
return atan(x)/x;
}
}
real_type
Atanc_D( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.03 ) {
return x*( -(2./3.) + x2*( (4./5.) + x2*( -(6./7.) + x2*( (8./9.) + x2*( -(10./11.) + x2*(12./13.))))));
} else {
return (1/(1+x2)-atan(x)/x)/x;
}
}
real_type
Atanc_DD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.02 ) {
return -2./3.+ x2*( (12./5.) + (-(30./7.) + x2 * ( (56./9.) + x2*( -(90./11.) + x2 * (132./13.)))));
} else {
return (2*atan(x)/x-(4*x2+2)/power2(1+x2))/x2;
}
}
real_type
Atanc_DDD( real_type x ) {
real_type x2 = x*x;
if ( abs(x) < 0.02 ) {
return x*(24./5.+x2*(-120./7. + x2 * (112./3. + x2 * (-720./11. + x2*(1320./13. - x2*728./5.)))));
} else {
return ( ((18*x2+16)*x2+6)/power3(x2+1)-6*atan(x)/x )/(x2*x);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static
real_type
maxabs3( real_type A, real_type B, real_type C ) {
real_type res = abs(A);
real_type absB = abs(B);
if ( res < absB ) res = absB;
real_type absC = abs(C);
if ( res < absC ) res = absC;
return res;
}
#endif
int_type
solveLinearQuadratic(
real_type A,
real_type B,
real_type C,
real_type a,
real_type b,
real_type c,
real_type * x,
real_type * y
) {
real_type m1 = maxabs3(A,B,C);
real_type m2 = maxabs3(a,b,c);
A /= m1; B /= m1; C /= m1;
a /= m2; b /= m2; c /= m2;
real_type Ab = A * b;
real_type Ba = B * a;
real_type tmp = A * Ab + B * Ba;
real_type disc = tmp - (C * C) * a * b;
real_type ACb = Ab*C;
real_type BCa = Ba*C;
if ( disc > machepsi100 ) {
// two solution
disc = sqrt(disc);
real_type Bdisc = B*disc;
real_type Adisc = A*disc;
x[0] = (ACb-Bdisc)/tmp;
x[1] = (ACb+Bdisc)/tmp;
y[0] = (BCa+Adisc)/tmp;
y[1] = (BCa-Adisc)/tmp;
return 2;
} if ( disc > -machepsi100 ) {
// one solution
x[0] = ACb/tmp;
y[0] = BCa/tmp;
return 1;
}
return 0; // no solution
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int_type
solveLinearQuadratic2(
real_type A,
real_type B,
real_type C,
real_type * x,
real_type * y
) {
real_type m = maxabs3(A,B,C);
A /= m; B /= m; C /= m;
real_type tmp = A*A + B*B;
real_type disc = tmp - (C * C);
real_type AC = A*C;
real_type BC = B*C;
if ( disc > machepsi100 ) {
// two solution
disc = sqrt(disc);
real_type Bdisc = B*disc;
real_type Adisc = A*disc;
x[0] = (AC-Bdisc)/tmp;
x[1] = (AC+Bdisc)/tmp;
y[0] = (BC+Adisc)/tmp;
y[1] = (BC-Adisc)/tmp;
return 2;
} if ( disc > -machepsi100 ) {
// one solution
x[0] = AC/tmp;
y[0] = BC/tmp;
return 1;
}
return 0; // no solution
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static
int_type
solveNLsysCircleCircle(
real_type kA,
real_type T,
real_type Tx,
real_type Ty,
real_type kB,
real_type x[2],
real_type y[2]
) {
real_type Tx2 = Tx*Tx;
real_type Ty2 = Ty*Ty;
real_type kB2 = kB*kB;
real_type kA2 = kA*kA;
real_type a = (Tx2+Ty2)*kB2/4+Tx*kA*kB+kA2;
real_type b = (Tx*kB+2*kA)*T-Ty2;
real_type c = T*T;
PolynomialRoots::Quadratic qsolve( a, b, c);
if ( qsolve.complexRoots() ) return 0;
real_type z[2] = { qsolve.real_root0(), qsolve.real_root1() };
int_type nint = 0;
for ( int_type i = 0; i < qsolve.numRoots(); ++i ) {
real_type tmp = z[i]*(4-kB2*z[i]);
if ( tmp < 0 ) continue;
real_type xx = kB*z[i]/2;
real_type yy = sqrt( tmp )/2;
tmp = Tx*xx+kA*z[i]+T;
if ( abs(tmp-Ty*yy) < abs(tmp+Ty*yy) ) yy = -yy;
x[nint] = xx;
y[nint] = yy;
++nint;
}
return nint;
}
static
real_type
invCoscSinc( real_type k, real_type x, real_type y ) {
real_type ds, s = y;
if ( abs(k) > sqrtMachepsi ) s = atan2( y*k, 1-k*x )/k;
int_type iter = 0;
do {
real_type sk = s*k;
ds = (y-Sinc(sk)*s)*cos(sk)/(1-sin(sk)*k*y);
s += ds;
} while ( abs(ds) > machepsi100 && ++iter < 5 );
return s;
}
#endif
int_type
intersectCircleCircle(
real_type x1,
real_type y1,
real_type theta1,
real_type kappa1,
real_type x2,
real_type y2,
real_type theta2,
real_type kappa2,
real_type * s1,
real_type * s2
) {
real_type dx = x2 - x1;
real_type dy = y2 - y1;
real_type L2 = dx*dx+dy*dy;
real_type L = sqrt(L2);
real_type alpha = atan2( dy, dx );
real_type a1 = alpha-theta1;
real_type a2 = alpha-theta2;
real_type t12 = theta1-theta2;
real_type Sa1 = L*sin(a1);
real_type Ca1 = L*cos(a1);
real_type Sa2 = L*sin(a2);
real_type Ca2 = L*cos(a2);
real_type S12 = sin(t12);
real_type C12 = cos(t12);
real_type T1 = L2*kappa2+2*Sa2;
real_type T2 = L2*kappa1-2*Sa1;
real_type xx1[2], yy1[2], xx2[2], yy2[3];
int_type nsol;
if ( abs(T1) > abs(T2) ) {
real_type Tx1 = -2*(Sa1*kappa2+C12);
real_type Ty1 = -2*(Ca1*kappa2+S12);
nsol = solveNLsysCircleCircle( kappa2, T1, Tx1, Ty1, kappa1, xx1, yy1 );
for ( int_type i = 0; i < nsol; ++i ) {
xx2[i] = C12*xx1[i]+S12*yy1[i]-Sa2;
yy2[i] = C12*yy1[i]-S12*xx1[i]-Ca2;
}
} else {
real_type Tx2 = 2*(Sa2*kappa1-C12);
real_type Ty2 = 2*(Ca2*kappa1+S12);
nsol = solveNLsysCircleCircle( kappa1, T2, Tx2, Ty2, kappa2, xx2, yy2 );
for ( int_type i = 0; i < nsol; ++i ) {
xx1[i] = C12*xx2[i]-S12*yy2[i]+Sa1;
yy1[i] = C12*yy2[i]+S12*xx2[i]+Ca1;
}
}
real_type len1 = Utils::m_2pi/(machepsi+abs(kappa1));
real_type len2 = Utils::m_2pi/(machepsi+abs(kappa1));
for ( int_type i = 0; i < nsol; ++i ) {
real_type ss1 = invCoscSinc( kappa1, xx1[i], yy1[i] );
real_type ss2 = invCoscSinc( kappa2, xx2[i], yy2[i] );
while ( ss1 < 0 ) ss1 += len1;
while ( ss2 < 0 ) ss2 += len2;
while ( ss1 > len1 ) ss1 -= len1;
while ( ss2 > len2 ) ss2 -= len2;
s1[i] = ss1;
s2[i] = ss2;
}
return nsol;
}
/*\
| __ ____ __ _ _____ _ _
| \ \/ /\ \ / / | |_ ___ |_ _| |__ ___| |_ __ _
| \ / \ V / | __/ _ \ | | | '_ \ / _ \ __/ _` |
| / \ | | | || (_) | | | | | | | __/ || (_| |
| /_/\_\ |_| \__\___/ |_| |_| |_|\___|\__\__,_|
\*/
void
xy_to_guess_angle(
int_type npts,
real_type const * x,
real_type const * y,
real_type * theta,
real_type * theta_min,
real_type * theta_max,
real_type * omega,
real_type * len
) {
//
// Compute guess angles
//
int_type ne = npts-1;
int_type ne1 = npts-2;
real_type dx = x[1]-x[0];
real_type dy = y[1]-y[0];
omega[0] = atan2(dy,dx);
len[0] = hypot(dy,dx);
for ( int_type j = 1; j < ne; ++j ) {
dx = x[j+1]-x[j];
dy = y[j+1]-y[j];
omega[j] = atan2(dy,dx);
len[j] = hypot(dy,dx);
real_type domega = omega[j]-omega[j-1];
domega -= round(domega/Utils::m_2pi)*Utils::m_2pi;
omega[j] = omega[j-1]+domega;
}
real_type const dangle = 0.99 * Utils::m_pi;
theta[0] = omega[0];
theta_min[0] = omega[0] - dangle;
theta_max[0] = omega[0] + dangle;
theta[ne] = omega[ne1];
theta_min[ne] = omega[ne1] - dangle;
theta_max[ne] = omega[ne1] + dangle;
real_type omega_L = omega[0];
real_type len_L = len[0];
for ( int_type j = 1; j < ne; ++j ) {
real_type omega_R = omega[j];
real_type len_R = len[j];
theta[j] = ( omega_L/len_L + omega_R / len_R ) / ( 1/len_L + 1/len_R );
if ( omega_R > omega_L ) {
theta_min[j] = omega_L;
theta_max[j] = omega_R;
} else {
theta_min[j] = omega_R;
theta_max[j] = omega_L;
}
theta_min[j] -= dangle;
theta_max[j] += dangle;
omega_L = omega_R;
len_L = len_R;
}
}
/*\
| ____ _ ____ ____
| / ___| ___ | |_ _____|___ \__ _|___ \
| \___ \ / _ \| \ \ / / _ \ __) \ \/ / __) |
| ___) | (_) | |\ V / __// __/ > < / __/
| |____/ \___/|_| \_/ \___|_____/_/\_\_____|
\*/
bool
Solve2x2::factorize( real_type A[2][2] ) {
// full pivoting
real_type Amax = abs(A[0][0]);
real_type tmp = abs(A[0][1]);
int_type ij = 0;
if ( tmp > Amax ) { ij = 1; Amax = tmp; }
tmp = abs(A[1][0]);
if ( tmp > Amax ) { ij = 2; Amax = tmp; }
tmp = abs(A[1][1]);
if ( tmp > Amax ) { ij = 3; Amax = tmp; }
if ( Utils::isZero(Amax) ) return false;
if ( (ij&0x01) == 0x01 ) { j[0] = 1; j[1] = 0; }
else { j[0] = 0; j[1] = 1; }
if ( (ij&0x02) == 0x02 ) { i[0] = 1; i[1] = 0; }
else { i[0] = 0; i[1] = 1; }
// apply factorization
LU[0][0] = A[i[0]][j[0]];
LU[0][1] = A[i[0]][j[1]];
LU[1][0] = A[i[1]][j[0]];
LU[1][1] = A[i[1]][j[1]];
LU[1][0] /= LU[0][0];
LU[1][1] -= LU[1][0]*LU[0][1];
// check for singularity
singular = abs( LU[1][1] ) < epsi;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
Solve2x2::solve( real_type const b[2], real_type x[2] ) const {
if ( singular ) {
// L^+ Pb
real_type tmp = (b[i[0]] + LU[1][0]*b[i[1]]) /
( (1+power2(LU[1][0]) ) * ( power2(LU[0][0])+power2(LU[0][1]) ) );
x[j[0]] = tmp*LU[0][0];
x[j[1]] = tmp*LU[0][1];
// check consistency
tmp = (LU[0][0]*x[j[0]]+LU[0][1]*x[j[1]]);
return hypot( b[i[0]]-tmp, b[i[1]]+tmp*LU[1][0] ) < hypot(b[0],b[1])*epsi;
} else { // non singular
// L^(-1) Pb
x[j[0]] = b[i[0]];
x[j[1]] = b[i[1]]-LU[1][0]*x[j[0]];
// U^(-1) x
x[j[1]] /= LU[1][1];
x[j[0]] = (x[j[0]]-LU[0][1]*x[j[1]])/LU[0][0];
return FP_INFINITE != fpclassify(x[0]) &&
FP_NAN != fpclassify(x[0]) &&
FP_INFINITE != fpclassify(x[1]) &&
FP_NAN != fpclassify(x[1]);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int_type
isCounterClockwise(
real_type const * P1,
real_type const * P2,
real_type const * P3
) {
real_type dx1 = P2[0] - P1[0];
real_type dy1 = P2[1] - P1[1];
real_type dx2 = P3[0] - P1[0];
real_type dy2 = P3[1] - P1[1];
real_type tol = machepsi10*(hypot(dx1,dy1)*hypot(dx2,dy2));
real_type det = dx1*dy2 - dy1*dx2;
if ( det > tol ) return 1;
else if ( det < -tol ) return -1;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
real_type
projectPointOnCircleArc(
real_type x0,
real_type y0,
real_type c0,
real_type s0,
real_type k,
real_type L,
real_type qx,
real_type qy
) {
real_type dx = x0 - qx;
real_type dy = y0 - qy;
real_type a0 = c0 * dy - s0 * dx;
real_type b0 = s0 * dy + c0 * dx;
real_type tmp = a0*k;
if ( 1+2*tmp > 0 ) {
tmp = b0/(1+tmp);
tmp *= -Atanc(tmp*k); // lunghezza
if ( tmp < 0 ) {
real_type absk = abs(k);
// if 2*pi*R + tmp <= L add 2*pi*R to the solution
if ( Utils::m_2pi <= absk*(L-tmp) ) tmp += Utils::m_2pi / absk;
}
return tmp;
} else {
real_type om = atan2( b0, a0+1/k );
if ( k < 0 ) om += Utils::m_pi;
real_type ss = -om/k;
real_type t = Utils::m_2pi/abs(k);
if ( ss < 0 ) ss += t;
else if ( ss > t ) ss -= t;
return ss;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
real_type
projectPointOnCircle(
real_type x0,
real_type y0,
real_type theta0,
real_type k,
real_type qx,
real_type qy
) {
real_type dx = x0 - qx;
real_type dy = y0 - qy;
real_type c0 = cos(theta0);
real_type s0 = sin(theta0);
real_type a0 = c0 * dy - s0 * dx;
real_type b0 = s0 * dy + c0 * dx;
real_type tmp = a0*k;
if ( 1+2*tmp > 0 ) {
tmp = b0/(1+tmp);
tmp *= -Atanc(tmp*k); // lunghezza
return tmp;
} else {
real_type om = atan2( b0, a0+1/k );
if ( k < 0 ) {
if ( om < 0 ) om += Utils::m_pi;
else om -= Utils::m_pi;
}
return -om/k;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int_type
isPointInTriangle(
real_type const * point,
real_type const * p1,
real_type const * p2,
real_type const * p3
) {
int_type d = isCounterClockwise(p1, p2, p3);
int_type a = isCounterClockwise(p1, p2, point);
int_type b = isCounterClockwise(p2, p3, point);
int_type c = isCounterClockwise(p3, p1, point);
if ( d < 0) { a = -a; b = -b; c = -c; }
if ( a < 0 ) return -1;
if ( b < 0 ) return -1;
if ( c < 0 ) return -1;
if ( a+b+c == 3 ) return 1;
return 0;
}
/*\
| ____ ____
| | __ ) __ _ ___ ___ / ___| _ _ ____ _____
| | _ \ / _` / __|/ _ \ | | | | | '__\ \ / / _ \
| | |_) | (_| \__ \ __/ |__| |_| | | \ V / __/
| |____/ \__,_|___/\___|\____\__,_|_| \_/ \___|
\*/
/*\
| _____ _ _ _
| |_ _| __ _ _ __ __| | | \ | |
| | | / _` | '_ \ / _` | | \| |
| | | | (_| | | | | (_| | | |\ |
| |_| \__,_|_| |_|\__,_| |_| \_|
\*/
real_type
BaseCurve::tx( real_type s ) const
{ return cos(theta(s)); }
real_type
BaseCurve::tx_D( real_type s ) const
{ return -sin(theta(s))*theta_D(s); }
real_type
BaseCurve::tx_DD( real_type s ) const {
real_type th = theta(s);
real_type th_D = theta_D(s);
real_type th_DD = theta_DD(s);
real_type C = cos(th);
real_type S = sin(th);
return -(th_DD*S+(th_D*th_D)*C);
}
real_type
BaseCurve::tx_DDD( real_type s ) const {
real_type th = theta(s);
real_type th_D = theta_D(s);
real_type th_DD = theta_DD(s);
real_type th_DDD = theta_DDD(s);
real_type C = cos(th);
real_type S = sin(th);
return (th_D*th_D*th_D-th_DDD)*S-3*th_DD*th_D*C;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
real_type
BaseCurve::ty( real_type s ) const
{ return sin(theta(s)); }
real_type
BaseCurve::ty_D( real_type s ) const
{ return cos(theta(s))*theta_D(s); }
real_type
BaseCurve::ty_DD( real_type s ) const {
real_type th = theta(s);
real_type th_D = theta_D(s);
real_type th_DD = theta_DD(s);
real_type C = cos(th);
real_type S = sin(th);
return th_DD*C-(th_D*th_D)*S;
}
real_type
BaseCurve::ty_DDD( real_type s ) const {
real_type th = theta(s);
real_type th_D = theta_D(s);
real_type th_DD = theta_DD(s);
real_type th_DDD = theta_DDD(s);
real_type C = cos(th);
real_type S = sin(th);
return (th_DDD-th_D*th_D*th_D)*C-3*(th_DD*th_D)*S;
}
/*\
| __ __ _
| ___ / _|/ _|___ ___| |_
| / _ \| |_| |_/ __|/ _ \ __|
| | (_) | _| _\__ \ __/ |_
| \___/|_| |_| |___/\___|\__|
\*/
real_type
BaseCurve::X_ISO( real_type s, real_type offs ) const
{ return X(s) + offs * nx_ISO(s); }
real_type
BaseCurve::Y_ISO( real_type s, real_type offs ) const
{ return Y(s) + offs * ny_ISO(s); }
real_type
BaseCurve::X_ISO_D( real_type s, real_type offs ) const
{ return X_D(s) + offs * nx_ISO_D(s); }
real_type
BaseCurve::Y_ISO_D( real_type s, real_type offs ) const
{ return Y_D(s) + offs * ny_ISO_D(s); }
real_type
BaseCurve::X_ISO_DD( real_type s, real_type offs ) const
{ return X_DD(s) + offs * nx_ISO_DD(s); }
real_type
BaseCurve::Y_ISO_DD( real_type s, real_type offs ) const
{ return Y_DD(s) + offs * ny_ISO_DD(s); }
real_type
BaseCurve::X_ISO_DDD( real_type s, real_type offs ) const
{ return X_DDD(s) + offs * nx_ISO_DDD(s); }
real_type
BaseCurve::Y_ISO_DDD( real_type s, real_type offs ) const
{ return Y_DDD(s) + offs * ny_ISO_DDD(s); }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
void
BaseCurve::eval_ISO(
real_type s,
real_type offs,
real_type & x,
real_type & y
) const {
real_type nx, ny;
nor_ISO( s, nx, ny );
eval( s, x, y );
x += offs * nx;
y += offs * ny;
}
void
BaseCurve::eval_ISO_D(
real_type s,
real_type offs,
real_type & x_D,
real_type & y_D
) const {
real_type nx_D, ny_D;
nor_ISO_D( s, nx_D, ny_D );
eval_D( s, x_D, y_D );
x_D += offs * nx_D;
y_D += offs * ny_D;
}
void
BaseCurve::eval_ISO_DD(
real_type s,
real_type offs,
real_type & x_DD,
real_type & y_DD
) const {
real_type nx_DD, ny_DD;
nor_ISO_D( s, nx_DD, ny_DD );
eval_DD( s, x_DD, y_DD );
x_DD += offs * nx_DD;
y_DD += offs * ny_DD;
}
void
BaseCurve::eval_ISO_DDD(
real_type s,
real_type offs,
real_type & x_DDD,
real_type & y_DDD
) const {
real_type nx_DDD, ny_DDD;
nor_ISO_D( s, nx_DDD, ny_DDD );
eval_DDD( s, x_DDD, y_DDD );
x_DDD += offs * nx_DDD;
y_DDD += offs * ny_DDD;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
// EOF: G2lib.cc