65#ifdef USE_ALTERNATE_CENTER_ALGO
71 double bc = ( b.
x*b.
x + b.
y*b.
y ) / 2.0;
72 double cd = ( -d.
x*d.
x - d.
y*d.
y ) / 2.0;
73 double det = -b.
x*d.
y + d.
x*b.
y;
75 if( fabs(det) < 1.0e-6 )
79 aCenter->
x = ( -bc*d.
y - cd*b.
y ) * det;
80 aCenter->
y = ( b.
x*cd + d.
x*bc ) * det;
90 VECTOR2I vectSeg = aSegEnd - aSegStart;
91 VECTOR2I vectPoint = aTestPoint - aSegStart;
94 if( (
long long) vectSeg.
x * vectPoint.
y - (
long long) vectSeg.
y * vectPoint.
x )
97 if( ( (
long long) vectSeg.
x * vectPoint.
x + (
long long) vectSeg.
y * vectPoint.
y ) <
98 ( (
long long) vectPoint.
x * vectPoint.
x + (
long long) vectPoint.
y * vectPoint.
y ) )
113 int64_t dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
114 int64_t num_a, num_b, den;
122 dX_a = int64_t{ a_p2_l1.
x } - a_p1_l1.
x;
123 dY_a = int64_t{ a_p2_l1.
y } - a_p1_l1.
y;
124 dX_b = int64_t{ a_p2_l2.
x } - a_p1_l2.
x;
125 dY_b = int64_t{ a_p2_l2.
y } - a_p1_l2.
y;
126 dX_ab = int64_t{ a_p1_l2.
x } - a_p1_l1.
x;
127 dY_ab = int64_t{ a_p1_l2.
y } - a_p1_l1.
y;
129 den = dY_a * dX_b - dY_b * dX_a ;
135 num_a = dY_ab * dX_b - dY_b * dX_ab;
136 num_b = dY_ab * dX_a - dY_a * dX_ab;
139 if( aIntersectionPoint )
141 *aIntersectionPoint = a_p1_l1;
142 aIntersectionPoint->
x +=
KiROUND( dX_a * (
double )num_a / (
double )den );
143 aIntersectionPoint->
y +=
KiROUND( dY_a * (
double )num_b / (
double )den );
183 std::swap( xmax, xmin );
186 std::swap( ymax, ymin );
189 if( ( ymin - aRefPoint.
y > aDist ) || ( aRefPoint.
y - ymax > aDist ) )
192 if( ( xmin - aRefPoint.
x > aDist ) || ( aRefPoint.
x - xmax > aDist ) )
196 if( aStart.
x == aEnd.
x && aRefPoint.
y > ymin && aRefPoint.
y < ymax )
199 if( aStart.
y == aEnd.
y && aRefPoint.
x > xmin && aRefPoint.
x < xmax )
202 SEG segment( aStart, aEnd );
210 VECTOR2I startVector = aStart - aCenter;
211 VECTOR2I endVector = aEnd - aCenter;
215 EDA_ANGLE midPointRotAngle = ( startAngle - endAngle ).Normalize180() / 2;
253 double sinus = angle.
Sin();
254 double cosinus = angle.
Cos();
256 pt.
x =
KiROUND( ( *pY * sinus ) + ( *pX * cosinus ) );
257 pt.
y =
KiROUND( ( *pY * cosinus ) - ( *pX * sinus ) );
319 double sinus = angle.
Sin();
320 double cosinus = angle.
Cos();
322 pt.
x = ( *pY * sinus ) + ( *pX * cosinus );
323 pt.
y = ( *pY * cosinus ) - ( *pX * sinus );
340 std::swap( start,
end );
346 std::swap( start,
end );
350 double chord = ( start -
end ).EuclideanNorm();
351 double sinHalfAngle = ( angle / 2.0 ).Sin();
354 if( sinHalfAngle == 0.0 )
358 double d = ( chord / 2.0 ) * ( angle / 2.0 ).Cos() / sinHalfAngle;
360 if( !std::isfinite( d ) )
368 return VECTOR2D( start + vc + vec2 );
376constexpr double kClusterExtent = 5.0;
381constexpr double kCoincidentRadius = 2.0;
382constexpr double kCoincidentRadiusSquared = kCoincidentRadius * kCoincidentRadius;
385constexpr double kSnapRadiusTolerance = 1.0;
388constexpr double kCollinearRadius = 1e17;
391constexpr double kMaxExactInteger = 9007199254740992.0;
397 auto [minX, maxX] = std::minmax( { aStart.
x, aMid.
x, aEnd.
x } );
398 auto [minY, maxY] = std::minmax( { aStart.
y, aMid.
y, aEnd.
y } );
400 if( maxX - minX < kClusterExtent && maxY - minY < kClusterExtent )
402 aCenter =
VECTOR2D( ( aStart.
x + aMid.
x + aEnd.
x ) / 3.0, ( aStart.
y + aMid.
y + aEnd.
y ) / 3.0 );
408 return ( a - b ).SquaredEuclideanNorm() < kCoincidentRadiusSquared;
412 if( coincident( aStart, aMid ) || coincident( aMid, aEnd ) )
414 aCenter =
VECTOR2D( ( aStart.
x + aEnd.
x ) / 2.0, ( aStart.
y + aEnd.
y ) / 2.0 );
418 if( coincident( aStart, aEnd ) )
420 aCenter =
VECTOR2D( ( aStart.
x + aMid.
x ) / 2.0, ( aStart.
y + aMid.
y ) / 2.0 );
431 VECTOR2D mid( ( aStart.
x + aEnd.
x ) / 2.0, ( aStart.
y + aEnd.
y ) / 2.0 );
438double det2(
double a,
double b,
double c,
double d )
441 double e = std::fma( -b, c, w );
442 double f = std::fma( a, d, -w );
452 if( !(
std::abs( aCenter.
x ) < kMaxExactInteger ) || !(
std::abs( aCenter.
y ) < kMaxExactInteger ) )
455 auto radiiAgree = [&](
const VECTOR2D& aCandidate )
457 double rs = ( aCandidate - aStart ).EuclideanNorm();
458 double rm = ( aCandidate - aMid ).EuclideanNorm();
459 double re = ( aCandidate - aEnd ).EuclideanNorm();
460 auto [minR, maxR] = std::minmax( { rs, rm, re } );
462 return maxR - minR <= kSnapRadiusTolerance;
465 for(
double grid : { 100.0, 10.0 } )
468 std::floor( aCenter.
y /
grid + 0.5 ) *
grid );
470 if( radiiAgree( candidate ) )
483 if( degenerateArcCenter( aStart, aMid, aEnd,
center ) )
487 double bx = aMid.
x - aStart.
x;
488 double by = aMid.
y - aStart.
y;
489 double cx = aEnd.
x - aStart.
x;
490 double cy = aEnd.
y - aStart.
y;
492 double b2 = std::fma( bx, bx, by * by );
493 double c2 = std::fma( cx, cx, cy * cy );
494 double d = 2.0 * det2( bx, by, cx, cy );
497 return collinearArcCenter( aStart, aEnd );
499 double ux = det2( b2, c2, by, cy ) / d;
500 double uy = det2( c2, b2, cx, bx ) / d;
502 return snapArcCenter(
VECTOR2D( aStart.
x + ux, aStart.
y + uy ), aStart, aMid, aEnd );
508 VECTOR2D dStart(
static_cast<double>( aStart.
x ),
static_cast<double>( aStart.
y ) );
509 VECTOR2D dMid(
static_cast<double>( aMid.
x ),
static_cast<double>( aMid.
y ) );
510 VECTOR2D dEnd(
static_cast<double>( aEnd.
x ),
static_cast<double>( aEnd.
y ) );
513 if( !degenerateArcCenter( dStart, dMid, dEnd, dCenter ) )
516 VECTOR2L b( int64_t( aMid.
x ) - aStart.
x, int64_t( aMid.
y ) - aStart.
y );
517 VECTOR2L c( int64_t( aEnd.
x ) - aStart.
x, int64_t( aEnd.
y ) - aStart.
y );
525 dCenter = collinearArcCenter( dStart, dEnd );
534 dCenter = snapArcCenter(
VECTOR2D( cx, cy ), dStart, dMid, dEnd );
540 iCenter.
x =
KiROUND( std::clamp( dCenter.
x,
541 double( std::numeric_limits<int>::min() + 100 ),
542 double( std::numeric_limits<int>::max() - 100 ) ) );
544 iCenter.
y =
KiROUND( std::clamp( dCenter.
y,
545 double( std::numeric_limits<int>::min() + 100 ),
546 double( std::numeric_limits<int>::max() - 100 ) ) );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
ecoord SquaredDistance(const SEG &aSeg) const
static SEG::ecoord Square(int a)
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_270
static constexpr EDA_ANGLE ANGLE_360
static constexpr EDA_ANGLE ANGLE_180
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static VECTOR2D CircleCenterFrom3Points(const VECTOR2D &p1, const VECTOR2D &p2, const VECTOR2D &p3)
const VECTOR2I CalcArcMid(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aMinArcAngle)
Return the middle point of an arc, half-way between aStart and aEnd.
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
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.
bool SegmentIntersectsSegment(const VECTOR2I &a_p1_l1, const VECTOR2I &a_p2_l1, const VECTOR2I &a_p1_l2, const VECTOR2I &a_p2_l2, VECTOR2I *aIntersectionPoint)
Test if two lines intersect.
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
const VECTOR2D CalcArcCenter(const VECTOR2D &aStart, const VECTOR2D &aEnd, const EDA_ANGLE &aAngle)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR2< int64_t > VECTOR2L
128-bit integers for exact products of 64-bit coordinate deltas.
double ToDouble(KI_INT128 aValue)
constexpr KI_INT128 CrossWide(const VECTOR2L &aA, const VECTOR2L &aB)
Exact aA.x * aB.y - aA.y * aB.x.