Move SHAPE_ARC to start->mid->end format
The arc shapes need to connect with their adjacent points. By storing the relevant points, we allow exact point matching on both ends of the arc as well as localize point storage.
This commit is contained in:
parent
951eaa13fe
commit
a8ab668122
|
@ -30,6 +30,7 @@
|
||||||
#include <geometry/shape.h>
|
#include <geometry/shape.h>
|
||||||
#include <math/box2.h> // for BOX2I
|
#include <math/box2.h> // for BOX2I
|
||||||
#include <math/vector2d.h> // for VECTOR2I
|
#include <math/vector2d.h> // for VECTOR2I
|
||||||
|
#include <trigo.h>
|
||||||
|
|
||||||
class SHAPE_LINE_CHAIN;
|
class SHAPE_LINE_CHAIN;
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ class SHAPE_ARC : public SHAPE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SHAPE_ARC() :
|
SHAPE_ARC() :
|
||||||
SHAPE( SH_ARC ), m_centralAngle( 0.0 ), m_width( 0 ) {};
|
SHAPE( SH_ARC ), m_width( 0 ) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHAPE_ARC ctor.
|
* SHAPE_ARC ctor.
|
||||||
|
@ -47,22 +48,19 @@ public:
|
||||||
* @param aWidth is the arc line thickness
|
* @param aWidth is the arc line thickness
|
||||||
*/
|
*/
|
||||||
SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint,
|
SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint,
|
||||||
double aCenterAngle, int aWidth = 0 ) :
|
double aCenterAngle, int aWidth = 0 );
|
||||||
SHAPE( SH_ARC ), m_p0( aArcStartPoint ), m_pc( aArcCenter ), m_centralAngle( aCenterAngle ),
|
|
||||||
m_width( aWidth )
|
|
||||||
{
|
|
||||||
update_bbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
SHAPE_ARC( const SHAPE_ARC& aOther )
|
/**
|
||||||
: SHAPE( SH_ARC )
|
* SHAPE_ARC ctor.
|
||||||
{
|
* @param aArcStart is the arc start point
|
||||||
m_p0 = aOther.m_p0;
|
* @param aArcEnd is the arc end point
|
||||||
m_pc = aOther.m_pc;
|
* @param aArcMid is the arc mid point
|
||||||
m_centralAngle = aOther.m_centralAngle;
|
* @param aWidth is the arc line thickness
|
||||||
m_width = aOther.m_width;
|
*/
|
||||||
m_bbox = aOther.m_bbox;
|
SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid,
|
||||||
}
|
const VECTOR2I& aArcEnd, int aWidth );
|
||||||
|
|
||||||
|
SHAPE_ARC( const SHAPE_ARC& aOther );
|
||||||
|
|
||||||
virtual ~SHAPE_ARC() {}
|
virtual ~SHAPE_ARC() {}
|
||||||
|
|
||||||
|
@ -71,10 +69,10 @@ public:
|
||||||
return new SHAPE_ARC( *this );
|
return new SHAPE_ARC( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
const VECTOR2I& GetP0() const { return m_p0; }
|
const VECTOR2I& GetP0() const { return m_start; }
|
||||||
const VECTOR2I GetP1() const;
|
const VECTOR2I& GetP1() const { return m_end; }
|
||||||
const VECTOR2I GetArcMid() const;
|
const VECTOR2I& GetArcMid() const { return m_mid; }
|
||||||
const VECTOR2I& GetCenter() const { return m_pc; }
|
VECTOR2I GetCenter() const;
|
||||||
|
|
||||||
const BOX2I BBox( int aClearance = 0 ) const override;
|
const BOX2I BBox( int aClearance = 0 ) const override;
|
||||||
|
|
||||||
|
@ -96,12 +94,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Move( const VECTOR2I& aVector ) override
|
void Move( const VECTOR2I& aVector ) override;
|
||||||
{
|
|
||||||
m_p0 += aVector;
|
|
||||||
m_pc += aVector;
|
|
||||||
update_bbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Rotate
|
* Function Rotate
|
||||||
|
@ -109,61 +102,21 @@ public:
|
||||||
* @param aCenter is the rotation center
|
* @param aCenter is the rotation center
|
||||||
* @param aAngle rotation angle in radians
|
* @param aAngle rotation angle in radians
|
||||||
*/
|
*/
|
||||||
void Rotate( double aAngle, const VECTOR2I& aCenter )
|
void Rotate( double aAngle, const VECTOR2I& aCenter );
|
||||||
{
|
|
||||||
m_p0 -= aCenter;
|
|
||||||
m_pc -= aCenter;
|
|
||||||
|
|
||||||
m_p0.Rotate( aAngle );
|
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } );
|
||||||
m_pc.Rotate( aAngle );
|
|
||||||
|
|
||||||
m_pc += aCenter;
|
|
||||||
m_p0 += aCenter;
|
|
||||||
update_bbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } )
|
|
||||||
{
|
|
||||||
if( aX )
|
|
||||||
{
|
|
||||||
m_p0.x = -m_p0.x + 2 * aVector.x;
|
|
||||||
m_pc.x = -m_pc.x + 2 * aVector.x;
|
|
||||||
m_centralAngle = - m_centralAngle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( aY )
|
|
||||||
{
|
|
||||||
m_p0.y = -m_p0.y + 2 * aVector.y;
|
|
||||||
m_pc.y = -m_pc.y + 2 * aVector.y;
|
|
||||||
m_centralAngle = - m_centralAngle;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_bbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetRadius() const;
|
int GetRadius() const;
|
||||||
|
|
||||||
SEG GetChord() const
|
SEG GetChord() const
|
||||||
{
|
{
|
||||||
return SEG( m_p0, GetP1() );
|
return SEG( m_start, m_end );
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetCentralAngle() const;
|
double GetCentralAngle() const;
|
||||||
double GetStartAngle() const;
|
double GetStartAngle() const;
|
||||||
double GetEndAngle() const;
|
double GetEndAngle() const;
|
||||||
|
|
||||||
/*
|
|
||||||
bool ConstructFromCorners( VECTOR2I aP0, VECTOR2I aP1, double aCenterAngle );
|
|
||||||
bool ConstructFromCircle( VECTOR2I aP0, double aRadius );
|
|
||||||
|
|
||||||
bool ConstructFromCenterAndAngles( VECTOR2I aCenter, double aRadius, double aStartAngle, double aCenterAngle );
|
|
||||||
|
|
||||||
bool ConstructFromCornerAndAngles( VECTOR2I aP0,
|
|
||||||
double aStartAngle,
|
|
||||||
double aCenterAngle,
|
|
||||||
double aRadius );
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a SHAPE_LINE_CHAIN of segments from a given arc
|
* Constructs a SHAPE_LINE_CHAIN of segments from a given arc
|
||||||
* @param aAccuracy maximum divergence from true arc given in internal units
|
* @param aAccuracy maximum divergence from true arc given in internal units
|
||||||
|
@ -187,8 +140,9 @@ private:
|
||||||
void update_bbox();
|
void update_bbox();
|
||||||
|
|
||||||
|
|
||||||
VECTOR2I m_p0, m_pc;
|
VECTOR2I m_start;
|
||||||
double m_centralAngle;
|
VECTOR2I m_mid;
|
||||||
|
VECTOR2I m_end;
|
||||||
|
|
||||||
int m_width;
|
int m_width;
|
||||||
BOX2I m_bbox;
|
BOX2I m_bbox;
|
||||||
|
|
|
@ -37,17 +37,53 @@
|
||||||
#include <type_traits> // for swap
|
#include <type_traits> // for swap
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint,
|
||||||
|
double aCenterAngle, int aWidth ) :
|
||||||
|
SHAPE( SH_ARC ), m_width( aWidth )
|
||||||
|
{
|
||||||
|
m_start = aArcStartPoint;
|
||||||
|
m_mid = aArcStartPoint;
|
||||||
|
m_end = aArcStartPoint;
|
||||||
|
|
||||||
|
RotatePoint( m_mid, aArcCenter, -aCenterAngle * 10.0 / 2.0 );
|
||||||
|
RotatePoint( m_end, aArcCenter, -aCenterAngle * 10.0 );
|
||||||
|
|
||||||
|
update_bbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid,
|
||||||
|
const VECTOR2I& aArcEnd, int aWidth ) :
|
||||||
|
SHAPE( SH_ARC ), m_start( aArcStart ), m_mid( aArcMid ), m_end( aArcEnd ),
|
||||||
|
m_width( aWidth )
|
||||||
|
{
|
||||||
|
update_bbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE_ARC::SHAPE_ARC( const SHAPE_ARC& aOther )
|
||||||
|
: SHAPE( SH_ARC )
|
||||||
|
{
|
||||||
|
m_start = aOther.m_start;
|
||||||
|
m_end = aOther.m_end;
|
||||||
|
m_mid = aOther.m_mid;
|
||||||
|
m_width = aOther.m_width;
|
||||||
|
m_bbox = aOther.m_bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
{
|
{
|
||||||
int minDist = aClearance + m_width / 2;
|
int minDist = aClearance + m_width / 2;
|
||||||
auto centerDist = aSeg.Distance( m_pc );
|
auto center = GetCenter();
|
||||||
|
auto centerDist = aSeg.Distance( center );
|
||||||
auto p1 = GetP1();
|
auto p1 = GetP1();
|
||||||
|
|
||||||
if( centerDist < minDist )
|
if( centerDist < minDist )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto ab = (aSeg.B - aSeg.A );
|
auto ab = (aSeg.B - aSeg.A );
|
||||||
auto ac = ( m_pc - aSeg.A );
|
auto ac = ( center - aSeg.A );
|
||||||
|
|
||||||
auto lenAbSq = ab.SquaredEuclideanNorm();
|
auto lenAbSq = ab.SquaredEuclideanNorm();
|
||||||
|
|
||||||
|
@ -61,7 +97,7 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
|
p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
|
||||||
p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
|
p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
|
||||||
|
|
||||||
auto p0pdist = ( m_p0 - p ).EuclideanNorm();
|
auto p0pdist = ( m_start - p ).EuclideanNorm();
|
||||||
|
|
||||||
if( p0pdist < minDist )
|
if( p0pdist < minDist )
|
||||||
return true;
|
return true;
|
||||||
|
@ -72,7 +108,7 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p0dist = aSeg.Distance( m_p0 );
|
auto p0dist = aSeg.Distance( m_start );
|
||||||
|
|
||||||
if( p0dist > minDist )
|
if( p0dist > minDist )
|
||||||
return true;
|
return true;
|
||||||
|
@ -86,99 +122,13 @@ bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
bool SHAPE_ARC::ConstructFromCorners( VECTOR2I aP0, VECTOR2I aP1, double aCenterAngle )
|
|
||||||
{
|
|
||||||
VECTOR2D mid = ( VECTOR2D( aP0 ) + VECTOR2D( aP1 ) ) * 0.5;
|
|
||||||
VECTOR2D chord = VECTOR2D( aP1 ) - VECTOR2D( aP0 );
|
|
||||||
double c = (aP1 - aP0).EuclideanNorm() / 2;
|
|
||||||
VECTOR2D d = chord.Rotate( M_PI / 2.0 ).Resize( c );
|
|
||||||
|
|
||||||
m_pc = mid + d * ( 1.0 / tan( aCenterAngle / 2.0 * M_PI / 180.0 ) );
|
|
||||||
m_p0 = aP0;
|
|
||||||
m_p1 = aP1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAPE_ARC::ConstructFromCornerAndAngles( VECTOR2I aP0,
|
|
||||||
double aStartAngle,
|
|
||||||
double aCenterAngle,
|
|
||||||
double aRadius )
|
|
||||||
{
|
|
||||||
m_p0 = aP0;
|
|
||||||
auto d1 = VECTOR2D( 1.0, 0.0 ).Rotate( aStartAngle * M_PI / 180.0 ) * aRadius;
|
|
||||||
auto d2 =
|
|
||||||
VECTOR2D( 1.0, 0.0 ).Rotate( (aStartAngle + aCenterAngle) * M_PI / 180.0 ) * aRadius;
|
|
||||||
|
|
||||||
m_pc = m_p0 - (VECTOR2I) d1;
|
|
||||||
m_p1 = m_pc + (VECTOR2I) d2;
|
|
||||||
|
|
||||||
if( aCenterAngle < 0 )
|
|
||||||
std::swap( m_p0, m_p1 );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHAPE_ARC::ConstructFromCenterAndAngles( VECTOR2I aCenter, double aRadius, double aStartAngle, double aCenterAngle )
|
|
||||||
{
|
|
||||||
double ea = aStartAngle + aCenterAngle;
|
|
||||||
|
|
||||||
m_fullCircle = false;
|
|
||||||
m_pc = aCenter;
|
|
||||||
m_p0.x = (int) ( (double) aCenter.x + aRadius * cos( aStartAngle * M_PI / 180.0 ) );
|
|
||||||
m_p0.y = (int) ( (double) aCenter.y + aRadius * sin( aStartAngle * M_PI / 180.0 ) );
|
|
||||||
m_p1.x = (int) ( (double) aCenter.x + aRadius * cos( ea * M_PI / 180.0 ) );
|
|
||||||
m_p1.y = (int) ( (double) aCenter.y + aRadius * sin( ea * M_PI / 180.0 ) );
|
|
||||||
|
|
||||||
if( aCenterAngle == 360.0 )
|
|
||||||
{
|
|
||||||
m_fullCircle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if ( aCenterAngle < 0.0 )
|
|
||||||
{
|
|
||||||
std::swap(m_p0, m_p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
const VECTOR2I SHAPE_ARC::GetP1() const
|
|
||||||
{
|
|
||||||
VECTOR2D rvec = m_p0 - m_pc;
|
|
||||||
auto ca = m_centralAngle * M_PI / 180.0;
|
|
||||||
VECTOR2I p1;
|
|
||||||
|
|
||||||
p1.x = KiROUND( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
|
|
||||||
p1.y = KiROUND( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
|
|
||||||
|
|
||||||
return p1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const VECTOR2I SHAPE_ARC::GetArcMid() const
|
|
||||||
{
|
|
||||||
VECTOR2D rvec = m_p0 - m_pc;
|
|
||||||
auto ca = m_centralAngle / 2.0 * M_PI / 180.0;
|
|
||||||
VECTOR2I p1;
|
|
||||||
|
|
||||||
p1.x = KiROUND( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
|
|
||||||
p1.y = KiROUND( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
|
|
||||||
|
|
||||||
return p1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_ARC::update_bbox()
|
void SHAPE_ARC::update_bbox()
|
||||||
{
|
{
|
||||||
std::vector<VECTOR2I> points;
|
std::vector<VECTOR2I> points;
|
||||||
// Put start and end points in the point list
|
// Put start and end points in the point list
|
||||||
points.push_back( m_p0 );
|
points.push_back( m_start );
|
||||||
points.push_back( GetP1() );
|
points.push_back( m_end );
|
||||||
// points.push_back( m_pc ); the center point is not necessary in the BBox
|
|
||||||
|
|
||||||
double start_angle = GetStartAngle();
|
double start_angle = GetStartAngle();
|
||||||
double end_angle = start_angle + GetCentralAngle();
|
double end_angle = start_angle + GetCentralAngle();
|
||||||
|
@ -194,7 +144,7 @@ void SHAPE_ARC::update_bbox()
|
||||||
for( int quad_angle = quad_angle_start; quad_angle <= quad_angle_end; ++quad_angle )
|
for( int quad_angle = quad_angle_start; quad_angle <= quad_angle_end; ++quad_angle )
|
||||||
{
|
{
|
||||||
const int radius = GetRadius();
|
const int radius = GetRadius();
|
||||||
VECTOR2I quad_pt = m_pc;
|
VECTOR2I quad_pt = GetCenter();
|
||||||
|
|
||||||
switch( quad_angle % 4 )
|
switch( quad_angle % 4 )
|
||||||
{
|
{
|
||||||
|
@ -242,41 +192,57 @@ bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
|
||||||
|
|
||||||
double SHAPE_ARC::GetStartAngle() const
|
double SHAPE_ARC::GetStartAngle() const
|
||||||
{
|
{
|
||||||
VECTOR2D d( m_p0 - m_pc );
|
VECTOR2D d( m_start - GetCenter() );
|
||||||
|
|
||||||
auto ang = 180.0 / M_PI * atan2( d.y, d.x );
|
auto ang = 180.0 / M_PI * atan2( d.y, d.x );
|
||||||
|
|
||||||
return ang;
|
return NormalizeAngleDegrees( ang, 0.0, 360.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double SHAPE_ARC::GetEndAngle() const
|
double SHAPE_ARC::GetEndAngle() const
|
||||||
{
|
{
|
||||||
double a = GetStartAngle() + m_centralAngle;
|
VECTOR2D d( m_end - GetCenter() );
|
||||||
|
|
||||||
if( a < 0.0 )
|
auto ang = 180.0 / M_PI * atan2( d.y, d.x );
|
||||||
a += 360.0;
|
|
||||||
else if ( a >= 360.0 )
|
|
||||||
a -= 360.0;
|
|
||||||
|
|
||||||
return a;
|
return NormalizeAngleDegrees( ang, 0.0, 360.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VECTOR2I SHAPE_ARC::GetCenter() const
|
||||||
|
{
|
||||||
|
return GetArcCenter( m_start, m_mid, m_end );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double SHAPE_ARC::GetCentralAngle() const
|
double SHAPE_ARC::GetCentralAngle() const
|
||||||
{
|
{
|
||||||
return m_centralAngle;
|
VECTOR2I center = GetCenter();
|
||||||
|
VECTOR2I p0 = m_start - center;
|
||||||
|
VECTOR2I p1 = m_mid - center;
|
||||||
|
VECTOR2I p2 = m_end - center;
|
||||||
|
double angle1 = ArcTangente( p1.y, p1.x ) - ArcTangente( p0.y, p0.x );
|
||||||
|
double angle2 = ArcTangente( p2.y, p2.x ) - ArcTangente( p1.y, p1.x );
|
||||||
|
|
||||||
|
return ( NormalizeAngle180( angle1 ) + NormalizeAngle180( angle2 ) ) / 10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_ARC::GetRadius() const
|
int SHAPE_ARC::GetRadius() const
|
||||||
{
|
{
|
||||||
return (m_p0 - m_pc).EuclideanNorm();
|
return ( m_start - GetCenter() ).EuclideanNorm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const SHAPE_LINE_CHAIN SHAPE_ARC::ConvertToPolyline( double aAccuracy ) const
|
const SHAPE_LINE_CHAIN SHAPE_ARC::ConvertToPolyline( double aAccuracy ) const
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN rv;
|
SHAPE_LINE_CHAIN rv;
|
||||||
double r = GetRadius();
|
double r = GetRadius();
|
||||||
double sa = GetStartAngle();
|
double sa = GetStartAngle();
|
||||||
auto c = GetCenter();
|
auto c = GetCenter();
|
||||||
|
double ca = GetCentralAngle();
|
||||||
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if( r == 0.0 )
|
if( r == 0.0 )
|
||||||
|
@ -285,7 +251,7 @@ const SHAPE_LINE_CHAIN SHAPE_ARC::ConvertToPolyline( double aAccuracy ) const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = GetArcToSegmentCount( r, aAccuracy, m_centralAngle );
|
n = GetArcToSegmentCount( r, aAccuracy, ca );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i = 0; i <= n ; i++ )
|
for( int i = 0; i <= n ; i++ )
|
||||||
|
@ -293,13 +259,59 @@ const SHAPE_LINE_CHAIN SHAPE_ARC::ConvertToPolyline( double aAccuracy ) const
|
||||||
double a = sa;
|
double a = sa;
|
||||||
|
|
||||||
if( n != 0 )
|
if( n != 0 )
|
||||||
a += m_centralAngle * (double) i / (double) n;
|
a += ( ca * i ) / n;
|
||||||
|
|
||||||
double x = c.x + r * cos( a * M_PI / 180.0 );
|
double x = c.x + r * cos( a * M_PI / 180.0 );
|
||||||
double y = c.y + r * sin( a * M_PI / 180.0 );
|
double y = c.y + r * sin( a * M_PI / 180.0 );
|
||||||
|
|
||||||
rv.Append( (int) x, (int) y );
|
rv.Append( KiROUND( x ), KiROUND( y ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHAPE_ARC::Move( const VECTOR2I& aVector )
|
||||||
|
{
|
||||||
|
m_start += aVector;
|
||||||
|
m_end += aVector;
|
||||||
|
m_mid += aVector;
|
||||||
|
update_bbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHAPE_ARC::Rotate( double aAngle, const VECTOR2I& aCenter )
|
||||||
|
{
|
||||||
|
m_start -= aCenter;
|
||||||
|
m_end -= aCenter;
|
||||||
|
m_mid -= aCenter;
|
||||||
|
|
||||||
|
m_start.Rotate( aAngle );
|
||||||
|
m_end.Rotate( aAngle );
|
||||||
|
m_mid.Rotate( aAngle );
|
||||||
|
|
||||||
|
m_start += aCenter;
|
||||||
|
m_end += aCenter;
|
||||||
|
m_mid += aCenter;
|
||||||
|
update_bbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHAPE_ARC::Mirror( bool aX, bool aY, const VECTOR2I& aVector )
|
||||||
|
{
|
||||||
|
if( aX )
|
||||||
|
{
|
||||||
|
m_start.x = -m_start.x + 2 * aVector.x;
|
||||||
|
m_end.x = -m_end.x + 2 * aVector.x;
|
||||||
|
m_mid.x = -m_mid.x + 2 * aVector.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aY )
|
||||||
|
{
|
||||||
|
m_start.y = -m_start.y + 2 * aVector.y;
|
||||||
|
m_end.y = -m_end.y + 2 * aVector.y;
|
||||||
|
m_mid.y = -m_mid.y + 2 * aVector.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_bbox();
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
|
|
||||||
ARC( const LINE& aParentLine, const SHAPE_ARC& aArc ) :
|
ARC( const LINE& aParentLine, const SHAPE_ARC& aArc ) :
|
||||||
LINKED_ITEM( ARC_T ),
|
LINKED_ITEM( ARC_T ),
|
||||||
m_arc( aArc.GetCenter(), aArc.GetP0(), aArc.GetCentralAngle(), aParentLine.Width() )
|
m_arc( aArc.GetP0(), aArc.GetArcMid(), aArc.GetP1(), aParentLine.Width() )
|
||||||
{
|
{
|
||||||
m_net = aParentLine.Net();
|
m_net = aParentLine.Net();
|
||||||
m_layers = aParentLine.Layers();
|
m_layers = aParentLine.Layers();
|
||||||
|
|
|
@ -799,9 +799,8 @@ std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( TRACK* aTrack )
|
||||||
std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( ARC* aArc )
|
std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( ARC* aArc )
|
||||||
{
|
{
|
||||||
std::unique_ptr< PNS::ARC > arc(
|
std::unique_ptr< PNS::ARC > arc(
|
||||||
new PNS::ARC( SHAPE_ARC( aArc->GetCenter(), aArc->GetStart(),
|
new PNS::ARC( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(), aArc->GetEnd(),
|
||||||
aArc->GetAngle(), aArc->GetWidth() ),
|
aArc->GetWidth() ), aArc->GetNetCode() )
|
||||||
aArc->GetNetCode() )
|
|
||||||
);
|
);
|
||||||
|
|
||||||
arc->SetLayers( LAYER_RANGE( aArc->GetLayer() ) );
|
arc->SetLayers( LAYER_RANGE( aArc->GetLayer() ) );
|
||||||
|
|
|
@ -54,9 +54,9 @@ struct ARC_PROPERTIES
|
||||||
*/
|
*/
|
||||||
static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
||||||
{
|
{
|
||||||
// Angular error - not this can get quite large for very small arcs,
|
// Angular error - note this can get quite large for very small arcs,
|
||||||
// as the integral position rounding has a relatively greater effect
|
// as the integral position rounding has a relatively greater effect
|
||||||
const double angle_tol_deg = 0.01;
|
const double angle_tol_deg = 1.0;
|
||||||
|
|
||||||
// Position error - rounding to nearest integer
|
// Position error - rounding to nearest integer
|
||||||
const int pos_tol = 1;
|
const int pos_tol = 1;
|
||||||
|
@ -67,12 +67,12 @@ static void CheckArcGeom( const SHAPE_ARC& aArc, const ARC_PROPERTIES& aProps )
|
||||||
KI_TEST::IsVecWithinTol<VECTOR2I>, ( aArc.GetP1() )( aProps.m_end_point )( pos_tol ) );
|
KI_TEST::IsVecWithinTol<VECTOR2I>, ( aArc.GetP1() )( aProps.m_end_point )( pos_tol ) );
|
||||||
BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
|
BOOST_CHECK_PREDICATE( KI_TEST::IsVecWithinTol<VECTOR2I>,
|
||||||
( aArc.GetCenter() )( aProps.m_center_point )( pos_tol ) );
|
( aArc.GetCenter() )( aProps.m_center_point )( pos_tol ) );
|
||||||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<double>,
|
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||||
( aArc.GetCentralAngle() )( aProps.m_center_angle )( angle_tol_deg ) );
|
( aArc.GetCentralAngle() )( aProps.m_center_angle )( 360.0 )( angle_tol_deg ) );
|
||||||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<double>,
|
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||||
( aArc.GetStartAngle() )( aProps.m_start_angle )( angle_tol_deg ) );
|
( aArc.GetStartAngle() )( aProps.m_start_angle )( 360.0 )( angle_tol_deg ) );
|
||||||
BOOST_CHECK_PREDICATE( KI_TEST::IsWithin<double>,
|
BOOST_CHECK_PREDICATE( KI_TEST::IsWithinWrapped<double>,
|
||||||
( aArc.GetEndAngle() )( aProps.m_end_angle )( angle_tol_deg ) );
|
( aArc.GetEndAngle() )( aProps.m_end_angle )( 360.0 )( angle_tol_deg ) );
|
||||||
BOOST_CHECK_PREDICATE(
|
BOOST_CHECK_PREDICATE(
|
||||||
KI_TEST::IsWithin<double>, ( aArc.GetRadius() )( aProps.m_radius )( pos_tol ) );
|
KI_TEST::IsWithin<double>, ( aArc.GetRadius() )( aProps.m_radius )( pos_tol ) );
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,26 @@
|
||||||
#ifndef NUMERIC__H
|
#ifndef NUMERIC__H
|
||||||
#define NUMERIC__H
|
#define NUMERIC__H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace KI_TEST
|
namespace KI_TEST
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is within a tolerance of a nominal value, wrapping to a given val
|
||||||
|
*
|
||||||
|
* @return value is in [( aNominal - aError ) % aWrap, ( aNominal + aError ) % aWrap]
|
||||||
|
*/
|
||||||
|
template <typename T> bool IsWithinWrapped( T aValue, T aNominal, T aWrap, T aError )
|
||||||
|
{
|
||||||
|
double diff = std::fmod( aNominal - aValue + aWrap / 2.0, aWrap );
|
||||||
|
|
||||||
|
if( diff < 0 )
|
||||||
|
diff += aWrap;
|
||||||
|
|
||||||
|
return diff - aWrap / 2.0 <= aError;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a value is within a tolerance of a nominal value
|
* Check if a value is within a tolerance of a nominal value
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue