82#define BEZIER_DBG "bezier"
98 m_ctrlPts.reserve( aControlPoints.size() );
100 for(
const VECTOR2I& pt : aControlPoints )
111 if( std::isnan( pt.x ) || std::isnan( pt.y ) )
127 double u = std::min( std::max( t, 0.0 ), 1.0 );
131 return 0.5 *
delta.EuclideanNorm() <= aMaxError;
140 double cross1 =
delta.Cross( D21 );
141 double cross2 =
delta.Cross( D31 );
143 double inv_delta_sq = 1.0 /
delta.SquaredEuclideanNorm();
144 double d1 = ( cross1 * cross1 ) * inv_delta_sq;
145 double d2 = ( cross2 * cross2 ) * inv_delta_sq;
147 double factor = ( cross1 * cross2 > 0.0 ) ? 3.0 / 4.0 : 4.0 / 9.0;
148 double f2 = factor * factor;
149 double tol = aMaxError * aMaxError;
151 return d1 * f2 <= tol && d2 * f2 <= tol;
163 std::vector<VECTOR2D> buffer;
166 aOutput.reserve( buffer.size() );
174 const double d = 0.6744897501960817;
175 const double d4 = d * d * d * d;
176 return x / ( 1.0 - d + std::pow( d4 + x * x * 0.25, 0.25 ) );
181 const double p = 0.39538816;
182 return x * ( 1.0 - p + std::sqrt( p * p + 0.25 * x * x ) );
188 double omt = 1.0 - t;
189 double omt2 = omt * omt;
197 double omt3 = omt * omt2;
220 double x0 = u0 / cross;
221 double x2 = u2 / cross;
227 int n = std::ceil( 0.5 *
std::abs( a2 - a0 ) * std::sqrt(
scale / aMaxError ) );
234 for(
int ii = 0; ii < n; ++ii )
237 double t = ( u - v0 ) / (
v2 - v0 );
238 aOutput.emplace_back(
eval( t ) );
251 double cross1 = D21.
Cross( D32 ) * D32.
Cross( D43 );
252 double cross2 = D21.
Cross( D32 ) * D21.
Cross( D43 );
256 else if( cross2 > 0.0 )
259 bool b1 = D21.
Dot( D32 ) > 0.0;
260 bool b2 = D32.
Dot( D43 ) > 0.0;
265 wxLogTrace(
BEZIER_DBG,
"numberOfInflectionPoints: rare case" );
274 double len_sq =
delta.SquaredEuclideanNorm();
279 double len = std::sqrt( len_sq );
304 VECTOR2D left_ctrl2 = left_ctrl1 + aT * ( tmp - left_ctrl1 );
306 VECTOR2D right_ctrl1 = tmp + aT * ( right_ctrl2 - tmp );
307 VECTOR2D shared = left_ctrl2 + aT * ( right_ctrl1 - left_ctrl2 );
328 wxLogTrace(
BEZIER_DBG,
"recursiveSegmentation with threshold %f", aThreshhold );
329 std::vector<BEZIER_POLY> stack;
335 stack.push_back( *
this );
337 while( !stack.empty() )
339 bezier = &stack.back();
343 wxLogTrace(
BEZIER_DBG,
"recursiveSegmentation dropping zero length segment" );
346 else if( bezier->
isFlat( aThreshhold ) )
348 aOutput.push_back( bezier->
m_ctrlPts[3] );
355 stack.push_back(
left );
359 wxLogTrace(
BEZIER_DBG,
"recursiveSegmentation generated %zu points", aOutput.size() );
372 double a = 3 *
A.Cross(
B );
373 double b = 3 *
A.Cross(
C );
374 double c =
B.Cross(
C );
377 double r2 = ( b * b - 4 * a * c );
382 if( r2 >= 0.0 && a != 0.0 )
384 double r = std::sqrt( r2 );
386 double t1 = ( ( -b + r ) / ( 2 * a ) );
387 double t2 = ( ( -b - r ) / ( 2 * a ) );
389 if( ( t1 > 0.0 && t1 < 1.0 ) && ( t2 > 0.0 && t2 < 1.0 ) )
399 if( t2 - t1 > 0.00001 )
401 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found 2 inflection points at t1 = %f, t2 = %f", t1, t2 );
406 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found 1 inflection point at t = %f", t1 );
410 else if( t1 > 0.0 && t1 < 1.0 )
413 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found 1 inflection point at t = %f", t1 );
416 else if( t2 > 0.0 && t2 < 1.0 )
419 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found 1 inflection point at t = %f", t2 );
423 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found no inflection points" );
427 wxLogTrace(
BEZIER_DBG,
"BEZIER_POLY Found no inflection points" );
434 std::vector<BEZIER_POLY> stack;
435 stack.push_back( std::vector<VECTOR2D>(4) );
436 stack.push_back( std::vector<VECTOR2D>(4) );
437 stack.push_back( std::vector<VECTOR2D>(4) );
438 stack.push_back( std::vector<VECTOR2D>(4) );
448 wxLogTrace(
BEZIER_DBG,
"cubicParabolicApprox: NaN detected" );
452 if( c->
isFlat( aMaxError ) )
454 wxLogTrace(
BEZIER_DBG,
"cubicParabolicApprox: General Flatness detected, adding %f %f",
463 double t = 2 * std::sqrt( aMaxError / ( 3.0 * d ) );
465 wxLogTrace(
BEZIER_DBG,
"cubicParabolicApprox: split point t = %f", t );
469 wxLogTrace(
BEZIER_DBG,
"cubicParabolicApprox: Invalid t value detected" );
479 if( b1->
isFlat( aMaxError ) )
493 if( b1 == &stack.front() )
513 wxLogTrace(
BEZIER_DBG,
"getCubicPoly Short circuit to PA" );
525 wxLogTrace(
BEZIER_DBG,
"getCubicPoly: 2 inflection points" );
542 else if( numOfIfP == 1 )
546 wxLogTrace(
BEZIER_DBG,
"getCubicPoly: 2nd inflection point not found" );
557 else if( numOfIfP == 1 )
559 wxLogTrace(
BEZIER_DBG,
"getCubicPoly: 1 inflection point" );
569 wxLogTrace(
BEZIER_DBG,
"getCubicPoly: Unknown inflection points" );
578 if( aMaxError <= 0.0 )
594 wxLogTrace(
BEZIER_DBG,
"GetPoly generated %zu points", aOutput.size() );
614 const int minBeziersPerCircle = 4;
617 const int numBeziers =
static_cast<int>(
621 const double angleIncrement = arcAngle.
AsRadians() / numBeziers;
637 double theta = angleIncrement;
638 double k = ( 4. / 3. ) * std::tan( theta / 4 );
650 { std::cos( theta ) + k * std::sin( theta ),
651 std::sin( theta ) - k * std::cos( theta ) },
652 { std::cos( theta ), std::sin( theta ) } };
657 auto transformPoint =
671 aPoint += aEllipse.
Center;
676 for(
int i = 0; i < numBeziers; i++ )
679 transformPoint( first.
Start, i * angleIncrement ),
680 transformPoint( first.
C1, i * angleIncrement ),
681 transformPoint( first.
C2, i * angleIncrement ),
682 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
Plain ellipse / elliptical-arc data.
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