Cleanup geometry functions

Added Distance(VECTOR2) function that returns a double.  Removed
superfluous EuclideanNorm, GetLineLength, integer constructor for
EDA_ANGLE (this promotes to double in the CTOR), DistanceLinePoint and
HitTestPoints

Also extended the size for arc calculations that get distances to center
points to avoid overflow
This commit is contained in:
Seth Hillbrand 2024-05-31 12:22:16 -07:00
parent 931de12072
commit a9ae86eefd
24 changed files with 111 additions and 195 deletions

View File

@ -467,7 +467,7 @@ bool DS_DRAW_ITEM_LINE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) cons
wxString DS_DRAW_ITEM_LINE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const wxString DS_DRAW_ITEM_LINE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
{ {
return wxString::Format( _( "Line, length %s" ), return wxString::Format( _( "Line, length %s" ),
aUnitsProvider->MessageTextFromValue( EuclideanNorm( GetStart() - GetEnd() ) ) ); aUnitsProvider->MessageTextFromValue( GetStart().Distance( GetEnd() ) ) );
} }

View File

@ -128,12 +128,12 @@ double EDA_SHAPE::GetLength() const
{ {
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
for( size_t ii = 1; ii < m_bezierPoints.size(); ++ii ) for( size_t ii = 1; ii < m_bezierPoints.size(); ++ii )
length += GetLineLength( m_bezierPoints[ ii - 1], m_bezierPoints[ii] ); length += m_bezierPoints[ ii - 1].Distance( m_bezierPoints[ii] );
return length; return length;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
return GetLineLength( GetStart(), GetEnd() ); return GetStart().Distance( GetEnd() );
case SHAPE_T::POLY: case SHAPE_T::POLY:
for( int ii = 0; ii < m_poly.COutline( 0 ).SegmentCount(); ii++ ) for( int ii = 0; ii < m_poly.COutline( 0 ).SegmentCount(); ii++ )
@ -623,11 +623,11 @@ int EDA_SHAPE::GetRadius() const
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
radius = GetLineLength( m_arcCenter, m_start ); radius = m_arcCenter.Distance( m_start );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
radius = GetLineLength( m_start, m_end ); radius = m_start.Distance( m_end );
break; break;
default: default:
@ -796,7 +796,7 @@ void EDA_SHAPE::ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
{ {
aList.emplace_back( _( "Length" ), aList.emplace_back( _( "Length" ),
aFrame->MessageTextFromValue( GetLineLength( GetStart(), GetEnd() ) )); aFrame->MessageTextFromValue( GetStart().Distance( GetEnd() ) ));
// angle counter-clockwise from 3'o-clock // angle counter-clockwise from 3'o-clock
EDA_ANGLE angle( atan2( (double)( GetStart().y - GetEnd().y ), EDA_ANGLE angle( atan2( (double)( GetStart().y - GetEnd().y ),
@ -869,19 +869,17 @@ const BOX2I EDA_SHAPE::getBoundingBox() const
bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{ {
int maxdist = aAccuracy; double maxdist = aAccuracy;
if( GetWidth() > 0 ) if( GetWidth() > 0 )
maxdist += GetWidth() / 2; maxdist += GetWidth() / 2.0;
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
{ {
int radius = GetRadius(); double radius = GetRadius();
double dist = aPosition.Distance( getCenter() );
VECTOR2I::extended_type dist = KiROUND<double, VECTOR2I::extended_type>(
EuclideanNorm( aPosition - getCenter() ) );
if( IsFilled() ) if( IsFilled() )
return dist <= radius + maxdist; // Filled circle hit-test return dist <= radius + maxdist; // Filled circle hit-test
@ -891,17 +889,15 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
case SHAPE_T::ARC: case SHAPE_T::ARC:
{ {
if( EuclideanNorm( aPosition - m_start ) <= maxdist ) if( aPosition.Distance( m_start ) <= maxdist )
return true; return true;
if( EuclideanNorm( aPosition - m_end ) <= maxdist ) if( aPosition.Distance( m_end ) <= maxdist )
return true; return true;
VECTOR2I relPos = aPosition - getCenter(); double radius = GetRadius();
int radius = GetRadius(); VECTOR2D relPos( VECTOR2D( aPosition ) - getCenter() );
double dist = relPos.EuclideanNorm();
VECTOR2I::extended_type dist =
KiROUND<double, VECTOR2I::extended_type>( EuclideanNorm( relPos ) );
if( IsFilled() ) if( IsFilled() )
{ {
@ -1491,14 +1487,14 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 1: case 1:
m_end = aPosition; m_end = aPosition;
radius = sqrt( sq( GetLineLength( m_start, m_end ) ) / 2.0 ); radius = m_start.Distance( m_end ) * M_SQRT1_2;
break; break;
case 2: case 2:
case 3: case 3:
{ {
VECTOR2I v = m_start - m_end; VECTOR2I v = m_start - m_end;
double chordBefore = sq( v.x ) + sq( v.y ); double chordBefore = v.SquaredEuclideanNorm();
if( m_editState == 2 ) if( m_editState == 2 )
m_start = aPosition; m_start = aPosition;
@ -1507,7 +1503,7 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
v = m_start - m_end; v = m_start - m_end;
double chordAfter = sq( v.x ) + sq( v.y ); double chordAfter = v.SquaredEuclideanNorm();
double ratio = 0.0; double ratio = 0.0;
if( chordBefore > 0 ) if( chordBefore > 0 )
@ -1520,8 +1516,8 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 4: case 4:
{ {
double radialA = GetLineLength( m_start, aPosition ); double radialA = m_start.Distance( aPosition );
double radialB = GetLineLength( m_end, aPosition ); double radialB = m_end.Distance( aPosition );
radius = ( radialA + radialB ) / 2.0; radius = ( radialA + radialB ) / 2.0;
} }
break; break;
@ -1534,9 +1530,9 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
// Calculate center based on start, end, and radius // Calculate center based on start, end, and radius
// //
// Let 'l' be the length of the chord and 'm' the middle point of the chord // Let 'l' be the length of the chord and 'm' the middle point of the chord
double l = GetLineLength( m_start, m_end ); double l = m_start.Distance( m_end );
VECTOR2D m = ( m_start + m_end ) / 2; VECTOR2D m = ( m_start + m_end ) / 2;
double sqRadDiff = sq( radius ) - sq( l / 2 ); double sqRadDiff = ( radius * radius ) - 0.25;
// Calculate 'd', the vector from the chord midpoint to the center // Calculate 'd', the vector from the chord midpoint to the center
VECTOR2D d; VECTOR2D d;
@ -1575,7 +1571,7 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 4: case 4:
// Pick the one closer to the mouse position // Pick the one closer to the mouse position
m_arcCenter = GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ? c1 : c2; m_arcCenter = c1.Distance( aPosition ) < c2.Distance( aPosition ) ? c1 : c2;
break; break;
} }
} }

View File

@ -491,7 +491,7 @@ void PLOTTER::segmentAsOval( const VECTOR2I& start, const VECTOR2I& end, int aWi
EDA_ANGLE orient( size ); EDA_ANGLE orient( size );
orient = -orient; // this is due to our Y axis orientation orient = -orient; // this is due to our Y axis orientation
size.x = KiROUND( EuclideanNorm( size ) ) + aWidth; size.x = size.EuclideanNorm() + aWidth;
size.y = aWidth; size.y = aWidth;
FlashPadOval( center, size, orient, aTraceMode, nullptr ); FlashPadOval( center, size, orient, aTraceMode, nullptr );

View File

@ -241,7 +241,7 @@ const BOX2I SCH_LINE::GetBoundingBox() const
double SCH_LINE::GetLength() const double SCH_LINE::GetLength() const
{ {
return GetLineLength( m_start, m_end ); return m_start.Distance( m_end );
} }
@ -768,7 +768,7 @@ wxString SCH_LINE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
} }
return wxString::Format( txtfmt, return wxString::Format( txtfmt,
aUnitsProvider->MessageTextFromValue( EuclideanNorm( m_start - m_end ) ) ); aUnitsProvider->MessageTextFromValue( m_start.Distance( m_end ) ) );
} }

View File

@ -1231,8 +1231,8 @@ int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
for( unsigned i = 0; i < numPoints; ++i ) for( unsigned i = 0; i < numPoints; ++i )
{ {
int distance = (int) DistanceLinePoint( poly.CPoint( i ), SEG seg = poly.GetSegment( i );
poly.CPoint( i + 1 ), cursor ); int distance = seg.Distance( cursor );
if( distance < currentMinDistance ) if( distance < currentMinDistance )
{ {

View File

@ -1264,9 +1264,9 @@ bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& a
{ {
SCH_LINE* line = (SCH_LINE*) aCollector[i]; SCH_LINE* line = (SCH_LINE*) aCollector[i];
if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) ) if( line->GetStartPoint().Distance( aWhere ) <= aCollector.m_Threshold )
flags = STARTPOINT; flags = STARTPOINT;
else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) ) else if( line->GetEndPoint().Distance( aWhere ) <= aCollector.m_Threshold )
flags = ENDPOINT; flags = ENDPOINT;
else else
flags = STARTPOINT | ENDPOINT; flags = STARTPOINT | ENDPOINT;
@ -1516,8 +1516,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
if( line ) if( line )
{ {
dist = KiROUND( DistanceLinePoint( line->GetStartPoint(), dist = line->GetSeg().Distance( aPos );
line->GetEndPoint(), aPos ) );
} }
else if( field ) else if( field )
{ {
@ -1567,13 +1566,13 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() ); SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
if( bbox.Contains( aPos ) ) if( bbox.Contains( aPos ) )
dist = KiROUND( EuclideanNorm( bbox.GetCenter() - aPos ) ); dist = bbox.GetCenter().Distance( aPos );
else else
rect.Collide( poss, closestDist, &dist ); rect.Collide( poss, closestDist, &dist );
} }
else else
{ {
dist = KiROUND( EuclideanNorm( bbox.GetCenter() - aPos ) ); dist = bbox.GetCenter().Distance( aPos );
} }
} }
else else

View File

@ -460,7 +460,7 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( APERTURE_MACRO* aApertMacro,
VECTOR2I end = VECTOR2I end =
mapPt( m_Params[4].GetValueFromMacro( aApertMacro ), m_Params[5].GetValueFromMacro( aApertMacro ), m_GerbMetric ); mapPt( m_Params[4].GetValueFromMacro( aApertMacro ), m_Params[5].GetValueFromMacro( aApertMacro ), m_GerbMetric );
VECTOR2I delta = end - start; VECTOR2I delta = end - start;
int len = KiROUND( EuclideanNorm( delta ) ); int len = delta.EuclideanNorm();
// To build the polygon, we must create a horizontal polygon starting to "start" // To build the polygon, we must create a horizontal polygon starting to "start"
// and rotate it to have the end point to "end" // and rotate it to have the end point to "end"

View File

@ -285,7 +285,7 @@ const BOX2I GERBER_DRAW_ITEM::GetBoundingBox() const
case GBR_CIRCLE: case GBR_CIRCLE:
{ {
double radius = GetLineLength( m_Start, m_End ); double radius = m_Start.Distance( m_End );
bbox.Inflate( radius, radius ); bbox.Inflate( radius, radius );
break; break;
} }
@ -490,7 +490,7 @@ void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OP
break; break;
case GBR_CIRCLE: case GBR_CIRCLE:
radius = KiROUND( GetLineLength( m_Start, m_End ) ); radius = KiROUND( m_Start.Distance( m_End ) );
halfPenWidth = m_Size.x >> 1; halfPenWidth = m_Size.x >> 1;
@ -867,7 +867,7 @@ bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
case GBR_ARC: case GBR_ARC:
{ {
double radius = GetLineLength( m_Start, m_ArcCentre ); double radius = m_Start.Distance( m_ArcCentre );
VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre ); VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x ); int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
@ -922,7 +922,7 @@ bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
radius = MIN_HIT_TEST_RADIUS; radius = MIN_HIT_TEST_RADIUS;
if( m_Flashed ) if( m_Flashed )
return HitTestPoints( m_Start, ref_pos, radius ); return m_Start.Distance( ref_pos ) <= radius;
else else
return TestSegmentHit( ref_pos, m_Start, m_End, radius ); return TestSegmentHit( ref_pos, m_Start, m_End, radius );
} }
@ -995,7 +995,7 @@ double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
break; break;
case GBR_ARC: case GBR_ARC:
size = GetLineLength( m_Start, m_ArcCentre ); size = m_Start.Distance( m_ArcCentre );
break; break;
default: default:

View File

@ -297,7 +297,7 @@ void GERBVIEW_PAINTER::draw( /*const*/ GERBER_DRAW_ITEM* aItem, int aLayer )
case GBR_CIRCLE: case GBR_CIRCLE:
{ {
isFilled = gvconfig()->m_Display.m_DisplayLinesFill; isFilled = gvconfig()->m_Display.m_DisplayLinesFill;
double radius = GetLineLength( aItem->m_Start, aItem->m_End ); double radius = aItem->m_Start.Distance( aItem->m_End );
m_gal->DrawCircle( start, radius ); m_gal->DrawCircle( start, radius );
break; break;
} }
@ -313,7 +313,7 @@ void GERBVIEW_PAINTER::draw( /*const*/ GERBER_DRAW_ITEM* aItem, int aLayer )
// Gerber arcs are 3-point (start, center, end) // Gerber arcs are 3-point (start, center, end)
// GAL needs center, radius, start angle, end angle // GAL needs center, radius, start angle, end angle
double radius = GetLineLength( arcStart, aItem->m_ArcCentre ); double radius = arcStart.Distance( aItem->m_ArcCentre );
VECTOR2D center = aItem->GetABPosition( aItem->m_ArcCentre ); VECTOR2D center = aItem->GetABPosition( aItem->m_ArcCentre );
VECTOR2D startVec = VECTOR2D( aItem->GetABPosition( arcStart ) ) - center; VECTOR2D startVec = VECTOR2D( aItem->GetABPosition( arcStart ) ) - center;
VECTOR2D endVec = VECTOR2D( aItem->GetABPosition( arcEnd ) ) - center; VECTOR2D endVec = VECTOR2D( aItem->GetABPosition( arcEnd ) ) - center;

View File

@ -106,48 +106,6 @@ public:
} }
} }
explicit EDA_ANGLE( const VECTOR2I& aVector )
{
/* gcc is surprisingly smart in optimizing these conditions in a tree! */
if( aVector.x == 0 && aVector.y == 0 )
{
m_value = 0;
}
else if( aVector.y == 0 )
{
if( aVector.x >= 0 )
m_value = 0.0;
else
m_value = -180.0;
}
else if( aVector.x == 0 )
{
if( aVector.y >= 0 )
m_value = 90.0;
else
m_value = -90.0;
}
else if( aVector.x == aVector.y )
{
if( aVector.x >= 0 )
m_value = 45.0;
else
m_value = -180.0 + 45.0;
}
else if( aVector.x == -aVector.y )
{
if( aVector.x >= 0 )
m_value = -45.0;
else
m_value = 180.0 - 45.0;
}
else
{
*this = EDA_ANGLE( atan2( (double) aVector.y, (double) aVector.x ), RADIANS_T );
}
}
EDA_ANGLE() : EDA_ANGLE() :
m_value( 0.0 ) m_value( 0.0 )
{} {}

View File

@ -253,8 +253,9 @@ public:
*/ */
bool IsCCW() const bool IsCCW() const
{ {
VECTOR2I v1 = m_end - m_mid; VECTOR2L mid = m_mid;
VECTOR2I v2 = m_start - m_mid; VECTOR2L v1 = m_end - mid;
VECTOR2L v2 = m_start - mid;
return v1.Cross( v2 ) > 0; return v1.Cross( v2 ) > 0;
} }

View File

@ -180,6 +180,12 @@ public:
*/ */
extended_type Dot( const VECTOR2<T>& aVector ) const; extended_type Dot( const VECTOR2<T>& aVector ) const;
/**
* Compute the distance between two vectors. This is a double precision
* value because the distance is frequently non-integer.
*/
double Distance( const VECTOR2<extended_type>& aVector ) const;
// Operators // Operators
@ -267,8 +273,15 @@ T VECTOR2<T>::EuclideanNorm() const
// 45° are common in KiCad, so we can optimize the calculation // 45° are common in KiCad, so we can optimize the calculation
if( std::abs( x ) == std::abs( y ) ) if( std::abs( x ) == std::abs( y ) )
return static_cast<T>( std::abs( x ) * M_SQRT2 ); return static_cast<T>( std::abs( x ) * M_SQRT2 );
if( x == 0 )
return static_cast<T>( std::abs( y ) );
if( y == 0 )
return static_cast<T>( std::abs( x ) );
return static_cast<T>( sqrt( (extended_type) x * x + (extended_type) y * y ) ); if( std::is_integral<T>::value )
return KiROUND<double, T>( std::hypot( x, y ) );
return static_cast<T>( std::hypot( x, y ) );
} }
@ -482,6 +495,13 @@ typename VECTOR2<T>::extended_type VECTOR2<T>::Dot( const VECTOR2<T>& aVector )
(extended_type) y * (extended_type) aVector.y; (extended_type) y * (extended_type) aVector.y;
} }
template <class T>
double VECTOR2<T>::Distance( const VECTOR2<extended_type>& aVector ) const
{
VECTOR2<double> diff( aVector.x - x, aVector.y - y );
return diff.EuclideanNorm();
}
template <class T> template <class T>
bool VECTOR2<T>::operator<( const VECTOR2<T>& aVector ) const bool VECTOR2<T>::operator<( const VECTOR2<T>& aVector ) const
@ -599,8 +619,8 @@ std::ostream& operator<<( std::ostream& aStream, const VECTOR2<T>& aVector )
/* Default specializations */ /* Default specializations */
typedef VECTOR2<double> VECTOR2D; typedef VECTOR2<double> VECTOR2D;
typedef VECTOR2<int> VECTOR2I; typedef VECTOR2<int32_t> VECTOR2I;
typedef VECTOR2<long long int> VECTOR2L; typedef VECTOR2<int64_t> VECTOR2L;
/* KiROUND specialization for vectors */ /* KiROUND specialization for vectors */
inline VECTOR2I KiROUND( const VECTOR2D& vec ) inline VECTOR2I KiROUND( const VECTOR2D& vec )

View File

@ -125,54 +125,6 @@ const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const VECTOR2I CalcArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter, const VECTOR2I CalcArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
bool aMinArcAngle = true ); bool aMinArcAngle = true );
inline double EuclideanNorm( const VECTOR2I& vector )
{
// this is working with doubles
return hypot( vector.x, vector.y );
}
/**
* Compute the distance between a line and a reference point.
*
* Reference: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
*
* @param linePointA Point on line.
* @param linePointB Point on line.
* @param referencePoint Reference point.
*/
inline double DistanceLinePoint( const VECTOR2I& linePointA, const VECTOR2I& linePointB,
const VECTOR2I& referencePoint )
{
// Some of the multiple double casts are redundant. However in the previous definition
// the cast was (implicitly) done too late, just before the division (EuclideanNorm gives
// a double so from int it would be promoted); that means that the whole expression were
// vulnerable to overflow during int multiplications
return fabs( ( static_cast<double>( linePointB.x - linePointA.x ) *
static_cast<double>( linePointA.y - referencePoint.y ) -
static_cast<double>( linePointA.x - referencePoint.x ) *
static_cast<double>( linePointB.y - linePointA.y) )
/ EuclideanNorm( linePointB - linePointA ) );
}
/**
* Test if two points are near each other.
*
* @param pointA First point.
* @param pointB Second point.
* @param threshold The maximum distance.
* @return true if \a pointA is within \a threshold of \a pointB otherwise false.
*/
inline bool HitTestPoints( const VECTOR2I& pointA, const VECTOR2I& pointB, double threshold )
{
VECTOR2I vectorAB = pointB - pointA;
// Compare the distances squared. The double is needed to avoid overflow during int
// multiplication
double sqdistance = (double)vectorAB.x * vectorAB.x + (double)vectorAB.y * vectorAB.y;
return sqdistance < threshold * threshold;
}
/** /**
* Test if \a aRefPoint is with \a aDistance on the line defined by \a aStart and \a aEnd.. * Test if \a aRefPoint is with \a aDistance on the line defined by \a aStart and \a aEnd..
* *
@ -184,18 +136,6 @@ inline bool HitTestPoints( const VECTOR2I& pointA, const VECTOR2I& pointB, doubl
bool TestSegmentHit( const VECTOR2I& aRefPoint, const VECTOR2I& aStart, const VECTOR2I& aEnd, bool TestSegmentHit( const VECTOR2I& aRefPoint, const VECTOR2I& aStart, const VECTOR2I& aEnd,
int aDist ); int aDist );
/**
* Return the length of a line segment defined by \a aPointA and \a aPointB.
*
* See also EuclideanNorm and Distance for the single vector or four scalar versions.
*
* @return Length of a line (as double)
*/
inline double GetLineLength( const VECTOR2I& aPointA, const VECTOR2I& aPointB )
{
return hypot( (double) aPointA.x - aPointB.x, (double) aPointA.y - aPointB.y );
}
// These are the usual degrees <-> radians conversion routines // These are the usual degrees <-> radians conversion routines
inline double DEG2RAD( double deg ) { return deg * M_PI / 180.0; } inline double DEG2RAD( double deg ) { return deg * M_PI / 180.0; }
inline double RAD2DEG( double rad ) { return rad * 180.0 / M_PI; } inline double RAD2DEG( double rad ) { return rad * 180.0 / M_PI; }

View File

@ -163,7 +163,7 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aBuffer, const VECTOR2I& aStart, co
} }
EDA_ANGLE delta_angle( endp ); EDA_ANGLE delta_angle( endp );
int seg_len = KiROUND( EuclideanNorm( endp ) ); int seg_len = endp.EuclideanNorm();
// Compute the outlines of the segment, and creates a polygon // Compute the outlines of the segment, and creates a polygon
// Note: the polygonal shape is built from the equivalent horizontal // Note: the polygonal shape is built from the equivalent horizontal

View File

@ -429,7 +429,7 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
if( !bbox.Contains( aP ) ) if( !bbox.Contains( aP ) )
return false; return false;
VECTOR2I center = GetCenter(); VECTOR2L center = GetCenter();
double radius = ( center - m_start ).EuclideanNorm(); double radius = ( center - m_start ).EuclideanNorm();
CIRCLE fullCircle( center, radius ); CIRCLE fullCircle( center, radius );
VECTOR2I nearestPt = fullCircle.NearestPoint( aP ); VECTOR2I nearestPt = fullCircle.NearestPoint( aP );
@ -488,14 +488,16 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
EDA_ANGLE SHAPE_ARC::GetStartAngle() const EDA_ANGLE SHAPE_ARC::GetStartAngle() const
{ {
EDA_ANGLE angle( m_start - GetCenter() ); VECTOR2L center = GetCenter();
EDA_ANGLE angle( m_start - center );
return angle.Normalize(); return angle.Normalize();
} }
EDA_ANGLE SHAPE_ARC::GetEndAngle() const EDA_ANGLE SHAPE_ARC::GetEndAngle() const
{ {
EDA_ANGLE angle( m_end - GetCenter() ); VECTOR2L center = GetCenter();
EDA_ANGLE angle( m_end - center );
return angle.Normalize(); return angle.Normalize();
} }
@ -523,7 +525,7 @@ EDA_ANGLE SHAPE_ARC::GetCentralAngle() const
if( m_start == m_end ) if( m_start == m_end )
return ANGLE_360; return ANGLE_360;
VECTOR2I center = GetCenter(); VECTOR2L center = GetCenter();
EDA_ANGLE angle1 = EDA_ANGLE( m_mid - center ) - EDA_ANGLE( m_start - center ); EDA_ANGLE angle1 = EDA_ANGLE( m_mid - center ) - EDA_ANGLE( m_start - center );
EDA_ANGLE angle2 = EDA_ANGLE( m_end - center ) - EDA_ANGLE( m_mid - center ); EDA_ANGLE angle2 = EDA_ANGLE( m_end - center ) - EDA_ANGLE( m_mid - center );

View File

@ -726,12 +726,12 @@ static int getMinDist( BOARD_CONNECTED_ITEM* aItem, const VECTOR2I& aPoint )
{ {
PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem ); PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
return std::min( GetLineLength( track->GetStart(), aPoint ), return std::min( track->GetStart().Distance(aPoint ),
GetLineLength( track->GetEnd(), aPoint ) ); track->GetEnd().Distance( aPoint ) );
} }
default: default:
return GetLineLength( aItem->GetPosition(), aPoint ); return aItem->GetPosition().Distance( aPoint );
} }
} }

View File

@ -1196,7 +1196,7 @@ void GENCAD_EXPORTER::FootprintWriteShape( FOOTPRINT* aFootprint, const wxString
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
{ {
int radius = KiROUND( GetLineLength( end, start ) ); int radius = KiROUND( end.Distance( start ) );
fprintf( m_file, "CIRCLE %g %g %g\n", fprintf( m_file, "CIRCLE %g %g %g\n",
start.x / SCALE_FACTOR, start.x / SCALE_FACTOR,

View File

@ -50,8 +50,8 @@
static void gen_arc( std::vector<VECTOR2I>& aBuffer, const VECTOR2I& aStartPoint, static void gen_arc( std::vector<VECTOR2I>& aBuffer, const VECTOR2I& aStartPoint,
const VECTOR2I& aCenter, const EDA_ANGLE& a_ArcAngle ) const VECTOR2I& aCenter, const EDA_ANGLE& a_ArcAngle )
{ {
auto first_point = aStartPoint - aCenter; VECTOR2D first_point = VECTOR2D( aStartPoint ) - aCenter;
auto radius = KiROUND( EuclideanNorm( first_point ) ); double radius = first_point.EuclideanNorm();
int seg_count = GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle ); int seg_count = GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle );
double increment_angle = a_ArcAngle.AsRadians() / seg_count; double increment_angle = a_ArcAngle.AsRadians() / seg_count;
@ -140,7 +140,7 @@ static INDUCTOR_S_SHAPE_RESULT BuildCornersList_S_Shape( std::vector<VECTOR2I>&
auto pt = aEndPoint - aStartPoint; auto pt = aEndPoint - aStartPoint;
EDA_ANGLE angle( pt ); EDA_ANGLE angle( pt );
int min_len = KiROUND( EuclideanNorm( pt ) ); int min_len = pt.EuclideanNorm();
int segm_len = 0; // length of segments int segm_len = 0; // length of segments
int full_len; // full len of shape (sum of length of all segments + arcs) int full_len; // full len of shape (sum of length of all segments + arcs)
@ -358,7 +358,7 @@ FOOTPRINT* MICROWAVE_TOOL::createMicrowaveInductor( MICROWAVE_INDUCTOR_PATTERN&
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>(); PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
VECTOR2I pt = aInductorPattern.m_End - aInductorPattern.m_Start; VECTOR2I pt = aInductorPattern.m_End - aInductorPattern.m_Start;
int min_len = KiROUND( EuclideanNorm( pt ) ); int min_len = pt.EuclideanNorm();
aInductorPattern.m_Length = min_len; aInductorPattern.m_Length = min_len;
// Enter the desired length. // Enter the desired length.

View File

@ -105,8 +105,8 @@ void HelperShapeLineChainFromAltiumVertices( SHAPE_LINE_CHAIN& aLine,
VECTOR2I arcStart = vertex.center + arcStartOffset; VECTOR2I arcStart = vertex.center + arcStartOffset;
VECTOR2I arcEnd = vertex.center + arcEndOffset; VECTOR2I arcEnd = vertex.center + arcEndOffset;
if( GetLineLength( arcStart, vertex.position ) if( arcStart.Distance( vertex.position )
< GetLineLength( arcEnd, vertex.position ) ) < arcEnd.Distance( vertex.position ) )
{ {
aLine.Append( SHAPE_ARC( vertex.center, arcStart, -angle ) ); aLine.Append( SHAPE_ARC( vertex.center, arcStart, -angle ) );
} }
@ -1413,7 +1413,7 @@ void ALTIUM_PCB::HelperParseDimensions6Linear( const ADIMENSION6& aElem )
dimension->SetEnd( *intersection ); dimension->SetEnd( *intersection );
int height = static_cast<int>( EuclideanNorm( direction ) ); int height = direction.EuclideanNorm();
if( ( direction.x > 0 || direction.y < 0 ) != ( aElem.angle >= 180.0 ) ) if( ( direction.x > 0 || direction.y < 0 ) != ( aElem.angle >= 180.0 ) )
height = -height; height = -height;
@ -1603,7 +1603,7 @@ void ALTIUM_PCB::HelperParseDimensions6Leader( const ADIMENSION6& aElem )
if( dirVec.x != 0 || dirVec.y != 0 ) if( dirVec.x != 0 || dirVec.y != 0 )
{ {
double scaling = EuclideanNorm( dirVec ) / aElem.arrowsize; double scaling = dirVec.EuclideanNorm() / aElem.arrowsize;
VECTOR2I arrVec = VECTOR2I arrVec =
VECTOR2I( KiROUND( dirVec.x / scaling ), KiROUND( dirVec.y / scaling ) ); VECTOR2I( KiROUND( dirVec.x / scaling ), KiROUND( dirVec.y / scaling ) );
RotatePoint( arrVec, EDA_ANGLE( 20.0, DEGREES_T ) ); RotatePoint( arrVec, EDA_ANGLE( 20.0, DEGREES_T ) );

View File

@ -1097,7 +1097,7 @@ void PCB_IO_EAGLE::loadPlain( wxXmlNode* aGraphics )
} }
else else
{ {
int offset = GetLineLength( pt3, pt1 ); int offset = KiROUND( pt3.Distance( pt1 ) );
if( pt1.y > pt2.y ) if( pt1.y > pt2.y )
dimension->SetHeight( offset ); dimension->SetHeight( offset );

View File

@ -557,7 +557,7 @@ FOOTPRINT* GPCB_FPL_CACHE::parseFOOTPRINT( LINE_READER* aLineReader )
VECTOR2I padPos( ( x1 + x2 ) / 2, ( y1 + y2 ) / 2 ); VECTOR2I padPos( ( x1 + x2 ) / 2, ( y1 + y2 ) / 2 );
pad->SetSize( VECTOR2I( KiROUND( EuclideanNorm( delta ) ) + width, width ) ); pad->SetSize( VECTOR2I( delta.EuclideanNorm() + width, width ) );
padPos += footprint->GetPosition(); padPos += footprint->GetPosition();
pad->SetPosition( padPos ); pad->SetPosition( padPos );

View File

@ -589,14 +589,14 @@ EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const VECTOR2I& point, int min_dist ) c
} }
else else
{ {
double dist = GetLineLength( m_Start, point ); double dist = m_Start.Distance( point );
if( min_dist >= KiROUND( dist ) ) if( min_dist >= dist )
result |= STARTPOINT; result |= STARTPOINT;
dist = GetLineLength( m_End, point ); dist = m_End.Distance( point );
if( min_dist >= KiROUND( dist ) ) if( min_dist >= dist )
result |= ENDPOINT; result |= ENDPOINT;
} }
@ -651,7 +651,7 @@ const BOX2I PCB_TRACK::GetBoundingBox() const
double PCB_TRACK::GetLength() const double PCB_TRACK::GetLength() const
{ {
return GetLineLength( m_Start, m_End ); return m_Start.Distance( m_End );
} }
@ -742,8 +742,9 @@ void PCB_ARC::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
bool PCB_ARC::IsCCW() const bool PCB_ARC::IsCCW() const
{ {
VECTOR2I start_end = m_End - m_Start; VECTOR2L start = m_Start;
VECTOR2I start_mid = m_Mid - m_Start; VECTOR2L start_end = m_End - start;
VECTOR2L start_mid = m_Mid - start;
return start_end.Cross( start_mid ) < 0; return start_end.Cross( start_mid ) < 0;
} }
@ -1399,18 +1400,17 @@ bool PCB_TRACK::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{ {
int max_dist = aAccuracy + ( m_Width / 2 ); double max_dist = aAccuracy + ( m_Width / 2.0 );
// Short-circuit common cases where the arc is connected to a track or via at an endpoint // Short-circuit common cases where the arc is connected to a track or via at an endpoint
if( EuclideanNorm( GetStart() - aPosition ) <= max_dist || if( GetStart().Distance( aPosition ) <= max_dist || GetEnd().Distance( aPosition ) <= max_dist )
EuclideanNorm( GetEnd() - aPosition ) <= max_dist )
{ {
return true; return true;
} }
VECTOR2I center = GetPosition(); VECTOR2L center = GetPosition();
VECTOR2I relpos = aPosition - center; VECTOR2L relpos = aPosition - center;
double dist = EuclideanNorm( relpos ); int64_t dist = relpos.EuclideanNorm();
double radius = GetRadius(); double radius = GetRadius();
if( std::abs( dist - radius ) > max_dist ) if( std::abs( dist - radius ) > max_dist )
@ -1536,13 +1536,13 @@ VECTOR2I PCB_ARC::GetPosition() const
double PCB_ARC::GetRadius() const double PCB_ARC::GetRadius() const
{ {
auto center = CalcArcCenter( m_Start, m_Mid , m_End ); auto center = CalcArcCenter( m_Start, m_Mid , m_End );
return GetLineLength( center, m_Start ); return center.Distance( m_Start );
} }
EDA_ANGLE PCB_ARC::GetAngle() const EDA_ANGLE PCB_ARC::GetAngle() const
{ {
VECTOR2I center = GetPosition(); VECTOR2D center = GetPosition();
EDA_ANGLE angle1 = EDA_ANGLE( m_Mid - center ) - EDA_ANGLE( m_Start - center ); EDA_ANGLE angle1 = EDA_ANGLE( m_Mid - center ) - EDA_ANGLE( m_Start - center );
EDA_ANGLE angle2 = EDA_ANGLE( m_End - center ) - EDA_ANGLE( m_Mid - center ); EDA_ANGLE angle2 = EDA_ANGLE( m_End - center ) - EDA_ANGLE( m_Mid - center );
@ -1552,7 +1552,7 @@ EDA_ANGLE PCB_ARC::GetAngle() const
EDA_ANGLE PCB_ARC::GetArcAngleStart() const EDA_ANGLE PCB_ARC::GetArcAngleStart() const
{ {
VECTOR2I pos( GetPosition() ); VECTOR2D pos( GetPosition() );
EDA_ANGLE angleStart( m_Start - pos ); EDA_ANGLE angleStart( m_Start - pos );
return angleStart.Normalize(); return angleStart.Normalize();
@ -1562,7 +1562,7 @@ EDA_ANGLE PCB_ARC::GetArcAngleStart() const
// Note: used in python tests. Ignore CLion's claim that it's unused.... // Note: used in python tests. Ignore CLion's claim that it's unused....
EDA_ANGLE PCB_ARC::GetArcAngleEnd() const EDA_ANGLE PCB_ARC::GetArcAngleEnd() const
{ {
VECTOR2I pos( GetPosition() ); VECTOR2D pos( GetPosition() );
EDA_ANGLE angleEnd( m_End - pos ); EDA_ANGLE angleEnd( m_End - pos );
return angleEnd.Normalize(); return angleEnd.Normalize();

View File

@ -675,8 +675,8 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent )
auto isTrackStartClosestToArcStart = auto isTrackStartClosestToArcStart =
[&]( PCB_TRACK* aTrack ) -> bool [&]( PCB_TRACK* aTrack ) -> bool
{ {
double trackStartToArcStart = GetLineLength( aTrack->GetStart(), theArc->GetStart() ); double trackStartToArcStart = aTrack->GetStart().Distance( theArc->GetStart() );
double trackEndToArcStart = GetLineLength( aTrack->GetEnd(), theArc->GetStart() ); double trackEndToArcStart = aTrack->GetEnd().Distance( theArc->GetStart() );
return trackStartToArcStart < trackEndToArcStart; return trackStartToArcStart < trackEndToArcStart;
}; };

View File

@ -1473,7 +1473,7 @@ void PCB_POINT_EDITOR::updateItem( BOARD_COMMIT* aCommit )
case PAD_SHAPE::CIRCLE: case PAD_SHAPE::CIRCLE:
{ {
VECTOR2I end = m_editPoints->Point( 0 ).GetPosition(); VECTOR2I end = m_editPoints->Point( 0 ).GetPosition();
int diameter = (int) EuclideanNorm( end - pad->GetPosition() ) * 2; int diameter = ( end - pad->GetPosition() ).SquaredEuclideanNorm();
pad->SetSize( VECTOR2I( diameter, diameter ) ); pad->SetSize( VECTOR2I( diameter, diameter ) );
break; break;