46double adaptiveSimpson(
F f,
double a,
double b,
double tol,
int maxDepth );
49double adaptiveSimpsonRec(
F f,
double a,
double b,
double tol,
double whole,
double fa,
double fb,
double fm,
52 const double m = 0.5 * ( a + b );
53 const double lm = 0.5 * ( a + m );
54 const double rm = 0.5 * ( m + b );
55 const double flm = f( lm );
56 const double frm = f( rm );
58 const double left = ( m - a ) * ( fa + 4.0 * flm + fm ) / 6.0;
59 const double right = ( b - m ) * ( fm + 4.0 * frm + fb ) / 6.0;
62 if( depth <= 0 ||
std::abs( diff ) < 15.0 * tol )
65 return adaptiveSimpsonRec( f, a, m, 0.5 * tol,
left, fa, fm, flm, depth - 1 )
66 + adaptiveSimpsonRec( f, m, b, 0.5 * tol,
right, fm, fb, frm, depth - 1 );
70double adaptiveSimpson(
F f,
double a,
double b,
double tol,
int maxDepth )
72 const double fa = f( a );
73 const double fb = f( b );
74 const double fm = f( 0.5 * ( a + b ) );
75 const double whole = ( b - a ) * ( fa + 4.0 * fm + fb ) / 6.0;
76 return adaptiveSimpsonRec( f, a, b, tol, whole, fa, fb, fm, maxDepth );
86template <
typename Eval>
87void subdivideEllipseArc(
double t0,
const VECTOR2I& p0,
double t1,
const VECTOR2I& p1,
double aMaxErrSq,
int aDepth,
96 const double tm = 0.5 * ( t0 + t1 );
99 const double mx = 0.5 * (
static_cast<double>( p0.
x ) + p1.
x );
100 const double my = 0.5 * (
static_cast<double>( p0.
y ) + p1.
y );
101 const double ex = pm.
x - mx;
102 const double ey = pm.
y - my;
104 if( ex * ex + ey * ey <= aMaxErrSq )
110 subdivideEllipseArc( t0, p0, tm, pm, aMaxErrSq, aDepth - 1, aEval, aOut );
111 subdivideEllipseArc( tm, pm, t1, p1, aMaxErrSq, aDepth - 1, aEval, aOut );
115constexpr double ROOT_EPSILON = 1e-12;
123std::vector<double> quadraticRoots(
double aA,
double aB,
double aC )
125 std::vector<double> roots;
129 if(
std::abs( aB ) >= ROOT_EPSILON )
130 roots.push_back( -aC / aB );
135 const double disc = aB * aB - 4.0 * aA * aC;
140 const double sq = std::sqrt( disc );
141 const double q = -0.5 * ( aB + ( aB >= 0.0 ?
sq : -
sq ) );
143 roots.push_back( q / aA );
146 roots.push_back( aC / q );
156std::vector<double> cubicRoots(
double aA,
double aB,
double aC,
double aD )
159 return quadraticRoots( aB, aC, aD );
161 const double b = aB / aA;
162 const double c = aC / aA;
163 const double d = aD / aA;
166 const double shift = b / 3.0;
167 const double p = c - b * b / 3.0;
168 const double q = 2.0 * b * b * b / 27.0 - b * c / 3.0 + d;
170 std::vector<double> roots;
171 const double disc = q * q / 4.0 + p * p * p / 27.0;
175 roots.push_back( -shift );
177 else if( disc > 0.0 )
179 const double sq = std::sqrt( disc );
180 roots.push_back( std::cbrt( -q / 2.0 +
sq ) + std::cbrt( -q / 2.0 -
sq ) - shift );
184 const double r = 2.0 * std::sqrt( -p / 3.0 );
185 const double arg = std::clamp( 3.0 * q / ( p * r ), -1.0, 1.0 );
186 const double phi = std::acos( arg ) / 3.0;
188 for(
int k = 0; k < 3; ++k )
189 roots.push_back( r * std::cos( phi - 2.0 *
M_PI * k / 3.0 ) - shift );
200std::vector<double> quarticRoots(
double aA,
double aB,
double aC,
double aD,
double aE )
203 return cubicRoots( aB, aC, aD, aE );
205 const double b = aB / aA;
206 const double c = aC / aA;
207 const double d = aD / aA;
208 const double e = aE / aA;
211 const double shift = b / 4.0;
212 const double p = c - 3.0 * b * b / 8.0;
213 const double q = d - b * c / 2.0 + b * b * b / 8.0;
214 const double r = e - b * d / 4.0 + b * b * c / 16.0 - 3.0 * b * b * b * b / 256.0;
216 std::vector<double> roots;
220 for(
double ySq : quadraticRoots( 1.0, p, r ) )
224 const double y = std::sqrt( ySq );
225 roots.push_back( y - shift );
226 roots.push_back( -y - shift );
233 double alphaSq = 0.0;
235 for(
double z : cubicRoots( 1.0, 2.0 * p, p * p - 4.0 * r, -q * q ) )
244 const double alpha = std::sqrt( alphaSq );
245 const double beta = ( p + alphaSq - q / alpha ) / 2.0;
246 const double gamma = ( p + alphaSq + q / alpha ) / 2.0;
248 for(
double y : quadraticRoots( 1.0, alpha, beta ) )
249 roots.push_back( y - shift );
251 for(
double y : quadraticRoots( 1.0, -alpha, gamma ) )
252 roots.push_back( y - shift );
258void dedupePoints( std::vector<VECTOR2I>& aPoints )
260 std::sort( aPoints.begin(), aPoints.end(),
263 return aLeft.x != aRight.x ? aLeft.x < aRight.x : aLeft.y < aRight.y;
266 aPoints.erase( std::unique( aPoints.begin(), aPoints.end() ), aPoints.end() );
287 m_ellipse( aCenter, aMajorRadius, aMinorRadius, aRotation ),
297 m_ellipse( aCenter, aMajorRadius, aMinorRadius, aRotation, aStartAngle, aEndAngle ),
306 m_ellipse( aCenter, aMajorEndpoint, aRatio ),
316 m_ellipse( aCenter, aMajorEndpoint, aRatio, aStartAngle, aEndAngle ),
385 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
386 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
393 const double dx = std::sqrt( a * a * cos2 + b * b * sin2 );
394 const double dy = std::sqrt( a * a * sin2 + b * b * cos2 );
396 const int idx =
static_cast<int>( std::ceil( dx ) ) + aClearance;
397 const int idy =
static_cast<int>( std::ceil( dy ) ) + aClearance;
402 auto eval = [&](
double theta ) ->
VECTOR2D
404 const double ct = std::cos( theta );
405 const double st = std::sin( theta );
412 double minX = std::min( p0.
x, p1.
x );
413 double maxX = std::max( p0.
x, p1.
x );
414 double minY = std::min( p0.
y, p1.
y );
415 double maxY = std::max( p0.
y, p1.
y );
420 const double candidates[4] = { thetaX, thetaX +
M_PI, thetaY, thetaY +
M_PI };
422 for(
double c : candidates )
428 minX = std::min( minX, p.
x );
429 maxX = std::max( maxX, p.
x );
430 minY = std::min( minY, p.
y );
431 maxY = std::max( maxY, p.
y );
434 const int iMinX =
static_cast<int>( std::floor( minX ) ) - aClearance;
435 const int iMaxX =
static_cast<int>( std::ceil( maxX ) ) + aClearance;
436 const int iMinY =
static_cast<int>( std::floor( minY ) ) - aClearance;
437 const int iMaxY =
static_cast<int>( std::ceil( maxY ) ) + aClearance;
440 VECTOR2I( iMaxX - iMinX, iMaxY - iMinY ) );
446 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
447 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
453 const double h = ( a - b ) / ( a + b );
454 const double h2 = h * h;
455 return M_PI * ( a + b ) * ( 1.0 + 3.0 * h2 / ( 10.0 + std::sqrt( 4.0 - 3.0 * h2 ) ) );
458 auto integrand = [a, b](
double theta ) ->
double
460 const double s = std::sin( theta );
461 const double c = std::cos( theta );
462 return std::sqrt( a * a * s * s + b * b * c * c );
468 return adaptiveSimpson( integrand, t0, t1, 1e-9, 20 );
474 if( aSeg.
A == aSeg.
B )
479 if( dSq == 0 || dSq < clearSq )
482 *aActual =
static_cast<int>( std::round( std::sqrt(
static_cast<double>( dSq ) ) ) );
495 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
496 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
497 const double aSq = a * a;
498 const double bSq = b * b;
500 const double alpha =
D.x *
D.x / aSq +
D.y *
D.y / bSq;
501 const double beta = 2.0 * ( Aloc.
x *
D.x / aSq + Aloc.
y *
D.y / bSq );
502 const double gamma = Aloc.
x * Aloc.
x / aSq + Aloc.
y * Aloc.
y / bSq - 1.0;
505 const double valB = alpha + beta + gamma;
528 const double disc = beta * beta - 4.0 * alpha * gamma;
530 if( disc >= 0.0 && alpha > 0.0 )
532 const double sqrtDisc = std::sqrt( disc );
533 const double twoAlpha = 2.0 * alpha;
534 const double t0 = ( -beta - sqrtDisc ) / twoAlpha;
535 const double t1 = ( -beta + sqrtDisc ) / twoAlpha;
536 const double roots[2] = { t0, t1 };
538 for(
double t : roots )
540 if( t < 0.0 || t > 1.0 )
543 const VECTOR2D hit( Aloc.
x + t *
D.x, Aloc.
y + t *
D.y );
548 const double angle = std::atan2( hit.
y / b, hit.
x / a );
561 double minDistSq = std::numeric_limits<double>::max();
571 bestOnSegment = Aloc;
576 bestOnSegment = Bloc;
580 const double dDotD =
D.x *
D.x +
D.y *
D.y;
585 const double theta0 = std::atan2( -b *
D.x, a *
D.y );
586 const double thetas[2] = { theta0, theta0 +
M_PI };
588 for(
double theta : thetas )
593 const double ex = a * std::cos( theta );
594 const double ey = b * std::sin( theta );
597 const double pDotD = ( ex - Aloc.
x ) *
D.x + ( ey - Aloc.
y ) *
D.y;
598 const double t = std::clamp( pDotD / dDotD, 0.0, 1.0 );
599 const double qx = Aloc.
x + t *
D.x;
600 const double qy = Aloc.
y + t *
D.y;
602 const double distSq = ( ex - qx ) * ( ex - qx ) + ( ey - qy ) * ( ey - qy );
604 if( distSq < minDistSq )
617 for(
const EDA_ANGLE& endAngle : endAngles )
619 const double angleRad = endAngle.AsRadians();
620 const double ex = a * std::cos( angleRad );
621 const double ey = b * std::sin( angleRad );
623 const double pDotD = ( ex - Aloc.
x ) *
D.x + ( ey - Aloc.
y ) *
D.y;
624 const double t = std::clamp( pDotD / dDotD, 0.0, 1.0 );
625 const double qx = Aloc.
x + t *
D.x;
626 const double qy = Aloc.
y + t *
D.y;
628 const double distSq = ( ex - qx ) * ( ex - qx ) + ( ey - qy ) * ( ey - qy );
630 if( distSq < minDistSq )
639 const double thresholdSq =
static_cast<double>( aClearance ) *
static_cast<double>( aClearance );
641 if( minDistSq > 0.0 && minDistSq >= thresholdSq )
645 *aActual =
static_cast<int>( std::round( std::sqrt( minDistSq ) ) );
647 *aLocation =
toWorld( bestOnSegment );
659 chain.SetClosed(
true );
674 m_ellipse.Mirror( aRef, aFlipDirection );
681 std::stringstream ss;
685 ss <<
"SHAPE_ELLIPSE( VECTOR2I( " <<
m_ellipse.Center.x <<
", " <<
m_ellipse.Center.y <<
" ), "
687 <<
m_ellipse.Rotation.AsDegrees() <<
", DEGREES_T )";
691 ss <<
", EDA_ANGLE( " <<
m_ellipse.StartAngle.AsDegrees() <<
", DEGREES_T )"
692 <<
", EDA_ANGLE( " <<
m_ellipse.EndAngle.AsDegrees() <<
", DEGREES_T )";
705 ss <<
" " <<
m_ellipse.StartAngle.AsDegrees() <<
" " <<
m_ellipse.EndAngle.AsDegrees();
721 const double rotRad =
m_ellipse.Rotation.AsRadians();
725 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
726 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
746 const double a =
static_cast<double>(
m_ellipse.MajorRadius ) + aAccuracy;
747 const double b =
static_cast<double>(
m_ellipse.MinorRadius ) + aAccuracy;
748 return ( lx * lx ) / ( a * a ) + ( ly * ly ) / ( b * b ) < 1.0;
770 static_cast<int>( std::round(
m_ellipse.Center.y + wy ) ) );
782 const double lx = aLocal.
x;
783 const double ly = aLocal.
y;
785 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
786 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
796 double x0Local = 0.0;
797 double x1Local = 0.0;
803 const double z0 = y0 / a;
804 const double z1 = y1 / b;
805 const double g = z0 * z0 + z1 * z1 - 1.0;
809 const double r0 = ( a / b ) * ( a / b );
810 const double n0 = r0 * z0;
812 double s0 = z1 - 1.0;
813 double s1 = ( g < 0.0 ) ? 0.0 : std::sqrt( n0 * n0 + z1 * z1 ) - 1.0;
816 for(
int iter = 0; iter < 64; ++iter )
818 s = 0.5 * ( s0 + s1 );
820 if( s == s0 || s == s1 )
823 const double ratio0 = n0 / ( s + r0 );
824 const double ratio1 = z1 / ( s + 1.0 );
825 const double gs = ratio0 * ratio0 + ratio1 * ratio1 - 1.0;
835 x0Local = r0 * y0 / ( s + r0 );
836 x1Local = y1 / ( s + 1.0 );
855 const double numer0 = a * y0;
856 const double denom0 = a * a - b * b;
858 if( numer0 < denom0 )
860 const double xde0 = numer0 / denom0;
862 x1Local = b * std::sqrt( std::max( 0.0, 1.0 - xde0 * xde0 ) );
871 const VECTOR2D closest( ( lx < 0.0 ) ? -x0Local : x0Local, ( ly < 0.0 ) ? -x1Local : x1Local );
876 const double closestTheta = std::atan2( closest.
y / b, closest.
x / a );
883 return ( aLocal - start ).SquaredEuclideanNorm() <= ( aLocal -
end ).SquaredEuclideanNorm() ? start :
end;
896 if( !
m_isArc && !aOutlineOnly )
905 const double dxE = closest.
x - local.
x;
906 const double dyE = closest.
y - local.
y;
908 return static_cast<SEG::ecoord>( dxE * dxE + dyE * dyE );
924 const double cd = std::cos(
delta );
925 const double sd = std::sin(
delta );
927 const double cr = std::cos( aRotation.
AsRadians() );
928 const double sr = std::sin( aRotation.
AsRadians() );
930 const double wx =
static_cast<double>(
m_ellipse.Center.x - aCenter.
x );
931 const double wy =
static_cast<double>(
m_ellipse.Center.y - aCenter.
y );
933 const double dx = wx * cr + wy * sr;
934 const double dy = -wx * sr + wy * cr;
936 const double p = 1.0 / ( aMajorR * aMajorR );
937 const double q = 1.0 / ( aMinorR * aMinorR );
940 conic.
Axx = p * cd * cd + q * sd * sd;
941 conic.
Axy = 2.0 * sd * cd * ( q - p );
942 conic.
Ayy = p * sd * sd + q * cd * cd;
943 conic.
Bx = 2.0 * ( p * dx * cd + q * dy * sd );
944 conic.
By = 2.0 * ( q * dy * cd - p * dx * sd );
945 conic.
C = p * dx * dx + q * dy * dy - 1.0;
953 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
954 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
957 const double cA = aConic.
Axx * a * a;
958 const double cB = aConic.
Axy * a * b;
959 const double cC = aConic.
Ayy * b * b;
960 const double cD = aConic.
Bx * a;
961 const double cE = aConic.
By * b;
962 const double cF = aConic.
C;
964 const auto value = [&](
double aTheta )
966 const double ct = std::cos( aTheta );
967 const double st = std::sin( aTheta );
968 return cA * ct * ct + cB * ct * st + cC * st * st + cD * ct + cE * st + cF;
971 const auto slope = [&](
double aTheta )
973 const double ct = std::cos( aTheta );
974 const double st = std::sin( aTheta );
975 return 2.0 * ( cC - cA ) * ct * st + cB * ( ct * ct - st * st ) - cD * st + cE * ct;
980 const double k4 = cA - cD + cF;
981 const double k3 = 2.0 * ( cE - cB );
982 const double k2 = 2.0 * ( cF - cA ) + 4.0 * cC;
983 const double k1 = 2.0 * ( cB + cE );
984 const double k0 = cA + cD + cF;
992 std::vector<double> params;
995 params.push_back( 2.0 * std::atan( u ) );
997 params.push_back(
M_PI );
999 std::vector<double>
result;
1001 for(
double theta : params )
1004 for(
int iter = 0; iter < 8; ++iter )
1006 const double f = value( theta );
1007 const double df = slope( theta );
1012 const double step = f / df;
1025 result.push_back( theta );
1037 std::vector<VECTOR2I> points;
1048 points.push_back( world );
1051 dedupePoints( points );
1058 std::vector<VECTOR2I> points;
1060 if( aRadius <= 0.0 )
1066 dedupePoints( points );
1084 std::erase_if( points,
1099 if( dir.
x == 0.0 && dir.
y == 0.0 )
1109 conic.
C = start.
y * dir.
x - start.
x * dir.
y;
1111 std::vector<VECTOR2I> points;
1117 if( aTreatAsLine || aSeg.
Contains( world ) )
1118 points.push_back( world );
1121 dedupePoints( points );
1131 const double a =
static_cast<double>(
m_ellipse.MajorRadius );
1132 const double b =
static_cast<double>(
m_ellipse.MinorRadius );
1138 auto eval = [=](
double theta ) ->
VECTOR2I
1140 const double ct = std::cos( theta );
1141 const double st = std::sin( theta );
1142 const double lx = a * ct;
1143 const double ly = b * st;
1144 const double wx = lx * cosRot - ly * sinRot;
1145 const double wy = lx * sinRot + ly * cosRot;
1146 return VECTOR2I(
static_cast<int>( std::round( cx + wx ) ),
static_cast<int>( std::round( cy + wy ) ) );
1149 double tStart, tEnd;
1152 const double maxErrSq =
static_cast<double>( aMaxError ) * aMaxError;
1155 const VECTOR2I pStart = eval( tStart );
1156 const VECTOR2I pEnd = eval( tEnd );
1159 subdivideEllipseArc( tStart, pStart, tEnd, pEnd, maxErrSq, 20, eval, out );
1175 const double twoPi = 2.0 *
M_PI;
1184 aStart =
m_ellipse.StartAngle.AsRadians();
1187 const double sweep = aEnd - aStart;
1189 if( sweep >= twoPi || sweep <= -twoPi )
1190 aEnd = aStart + twoPi;
1191 else if( aEnd < aStart )
1198 const double twoPi = 2.0 *
M_PI;
1199 double tStart, tEnd;
1203 double t = aAngleRad;
1206 while( t >= tStart + twoPi )
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Represent basic circle geometry with utility geometry functions.
VECTOR2I Center
Public to make access simpler.
int Radius
Public to make access simpler.
EDA_ANGLE GetAngleAtPoint(const VECTOR2< NumericType > &aPt) const
Get the parametric angle of a point on the ellipse.
VECTOR2< NumericType > Center
VECTOR2I::extended_type ecoord
bool Contains(const SEG &aSeg) const
VECTOR2I NearestPoint(const VECTOR2I &aP) const
const VECTOR2I & GetCenter() const
void SetRotation(const EDA_ANGLE &aAngle)
void updateCache()
Recompute cached sin/cos and inverse-radius-squared values.
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
void SetMajorRadius(int aRadius)
ELLIPSE< int > m_ellipse
Wrapped geometric data (from geometry/ellipse.h)
bool isAngleInSweep(double aAngleRad) const
Return true if aAngleRad falls between StartAngle and EndAngle (counter-clockwise sweep).
SEG::ecoord SquaredDistance(const VECTOR2I &aP, bool aOutlineOnly=false) const override
double m_invMinorRSq
1 / MinorRadius ^ 2
void SetStartAngle(const EDA_ANGLE &aAngle)
VECTOR2D toLocal(const VECTOR2I &aP) const
CONIC conicOf(const VECTOR2I &aCenter, double aMajorR, double aMinorR, const EDA_ANGLE &aRotation) const
Write an ellipse with the given world placement as a conic in this local frame.
double m_cosRot
cos(Rotation)
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
const std::string Format(bool aCplusPlus=true) const override
Serialize the ellipse.
VECTOR2I toWorld(const VECTOR2D &aP) const
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
std::vector< double > conicRoots(const CONIC &aConic) const
Parameter angles of this curve where aConic is zero, already limited to its sweep.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the ellipse across a horizontal or vertical axis passing through aRef.
VECTOR2D pointAtParam(double aTheta) const
Point on the full ellipse at parameter angle aTheta, in the local frame.
void sweepRange(double &aStart, double &aEnd) const
Canonical CCW sweep in radians; aEnd >= aStart. Used by all sweep-aware paths.
void normalize()
If major < minor, swap them and add 90 degrees to rotation.
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Find the point on the curve closest to aP.
std::vector< VECTOR2I > intersectCircle(const VECTOR2I &aCenter, double aRadius) const
Points where this curve crosses a full circle, before any sweep of that circle applies.
void SetCenter(const VECTOR2I &aCenter)
std::vector< VECTOR2I > Intersect(const SHAPE_ELLIPSE &aOther) const
Find the points where this curve crosses another one.
void SetMinorRadius(int aRadius)
double m_invMajorRSq
1 / MajorRadius ^ 2
double m_sinRot
sin(Rotation)
VECTOR2D closestLocalPoint(const VECTOR2D &aLocal) const
Point of the curve closest to aLocal, both in the local frame.
void Move(const VECTOR2I &aVector) override
bool Collide(const SEG &aSeg, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the segment aSeg than aClearance,...
bool m_isArc
true if open elliptical arc, false if closed ellipse
void SetEndAngle(const EDA_ANGLE &aAngle)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
virtual const std::string Format(bool aCplusPlus=true) const
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ SH_ELLIPSE
ellipse or elliptical arc
A conic curve Axx x^2 + Axy xy + Ayy y^2 + Bx x + By y + C = 0, written in this ellipse's local frame...
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D