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;
394constexpr double kMinArcCenter = std::numeric_limits<int>::min() + 100.0;
395constexpr double kMaxArcCenter = std::numeric_limits<int>::max() - 100.0;
401 auto [minX, maxX] = std::minmax( { aStart.
x, aMid.
x, aEnd.
x } );
402 auto [minY, maxY] = std::minmax( { aStart.
y, aMid.
y, aEnd.
y } );
404 if( maxX - minX < kClusterExtent && maxY - minY < kClusterExtent )
406 aCenter =
VECTOR2D( ( aStart.
x + aMid.
x + aEnd.
x ) / 3.0, ( aStart.
y + aMid.
y + aEnd.
y ) / 3.0 );
412 return ( a - b ).SquaredEuclideanNorm() < kCoincidentRadiusSquared;
416 if( coincident( aStart, aMid ) || coincident( aMid, aEnd ) )
418 aCenter =
VECTOR2D( ( aStart.
x + aEnd.
x ) / 2.0, ( aStart.
y + aEnd.
y ) / 2.0 );
422 if( coincident( aStart, aEnd ) )
424 aCenter =
VECTOR2D( ( aStart.
x + aMid.
x ) / 2.0, ( aStart.
y + aMid.
y ) / 2.0 );
435 VECTOR2D mid( ( aStart.
x + aEnd.
x ) / 2.0, ( aStart.
y + aEnd.
y ) / 2.0 );
442double det2(
double a,
double b,
double c,
double d )
445 double e = std::fma( -b, c, w );
446 double f = std::fma( a, d, -w );
456 if( !(
std::abs( aCenter.
x ) < kMaxExactInteger ) || !(
std::abs( aCenter.
y ) < kMaxExactInteger ) )
459 auto radiiAgree = [&](
const VECTOR2D& aCandidate )
461 double rs = ( aCandidate - aStart ).EuclideanNorm();
462 double rm = ( aCandidate - aMid ).EuclideanNorm();
463 double re = ( aCandidate - aEnd ).EuclideanNorm();
464 auto [minR, maxR] = std::minmax( { rs, rm, re } );
466 return maxR - minR <= kSnapRadiusTolerance;
469 for(
double grid : { 100.0, 10.0 } )
472 std::floor( aCenter.
y /
grid + 0.5 ) *
grid );
474 if( radiiAgree( candidate ) )
484 VECTOR2D dStart(
static_cast<double>( aStart.
x ),
static_cast<double>( aStart.
y ) );
485 VECTOR2D dMid(
static_cast<double>( aMid.
x ),
static_cast<double>( aMid.
y ) );
486 VECTOR2D dEnd(
static_cast<double>( aEnd.
x ),
static_cast<double>( aEnd.
y ) );
489 if( degenerateArcCenter( dStart, dMid, dEnd, dCenter ) )
493 VECTOR2L b( int64_t( aMid.
x ) - aStart.
x, int64_t( aMid.
y ) - aStart.
y );
494 VECTOR2L c( int64_t( aEnd.
x ) - aStart.
x, int64_t( aEnd.
y ) - aStart.
y );
501 return collinearArcCenter( dStart, dEnd );
508 return snapArcCenter(
VECTOR2D( cx, cy ), dStart, dMid, dEnd );
517 if( degenerateArcCenter( aStart, aMid, aEnd,
center ) )
521 double bx = aMid.
x - aStart.
x;
522 double by = aMid.
y - aStart.
y;
523 double cx = aEnd.
x - aStart.
x;
524 double cy = aEnd.
y - aStart.
y;
526 double b2 = std::fma( bx, bx, by * by );
527 double c2 = std::fma( cx, cx, cy * cy );
528 double d = 2.0 * det2( bx, by, cx, cy );
531 return collinearArcCenter( aStart, aEnd );
533 double ux = det2( b2, c2, by, cy ) / d;
534 double uy = det2( c2, b2, cx, bx ) / d;
536 return snapArcCenter(
VECTOR2D( aStart.
x + ux, aStart.
y + uy ), aStart, aMid, aEnd );
542 VECTOR2D dCenter = unclampedArcCenter( aStart, aMid, aEnd );
544 return VECTOR2I(
KiROUND( std::clamp( dCenter.
x, kMinArcCenter, kMaxArcCenter ) ),
545 KiROUND( std::clamp( dCenter.
y, kMinArcCenter, kMaxArcCenter ) ) );
560 return !(
center.x >= kMinArcCenter &&
center.x <= kMaxArcCenter &&
center.y >= kMinArcCenter
561 &&
center.y <= kMaxArcCenter );
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.
bool IsStraightArc(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
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.