86#define BEZIER_DBG "bezier" 
  102    m_ctrlPts.reserve( aControlPoints.size() );
 
  104    for( 
const VECTOR2I& pt : aControlPoints )
 
 
  115        if( std::isnan( pt.x ) || std::isnan( pt.y ) )
 
 
  131        double   u = std::min( std::max( t, 0.0 ), 1.0 );
 
  135        return 0.5 * 
delta.EuclideanNorm() <= aMaxError;
 
  144        double cross1 = 
delta.Cross( D21 );
 
  145        double cross2 = 
delta.Cross( D31 );
 
  147        double inv_delta_sq = 1.0 / 
delta.SquaredEuclideanNorm();
 
  148        double d1 = ( cross1 * cross1 ) * inv_delta_sq;
 
  149        double d2 = ( cross2 * cross2 ) * inv_delta_sq;
 
  151        double factor = ( cross1 * cross2 > 0.0 ) ? 3.0 / 4.0 : 4.0 / 9.0;
 
  152        double f2 = factor * factor;
 
  153        double tol = aMaxError * aMaxError;
 
  155        return d1 * f2 <= tol && d2 * f2 <= tol;
 
 
  167    std::vector<VECTOR2D> buffer;
 
  170    aOutput.reserve( buffer.size() );
 
 
  178    const double d = 0.6744897501960817;
 
  179    const double d4 = d * d * d * d;
 
  180    return x / ( 1.0 - d + std::pow( d4 + x * x * 0.25, 0.25 ) );
 
 
  185    const double p = 0.39538816;
 
  186    return x * ( 1.0 - p + std::sqrt( p * p + 0.25 * x * x ) );
 
 
  192    double omt = 1.0 - t;
 
  193    double omt2 = omt * omt;
 
  201        double omt3 = omt * omt2;
 
 
  224    double x0 = u0 / cross;
 
  225    double x2 = u2 / cross;
 
  231    int n = std::ceil( 0.5 * 
std::abs( a2 - a0 ) * std::sqrt( 
scale / aMaxError ) );
 
  238    for( 
int ii = 0; ii < n; ++ii )
 
  241        double t = ( u - v0 ) / ( 
v2 - v0 );
 
  242        aOutput.emplace_back( 
eval( t ) );
 
 
  255    double cross1 = D21.
Cross( D32 ) * D32.
Cross( D43 );
 
  256    double cross2 = D21.
Cross( D32 ) * D21.
Cross( D43 );
 
  260    else if( cross2 > 0.0 )
 
  263    bool b1 = D21.
Dot( D32 ) > 0.0;
 
  264    bool b2 = D32.
Dot( D43 ) > 0.0;
 
  269    wxLogTrace( 
BEZIER_DBG, 
"numberOfInflectionPoints: rare case" );
 
 
  278    double len_sq = 
delta.SquaredEuclideanNorm();
 
  283    double len = std::sqrt( len_sq );
 
 
  308        VECTOR2D left_ctrl2 = left_ctrl1 + aT * ( tmp - left_ctrl1 );
 
  310        VECTOR2D right_ctrl1 = tmp + aT * ( right_ctrl2 - tmp );
 
  311        VECTOR2D shared = left_ctrl2 + aT * ( right_ctrl1 - left_ctrl2 );
 
 
  332    wxLogTrace( 
BEZIER_DBG, 
"recursiveSegmentation with threshold %f", aThreshhold );
 
  333    std::vector<BEZIER_POLY> stack;
 
  339    stack.push_back( *
this );
 
  341    while( !stack.empty() )
 
  343        bezier = &stack.back();
 
  347            wxLogTrace( 
BEZIER_DBG, 
"recursiveSegmentation dropping zero length segment" );
 
  350        else if( bezier->
isFlat( aThreshhold ) )
 
  352            aOutput.push_back( bezier->
m_ctrlPts[3] );
 
  359            stack.push_back( 
left );
 
  363    wxLogTrace( 
BEZIER_DBG, 
"recursiveSegmentation generated %zu points", aOutput.size() );
 
 
  376    double a = 3 * 
A.Cross( 
B );
 
  377    double b = 3 * 
A.Cross( 
C );
 
  378    double c = 
B.Cross( 
C );
 
  381    double r2 = ( b * b - 4 * a * c );
 
  386    if( r2 >= 0.0 && a != 0.0 )
 
  388        double r = std::sqrt( r2 );
 
  390        double t1 = ( ( -b + r ) / ( 2 * a ) );
 
  391        double t2 = ( ( -b - r ) / ( 2 * a ) );
 
  393        if( ( t1 > 0.0 && t1 < 1.0 ) && ( t2 > 0.0 && t2 < 1.0 ) )
 
  403            if( t2 - t1 > 0.00001 )
 
  405                wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found 2 inflection points at t1 = %f, t2 = %f", t1, t2 );
 
  410                wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found 1 inflection point at t = %f", t1 );
 
  414        else if( t1 > 0.0 && t1 < 1.0 )
 
  417            wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found 1 inflection point at t = %f", t1 );
 
  420        else if( t2 > 0.0 && t2 < 1.0 )
 
  423            wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found 1 inflection point at t = %f", t2 );
 
  427        wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found no inflection points" );
 
  431    wxLogTrace( 
BEZIER_DBG, 
"BEZIER_POLY Found no inflection points" );
 
 
  438    std::vector<BEZIER_POLY> stack;
 
  439    stack.push_back( std::vector<VECTOR2D>(4) );
 
  440    stack.push_back( std::vector<VECTOR2D>(4) );
 
  441    stack.push_back( std::vector<VECTOR2D>(4) );
 
  442    stack.push_back( std::vector<VECTOR2D>(4) );
 
  452            wxLogDebug( 
"cubicParabolicApprox: NaN detected" );
 
  456        if( c->
isFlat( aMaxError ) )
 
  466        double t = 2 * std::sqrt( aMaxError / ( 3.0 * d ) ); 
 
  468        wxLogTrace( 
BEZIER_DBG, 
"cubicParabolicApprox: split point t = %f", t );
 
  472            wxLogTrace( 
BEZIER_DBG, 
"cubicParabolicApprox: Invalid t value detected" );
 
  482        if( b1->
isFlat( aMaxError ) )
 
  496        if( b1 == &stack.front() )
 
 
  516        wxLogTrace( 
BEZIER_DBG, 
"getCubicPoly Short circuit to PA" );
 
  528        wxLogTrace( 
BEZIER_DBG, 
"getCubicPoly: 2 inflection points" );
 
  541        else if( numOfIfP == 1 )
 
  545            wxLogTrace( 
BEZIER_DBG, 
"getCubicPoly: 2nd inflection point not found" );
 
  558    else if( numOfIfP == 1 )
 
  560        wxLogTrace( 
BEZIER_DBG, 
"getCubicPoly: 1 inflection point" );
 
  570        wxLogTrace( 
BEZIER_DBG, 
"getCubicPoly: Unknown inflection points" );
 
 
  579    if( aMaxError <= 0.0 )
 
  595    wxLogTrace( 
BEZIER_DBG, 
"GetPoly generated %zu points", aOutput.size() );
 
 
  615    const int minBeziersPerCircle = 4;
 
  618    const int numBeziers = 
static_cast<int>(
 
  622    const double angleIncrement = arcAngle.
AsRadians() / numBeziers;
 
  638    double theta = angleIncrement;
 
  639    double k     = ( 4. / 3. ) * std::tan( theta / 4 );
 
  651                             { std::cos( theta ) + k * std::sin( theta ),
 
  652                               std::sin( theta ) - k * std::cos( theta ) },
 
  653                             { std::cos( theta ), std::sin( theta ) } };
 
  658    auto transformPoint =
 
  672                aPoint += aEllipse.
Center;
 
  677    for( 
int i = 0; i < numBeziers; i++ )
 
  680                transformPoint( first.
Start, i * angleIncrement ),
 
  681                transformPoint( first.
C1,    i * angleIncrement ),
 
  682                transformPoint( first.
C2,    i * angleIncrement ),
 
  683                transformPoint( first.
End,   i * angleIncrement )
 
 
static double approx_int(double x)
 
static double approx_inv_int(double x)
 
void TransformEllipseToBeziers(const ELLIPSE< T > &aEllipse, std::vector< BEZIER< T > > &aBeziers)
Transforms an ellipse or elliptical arc into a set of quadratic Bezier curves that approximate it.
 
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
 
void recursiveSegmentation(std::vector< VECTOR2D > &aOutput, double aMaxError)
 
void getQuadPoly(std::vector< VECTOR2D > &aOutput, double aMaxError)
 
int numberOfInflectionPoints()
 
double thirdControlPointDeviation()
 
void cubicParabolicApprox(std::vector< VECTOR2D > &aOutput, double aMaxError)
 
double m_minSegLen
Control points.
 
void getCubicPoly(std::vector< VECTOR2D > &aOutput, double aMaxError)
 
BEZIER_POLY(const VECTOR2I &aStart, const VECTOR2I &aCtrl1, const VECTOR2I &aCtrl2, const VECTOR2I &aEnd)
 
void subdivide(double aT, BEZIER_POLY &aLeft, BEZIER_POLY &aRight)
 
bool isFlat(double aMaxError) const
 
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
 
int findInflectionPoints(double &aT1, double &aT2)
 
std::vector< VECTOR2D > m_ctrlPts
 
Generic cubic Bezier representation.
 
VECTOR2< NumericType > Start
 
VECTOR2< NumericType > C1
 
VECTOR2< NumericType > C2
 
VECTOR2< NumericType > End
 
This class was created to handle importing ellipses from other file formats that support them nativel...
 
VECTOR2< NumericType > Center
 
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
 
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
 
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
 
static constexpr EDA_ANGLE ANGLE_0
 
static constexpr EDA_ANGLE ANGLE_360
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
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