32 #include <type_traits> 43 const wxPoint& aTestPoint )
45 wxPoint vectSeg = aSegEnd - aSegStart;
46 wxPoint vectPoint = aTestPoint - aSegStart;
49 if( (
long long) vectSeg.x * vectPoint.y - (
long long) vectSeg.y * vectPoint.x )
52 if( ( (
long long) vectSeg.x * vectPoint.x + (
long long) vectSeg.y * vectPoint.y ) <
53 ( (
long long) vectPoint.x * vectPoint.x + (
long long) vectPoint.y * vectPoint.y ) )
62 const wxPoint& a_p1_l2,
const wxPoint& a_p2_l2,
63 wxPoint* aIntersectionPoint )
69 int64_t dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
70 int64_t num_a, num_b, den;
78 dX_a = int64_t{ a_p2_l1.x } - a_p1_l1.x;
79 dY_a = int64_t{ a_p2_l1.y } - a_p1_l1.y;
80 dX_b = int64_t{ a_p2_l2.x } - a_p1_l2.x;
81 dY_b = int64_t{ a_p2_l2.y } - a_p1_l2.y;
82 dX_ab = int64_t{ a_p1_l2.x } - a_p1_l1.x;
83 dY_ab = int64_t{ a_p1_l2.y } - a_p1_l1.y;
85 den = dY_a * dX_b - dY_b * dX_a ;
91 num_a = dY_ab * dX_b - dY_b * dX_ab;
92 num_b = dY_ab * dX_a - dY_a * dX_ab;
95 if( aIntersectionPoint )
97 *aIntersectionPoint = a_p1_l1;
98 aIntersectionPoint->x +=
KiROUND( dX_a * (
double )num_a / (
double )den );
99 aIntersectionPoint->y +=
KiROUND( dY_a * (
double )num_b / (
double )den );
129 bool TestSegmentHit(
const wxPoint& aRefPoint,
const wxPoint& aStart,
const wxPoint& aEnd,
136 wxPoint
delta = aStart - aRefPoint;
139 std::swap( xmax, xmin );
142 std::swap( ymax, ymin );
145 if( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) )
148 if( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) )
152 if( aStart.x == aEnd.x && aRefPoint.y > ymin && aRefPoint.y < ymax )
153 return std::abs(
delta.x ) <= aDist;
155 if( aStart.y == aEnd.y && aRefPoint.x > xmin && aRefPoint.x < xmax )
156 return std::abs(
delta.y ) <= aDist;
158 SEG segment( aStart, aEnd );
166 VECTOR2I startVector = aStart - aCenter;
167 VECTOR2I endVector = aEnd - aCenter;
169 double startAngle =
ArcTangente( startVector.
y, startVector.
x );
174 midPointRotAngleDeciDeg += 1800.0;
177 RotatePoint( newMid, aCenter, midPointRotAngleDeciDeg );
189 if( dx == 0 && dy == 0 )
225 return RAD2DECIDEG( std::atan2( (
double) dy, (
double) dx ) );
245 else if(
angle == 1800 )
250 else if(
angle == 2700 )
259 double sinus = sin( fangle );
260 double cosinus = cos( fangle );
261 double fpx = (*pY * sinus ) + (*pX * cosinus );
262 double fpy = (*pY * cosinus ) - (*pX * sinus );
287 ox = point->x - centre.x;
288 oy = point->y - centre.y;
291 point->x = ox + centre.x;
292 point->y = oy + centre.y;
297 wxPoint c( centre.
x, centre.
y );
298 wxPoint p( point.
x, point.
y );
337 else if(
angle == 1800 )
342 else if(
angle == 2700 )
351 double sinus = sin( fangle );
352 double cosinus = cos( fangle );
354 double fpx = (*pY * sinus ) + (*pX * cosinus );
355 double fpy = (*pY * cosinus ) - (*pX * sinus );
369 std::swap( start, end );
370 aAngle = abs( aAngle );
375 std::swap( start, end );
376 aAngle = 360 - aAngle;
380 double r = chord / ( 2.0 * sin( ( aAngle / 2.0 ) * M_PI / 180.0 ) );
384 vec = vec.
Rotate( ( 90.0 - aAngle / 2.0 ) * M_PI / 180.0 );
393 double yDelta_21 = aMid.
y - aStart.
y;
394 double xDelta_21 = aMid.
x - aStart.
x;
395 double yDelta_32 = aEnd.
y - aMid.
y;
396 double xDelta_32 = aEnd.
x - aMid.
x;
401 if( ( ( xDelta_21 == 0.0 ) && ( yDelta_32 == 0.0 ) ) ||
402 ( ( yDelta_21 == 0.0 ) && ( xDelta_32 == 0.0 ) ) )
404 center.
x = ( aStart.
x + aEnd.
x ) / 2.0;
405 center.
y = ( aStart.
y + aEnd.
y ) / 2.0 ;
410 if( xDelta_21 == 0.0 )
411 xDelta_21 = std::numeric_limits<double>::epsilon();
413 if( xDelta_32 == 0.0 )
414 xDelta_32 = -std::numeric_limits<double>::epsilon();
416 double aSlope = yDelta_21 / xDelta_21;
417 double bSlope = yDelta_32 / xDelta_32;
422 if( aSlope == bSlope )
428 center.
x = ( aStart.
x + aMid.
x ) / 2.0;
429 center.
y = ( aStart.
y + aMid.
y ) / 2.0 ;
437 aSlope += std::numeric_limits<double>::epsilon();
438 bSlope -= std::numeric_limits<double>::epsilon();
444 aSlope = std::numeric_limits<double>::epsilon();
454 double abSlopeStartEndY = aSlope * bSlope * ( aStart.
y - aEnd.
y );
455 double dabSlopeStartEndY = abSlopeStartEndY * std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
456 + ( dbSlope / bSlope * dbSlope / bSlope )
457 + ( M_SQRT1_2 / ( aStart.
y - aEnd.
y )
458 * M_SQRT1_2 / ( aStart.
y - aEnd.
y ) ) );
460 double bSlopeStartMidX = bSlope * ( aStart.
x + aMid.
x );
461 double dbSlopeStartMidX = bSlopeStartMidX * std::sqrt( ( dbSlope / bSlope * dbSlope / bSlope )
462 + ( M_SQRT1_2 / ( aStart.
x + aMid.
x )
463 * M_SQRT1_2 / ( aStart.
x + aMid.
x ) ) );
465 double aSlopeMidEndX = aSlope * ( aMid.
x + aEnd.
x );
466 double daSlopeMidEndX = aSlopeMidEndX * std::sqrt( ( daSlope / aSlope * daSlope / aSlope )
467 + ( M_SQRT1_2 / ( aMid.
x + aEnd.
x )
468 * M_SQRT1_2 / ( aMid.
x + aEnd.
x ) ) );
470 double twiceBASlopeDiff = 2 * ( bSlope - aSlope );
471 double dtwiceBASlopeDiff = 2 * std::sqrt( dbSlope * dbSlope + daSlope * daSlope );
473 double centerNumeratorX = abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX;
474 double dCenterNumeratorX = std::sqrt( dabSlopeStartEndY * dabSlopeStartEndY
475 + dbSlopeStartMidX * dbSlopeStartMidX
476 + daSlopeMidEndX * daSlopeMidEndX );
478 double centerX = ( abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX ) / twiceBASlopeDiff;
480 double dCenterX = centerX * std::sqrt( ( dCenterNumeratorX / centerNumeratorX * dCenterNumeratorX / centerNumeratorX )
481 + ( dtwiceBASlopeDiff / twiceBASlopeDiff * dtwiceBASlopeDiff / twiceBASlopeDiff ) );
484 double centerNumeratorY = ( ( aStart.
x + aMid.
x ) / 2.0 - centerX );
485 double dCenterNumeratorY = std::sqrt( 1.0 / 8.0 + dCenterX * dCenterX );
487 double centerFirstTerm = centerNumeratorY / aSlope;
488 double dcenterFirstTermY = centerFirstTerm * std::sqrt(
489 ( dCenterNumeratorY/ centerNumeratorY * dCenterNumeratorY / centerNumeratorY )
490 + ( daSlope / aSlope * daSlope / aSlope ) );
492 double centerY = centerFirstTerm + ( aStart.
y + aMid.
y ) / 2.0;
493 double dCenterY = std::sqrt( dcenterFirstTermY * dcenterFirstTermY + 1.0 / 8.0 );
495 double rounded100CenterX = std::floor( ( centerX + 50.0 ) / 100.0 ) * 100.0;
496 double rounded100CenterY = std::floor( ( centerY + 50.0 ) / 100.0 ) * 100.0;
497 double rounded10CenterX = std::floor( ( centerX + 5.0 ) / 10.0 ) * 10.0;
498 double rounded10CenterY = std::floor( ( centerY + 5.0 ) / 10.0 ) * 10.0;
504 if( std::abs( rounded100CenterX - centerX ) < dCenterX && std::abs( rounded100CenterY - centerY ) < dCenterY )
506 center.
x = rounded100CenterX;
507 center.
y = rounded100CenterY;
509 else if( std::abs( rounded10CenterX - centerX ) < dCenterX && std::abs( rounded10CenterY - centerY ) < dCenterY )
511 center.
x = rounded10CenterX;
512 center.
y = rounded10CenterY;
527 VECTOR2D dStart( static_cast<double>( aStart.
x ), static_cast<double>( aStart.
y ) );
528 VECTOR2D dMid( static_cast<double>( aMid.
x ), static_cast<double>( aMid.
y ) );
529 VECTOR2D dEnd( static_cast<double>( aEnd.
x ), static_cast<double>( aEnd.
y ) );
534 iCenter.
x =
KiROUND( Clamp<double>(
double( std::numeric_limits<int>::min() / 2.0 ),
536 double( std::numeric_limits<int>::max() / 2.0 ) ) );
538 iCenter.
y =
KiROUND( Clamp<double>(
double( std::numeric_limits<int>::min() / 2.0 ),
540 double( std::numeric_limits<int>::max() / 2.0 ) ) );
546 const wxPoint
CalcArcCenter(
const wxPoint& aStart,
const wxPoint& aMid,
const wxPoint& aEnd )
548 VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
549 VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
550 VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
555 iCenter.x =
KiROUND( Clamp<double>(
double( std::numeric_limits<int>::min() / 2.0 ),
557 double( std::numeric_limits<int>::max() / 2.0 ) ) );
559 iCenter.y =
KiROUND( Clamp<double>(
double( std::numeric_limits<int>::min() / 2.0 ),
561 double( std::numeric_limits<int>::max() / 2.0 ) ) );
572 VECTOR2D startLine = aStart - center;
584 bool clockwise = ( ( v1.Angle() -
v2.
Angle() ) > 0 );
587 if( clockwise &&
angle < 0.0 )
589 else if( !clockwise &&
angle > 0.0 )
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
bool IsPointOnSegment(const wxPoint &aSegStart, const wxPoint &aSegEnd, const wxPoint &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
Define a general 2D-vector/point.
double RAD2DECIDEG(double rad)
ecoord SquaredDistance(const SEG &aSeg) const
void RotatePoint(int *pX, int *pY, double angle)
void NORMALIZE_ANGLE_POS(T &Angle)
static SEG::ecoord Square(int a)
T NormalizeAngle180(T Angle)
Normalize angle to be in the -180.0 .. 180.0 range.
VECTOR2< double > VECTOR2D
double ArcTangente(int dy, int dx)
double CalcArcAngle(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Return the subtended angle for a given arc.
double Angle() const
Compute the angle of the vector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
double DECIDEG2RAD(double deg)
bool SegmentIntersectsSegment(const wxPoint &a_p1_l1, const wxPoint &a_p2_l1, const wxPoint &a_p1_l2, const wxPoint &a_p2_l2, wxPoint *aIntersectionPoint)
Test if two lines intersect.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
bool TestSegmentHit(const wxPoint &aRefPoint, const wxPoint &aStart, const wxPoint &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
const VECTOR2D CalcArcCenter(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aAngle)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
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.