Overhaul arc internal model to not over-specify information.

This commit is contained in:
Jeff Young 2021-07-17 20:56:18 +01:00
parent 8b08c9e53f
commit 9b9e379aa0
63 changed files with 1546 additions and 1107 deletions

View File

@ -689,7 +689,7 @@ void BOARD_ADAPTER::addShapeWithClearance( const PCB_SHAPE* aShape,
{ {
unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() ); unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
transformArcToSegments( aShape->GetCenter(), aShape->GetArcStart(), aShape->GetAngle(), transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
segCount, linewidth, aDstContainer, *aShape ); segCount, linewidth, aDstContainer, *aShape );
} }
break; break;

View File

@ -39,7 +39,7 @@ EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aDefaultLineWidth ) :
m_shape( aType ), m_shape( aType ),
m_width( aDefaultLineWidth ) m_width( aDefaultLineWidth )
{ {
m_angle = 0; m_arcAngle = 0;
m_filled = false; m_filled = false;
} }
@ -82,15 +82,17 @@ wxString EDA_SHAPE::SHAPE_T_asString() const
} }
void EDA_SHAPE::SetShapePos( const wxPoint& aPos ) void EDA_SHAPE::setPosition( const wxPoint& aPos )
{ {
m_start = aPos; move( aPos - getPosition() );
} }
wxPoint EDA_SHAPE::GetShapePos() const wxPoint EDA_SHAPE::getPosition() const
{ {
if( m_shape == SHAPE_T::POLY ) if( m_shape == SHAPE_T::ARC )
return getCenter();
else if( m_shape == SHAPE_T::POLY )
return (wxPoint) m_poly.CVertex( 0 ); return (wxPoint) m_poly.CVertex( 0 );
else else
return m_start; return m_start;
@ -119,10 +121,10 @@ double EDA_SHAPE::GetLength() const
return length; return length;
case SHAPE_T::ARC: case SHAPE_T::ARC:
return 2 * M_PI * GetRadius() * ( GetAngle() / 3600.0 ); return 2 * M_PI * GetRadius() * ( GetArcAngle() / 3600.0 );
default: default:
wxFAIL_MSG( "EDA_SHAPE::GetLength not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
return 0.0; return 0.0;
} }
} }
@ -130,25 +132,24 @@ double EDA_SHAPE::GetLength() const
void EDA_SHAPE::move( const wxPoint& aMoveVector ) void EDA_SHAPE::move( const wxPoint& aMoveVector )
{ {
// Move vector should not affect start/end for polygon since it will
// be applied directly to polygon outline.
if( m_shape != SHAPE_T::POLY )
{
m_start += aMoveVector;
m_end += aMoveVector;
}
switch ( m_shape ) switch ( m_shape )
{ {
case SHAPE_T::ARC:
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
m_start += aMoveVector;
m_end += aMoveVector;
m_arcCenter += aMoveVector;
break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
m_poly.Move( VECTOR2I( aMoveVector ) ); m_poly.Move( VECTOR2I( aMoveVector ) );
break; break;
case SHAPE_T::ARC:
m_thirdPoint += aMoveVector;
break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
m_start += aMoveVector;
m_end += aMoveVector;
m_bezierC1 += aMoveVector; m_bezierC1 += aMoveVector;
m_bezierC2 += aMoveVector; m_bezierC2 += aMoveVector;
@ -158,7 +159,7 @@ void EDA_SHAPE::move( const wxPoint& aMoveVector )
break; break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::ShapeMove not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
} }
@ -174,22 +175,19 @@ void EDA_SHAPE::scale( double aScale )
int radius = GetRadius(); int radius = GetRadius();
scalePt( m_start );
scalePt( m_end );
// specific parameters: // specific parameters:
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::BEZIER:
scalePt( m_bezierC1 );
scalePt( m_bezierC2 );
break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
scalePt( m_thirdPoint ); case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
scalePt( m_start );
scalePt( m_end );
scalePt( m_arcCenter );
break; break;
case SHAPE_T::CIRCLE: // ring or circle case SHAPE_T::CIRCLE: // ring or circle
scalePt( m_start );
m_end.x = m_start.x + KiROUND( radius * aScale ); m_end.x = m_start.x + KiROUND( radius * aScale );
m_end.y = m_start.y; m_end.y = m_start.y;
break; break;
@ -208,8 +206,15 @@ void EDA_SHAPE::scale( double aScale )
} }
break; break;
case SHAPE_T::BEZIER:
scalePt( m_start );
scalePt( m_end );
scalePt( m_bezierC1 );
scalePt( m_bezierC2 );
break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::ShapeScale not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
} }
@ -225,7 +230,7 @@ void EDA_SHAPE::rotate( const wxPoint& aRotCentre, double aAngle )
// these can all be done by just rotating the constituent points // these can all be done by just rotating the constituent points
RotatePoint( &m_start, aRotCentre, aAngle ); RotatePoint( &m_start, aRotCentre, aAngle );
RotatePoint( &m_end, aRotCentre, aAngle ); RotatePoint( &m_end, aRotCentre, aAngle );
RotatePoint( &m_thirdPoint, aRotCentre, aAngle ); RotatePoint( &m_arcCenter, aRotCentre, aAngle );
break; break;
case SHAPE_T::RECT: case SHAPE_T::RECT:
@ -263,7 +268,7 @@ void EDA_SHAPE::rotate( const wxPoint& aRotCentre, double aAngle )
break; break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::ShapeRotate not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
} }
@ -271,26 +276,24 @@ void EDA_SHAPE::rotate( const wxPoint& aRotCentre, double aAngle )
void EDA_SHAPE::flip( const wxPoint& aCentre, bool aFlipLeftRight ) void EDA_SHAPE::flip( const wxPoint& aCentre, bool aFlipLeftRight )
{ {
if( aFlipLeftRight )
{
m_start.x = aCentre.x - ( m_start.x - aCentre.x );
m_end.x = aCentre.x - ( m_end.x - aCentre.x );
}
else
{
m_start.y = aCentre.y - ( m_start.y - aCentre.y );
m_end.y = aCentre.y - ( m_end.y - aCentre.y );
}
switch ( m_shape ) switch ( m_shape )
{ {
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
case SHAPE_T::ARC: case SHAPE_T::ARC:
if( aFlipLeftRight ) if( aFlipLeftRight )
m_thirdPoint.x = aCentre.x - ( m_thirdPoint.x - aCentre.x ); {
m_start.x = aCentre.x - ( m_start.x - aCentre.x );
m_end.x = aCentre.x - ( m_end.x - aCentre.x );
m_arcCenter.x = aCentre.x - ( m_arcCenter.x - aCentre.x );
}
else else
m_thirdPoint.y = aCentre.y - ( m_thirdPoint.y - aCentre.y ); {
m_start.y = aCentre.y - ( m_start.y - aCentre.y );
m_angle = -m_angle; m_end.y = aCentre.y - ( m_end.y - aCentre.y );
m_arcCenter.y = aCentre.y - ( m_arcCenter.y - aCentre.y );
}
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -301,11 +304,15 @@ void EDA_SHAPE::flip( const wxPoint& aCentre, bool aFlipLeftRight )
{ {
if( aFlipLeftRight ) if( aFlipLeftRight )
{ {
m_start.x = aCentre.x - ( m_start.x - aCentre.x );
m_end.x = aCentre.x - ( m_end.x - aCentre.x );
m_bezierC1.x = aCentre.x - ( m_bezierC1.x - aCentre.x ); m_bezierC1.x = aCentre.x - ( m_bezierC1.x - aCentre.x );
m_bezierC2.x = aCentre.x - ( m_bezierC2.x - aCentre.x ); m_bezierC2.x = aCentre.x - ( m_bezierC2.x - aCentre.x );
} }
else else
{ {
m_start.y = aCentre.y - ( m_start.y - aCentre.y );
m_end.y = aCentre.y - ( m_end.y - aCentre.y );
m_bezierC1.y = aCentre.y - ( m_bezierC1.y - aCentre.y ); m_bezierC1.y = aCentre.y - ( m_bezierC1.y - aCentre.y );
m_bezierC2.y = aCentre.y - ( m_bezierC2.y - aCentre.y ); m_bezierC2.y = aCentre.y - ( m_bezierC2.y - aCentre.y );
} }
@ -317,13 +324,8 @@ void EDA_SHAPE::flip( const wxPoint& aCentre, bool aFlipLeftRight )
} }
break; break;
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::ShapeFlip not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
} }
@ -358,78 +360,59 @@ const std::vector<wxPoint> EDA_SHAPE::buildBezierToSegmentsPointsList( int aMinS
wxPoint EDA_SHAPE::getCenter() const wxPoint EDA_SHAPE::getCenter() const
{ {
wxPoint c;
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
return m_arcCenter;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
c = m_start; return m_start;
break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
// Midpoint of the line // Midpoint of the line
c = ( GetStart() + GetEnd() ) / 2; return ( m_start + m_end ) / 2;
break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
case SHAPE_T::RECT: case SHAPE_T::RECT:
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
c = getBoundingBox().Centre(); return getBoundingBox().Centre();
break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::GetCentre not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; return wxPoint();
} }
return c;
} }
wxPoint EDA_SHAPE::GetArcEnd() const void EDA_SHAPE::SetCenter( const wxPoint& aCenter )
{ {
wxPoint endPoint( m_end ); // start of arc
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
endPoint = m_thirdPoint; m_arcCenter = aCenter;
break;
case SHAPE_T::CIRCLE:
m_start = aCenter;
break; break;
default: default:
break; UNIMPLEMENTED_FOR( SHAPE_T_asString() );
} }
return endPoint; // after rotation, the end of the arc.
} }
wxPoint EDA_SHAPE::GetArcMid() const wxPoint EDA_SHAPE::GetArcMid() const
{ {
wxPoint endPoint( m_end ); wxPoint mid = m_start;
RotatePoint( &mid, m_arcCenter, -m_arcAngle / 2.0 );
switch( m_shape ) return mid;
{
case SHAPE_T::ARC:
// rotate the starting point of the arc, given by m_End, through half
// the angle m_Angle to get the middle of the arc.
// m_Start is the arc centre
endPoint = m_end; // m_End = start point of arc
RotatePoint( &endPoint, m_start, -m_angle / 2.0 );
break;
default:
break;
}
return endPoint; // after rotation, the end of the arc.
} }
double EDA_SHAPE::GetArcAngleStart() const double EDA_SHAPE::GetArcAngleStart() const
{ {
wxPoint arcStart = GetArcStart(); wxPoint arcStart = GetStart();
wxPoint center = getCenter(); wxPoint center = getCenter();
double angleStart = ArcTangente( arcStart.y - center.y, arcStart.x - center.x ); double angleStart = ArcTangente( arcStart.y - center.y, arcStart.x - center.x );
@ -441,9 +424,10 @@ double EDA_SHAPE::GetArcAngleStart() const
return angleStart; return angleStart;
} }
double EDA_SHAPE::GetArcAngleEnd() const double EDA_SHAPE::GetArcAngleEnd() const
{ {
wxPoint arcEnd = GetArcEnd(); wxPoint arcEnd = GetEnd();
wxPoint center = getCenter(); wxPoint center = getCenter();
double angleStart = ArcTangente( arcEnd.y - center.y, arcEnd.x - center.x ); double angleStart = ArcTangente( arcEnd.y - center.y, arcEnd.x - center.x );
@ -458,46 +442,60 @@ double EDA_SHAPE::GetArcAngleEnd() const
int EDA_SHAPE::GetRadius() const int EDA_SHAPE::GetRadius() const
{ {
double radius = GetLineLength( m_start, m_end ); double radius = 0.0;
// don't allow degenerate arcs switch( m_shape )
{
case SHAPE_T::ARC:
radius = GetLineLength( m_arcCenter, m_start );
break;
case SHAPE_T::CIRCLE:
radius = GetLineLength( m_start, m_end );
break;
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
}
// don't allow degenerate circles/arcs
return std::max( 1, KiROUND( radius ) ); return std::max( 1, KiROUND( radius ) );
} }
void EDA_SHAPE::SetArcGeometry( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd ) void EDA_SHAPE::SetArcGeometry( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd )
{ {
SetArcStart( aStart ); m_start = aStart;
SetArcEnd( aEnd ); m_end = aEnd;
m_arcCenter = CalcArcCenter( aStart, aMid, aEnd );
// Sadly we currently store center and angle rather than mid. So we have to calculate VECTOR2D startLine = m_start - m_arcCenter;
// those. VECTOR2D endLine = aEnd - m_arcCenter;
wxPoint center = GetArcCenter( aStart, aMid, aEnd ); bool clockwise = m_arcAngle > 0;
VECTOR2D startLine = aStart - center;
VECTOR2D endLine = aEnd - center;
bool clockwise = GetAngle() > 0;
double angle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
if( clockwise && angle < 0.0 ) m_arcAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
angle += 3600.0;
else if( !clockwise && angle > 0.0 )
angle -= 3600.0;
SetAngle( angle, false ); if( clockwise && m_arcAngle < 0.0 )
SetArcCenter( center ); m_arcAngle += 3600.0;
else if( !clockwise && m_arcAngle > 0.0 )
m_arcAngle -= 3600.0;
} }
void EDA_SHAPE::SetAngle( double aAngle, bool aUpdateEnd ) void EDA_SHAPE::SetArcAngle( double aAngle )
{ {
// m_Angle must be >= -360 and <= +360 degrees // m_Angle must be >= -360 and <= +360 degrees
m_angle = NormalizeAngle360Max( aAngle ); m_arcAngle = NormalizeAngle360Max( aAngle );
}
if( aUpdateEnd )
{ void EDA_SHAPE::SetArcAngleAndEnd( double aAngle )
m_thirdPoint = m_end; {
RotatePoint( &m_thirdPoint, m_start, -m_angle ); // m_Angle must be >= -360 and <= +360 degrees
} m_arcAngle = NormalizeAngle360Max( aAngle );
m_end = m_start;
RotatePoint( &m_end, m_arcCenter, -m_arcAngle );
} }
@ -514,17 +512,17 @@ void EDA_SHAPE::ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
aList.emplace_back( shape, _( "Circle" ) ); aList.emplace_back( shape, _( "Circle" ) );
msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) ); msg = MessageTextFromValue( units, GetLineLength( GetStart(), GetEnd() ) );
aList.emplace_back( _( "Radius" ), msg ); aList.emplace_back( _( "Radius" ), msg );
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
aList.emplace_back( shape, _( "Arc" ) ); aList.emplace_back( shape, _( "Arc" ) );
msg.Printf( wxT( "%.1f" ), m_angle / 10.0 ); msg.Printf( wxT( "%.1f" ), m_arcAngle / 10.0 );
aList.emplace_back( _( "Angle" ), msg ); aList.emplace_back( _( "Angle" ), msg );
msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) ); msg = MessageTextFromValue( units, GetLineLength( getCenter(), GetStart() ) );
aList.emplace_back( _( "Radius" ), msg ); aList.emplace_back( _( "Radius" ), msg );
break; break;
@ -545,10 +543,10 @@ void EDA_SHAPE::ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
case SHAPE_T::RECT: case SHAPE_T::RECT:
aList.emplace_back( shape, _( "Rectangle" ) ); aList.emplace_back( shape, _( "Rectangle" ) );
msg = MessageTextFromValue( units, std::abs( m_end.x - m_start.x ) ); msg = MessageTextFromValue( units, std::abs( GetEnd().x - GetStart().x ) );
aList.emplace_back( _( "Width" ), msg ); aList.emplace_back( _( "Width" ), msg );
msg = MessageTextFromValue( units, std::abs( m_end.y - m_start.y ) ); msg = MessageTextFromValue( units, std::abs( GetEnd().y - GetStart().y ) );
aList.emplace_back( _( "Height" ), msg ); aList.emplace_back( _( "Height" ), msg );
break; break;
@ -556,12 +554,12 @@ void EDA_SHAPE::ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
{ {
aList.emplace_back( shape, _( "Segment" ) ); aList.emplace_back( shape, _( "Segment" ) );
msg = MessageTextFromValue( units, GetLineLength( m_start, m_end ) ); msg = MessageTextFromValue( units, GetLineLength( GetStart(), GetEnd() ) );
aList.emplace_back( _( "Length" ), msg ); aList.emplace_back( _( "Length" ), msg );
// angle counter-clockwise from 3'o-clock // angle counter-clockwise from 3'o-clock
const double deg = RAD2DEG( atan2( (double)( m_start.y - m_end.y ), const double deg = RAD2DEG( atan2( (double)( GetStart().y - GetEnd().y ),
(double)( m_end.x - m_start.x ) ) ); (double)( GetEnd().x - GetStart().x ) ) );
aList.emplace_back( _( "Angle" ), wxString::Format( "%.1f", deg ) ); aList.emplace_back( _( "Angle" ), wxString::Format( "%.1f", deg ) );
} }
break; break;
@ -579,23 +577,21 @@ const EDA_RECT EDA_SHAPE::getBoundingBox() const
{ {
EDA_RECT bbox; EDA_RECT bbox;
bbox.SetOrigin( m_start );
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::RECT: case SHAPE_T::RECT:
bbox = EDA_RECT(); // re-init for merging
for( wxPoint& pt : GetRectCorners() ) for( wxPoint& pt : GetRectCorners() )
bbox.Merge( pt ); bbox.Merge( pt );
break; break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
bbox.SetEnd( m_end ); bbox.SetOrigin( GetStart() );
bbox.SetEnd( GetEnd() );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
bbox.SetOrigin( GetStart() );
bbox.Inflate( GetRadius() ); bbox.Inflate( GetRadius() );
break; break;
@ -607,8 +603,6 @@ const EDA_RECT EDA_SHAPE::getBoundingBox() const
if( m_poly.IsEmpty() ) if( m_poly.IsEmpty() )
break; break;
bbox = EDA_RECT(); // re-init for merging
for( auto iter = m_poly.CIterate(); iter; iter++ ) for( auto iter = m_poly.CIterate(); iter; iter++ )
{ {
wxPoint pt( iter->x, iter->y ); wxPoint pt( iter->x, iter->y );
@ -622,13 +616,14 @@ const EDA_RECT EDA_SHAPE::getBoundingBox() const
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
bbox.Merge( m_bezierC1 ); bbox.SetOrigin( GetStart() );
bbox.Merge( m_bezierC2 ); bbox.Merge( GetBezierC1() );
bbox.Merge( m_end ); bbox.Merge( GetBezierC2() );
bbox.Merge( GetEnd() );
break; break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::getBoundingBox not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
@ -682,10 +677,10 @@ bool EDA_SHAPE::hitTest( const wxPoint& aPosition, int aAccuracy ) const
// Check angle: inside the arc angle when it is > 0 and outside the not drawn arc when // Check angle: inside the arc angle when it is > 0 and outside the not drawn arc when
// it is < 0 // it is < 0
if( GetAngle() >= 0.0 ) if( GetArcAngle() >= 0.0 )
return arc_hittest <= GetAngle(); return arc_hittest <= GetArcAngle();
else else
return arc_hittest >= ( 3600.0 + GetAngle() ); return arc_hittest >= ( 3600.0 + GetArcAngle() );
} }
else else
{ {
@ -705,7 +700,7 @@ bool EDA_SHAPE::hitTest( const wxPoint& aPosition, int aAccuracy ) const
return false; return false;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
return TestSegmentHit( aPosition, m_start, m_end, maxdist ); return TestSegmentHit( aPosition, GetStart(), GetEnd(), maxdist );
case SHAPE_T::RECT: case SHAPE_T::RECT:
if( IsFilled() ) // Filled rect hit-test if( IsFilled() ) // Filled rect hit-test
@ -903,7 +898,7 @@ bool EDA_SHAPE::hitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy )
} }
default: default:
wxFAIL_MSG( "EDA_SHAPE::hitTest(rect) not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
return false; return false;
} }
} }
@ -949,11 +944,8 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
{ {
// Do not include the center, which is not necessarily // Do not include the center, which is not necessarily
// inside the BB of a arc with a small angle // inside the BB of a arc with a small angle
aBBox.SetOrigin( m_end ); aBBox.SetOrigin( m_start );
aBBox.Merge( m_end );
wxPoint end = m_end;
RotatePoint( &end, m_start, -m_angle );
aBBox.Merge( end );
// Determine the starting quarter // Determine the starting quarter
// 0 right-bottom // 0 right-bottom
@ -962,24 +954,24 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
// 3 right-top // 3 right-top
unsigned int quarter = 0; // assume right-bottom unsigned int quarter = 0; // assume right-bottom
if( m_end.x < m_start.x ) if( m_start.x < m_arcCenter.x )
{ {
if( m_end.y <= m_start.y ) if( m_start.y <= m_arcCenter.y )
quarter = 2; quarter = 2;
else // ( m_End.y > m_Start.y ) else // ( m_start.y > m_arcCenter.y )
quarter = 1; quarter = 1;
} }
else if( m_end.x >= m_start.x ) else if( m_start.x >= m_arcCenter.x )
{ {
if( m_end.y < m_start.y ) if( m_start.y < m_arcCenter.y )
quarter = 3; quarter = 3;
else if( m_end.x == m_start.x ) else if( m_start.x == m_arcCenter.x )
quarter = 1; quarter = 1;
} }
int radius = GetRadius(); int radius = GetRadius();
int angle = (int) GetArcAngleStart() % 900 + m_angle; int angle = (int) GetArcAngleStart() % 900 + m_arcAngle;
bool directionCW = ( m_angle > 0 ); // Is the direction of arc clockwise? bool directionCW = ( m_arcAngle > 0 ); // Is the direction of arc clockwise?
// Make the angle positive, so we go clockwise and merge points belonging to the arc // Make the angle positive, so we go clockwise and merge points belonging to the arc
if( !directionCW ) if( !directionCW )
@ -992,10 +984,10 @@ void EDA_SHAPE::computeArcBBox( EDA_RECT& aBBox ) const
{ {
switch( quarter ) switch( quarter )
{ {
case 0: aBBox.Merge( wxPoint( m_start.x, m_start.y + radius ) ); break; // down case 0: aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y + radius ) ); break; // down
case 1: aBBox.Merge( wxPoint( m_start.x - radius, m_start.y ) ); break; // left case 1: aBBox.Merge( wxPoint( m_arcCenter.x - radius, m_arcCenter.y ) ); break; // left
case 2: aBBox.Merge( wxPoint( m_start.x, m_start.y - radius ) ); break; // up case 2: aBBox.Merge( wxPoint( m_arcCenter.x, m_arcCenter.y - radius ) ); break; // up
case 3: aBBox.Merge( wxPoint( m_start.x + radius, m_start.y ) ); break; // right case 3: aBBox.Merge( wxPoint( m_arcCenter.x + radius, m_arcCenter.y ) ); break; // right
} }
if( directionCW ) if( directionCW )
@ -1030,12 +1022,12 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes() const
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
effectiveShapes.emplace_back( new SHAPE_ARC( getCenter(), GetArcStart(), effectiveShapes.emplace_back( new SHAPE_ARC( m_arcCenter, m_start, m_arcAngle / 10.0,
GetAngle() / 10.0, m_width ) ); m_width ) );
break; break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
effectiveShapes.emplace_back( new SHAPE_SEGMENT( GetStart(), GetEnd(), m_width ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( m_start, m_end, m_width ) );
break; break;
case SHAPE_T::RECT: case SHAPE_T::RECT:
@ -1068,8 +1060,8 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes() const
for( int i = 0; i < l.SegmentCount(); i++ ) for( int i = 0; i < l.SegmentCount(); i++ )
{ {
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A, effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ).A, l.Segment( i ).B,
l.Segment( i ).B, m_width ) ); m_width ) );
} }
} }
@ -1110,7 +1102,7 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes() const
break; break;
default: default:
wxFAIL_MSG( "EDA_SHAPE::MakeEffectiveShapes not implemented for " + SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );
break; break;
} }
@ -1166,9 +1158,9 @@ void EDA_SHAPE::SwapShape( EDA_SHAPE* aImage )
std::swap( m_width, image->m_width ); std::swap( m_width, image->m_width );
std::swap( m_start, image->m_start ); std::swap( m_start, image->m_start );
std::swap( m_end, image->m_end ); std::swap( m_end, image->m_end );
std::swap( m_thirdPoint, image->m_thirdPoint ); std::swap( m_arcCenter, image->m_arcCenter );
std::swap( m_shape, image->m_shape ); std::swap( m_shape, image->m_shape );
std::swap( m_angle, image->m_angle ); std::swap( m_arcAngle, image->m_arcAngle );
std::swap( m_bezierC1, image->m_bezierC1 ); std::swap( m_bezierC1, image->m_bezierC1 );
std::swap( m_bezierC2, image->m_bezierC2 ); std::swap( m_bezierC2, image->m_bezierC2 );
std::swap( m_bezierPoints, image->m_bezierPoints ); std::swap( m_bezierPoints, image->m_bezierPoints );
@ -1184,11 +1176,11 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
TEST_PT( m_start, aOther->m_start ); TEST_PT( m_start, aOther->m_start );
TEST_PT( m_end, aOther->m_end ); TEST_PT( m_end, aOther->m_end );
TEST( (int) m_shape, (int) aOther->m_shape ); TEST( m_shape, aOther->m_shape );
if( m_shape == SHAPE_T::ARC ) if( m_shape == SHAPE_T::ARC )
{ {
TEST_PT( m_thirdPoint, aOther->m_thirdPoint ); TEST_PT( m_arcCenter, aOther->m_arcCenter );
} }
else if( m_shape == SHAPE_T::BEZIER ) else if( m_shape == SHAPE_T::BEZIER )
{ {
@ -1198,11 +1190,14 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
else if( m_shape == SHAPE_T::POLY ) else if( m_shape == SHAPE_T::POLY )
{ {
TEST( m_poly.TotalVertices(), aOther->m_poly.TotalVertices() ); TEST( m_poly.TotalVertices(), aOther->m_poly.TotalVertices() );
for( int ii = 0; ii < m_poly.TotalVertices(); ++ii )
TEST_PT( m_poly.CVertex( ii ), aOther->m_poly.CVertex( ii ) );
} }
for( size_t ii = 0; ii < m_bezierPoints.size(); ++ii )
TEST_PT( m_bezierPoints[ii], aOther->m_bezierPoints[ii] );
for( int ii = 0; ii < m_poly.TotalVertices(); ++ii )
TEST_PT( m_poly.CVertex( ii ), aOther->m_poly.CVertex( ii ) );
TEST( m_width, aOther->m_width ); TEST( m_width, aOther->m_width );
return 0; return 0;

View File

@ -138,33 +138,44 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
case PCB_FP_SHAPE_T: case PCB_FP_SHAPE_T:
{ {
const FP_SHAPE* segment = static_cast<const FP_SHAPE*>( aItem ); const FP_SHAPE* shape = static_cast<const FP_SHAPE*>( aItem );
ret = hash_board_item( segment, aFlags ); ret = hash_board_item( shape, aFlags );
hash_combine( ret, segment->GetShape() ); hash_combine( ret, shape->GetShape() );
hash_combine( ret, segment->GetWidth() ); hash_combine( ret, shape->GetWidth() );
hash_combine( ret, segment->IsFilled() ); hash_combine( ret, shape->IsFilled() );
hash_combine( ret, segment->GetRadius() ); hash_combine( ret, shape->GetRadius() );
if( aFlags & HASH_POS ) if( aFlags & HASH_POS )
{ {
if( aFlags & REL_COORD ) if( aFlags & REL_COORD )
{ {
hash_combine( ret, segment->GetStart0().x ); hash_combine( ret, shape->GetStart0().x );
hash_combine( ret, segment->GetStart0().y ); hash_combine( ret, shape->GetStart0().y );
hash_combine( ret, segment->GetEnd0().x ); hash_combine( ret, shape->GetEnd0().x );
hash_combine( ret, segment->GetEnd0().y ); hash_combine( ret, shape->GetEnd0().y );
if( shape->GetShape() == SHAPE_T::ARC )
{
hash_combine( ret, shape->GetCenter0().x );
hash_combine( ret, shape->GetCenter0().y );
hash_combine( ret, shape->GetArcAngle() );
}
} }
else else
{ {
hash_combine( ret, segment->GetStart().x ); hash_combine( ret, shape->GetStart().x );
hash_combine( ret, segment->GetStart().y ); hash_combine( ret, shape->GetStart().y );
hash_combine( ret, segment->GetEnd().x ); hash_combine( ret, shape->GetEnd().x );
hash_combine( ret, segment->GetEnd().y ); hash_combine( ret, shape->GetEnd().y );
if( shape->GetShape() == SHAPE_T::ARC )
{
hash_combine( ret, shape->GetCenter().x );
hash_combine( ret, shape->GetCenter().y );
hash_combine( ret, shape->GetArcAngle() );
}
} }
} }
if( aFlags & HASH_ROT )
hash_combine( ret, segment->GetAngle() );
} }
break; break;

View File

@ -46,9 +46,6 @@ static inline wxPoint twoPointVector( const wxPoint &startPoint, const wxPoint &
LIB_ARC::LIB_ARC( LIB_SYMBOL* aParent ) : LIB_ITEM( LIB_ARC_T, aParent ) LIB_ARC::LIB_ARC( LIB_SYMBOL* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
{ {
m_Radius = 0;
m_t1 = 0;
m_t2 = 0;
m_Width = 0; m_Width = 0;
m_fill = FILL_TYPE::NO_FILL; m_fill = FILL_TYPE::NO_FILL;
m_isFillable = true; m_isFillable = true;
@ -56,6 +53,12 @@ LIB_ARC::LIB_ARC( LIB_SYMBOL* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
} }
int LIB_ARC::GetRadius() const
{
return KiROUND( GetLineLength( GetCenter(), GetStart() ) );
}
bool LIB_ARC::HitTest( const wxPoint& aRefPoint, int aAccuracy ) const bool LIB_ARC::HitTest( const wxPoint& aRefPoint, int aAccuracy ) const
{ {
int mindist = std::max( aAccuracy + GetPenWidth() / 2, int mindist = std::max( aAccuracy + GetPenWidth() / 2,
@ -66,7 +69,7 @@ bool LIB_ARC::HitTest( const wxPoint& aRefPoint, int aAccuracy ) const
int distance = KiROUND( GetLineLength( m_Pos, relativePosition ) ); int distance = KiROUND( GetLineLength( m_Pos, relativePosition ) );
if( abs( distance - m_Radius ) > mindist ) if( abs( distance - GetRadius() ) > mindist )
return false; return false;
// We are on the circle, ensure we are only on the arc, i.e. between // We are on the circle, ensure we are only on the arc, i.e. between
@ -147,12 +150,6 @@ int LIB_ARC::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFl
if( m_Pos.y != tmp->m_Pos.y ) if( m_Pos.y != tmp->m_Pos.y )
return m_Pos.y - tmp->m_Pos.y; return m_Pos.y - tmp->m_Pos.y;
if( m_t1 != tmp->m_t1 )
return m_t1 - tmp->m_t1;
if( m_t2 != tmp->m_t2 )
return m_t2 - tmp->m_t2;
return 0; return 0;
} }
@ -186,20 +183,6 @@ void LIB_ARC::MirrorHorizontal( const wxPoint& aCenter )
m_ArcEnd.x *= -1; m_ArcEnd.x *= -1;
m_ArcEnd.x += aCenter.x; m_ArcEnd.x += aCenter.x;
std::swap( m_ArcStart, m_ArcEnd ); std::swap( m_ArcStart, m_ArcEnd );
std::swap( m_t1, m_t2 );
m_t1 = 1800 - m_t1;
m_t2 = 1800 - m_t2;
if( m_t1 > 3600 || m_t2 > 3600 )
{
m_t1 -= 3600;
m_t2 -= 3600;
}
else if( m_t1 < -3600 || m_t2 < -3600 )
{
m_t1 += 3600;
m_t2 += 3600;
}
} }
@ -215,20 +198,6 @@ void LIB_ARC::MirrorVertical( const wxPoint& aCenter )
m_ArcEnd.y *= -1; m_ArcEnd.y *= -1;
m_ArcEnd.y += aCenter.y; m_ArcEnd.y += aCenter.y;
std::swap( m_ArcStart, m_ArcEnd ); std::swap( m_ArcStart, m_ArcEnd );
std::swap( m_t1, m_t2 );
m_t1 = - m_t1;
m_t2 = - m_t2;
if( m_t1 > 3600 || m_t2 > 3600 )
{
m_t1 -= 3600;
m_t2 -= 3600;
}
else if( m_t1 < -3600 || m_t2 < -3600 )
{
m_t1 += 3600;
m_t2 += 3600;
}
} }
@ -238,19 +207,6 @@ void LIB_ARC::Rotate( const wxPoint& aCenter, bool aRotateCCW )
RotatePoint( &m_Pos, aCenter, rot_angle ); RotatePoint( &m_Pos, aCenter, rot_angle );
RotatePoint( &m_ArcStart, aCenter, rot_angle ); RotatePoint( &m_ArcStart, aCenter, rot_angle );
RotatePoint( &m_ArcEnd, aCenter, rot_angle ); RotatePoint( &m_ArcEnd, aCenter, rot_angle );
m_t1 -= rot_angle;
m_t2 -= rot_angle;
if( m_t1 > 3600 || m_t2 > 3600 )
{
m_t1 -= 3600;
m_t2 -= 3600;
}
else if( m_t1 < -3600 || m_t2 < -3600 )
{
m_t1 += 3600;
m_t2 += 3600;
}
} }
@ -259,27 +215,30 @@ void LIB_ARC::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
{ {
wxASSERT( aPlotter != nullptr ); wxASSERT( aPlotter != nullptr );
int t1 = m_t1; wxPoint center = aTransform.TransformCoordinate( GetCenter() ) + aOffset;
int t2 = m_t2; int startAngle;
wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; int endAngle;
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() );
FILL_TYPE fill = aFill ? m_fill : FILL_TYPE::NO_FILL;
aTransform.MapAngles( &t1, &t2 ); CalcAngles( startAngle, endAngle );
aTransform.MapAngles( &startAngle, &endAngle );
if( aFill && m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) if( fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR )
{ {
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) );
aPlotter->Arc( pos, -t2, -t1, m_Radius, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 ); aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, 0 );
if( pen_size <= 0 )
return;
else
fill = FILL_TYPE::NO_FILL;
} }
bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR; pen_size = std::max( pen_size, aPlotter->RenderSettings()->GetMinPenWidth() );
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() );
if( !already_filled || pen_size > 0 ) aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
{ aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, pen_size );
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
aPlotter->Arc( pos, -t2, -t1, m_Radius, already_filled ? FILL_TYPE::NO_FILL : m_fill,
pen_size );
}
} }
@ -305,15 +264,12 @@ void LIB_ARC::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, v
pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset; pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset;
pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset; pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset;
posc = aTransform.TransformCoordinate( m_Pos ) + aOffset; posc = aTransform.TransformCoordinate( m_Pos ) + aOffset;
int pt1 = m_t1;
int pt2 = m_t2;
bool swap = aTransform.MapAngles( &pt1, &pt2 );
if( swap ) int t1;
{ int t2;
std::swap( pos1.x, pos2.x );
std::swap( pos1.y, pos2.y ); CalcAngles( t1, t2 );
} aTransform.MapAngles( &t1, &t2 );
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) if( forceNoFill || m_fill == FILL_TYPE::NO_FILL )
{ {
@ -324,33 +280,29 @@ void LIB_ARC::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, v
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR )
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND );
GRFilledArc( nullptr, DC, posc.x, posc.y, pt1, pt2, m_Radius, penWidth, color, color ); GRFilledArc( nullptr, DC, posc.x, posc.y, t1, t2, GetRadius(), penWidth, color, color );
} }
} }
const EDA_RECT LIB_ARC::GetBoundingBox() const const EDA_RECT LIB_ARC::GetBoundingBox() const
{ {
int radius = GetRadius();
int minX, minY, maxX, maxY, angleStart, angleEnd; int minX, minY, maxX, maxY, angleStart, angleEnd;
EDA_RECT rect; EDA_RECT rect;
wxPoint nullPoint, startPos, endPos, centerPos; wxPoint nullPoint, startPos, endPos, centerPos;
wxPoint normStart = m_ArcStart - m_Pos; wxPoint normStart = m_ArcStart - m_Pos;
wxPoint normEnd = m_ArcEnd - m_Pos; wxPoint normEnd = m_ArcEnd - m_Pos;
if( ( normStart == nullPoint ) || ( normEnd == nullPoint ) || ( m_Radius == 0 ) ) if( normStart == nullPoint || normEnd == nullPoint || radius == 0 )
return rect; return rect;
endPos = DefaultTransform.TransformCoordinate( m_ArcEnd ); endPos = DefaultTransform.TransformCoordinate( m_ArcEnd );
startPos = DefaultTransform.TransformCoordinate( m_ArcStart ); startPos = DefaultTransform.TransformCoordinate( m_ArcStart );
centerPos = DefaultTransform.TransformCoordinate( m_Pos ); centerPos = DefaultTransform.TransformCoordinate( m_Pos );
angleStart = m_t1;
angleEnd = m_t2;
if( DefaultTransform.MapAngles( &angleStart, &angleEnd ) ) CalcAngles( angleStart, angleEnd );
{ DefaultTransform.MapAngles( &angleStart, &angleEnd );
std::swap( endPos.x, startPos.x );
std::swap( endPos.y, startPos.y );
}
/* Start with the start and end point of the arc. */ /* Start with the start and end point of the arc. */
minX = std::min( startPos.x, endPos.x ); minX = std::min( startPos.x, endPos.x );
@ -360,23 +312,23 @@ const EDA_RECT LIB_ARC::GetBoundingBox() const
/* Zero degrees is a special case. */ /* Zero degrees is a special case. */
if( angleStart == 0 ) if( angleStart == 0 )
maxX = centerPos.x + m_Radius; maxX = centerPos.x + radius;
/* Arc end angle wrapped passed 360. */ /* Arc end angle wrapped passed 360. */
if( angleStart > angleEnd ) if( angleStart > angleEnd )
angleEnd += 3600; angleEnd += 3600;
if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */ if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */
maxY = centerPos.y + m_Radius; maxY = centerPos.y + radius;
if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */ if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */
minX = centerPos.x - m_Radius; minX = centerPos.x - radius;
if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */ if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */
minY = centerPos.y - m_Radius; minY = centerPos.y - radius;
if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */ if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */
maxX = centerPos.x + m_Radius; maxX = centerPos.x + radius;
rect.SetOrigin( minX, minY ); rect.SetOrigin( minX, minY );
rect.SetEnd( maxX, maxY ); rect.SetEnd( maxX, maxY );
@ -407,7 +359,7 @@ void LIB_ARC::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITE
wxString LIB_ARC::GetSelectMenuText( EDA_UNITS aUnits ) const wxString LIB_ARC::GetSelectMenuText( EDA_UNITS aUnits ) const
{ {
return wxString::Format( _( "Arc, radius %s" ), return wxString::Format( _( "Arc, radius %s" ),
MessageTextFromValue( aUnits, m_Radius ) ); MessageTextFromValue( aUnits, GetRadius() ) );
} }
@ -428,6 +380,8 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
{ {
#define sq( x ) pow( x, 2 ) #define sq( x ) pow( x, 2 )
int radius = GetRadius();
// Edit state 0: drawing: place ArcStart // Edit state 0: drawing: place ArcStart
// Edit state 1: drawing: place ArcEnd (center calculated for 90-degree subtended angle) // Edit state 1: drawing: place ArcEnd (center calculated for 90-degree subtended angle)
// Edit state 2: point editing: move ArcStart (center calculated for invariant subtended angle) // Edit state 2: point editing: move ArcStart (center calculated for invariant subtended angle)
@ -440,14 +394,12 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
m_ArcStart = aPosition; m_ArcStart = aPosition;
m_ArcEnd = aPosition; m_ArcEnd = aPosition;
m_Pos = aPosition; m_Pos = aPosition;
m_Radius = 0; radius = 0;
m_t1 = 0;
m_t2 = 0;
return; return;
case 1: case 1:
m_ArcEnd = aPosition; m_ArcEnd = aPosition;
m_Radius = KiROUND( sqrt( pow( GetLineLength( m_ArcStart, m_ArcEnd ), 2 ) / 2.0 ) ); radius = KiROUND( sqrt( sq( GetLineLength( m_ArcStart, m_ArcEnd ) ) / 2.0 ) );
break; break;
case 2: case 2:
@ -465,10 +417,10 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
double chordAfter = sq( v.x ) + sq( v.y ); double chordAfter = sq( v.x ) + sq( v.y );
double ratio = chordAfter / chordBefore; double ratio = chordAfter / chordBefore;
if( ratio > 0 ) if( ratio != 0 )
{ {
m_Radius = int( sqrt( m_Radius * m_Radius * ratio ) ) + 1; radius = std::max( int( sqrt( sq( radius ) * ratio ) ) + 1,
m_Radius = std::max( m_Radius, int( sqrt( chordAfter ) / 2 ) + 1 ); int( sqrt( chordAfter ) / 2 ) + 1 );
} }
break; break;
@ -478,7 +430,7 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
{ {
double chordA = GetLineLength( m_ArcStart, aPosition ); double chordA = GetLineLength( m_ArcStart, aPosition );
double chordB = GetLineLength( m_ArcEnd, aPosition ); double chordB = GetLineLength( m_ArcEnd, aPosition );
m_Radius = int( ( chordA + chordB ) / 2.0 ) + 1; radius = int( ( chordA + chordB ) / 2.0 ) + 1;
break; break;
} }
} }
@ -491,8 +443,8 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
// Calculate 'd', the vector from the chord midpoint to the center // Calculate 'd', the vector from the chord midpoint to the center
wxPoint d; wxPoint d;
d.x = KiROUND( sqrt( sq( m_Radius ) - sq( l/2 ) ) * ( m_ArcStart.y - m_ArcEnd.y ) / l ); d.x = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_ArcStart.y - m_ArcEnd.y ) / l );
d.y = KiROUND( sqrt( sq( m_Radius ) - sq( l/2 ) ) * ( m_ArcEnd.x - m_ArcStart.x ) / l ); d.y = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_ArcEnd.x - m_ArcStart.x ) / l );
wxPoint c1 = m + d; wxPoint c1 = m + d;
wxPoint c2 = m - d; wxPoint c2 = m - d;
@ -525,63 +477,65 @@ void LIB_ARC::CalcEdit( const wxPoint& aPosition )
m_Pos = ( GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ) ? c1 : c2; m_Pos = ( GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ) ? c1 : c2;
break; break;
} }
CalcRadiusAngles();
} }
void LIB_ARC::CalcRadiusAngles() void LIB_ARC::CalcAngles( int& aStartAngle, int& aEndAngle ) const
{ {
wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart ); wxPoint centerStartVector = twoPointVector( GetCenter(), GetStart() );
wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd ); wxPoint centerEndVector = twoPointVector( GetCenter(), GetEnd() );
m_Radius = KiROUND( EuclideanNorm( centerStartVector ) );
// Angles in Eeschema are still integers // Angles in Eeschema are still integers
m_t1 = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) ); aStartAngle = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) );
m_t2 = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) ); aEndAngle = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) );
NORMALIZE_ANGLE_POS( m_t1 ); NORMALIZE_ANGLE_POS( aStartAngle );
NORMALIZE_ANGLE_POS( m_t2 ); // angles = 0 .. 3600 NORMALIZE_ANGLE_POS( aEndAngle ); // angles = 0 .. 3600
// Restrict angle to less than 180 to avoid PBS display mirror Trace because it is // Restrict angle to less than 180 to avoid PBS display mirror Trace because it is
// assumed that the arc is less than 180 deg to find orientation after rotate or mirror. // assumed that the arc is less than 180 deg to find orientation after rotate or mirror.
if( ( m_t2 - m_t1 ) > 1800 ) if( ( aEndAngle - aStartAngle ) > 1800 )
m_t2 -= 3600; aEndAngle -= 3600;
else if( ( m_t2 - m_t1 ) <= -1800 ) else if( ( aEndAngle - aStartAngle ) <= -1800 )
m_t2 += 3600; aEndAngle += 3600;
while( ( m_t2 - m_t1 ) >= 1800 ) while( ( aEndAngle - aStartAngle ) >= 1800 )
{ {
m_t2--; aEndAngle--;
m_t1++; aStartAngle++;
} }
while( ( m_t1 - m_t2 ) >= 1800 ) while( ( aStartAngle - aEndAngle ) >= 1800 )
{ {
m_t2++; aEndAngle++;
m_t1--; aStartAngle--;
} }
NORMALIZE_ANGLE_POS( m_t1 ); NORMALIZE_ANGLE_POS( aStartAngle );
if( !IsMoving() ) if( !IsMoving() )
NORMALIZE_ANGLE_POS( m_t2 ); NORMALIZE_ANGLE_POS( aEndAngle );
} }
VECTOR2I LIB_ARC::CalcMidPoint() const VECTOR2I LIB_ARC::CalcMidPoint() const
{ {
VECTOR2D midPoint; VECTOR2D midPoint;
double startAngle = static_cast<double>( m_t1 ) / 10.0; int radius = GetRadius();
double endAngle = static_cast<double>( m_t2 ) / 10.0; int t1;
int t2;
CalcAngles( t1, t2 );
double startAngle = static_cast<double>( t1 ) / 10.0;
double endAngle = static_cast<double>( t2 ) / 10.0;
if( endAngle < startAngle ) if( endAngle < startAngle )
endAngle -= 360.0; endAngle -= 360.0;
double midPointAngle = ( ( endAngle - startAngle ) / 2.0 ) + startAngle; double midPointAngle = ( ( endAngle - startAngle ) / 2.0 ) + startAngle;
double x = cos( DEG2RAD( midPointAngle ) ) * m_Radius; double x = cos( DEG2RAD( midPointAngle ) ) * radius;
double y = sin( DEG2RAD( midPointAngle ) ) * m_Radius; double y = sin( DEG2RAD( midPointAngle ) ) * radius;
midPoint.x = KiROUND( x ) + m_Pos.x; midPoint.x = KiROUND( x ) + m_Pos.x;
midPoint.y = KiROUND( y ) + m_Pos.y; midPoint.y = KiROUND( y ) + m_Pos.y;
@ -589,15 +543,3 @@ VECTOR2I LIB_ARC::CalcMidPoint() const
return midPoint; return midPoint;
} }
void LIB_ARC::CalcEndPoints()
{
double startAngle = DEG2RAD( static_cast<double>( m_t1 ) / 10.0 );
double endAngle = DEG2RAD( static_cast<double>( m_t2 ) / 10.0 );
m_ArcStart.x = KiROUND( cos( startAngle ) * m_Radius ) + m_Pos.x;
m_ArcStart.y = KiROUND( sin( startAngle ) * m_Radius ) + m_Pos.y;
m_ArcEnd.x = KiROUND( cos( endAngle ) * m_Radius ) + m_Pos.x;
m_ArcEnd.y = KiROUND( sin( endAngle ) * m_Radius ) + m_Pos.y;
}

View File

@ -80,14 +80,7 @@ public:
int GetWidth() const override { return m_Width; } int GetWidth() const override { return m_Width; }
void SetWidth( int aWidth ) override { m_Width = aWidth; } void SetWidth( int aWidth ) override { m_Width = aWidth; }
void SetRadius( int aRadius ) { m_Radius = aRadius; } int GetRadius() const;
int GetRadius() const { return m_Radius; }
void SetFirstRadiusAngle( int aAngle ) { m_t1 = aAngle; }
int GetFirstRadiusAngle() const { return m_t1; }
void SetSecondRadiusAngle( int aAngle ) { m_t2 = aAngle; }
int GetSecondRadiusAngle() const { return m_t2; }
wxPoint GetStart() const { return m_ArcStart; } wxPoint GetStart() const { return m_ArcStart; }
void SetStart( const wxPoint& aPoint ) { m_ArcStart = aPoint; } void SetStart( const wxPoint& aPoint ) { m_ArcStart = aPoint; }
@ -95,6 +88,10 @@ public:
wxPoint GetEnd() const { return m_ArcEnd; } wxPoint GetEnd() const { return m_ArcEnd; }
void SetEnd( const wxPoint& aPoint ) { m_ArcEnd = aPoint; } void SetEnd( const wxPoint& aPoint ) { m_ArcEnd = aPoint; }
wxPoint GetCenter() const { return m_Pos; }
void SetCenter( const wxPoint& aPoint ) { m_Pos = aPoint; }
/** /**
* Calculate the arc mid point using the arc start and end angles and radius length. * Calculate the arc mid point using the arc start and end angles and radius length.
* *
@ -106,14 +103,9 @@ public:
VECTOR2I CalcMidPoint() const; VECTOR2I CalcMidPoint() const;
/** /**
* Calculate the start and end points using the center point and the two angles. * Calculate the start and end angles of an arc using the start, end, and center points.
*/ */
void CalcEndPoints(); void CalcAngles( int& aStartAngle, int& aEndAngle ) const;
/**
* Calculate the radius and angle of an arc using the start, end, and center points.
*/
void CalcRadiusAngles();
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
@ -145,9 +137,6 @@ private:
ARC_STATUS_OUTLINE, ARC_STATUS_OUTLINE,
}; };
int m_Radius;
int m_t1; // First radius angle of the arc in 0.1 degrees.
int m_t2; /* Second radius angle of the arc in 0.1 degrees. */
wxPoint m_ArcStart; wxPoint m_ArcStart;
wxPoint m_ArcEnd; /* Arc end position. */ wxPoint m_ArcEnd; /* Arc end position. */
wxPoint m_Pos; /* Radius center point. */ wxPoint m_Pos; /* Radius center point. */

570
eeschema/lib_shape.cpp Normal file
View File

@ -0,0 +1,570 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <sch_draw_panel.h>
#include <plotter.h>
#include <base_units.h>
#include <widgets/msgpanel.h>
#include <bitmaps.h>
#include <eda_draw_frame.h>
#include <general.h>
#include <lib_shape.h>
LIB_SHAPE::LIB_SHAPE( LIB_SYMBOL* aParent, SHAPE_T aShape, int aDefaultLineWidth,
FILL_T aFillType ) :
LIB_ITEM( LIB_SHAPE_T, aParent ),
EDA_SHAPE( aShape, aDefaultLineWidth, aFillType )
{
}
bool LIB_SHAPE::HitTest( const wxPoint& aPosRef, int aAccuracy ) const
{
if( aAccuracy < Mils2iu( MINIMUM_SELECTION_DISTANCE ) )
aAccuracy = Mils2iu( MINIMUM_SELECTION_DISTANCE );
return hitTest( DefaultTransform.TransformCoordinate( aPosRef ), aAccuracy );
}
bool LIB_SHAPE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) )
return false;
return hitTest( aRect, aContained, aAccuracy );
}
EDA_ITEM* LIB_SHAPE::Clone() const
{
return new LIB_SHAPE( *this );
}
int LIB_SHAPE::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const
{
int retv = LIB_ITEM::compare( aOther, aCompareFlags );
if( retv )
return retv;
return EDA_SHAPE::Compare( &static_cast<const LIB_SHAPE&>( aOther ) );
}
void LIB_SHAPE::Offset( const wxPoint& aOffset )
{
move( aOffset );
}
void LIB_SHAPE::MoveTo( const wxPoint& aPosition )
{
setPosition( aPosition );
}
void LIB_SHAPE::MirrorHorizontal( const wxPoint& aCenter )
{
flip( aCenter, true );
}
void LIB_SHAPE::MirrorVertical( const wxPoint& aCenter )
{
flip( aCenter, false );
}
void LIB_SHAPE::Rotate( const wxPoint& aCenter, bool aRotateCCW )
{
int rot_angle = aRotateCCW ? -900 : 900;
rotate( aCenter, rot_angle );
}
void LIB_SHAPE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
const TRANSFORM& aTransform ) const
{
wxPoint start = aTransform.TransformCoordinate( m_start ) + aOffset;
wxPoint end = aTransform.TransformCoordinate( m_end ) + aOffset;
wxPoint center;
int startAngle;
int endAngle;
int pen_size = GetPenWidth();
FILL_T fill = aFill ? m_fill : FILL_TYPE::NO_FILL;
static std::vector<wxPoint> cornerList;
if( GetShape() == SHAPE_T::POLYGON )
{
cornerList.clear();
for( const VECTOR2I& pt : m_poly.Outline( 0 ).CPoints() )
cornerList.push_back( aTransform.TransformCoordinate( (wxPoint) pt ) + aOffset );
}
else if( GetShape() == SHAPE_T::CURVE )
{
cornerList.clear();
for( const wxPoint& pt : m_bezierPoints )
cornerList.push_back( aTransform.TransformCoordinate( pt ) + aOffset );
}
else if( GetShape() == SHAPE_T::ARC )
{
center = aTransform.TransformCoordinate( getCenter() ) + aOffset;
startAngle = GetArcAngleStart();
endAngle = GetArcAngleEnd();
aTransform.MapAngles( &startAngle, &endAngle );
}
if( fill == FILL_T::FILLED_WITH_BG_BODYCOLOR )
{
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) );
switch( GetShape() )
{
case SHAPE_T::ARC:
aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, 0 );
break;
case SHAPE_T::CIRCLE:
aPlotter->Circle( start, GetRadius() * 2, fill, 0 );
break;
case SHAPE_T::RECT:
aPlotter->Rect( start, end, fill, 0 );
break;
case SHAPE_T::POLYGON:
case SHAPE_T::CURVE:
aPlotter->PlotPoly( cornerList, fill, 0 );
break;
default:
wxFAIL_MSG( "LIB_SHAPE::Plot not implemented for " + SHAPE_T_asString() );
}
if( pen_size <= 0 )
return;
else
fill = FILL_T::NO_FILL;
}
pen_size = std::max( pen_size, aPlotter->RenderSettings()->GetMinPenWidth() );
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
switch( GetShape() )
{
case SHAPE_T::ARC:
aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, pen_size );
break;
case SHAPE_T::CIRCLE:
aPlotter->Circle( start, GetRadius() * 2, fill, pen_size );
break;
case SHAPE_T::RECT:
aPlotter->Rect( start, end, fill, pen_size );
break;
case SHAPE_T::POLYGON:
case SHAPE_T::CURVE:
aPlotter->PlotPoly( cornerList, fill, pen_size );
break;
default:
wxFAIL_MSG( "LIB_SHAPE::Plot not implemented for " + SHAPE_T_asString() );
}
}
int LIB_SHAPE::GetPenWidth() const
{
// Historically 0 meant "default width" and negative numbers meant "don't stroke".
if( GetWidth() < 0 && GetFillType() != FILL_T::NO_FILL )
return 0;
else
return std::max( GetWidth(), 1 );
}
void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
void* aData, const TRANSFORM& aTransform )
{
bool forceNoFill = static_cast<bool>( aData );
int penWidth = GetPenWidth();
if( forceNoFill && IsFilled() && penWidth == 0 )
return;
wxDC* DC = aSettings->GetPrintDC();
wxPoint pt1 = aTransform.TransformCoordinate( m_start ) + aOffset;
wxPoint pt2 = aTransform.TransformCoordinate( m_end ) + aOffset;
wxPoint c;
int t1;
int t2;
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE );
unsigned ptCount = 0;
wxPoint* buffer = nullptr;
if( GetShape() == SHAPE_T::POLYGON )
{
SHAPE_LINE_CHAIN poly = m_poly.Outline( 0 );
ptCount = poly.GetPointCount();
buffer = new wxPoint[ ptCount ];
for( unsigned ii = 0; ii < ptCount; ++ii )
buffer[ii] = aTransform.TransformCoordinate( (wxPoint) poly.CPoint( ii ) ) + aOffset;
}
else if( GetShape() == SHAPE_T::CURVE )
{
ptCount = m_bezierPoints.size();
buffer = new wxPoint[ ptCount ];
for( size_t ii = 0; ii < ptCount; ++ii )
buffer[ii] = aTransform.TransformCoordinate( m_bezierPoints[ii] ) + aOffset;
}
else if( GetShape() == SHAPE_T::ARC )
{
c = aTransform.TransformCoordinate( getCenter() ) + aOffset;
t1 = GetArcAngleStart();
t2 = GetArcAngleEnd();
aTransform.MapAngles( &t1, &t2 );
}
if( forceNoFill || GetFillType() == FILL_T::NO_FILL )
{
penWidth = std::max( penWidth, aSettings->GetDefaultPenWidth() );
switch( GetShape() )
{
case SHAPE_T::ARC:
GRArc1( nullptr, DC, pt2.x, pt2.y, pt1.x, pt1.y, c.x, c.y, penWidth, color );
break;
case SHAPE_T::CIRCLE:
GRCircle( nullptr, DC, pt1.x, pt1.y, GetRadius(), penWidth, color );
break;
case SHAPE_T::RECT:
GRRect( nullptr, DC, pt1.x, pt1.y, pt2.x, pt2.y, penWidth, color );
break;
case SHAPE_T::POLYGON:
GRPoly( nullptr, DC, ptCount, buffer, false, penWidth, color, color );
break;
case SHAPE_T::CURVE:
GRPoly( nullptr, DC, ptCount, buffer, false, penWidth, color, color );
break;
default:
wxFAIL_MSG( "LIB_SHAPE::print not implemented for " + SHAPE_T_asString() );
}
}
else
{
if( GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR )
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND );
switch( GetShape() )
{
case SHAPE_T::ARC:
GRFilledArc( nullptr, DC, c.x, c.y, t1, t2, GetRadius(), penWidth, color, color );
break;
case SHAPE_T::CIRCLE:
GRFilledCircle( nullptr, DC, pt1.x, pt1.y, GetRadius(), 0, color, color );
break;
case SHAPE_T::RECT:
GRFilledRect( nullptr, DC, pt1.x, pt1.y, pt2.x, pt2.y, penWidth, color, color );
break;
case SHAPE_T::POLYGON:
GRPoly( nullptr, DC, ptCount, buffer, true, penWidth, color, color );
break;
case SHAPE_T::CURVE:
GRPoly( nullptr, DC, ptCount, buffer, true, penWidth, color, color );
break;
default:
wxFAIL_MSG( "LIB_SHAPE::print not implemented for " + SHAPE_T_asString() );
}
}
delete[] buffer;
}
const EDA_RECT LIB_SHAPE::GetBoundingBox() const
{
EDA_RECT rect = getBoundingBox();
rect.RevertYAxis();
return rect;
}
void LIB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList )
{
LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
ShapeGetMsgPanelInfo( aFrame, aList );
}
wxString LIB_SHAPE::GetSelectMenuText( EDA_UNITS aUnits ) const
{
switch( GetShape() )
{
case SHAPE_T::ARC:
return wxString::Format( _( "Arc, radius %s" ),
MessageTextFromValue( aUnits, GetRadius() ) );
case SHAPE_T::CIRCLE:
return wxString::Format( _( "Circle, radius %s" ),
MessageTextFromValue( aUnits, GetRadius() ) );
case SHAPE_T::RECT:
return wxString::Format( _( "Rectangle, width %s height %s" ),
MessageTextFromValue( aUnits, std::abs( m_start.x - m_end.x ) ),
MessageTextFromValue( aUnits, std::abs( m_start.y - m_end.y ) ) );
case SHAPE_T::POLYGON:
return wxString::Format( _( "Polyline, %d points" ),
int( m_poly.Outline( 0 ).GetPointCount() ) );
case SHAPE_T::CURVE:
return wxString::Format( _( "Bezier Curve, %d points" ),
int( m_bezierPoints.size() ) );
default:
wxFAIL_MSG( "LIB_SHAPE::GetSelectMenuText unimplemented for " + SHAPE_T_asString() );
return wxEmptyString;
}
}
BITMAPS LIB_SHAPE::GetMenuImage() const
{
switch( GetShape() )
{
case SHAPE_T::SEGMENT: return BITMAPS::add_line;
case SHAPE_T::ARC: return BITMAPS::add_arc;
case SHAPE_T::CIRCLE: return BITMAPS::add_circle;
case SHAPE_T::RECT: return BITMAPS::add_rectangle;
case SHAPE_T::POLYGON: return BITMAPS::add_graphical_segments;
default:
wxFAIL_MSG( "LIB_SHAPE::GetMenuImage unimplemented for " + SHAPE_T_asString() );
return BITMAPS::question_mark;
}
}
void LIB_SHAPE::BeginEdit( const wxPoint& aPosition )
{
switch( GetShape() )
{
case SHAPE_T::SEGMENT:
case SHAPE_T::CIRCLE:
case SHAPE_T::RECT:
SetPosition( aPosition );
SetEnd( aPosition );
break;
case SHAPE_T::ARC:
SetStart( aPosition );
SetEnd( aPosition );
SetEditState( 1 );
break;
case SHAPE_T::POLYGON:
// Start and end of the first segment (co-located for now)
m_poly.Outline( 0 ).Append( aPosition );
m_poly.Outline( 0 ).Append( aPosition, true );
break;
default:
wxFAIL_MSG( "LIB_SHAPE::BeginEdit not implemented for " + SHAPE_T_asString() );
}
}
bool LIB_SHAPE::ContinueEdit( const wxPoint& aPosition )
{
switch( GetShape() )
{
case SHAPE_T::SEGMENT:
case SHAPE_T::CIRCLE:
case SHAPE_T::RECT:
return false;
case SHAPE_T::POLYGON:
{
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
// do not add zero-length segments
if( poly.CPoint( poly.GetPointCount() - 2 ) != poly.CLastPoint() )
poly.Append( aPosition );
}
return true;
default:
wxFAIL_MSG( "LIB_SHAPE::ContinueEdit not implemented for " + SHAPE_T_asString() );
return false;
}
}
void LIB_SHAPE::CalcEdit( const wxPoint& aPosition )
{
#define sq( x ) pow( x, 2 )
switch( GetShape() )
{
case SHAPE_T::SEGMENT:
case SHAPE_T::CIRCLE:
case SHAPE_T::RECT:
SetEnd( aPosition );
break;
case SHAPE_T::POLYGON:
m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition );
break;
case SHAPE_T::ARC:
// Edit state 0: drawing: place start
// Edit state 1: drawing: place end (center calculated for 90-degree subtended angle)
// Edit state 2: point edit: move start (center calculated for invariant subtended angle)
// Edit state 3: point edit: move end (center calculated for invariant subtended angle)
// Edit state 4: point edit: move center
// Edit state 5: point edit: move arc-mid-point
switch( m_editState )
{
case 0:
SetArcGeometry( aPosition, aPosition, aPosition );
return;
case 1:
{
wxPoint start = GetStart();
wxPoint end = aPosition;
wxPoint center = CalcArcCenter( start, end, 90.0 );
wxPoint mid = (wxPoint) CalcArcMid( start, end, center, true );
SetArcGeometry( start, mid, aPosition );
}
break;
case 2:
{
wxPoint delta = aPosition - GetStart();
SetArcGeometry( aPosition, GetArcMid() + delta/2, GetEnd() );
}
break;
case 3:
{
wxPoint delta = aPosition - GetEnd();
SetArcGeometry( GetStart(), GetArcMid() + delta/2, aPosition );
}
break;
case 4:
MoveTo( aPosition );
break;
case 5:
SetArcGeometry( GetStart(), aPosition, GetEnd() );
break;
}
break;
default:
wxFAIL_MSG( "LIB_SHAPE::CalcEdit not implemented for " + SHAPE_T_asString() );
}
}
void LIB_SHAPE::EndEdit()
{
switch( GetShape() )
{
case SHAPE_T::ARC:
case SHAPE_T::SEGMENT:
case SHAPE_T::CIRCLE:
case SHAPE_T::RECT:
break;
case SHAPE_T::POLYGON:
{
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
// do not include last point twice
if( poly.GetPointCount() > 2 )
{
if( poly.CPoint( poly.GetPointCount() - 2 ) == poly.CLastPoint() )
poly.Remove( poly.GetPointCount() - 1 );
}
}
break;
default:
wxFAIL_MSG( "LIB_SHAPE::EndEdit not implemented for " + SHAPE_T_asString() );
}
}
void LIB_SHAPE::AddPoint( const wxPoint& aPosition )
{
if( GetShape() == SHAPE_T::POLYGON )
{
if( m_poly.IsEmpty() )
m_poly.NewOutline();
m_poly.Outline( 0 ).Append( aPosition, true );
}
else
{
wxFAIL_MSG( "LIB_SHAPE::AddPoint not implemented for " + SHAPE_T_asString() );
}
}

108
eeschema/lib_shape.h Normal file
View File

@ -0,0 +1,108 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef LIB_SHAPE_H
#define LIB_SHAPE_H
#include <lib_item.h>
#include <eda_shape.h>
class LIB_SHAPE : public LIB_ITEM, public EDA_SHAPE
{
public:
LIB_SHAPE( LIB_SYMBOL* aParent, SHAPE_T aShape, int aLineWidth = 0,
FILL_T aFillType = FILL_T::NO_FILL );
// Do not create a copy constructor. The one generated by the compiler is adequate.
~LIB_SHAPE() { }
wxString GetClass() const override
{
return wxT( "LIB_SHAPE" );
}
wxString GetTypeName() const override
{
return ShowShape();
}
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
int GetPenWidth() const override;
const EDA_RECT GetBoundingBox() const override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
void BeginEdit( const wxPoint& aStartPoint ) override;
bool ContinueEdit( const wxPoint& aPosition ) override;
void CalcEdit( const wxPoint& aPosition ) override;
void EndEdit() override;
void AddPoint( const wxPoint& aPosition );
void Offset( const wxPoint& aOffset ) override;
void MoveTo( const wxPoint& aPosition ) override;
wxPoint GetPosition() const override { return getPosition(); }
void SetPosition( const wxPoint& aPosition ) override { setPosition( aPosition ); }
void MirrorHorizontal( const wxPoint& aCenter ) override;
void MirrorVertical( const wxPoint& aCenter ) override;
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override;
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill,
const TRANSFORM& aTransform ) const override;
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
BITMAPS GetMenuImage() const override;
EDA_ITEM* Clone() const override;
private:
/**
* @copydoc LIB_ITEM::compare()
*
* The circle specific sort order is as follows:
* - Circle horizontal (X) position.
* - Circle vertical (Y) position.
* - Circle radius.
*/
int compare( const LIB_ITEM& aOther,
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override;
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData,
const TRANSFORM& aTransform ) override;
double getParentOrientation() const override { return 0.0; }
wxPoint getParentPosition() const override { return wxPoint(); }
};
#endif // LIB_SHAPE_H

View File

@ -196,7 +196,7 @@ SCH_CONNECTION* SCH_ITEM::InitializeConnection( const SCH_SHEET_PATH& aSheet,
void SCH_ITEM::SwapData( SCH_ITEM* aItem ) void SCH_ITEM::SwapData( SCH_ITEM* aItem )
{ {
wxFAIL_MSG( wxT( "SwapData() method not implemented for class " ) + GetClass() ); UNIMPLEMENTED_FOR( GetClass() );
} }

View File

@ -579,37 +579,14 @@ void SCH_PAINTER::draw( const LIB_ARC *aArc, int aLayer )
if( setDeviceColors( aArc, aLayer ) ) if( setDeviceColors( aArc, aLayer ) )
{ {
int sai = aArc->GetFirstRadiusAngle(); int startAngle;
int eai = aArc->GetSecondRadiusAngle(); int endAngle;
aArc->CalcAngles( startAngle, endAngle );
/** TRANSFORM().MapAngles( &startAngle, &endAngle );
* This accounts for an oddity in the old library format, where the symbol
* is overdefined. The previous draw (based on wxwidgets) used start point and end
* point and always drew counter-clockwise. The new GAL draw takes center, radius and
* start/end angles. All of these points were stored in the file, so we need to mimic the
* swapping of start/end points rather than using the stored angles in order to properly map
* edge cases.
*
* todo(v6): Remove this hack when we update the file format and do translation on loading.
*/
if( !TRANSFORM().MapAngles( &sai, &eai ) )
{
LIB_ARC new_arc( *aArc );
new_arc.SetStart( aArc->GetEnd() ); m_gal->DrawArc( mapCoords( aArc->GetCenter() ), aArc->GetRadius(),
new_arc.SetEnd( aArc->GetStart() ); DECIDEG2RAD( startAngle ), DECIDEG2RAD( endAngle ) );
new_arc.CalcRadiusAngles();
sai = new_arc.GetFirstRadiusAngle();
eai = new_arc.GetSecondRadiusAngle();
TRANSFORM().MapAngles( &sai, &eai );
}
double sa = (double) sai * M_PI / 1800.0;
double ea = (double) eai * M_PI / 1800.0 ;
VECTOR2D pos = mapCoords( aArc->GetPosition() );
m_gal->DrawArc( pos, aArc->GetRadius(), sa, ea );
} }
} }

View File

@ -62,7 +62,7 @@
#include <wx/log.h> #include <wx/log.h>
#include <wx/zstream.h> #include <wx/zstream.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <trigo.h>
const wxPoint GetRelativePosition( const wxPoint& aPosition, const SCH_SYMBOL* aSymbol ) const wxPoint GetRelativePosition( const wxPoint& aPosition, const SCH_SYMBOL* aSymbol )
{ {
@ -1350,21 +1350,23 @@ void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aPropertie
} }
else else
{ {
if( fmod( 360.0 + elem.endAngle - elem.startAngle, 360.0 ) > 180.0 )
{
m_reporter->Report( _( "Arcs in symbols cannot exceed 180 degrees." ),
RPT_SEVERITY_ERROR );
return;
}
LIB_ARC* arc = new LIB_ARC( libSymbolIt->second ); LIB_ARC* arc = new LIB_ARC( libSymbolIt->second );
libSymbolIt->second->AddDrawItem( arc ); libSymbolIt->second->AddDrawItem( arc );
arc->SetUnit( elem.ownerpartid ); arc->SetUnit( elem.ownerpartid );
arc->SetPosition( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
arc->SetRadius( elem.radius ); arc->SetCenter( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
arc->SetFirstRadiusAngle( elem.startAngle * 10. );
arc->SetSecondRadiusAngle( elem.endAngle * 10. ); wxPoint arcStart( elem.radius, 0 );
arc->CalcEndPoints(); RotatePoint( &arcStart.x, &arcStart.y, -elem.startAngle * 10.0 );
arcStart += arc->GetCenter();
arc->SetStart( arcStart );
wxPoint arcEnd( elem.radius, 0 );
RotatePoint( &arcEnd.x, &arcEnd.y, -elem.endAngle * 10.0 );
arcEnd += arc->GetCenter();
arc->SetEnd( arcEnd );
arc->SetWidth( elem.lineWidth );
} }
} }
} }

View File

@ -1590,15 +1590,16 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSymDefIntoLibrary( const SYMDEF_ID& aSymdef
} }
void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
const std::vector<VERTEX>& aCadstarVertices, wxPoint aSymbolOrigin, LIB_SYMBOL* aSymbol, wxPoint aSymbolOrigin,
int aGateNumber, int aLineThickness ) LIB_SYMBOL* aSymbol,
int aGateNumber,
int aLineThickness )
{ {
const VERTEX* prev = &aCadstarVertices.at( 0 ); const VERTEX* prev = &aCadstarVertices.at( 0 );
const VERTEX* cur; const VERTEX* cur;
wxASSERT_MSG( wxASSERT_MSG( prev->Type == VERTEX_TYPE::POINT, "First vertex should always be a point." );
prev->Type == VERTEX_TYPE::POINT, "First vertex should always be a point vertex" );
for( size_t i = 1; i < aCadstarVertices.size(); i++ ) for( size_t i = 1; i < aCadstarVertices.size(); i++ )
{ {
@ -1651,7 +1652,6 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices(
( (LIB_ARC*) segment )->SetEnd( endPoint ); ( (LIB_ARC*) segment )->SetEnd( endPoint );
} }
( (LIB_ARC*) segment )->CalcRadiusAngles();
break; break;
} }
@ -2778,7 +2778,6 @@ LIB_SYMBOL* CADSTAR_SCH_ARCHIVE_LOADER::getScaledLibPart( const LIB_SYMBOL* aSym
arc.SetPosition( scalePt( arc.GetPosition() ) ); arc.SetPosition( scalePt( arc.GetPosition() ) );
arc.SetStart( scalePt( arc.GetStart() ) ); arc.SetStart( scalePt( arc.GetStart() ) );
arc.SetEnd( scalePt( arc.GetEnd() ) ); arc.SetEnd( scalePt( arc.GetEnd() ) );
arc.CalcRadiusAngles(); // Maybe not needed?
} }
break; break;

View File

@ -1581,7 +1581,7 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode,
bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol, bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol,
EDEVICE* aDevice, int aGateNumber, const wxString& aGateName ) EDEVICE* aDevice, int aGateNumber, const wxString& aGateName )
{ {
wxString symbolName = aSymbolNode->GetAttribute( "name" ); wxString symbolName = aSymbolNode->GetAttribute( "name" );
std::vector<LIB_ITEM*> items; std::vector<LIB_ITEM*> items;
@ -1831,8 +1831,6 @@ LIB_ITEM* SCH_EAGLE_PLUGIN::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol
arc->SetEnd( begin ); arc->SetEnd( begin );
} }
arc->SetRadius( radius );
arc->CalcRadiusAngles();
arc->SetUnit( aGateNumber ); arc->SetUnit( aGateNumber );
return (LIB_ITEM*) arc.release(); return (LIB_ITEM*) arc.release();
@ -1891,25 +1889,11 @@ LIB_PIN* SCH_EAGLE_PLUGIN::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, wxXmlN
switch( roti ) switch( roti )
{ {
default: case 0: pin->SetOrientation( 'R' ); break;
wxASSERT_MSG( false, wxString::Format( "Unhandled orientation (%d degrees)", roti ) ); case 90: pin->SetOrientation( 'U' ); break;
KI_FALLTHROUGH; case 180: pin->SetOrientation( 'L' ); break;
case 270: pin->SetOrientation( 'D' ); break;
case 0: default: wxFAIL_MSG( wxString::Format( "Unhandled orientation (%d degrees).", roti ) );
pin->SetOrientation( 'R' );
break;
case 90:
pin->SetOrientation( 'U' );
break;
case 180:
pin->SetOrientation( 'L' );
break;
case 270:
pin->SetOrientation( 'D' );
break;
} }
pin->SetLength( Mils2iu( 300 ) ); // Default pin length when not defined. pin->SetLength( Mils2iu( 300 ) ); // Default pin length when not defined.
@ -1959,17 +1943,11 @@ LIB_PIN* SCH_EAGLE_PLUGIN::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, wxXmlN
wxString function = aEPin->function.Get(); wxString function = aEPin->function.Get();
if( function == "dot" ) if( function == "dot" )
{
pin->SetShape( GRAPHIC_PINSHAPE::INVERTED ); pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
}
else if( function == "clk" ) else if( function == "clk" )
{
pin->SetShape( GRAPHIC_PINSHAPE::CLOCK ); pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
}
else if( function == "dotclk" ) else if( function == "dotclk" )
{
pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK ); pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
}
} }
return pin.release(); return pin.release();

View File

@ -916,6 +916,8 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc()
wxPoint midPoint; wxPoint midPoint;
wxPoint endPoint; wxPoint endPoint;
wxPoint pos; wxPoint pos;
int startAngle;
int endAngle;
FILL_PARAMS fill; FILL_PARAMS fill;
bool hasMidPoint = false; bool hasMidPoint = false;
std::unique_ptr<LIB_ARC> arc = std::make_unique<LIB_ARC>( nullptr ); std::unique_ptr<LIB_ARC> arc = std::make_unique<LIB_ARC>( nullptr );
@ -964,19 +966,16 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc()
break; break;
case T_length: case T_length:
arc->SetRadius( parseInternalUnits( "radius length" ) ); parseInternalUnits( "radius length" );
NeedRIGHT(); NeedRIGHT();
break; break;
case T_angles: case T_angles:
{ {
int angle1 = KiROUND( parseDouble( "start radius angle" ) * 10.0 ); startAngle = KiROUND( parseDouble( "start radius angle" ) * 10.0 );
int angle2 = KiROUND( parseDouble( "end radius angle" ) * 10.0 ); endAngle = KiROUND( parseDouble( "end radius angle" ) * 10.0 );
NORMALIZE_ANGLE_POS( startAngle );
NORMALIZE_ANGLE_POS( angle1 ); NORMALIZE_ANGLE_POS( endAngle );
NORMALIZE_ANGLE_POS( angle2 );
arc->SetFirstRadiusAngle( angle1 );
arc->SetSecondRadiusAngle( angle2 );
NeedRIGHT(); NeedRIGHT();
break; break;
} }
@ -1016,13 +1015,25 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc()
if( hasMidPoint ) if( hasMidPoint )
{ {
VECTOR2I center = GetArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ); VECTOR2I center = CalcArcCenter( arc->GetStart(), midPoint, arc->GetEnd());
arc->SetPosition( wxPoint( center.x, center.y ) ); arc->SetCenter( (wxPoint) center );
}
// @todo Calculate the radius. else
{
arc->CalcRadiusAngles(); /**
* This accounts for an oddity in the old library format, where the symbol is overdefined.
* The previous draw (based on wxwidgets) used start point and end point and always drew
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of
* these points were stored in the file, so we need to mimic the swapping of start/end
* points rather than using the stored angles in order to properly map edge cases.
*/
if( !TRANSFORM().MapAngles( &startAngle, &endAngle ) )
{
wxPoint temp = arc->GetStart();
arc->SetStart( arc->GetEnd() );
arc->SetEnd( temp );
}
} }
return arc.release(); return arc.release();

View File

@ -1810,13 +1810,14 @@ void SCH_SEXPR_PLUGIN_CACHE::saveArc( LIB_ARC* aArc, OUTPUTFORMATTER& aFormatter
{ {
wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." ); wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
int x1 = aArc->GetFirstRadiusAngle(); int x1;
int x2;
aArc->CalcAngles( x1, x2 );
if( x1 > 1800 ) if( x1 > 1800 )
x1 -= 3600; x1 -= 3600;
int x2 = aArc->GetSecondRadiusAngle();
if( x2 > 1800 ) if( x2 > 1800 )
x2 -= 3600; x2 -= 3600;

View File

@ -3280,15 +3280,13 @@ LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbol,
center.y = Mils2Iu( parseInt( aReader, line, &line ) ); center.y = Mils2Iu( parseInt( aReader, line, &line ) );
arc->SetPosition( center ); arc->SetPosition( center );
arc->SetRadius( Mils2Iu( parseInt( aReader, line, &line ) ) );
int radius = Mils2Iu( parseInt( aReader, line, &line ) );
int angle1 = parseInt( aReader, line, &line ); int angle1 = parseInt( aReader, line, &line );
int angle2 = parseInt( aReader, line, &line ); int angle2 = parseInt( aReader, line, &line );
NORMALIZE_ANGLE_POS( angle1 ); NORMALIZE_ANGLE_POS( angle1 );
NORMALIZE_ANGLE_POS( angle2 ); NORMALIZE_ANGLE_POS( angle2 );
arc->SetFirstRadiusAngle( angle1 );
arc->SetSecondRadiusAngle( angle2 );
arc->SetUnit( parseInt( aReader, line, &line ) ); arc->SetUnit( parseInt( aReader, line, &line ) );
arc->SetConvert( parseInt( aReader, line, &line ) ); arc->SetConvert( parseInt( aReader, line, &line ) );
@ -3316,17 +3314,31 @@ LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbol,
{ {
// Actual Coordinates of arc ends are not read from file // Actual Coordinates of arc ends are not read from file
// (old library), calculate them // (old library), calculate them
wxPoint arcStart( arc->GetRadius(), 0 ); wxPoint arcStart( radius, 0 );
wxPoint arcEnd( arc->GetRadius(), 0 ); wxPoint arcEnd( radius, 0 );
RotatePoint( &arcStart.x, &arcStart.y, -angle1 ); RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
arcStart += arc->GetPosition(); arcStart += arc->GetCenter();
arc->SetStart( arcStart ); arc->SetStart( arcStart );
RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 ); RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
arcEnd += arc->GetPosition(); arcEnd += arc->GetCenter();
arc->SetEnd( arcEnd ); arc->SetEnd( arcEnd );
} }
/**
* This accounts for an oddity in the old library format, where the symbol is overdefined.
* The previous draw (based on wxwidgets) used start point and end point and always drew
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of
* these points were stored in the file, so we need to mimic the swapping of start/end
* points rather than using the stored angles in order to properly map edge cases.
*/
if( !TRANSFORM().MapAngles( &angle1, &angle2 ) )
{
wxPoint temp = arc->GetStart();
arc->SetStart( arc->GetEnd() );
arc->SetEnd( temp );
}
return arc; return arc;
} }
@ -3955,43 +3967,41 @@ void SCH_LEGACY_PLUGIN_CACHE::saveArc( LIB_ARC* aArc, OUTPUTFORMATTER& aFormatte
{ {
wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." ); wxCHECK_RET( aArc && aArc->Type() == LIB_ARC_T, "Invalid LIB_ARC object." );
int x1 = aArc->GetFirstRadiusAngle(); int x1;
int x2;
aArc->CalcAngles( x1, x2 );
if( x1 > 1800 ) if( x1 > 1800 )
x1 -= 3600; x1 -= 3600;
int x2 = aArc->GetSecondRadiusAngle();
if( x2 > 1800 ) if( x2 > 1800 )
x2 -= 3600; x2 -= 3600;
aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n", aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
Iu2Mils( aArc->GetPosition().x ), Iu2Mils( aArc->GetPosition().y ), Iu2Mils( aArc->GetPosition().x ), Iu2Mils( aArc->GetPosition().y ),
Iu2Mils( aArc->GetRadius() ), x1, x2, aArc->GetUnit(), aArc->GetConvert(), Iu2Mils( aArc->GetRadius() ), x1, x2, aArc->GetUnit(), aArc->GetConvert(),
Iu2Mils( aArc->GetWidth() ), Iu2Mils( aArc->GetWidth() ), fill_tab[ (int) aArc->GetFillMode() ],
fill_tab[ static_cast<int>( aArc->GetFillMode() ) ],
Iu2Mils( aArc->GetStart().x ), Iu2Mils( aArc->GetStart().y ), Iu2Mils( aArc->GetStart().x ), Iu2Mils( aArc->GetStart().y ),
Iu2Mils( aArc->GetEnd().x ), Iu2Mils( aArc->GetEnd().y ) ); Iu2Mils( aArc->GetEnd().x ), Iu2Mils( aArc->GetEnd().y ) );
} }
void SCH_LEGACY_PLUGIN_CACHE::saveBezier( LIB_BEZIER* aBezier, void SCH_LEGACY_PLUGIN_CACHE::saveBezier( LIB_BEZIER* aBezier, OUTPUTFORMATTER& aFormatter )
OUTPUTFORMATTER& aFormatter )
{ {
wxCHECK_RET( aBezier && aBezier->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." ); wxCHECK_RET( aBezier && aBezier->Type() == LIB_BEZIER_T, "Invalid LIB_BEZIER object." );
aFormatter.Print( 0, "B %u %d %d %d", (unsigned)aBezier->GetPoints().size(), aFormatter.Print( 0, "B %u %d %d %d", (unsigned)aBezier->GetPoints().size(),
aBezier->GetUnit(), aBezier->GetConvert(), Iu2Mils( aBezier->GetWidth() ) ); aBezier->GetUnit(), aBezier->GetConvert(), Iu2Mils( aBezier->GetWidth() ) );
for( const auto& pt : aBezier->GetPoints() ) for( const wxPoint& pt : aBezier->GetPoints() )
aFormatter.Print( 0, " %d %d", Iu2Mils( pt.x ), Iu2Mils( pt.y ) ); aFormatter.Print( 0, " %d %d", Iu2Mils( pt.x ), Iu2Mils( pt.y ) );
aFormatter.Print( 0, " %c\n", fill_tab[static_cast<int>( aBezier->GetFillMode() )] ); aFormatter.Print( 0, " %c\n", fill_tab[static_cast<int>( aBezier->GetFillMode() )] );
} }
void SCH_LEGACY_PLUGIN_CACHE::saveCircle( LIB_CIRCLE* aCircle, void SCH_LEGACY_PLUGIN_CACHE::saveCircle( LIB_CIRCLE* aCircle, OUTPUTFORMATTER& aFormatter )
OUTPUTFORMATTER& aFormatter )
{ {
wxCHECK_RET( aCircle && aCircle->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." ); wxCHECK_RET( aCircle && aCircle->Type() == LIB_CIRCLE_T, "Invalid LIB_CIRCLE object." );

View File

@ -92,28 +92,9 @@ public:
void SetWidth( int aWidth ) { m_width = aWidth; } void SetWidth( int aWidth ) { m_width = aWidth; }
int GetWidth() const { return m_width; } int GetWidth() const { return m_width; }
/**
* Set the angle for arcs, and normalizes it within the range 0 - 360 degrees.
*
* @param aAngle is tenths of degrees, but will soon be degrees.
* @param aUpdateEnd set to true to update also arc end coordinates m_thirdPoint, so must
* be called after setting m_Start and m_End.
*/
virtual void SetAngle( double aAngle, bool aUpdateEnd = true );
double GetAngle() const { return m_angle; }
void SetShape( SHAPE_T aShape ) { m_shape = aShape; } void SetShape( SHAPE_T aShape ) { m_shape = aShape; }
SHAPE_T GetShape() const { return m_shape; } SHAPE_T GetShape() const { return m_shape; }
void SetBezierC1( const wxPoint& aPoint ) { m_bezierC1 = aPoint; }
const wxPoint& GetBezierC1() const { return m_bezierC1; }
void SetBezierC2( const wxPoint& aPoint ) { m_bezierC2 = aPoint; }
const wxPoint& GetBezierC2() const { return m_bezierC2; }
void SetShapePos( const wxPoint& aPos );
wxPoint GetShapePos() const;
/** /**
* Return the starting point of the graphic. * Return the starting point of the graphic.
*/ */
@ -135,22 +116,26 @@ public:
void SetEndX( int x ) { m_end.x = x; } void SetEndX( int x ) { m_end.x = x; }
/** /**
* Function GetThirdPoint * Set the angle for arcs, and normalizes it within the range 0 - 360 degrees.
* returns the third point point of the graphic *
* @param aAngle is tenths of degrees, but will soon be degrees.
*/ */
const wxPoint& GetThirdPoint() const { return m_thirdPoint; } virtual void SetArcAngle( double aAngle );
int GetThirdPointY() { return m_thirdPoint.y; } virtual void SetArcAngleAndEnd( double aAngle );
int GetThirdPointX() { return m_thirdPoint.x; } double GetArcAngle() const { return m_arcAngle; }
void SetThirdPoint( const wxPoint& aPoint ) { m_thirdPoint = aPoint; }
void SetThirdPointY( int y ) { m_thirdPoint.y = y; } void SetBezierC1( const wxPoint& aPt ) { m_bezierC1 = aPt; }
void SetThirdPointX( int x ) { m_thirdPoint.x = x; } const wxPoint& GetBezierC1() const { return m_bezierC1; }
void SetBezierC2( const wxPoint& aPt ) { m_bezierC2 = aPt; }
const wxPoint& GetBezierC2() const { return m_bezierC2; }
wxPoint getCenter() const;
void SetCenter( const wxPoint& aCenter );
// Some attributes are read only, since they are derived from m_Start, m_End, and m_Angle. // Some attributes are read only, since they are derived from m_Start, m_End, and m_Angle.
// No Set...() function for these attributes. // No Set...() function for these attributes.
wxPoint getCenter() const;
wxPoint GetArcStart() const { return m_end; }
wxPoint GetArcEnd() const;
wxPoint GetArcMid() const; wxPoint GetArcMid() const;
std::vector<wxPoint> GetRectCorners() const; std::vector<wxPoint> GetRectCorners() const;
@ -164,35 +149,8 @@ public:
*/ */
double GetArcAngleEnd() const; double GetArcAngleEnd() const;
/**
* Return the radius of this item.
*
* Has meaning only for arcs and circles.
*/
int GetRadius() const; int GetRadius() const;
/**
* Initialize the start arc point.
*
* Can be used for circles to initialize one point of the cicumference.
*/
void SetArcStart( const wxPoint& aArcStartPoint )
{
m_end = aArcStartPoint;
}
/**
* Initialize the end arc point.
*
* Can be used for circles to initialize one point of the cicumference.
*/
void SetArcEnd( const wxPoint& aArcEndPoint )
{
m_thirdPoint = aArcEndPoint;
}
void SetArcCenter( const wxPoint& aCenterPoint ) { m_start = aCenterPoint; }
/** /**
* Set the three controlling points for an arc. * Set the three controlling points for an arc.
* *
@ -278,6 +236,9 @@ public:
int Compare( const EDA_SHAPE* aOther ) const; int Compare( const EDA_SHAPE* aOther ) const;
protected: protected:
void setPosition( const wxPoint& aPos );
wxPoint getPosition() const;
void move( const wxPoint& aMoveVector ); void move( const wxPoint& aMoveVector );
void rotate( const wxPoint& aRotCentre, double aAngle ); void rotate( const wxPoint& aRotCentre, double aAngle );
void flip( const wxPoint& aCentre, bool aFlipLeftRight ); void flip( const wxPoint& aCentre, bool aFlipLeftRight );
@ -300,11 +261,11 @@ protected:
SHAPE_T m_shape; // Shape: line, Circle, Arc SHAPE_T m_shape; // Shape: line, Circle, Arc
int m_width; // thickness of lines ... int m_width; // thickness of lines ...
bool m_filled; // Pretty much what it says on the tin... bool m_filled; // Pretty much what it says on the tin...
wxPoint m_start; // Line start point or Circle and Arc center wxPoint m_start; // Line start point or Circle center
wxPoint m_end; // Line end point or circle and arc start point wxPoint m_end; // Line end point or Circle 3 o'clock point
wxPoint m_thirdPoint; // Used only for Arcs: arc end point wxPoint m_arcCenter; // Used only for Arcs: arc end point
double m_angle; // Used only for Arcs: Arc angle in 1/10 deg double m_arcAngle; // Used only for Arcs: Arc angle in 1/10 deg
wxPoint m_bezierC1; // Bezier Control Point 1 wxPoint m_bezierC1; // Bezier Control Point 1
wxPoint m_bezierC2; // Bezier Control Point 2 wxPoint m_bezierC2; // Bezier Control Point 2

View File

@ -117,4 +117,7 @@ static inline wxString FROM_UTF8( const char* cstring )
return line; return line;
} }
#define UNIMPLEMENTED_FOR( type ) \
wxFAIL_MSG( wxString::Format( "%s: unimplemented for %s", __FUNCTION__, type ) )
#endif // MACROS_H #endif // MACROS_H

View File

@ -106,15 +106,15 @@ void RotatePoint( double *pX, double *pY, double cx, double cy, double angle );
* @param aEnd The ending point of the circle (equivalent to aStart) * @param aEnd The ending point of the circle (equivalent to aStart)
* @return The center of the circle * @return The center of the circle
*/ */
const VECTOR2I GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd ); const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd );
const VECTOR2D GetArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd ); const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd );
const wxPoint GetArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd ); const wxPoint CalcArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd );
const wxPoint GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle ); const wxPoint CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle );
/** /**
* Return the subtended angle for a given arc. * Return the subtended angle for a given arc.
*/ */
double GetArcAngle( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd ); double CalcArcAngle( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd );
/** /**
* Return the middle point of an arc, half-way between aStart and aEnd. There are two possible * Return the middle point of an arc, half-way between aStart and aEnd. There are two possible
@ -127,8 +127,8 @@ double GetArcAngle( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I
* @param aMinArcAngle If true, returns the point that results in the smallest arc angle. * @param aMinArcAngle If true, returns the point that results in the smallest arc angle.
* @return The middle point of the arc * @return The middle point of the arc
*/ */
const VECTOR2I GetArcMid( 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 );
/* Return the arc tangent of 0.1 degrees coord vector dx, dy /* Return the arc tangent of 0.1 degrees coord vector dx, dy
* between -1800 and 1800 * between -1800 and 1800

View File

@ -24,7 +24,7 @@
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <math/vector2d.h> // for VECTOR2I #include <math/vector2d.h> // for VECTOR2I
#include <math.h> // for sqrt #include <math.h> // for sqrt
#include <trigo.h> // for GetArcMid #include <trigo.h> // for CalcArcMid
CIRCLE::CIRCLE() CIRCLE::CIRCLE()
@ -126,7 +126,7 @@ CIRCLE& CIRCLE::ConstructFromTanTanPt( const SEG& aLineA, const SEG& aLineB, con
// Calculate bisector // Calculate bisector
VECTOR2I lineApt = furthestFromIntersect( aLineA.A, aLineA.B ); VECTOR2I lineApt = furthestFromIntersect( aLineA.A, aLineA.B );
VECTOR2I lineBpt = furthestFromIntersect( aLineB.A, aLineB.B ); VECTOR2I lineBpt = furthestFromIntersect( aLineB.A, aLineB.B );
VECTOR2I bisectorPt = GetArcMid( lineApt, lineBpt, intersectPoint, true ); VECTOR2I bisectorPt = CalcArcMid( lineApt, lineBpt, intersectPoint, true );
anglebisector.A = intersectPoint; anglebisector.A = intersectPoint;
anglebisector.B = bisectorPt; anglebisector.B = bisectorPt;

View File

@ -188,7 +188,7 @@ SHAPE_ARC& SHAPE_ARC::ConstructFromStartEndAngle( const VECTOR2I& aStart, const
m_end = aEnd; m_end = aEnd;
m_width = aWidth; m_width = aWidth;
VECTOR2I center( GetArcCenter( aStart, aEnd, aAngle ) ); VECTOR2I center( CalcArcCenter( aStart, aEnd, aAngle ) );
RotatePoint( m_mid, center, -aAngle * 10.0 / 2.0 ); RotatePoint( m_mid, center, -aAngle * 10.0 / 2.0 );
@ -463,7 +463,7 @@ double SHAPE_ARC::GetEndAngle() const
VECTOR2I SHAPE_ARC::GetCenter() const VECTOR2I SHAPE_ARC::GetCenter() const
{ {
return GetArcCenter( m_start, m_mid, m_end ); return CalcArcCenter( m_start, m_mid, m_end );
} }

View File

@ -38,7 +38,7 @@
#include <math/box2.h> // for BOX2I #include <math/box2.h> // for BOX2I
#include <math/util.h> // for rescale #include <math/util.h> // for rescale
#include <math/vector2d.h> // for VECTOR2, VECTOR2I #include <math/vector2d.h> // for VECTOR2, VECTOR2I
#include <trigo.h> // for RAD2DECIDEG, GetArcAngle #include <trigo.h> // for RAD2DECIDEG, CalcArcAngle
class SHAPE; class SHAPE;

View File

@ -160,8 +160,8 @@ bool TestSegmentHit( const wxPoint& aRefPoint, const wxPoint& aStart, const wxPo
} }
const VECTOR2I GetArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter, const VECTOR2I CalcArcMid( const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
bool aMinArcAngle ) bool aMinArcAngle )
{ {
VECTOR2I startVector = aStart - aCenter; VECTOR2I startVector = aStart - aCenter;
VECTOR2I endVector = aEnd - aCenter; VECTOR2I endVector = aEnd - aCenter;
@ -359,7 +359,7 @@ void RotatePoint( double* pX, double* pY, double angle )
} }
const wxPoint GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle ) const wxPoint CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle )
{ {
VECTOR2I start = aStart; VECTOR2I start = aStart;
VECTOR2I end = aEnd; VECTOR2I end = aEnd;
@ -387,7 +387,7 @@ const wxPoint GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double
} }
const VECTOR2D GetArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd ) const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
{ {
VECTOR2D center; VECTOR2D center;
double yDelta_21 = aMid.y - aStart.y; double yDelta_21 = aMid.y - aStart.y;
@ -451,12 +451,12 @@ const VECTOR2D GetArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const
} }
const VECTOR2I GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd ) const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
{ {
VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) ); VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) ); VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) ); VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
VECTOR2D dCenter = GetArcCenter( dStart, dMid, dEnd ); VECTOR2D dCenter = CalcArcCenter( dStart, dMid, dEnd );
VECTOR2I iCenter; VECTOR2I iCenter;
@ -472,12 +472,12 @@ const VECTOR2I GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const
} }
const wxPoint GetArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd ) const wxPoint CalcArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd )
{ {
VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) ); VECTOR2D dStart( static_cast<double>( aStart.x ), static_cast<double>( aStart.y ) );
VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) ); VECTOR2D dMid( static_cast<double>( aMid.x ), static_cast<double>( aMid.y ) );
VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) ); VECTOR2D dEnd( static_cast<double>( aEnd.x ), static_cast<double>( aEnd.y ) );
VECTOR2D dCenter = GetArcCenter( dStart, dMid, dEnd ); VECTOR2D dCenter = CalcArcCenter( dStart, dMid, dEnd );
wxPoint iCenter; wxPoint iCenter;
@ -493,9 +493,9 @@ const wxPoint GetArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wx
} }
double GetArcAngle( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd ) double CalcArcAngle( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
{ {
VECTOR2I center = GetArcCenter( aStart, aMid, aEnd ); VECTOR2I center = CalcArcCenter( aStart, aMid, aEnd );
// Check if the new arc is CW or CCW // Check if the new arc is CW or CCW
VECTOR2D startLine = aStart - center; VECTOR2D startLine = aStart - center;

View File

@ -762,35 +762,34 @@ void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1, LSET a
} }
void AR_MATRIX::TraceSegmentPcb( PCB_SHAPE* pt_segm, int color, int marge, void AR_MATRIX::TraceSegmentPcb( PCB_SHAPE* aShape, int aColor, int aMargin,
AR_MATRIX::CELL_OP op_logic ) AR_MATRIX::CELL_OP op_logic )
{ {
int half_width = ( pt_segm->GetWidth() / 2 ) + marge; int half_width = ( aShape->GetWidth() / 2 ) + aMargin;
// Calculate the bounding rectangle of the segment (if H, V or Via) // Calculate the bounding rectangle of the segment (if H, V or Via)
int ux0 = pt_segm->GetStart().x - GetBrdCoordOrigin().x;
int uy0 = pt_segm->GetStart().y - GetBrdCoordOrigin().y;
int ux1 = pt_segm->GetEnd().x - GetBrdCoordOrigin().x;
int uy1 = pt_segm->GetEnd().y - GetBrdCoordOrigin().y;
LAYER_NUM layer = UNDEFINED_LAYER; // Draw on all layers LAYER_NUM layer = UNDEFINED_LAYER; // Draw on all layers
switch( pt_segm->GetShape() ) if( aShape->GetShape() == SHAPE_T::CIRCLE || aShape->GetShape() == SHAPE_T::SEGMENT )
{ {
case SHAPE_T::CIRCLE: int ux0 = aShape->GetStart().x - GetBrdCoordOrigin().x;
traceCircle( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic ); int uy0 = aShape->GetStart().y - GetBrdCoordOrigin().y;
break; int ux1 = aShape->GetEnd().x - GetBrdCoordOrigin().x;
int uy1 = aShape->GetEnd().y - GetBrdCoordOrigin().y;
case SHAPE_T::ARC: if( aShape->GetShape() == SHAPE_T::CIRCLE )
traceArc( ux0, uy0, ux1, uy1, pt_segm->GetAngle(), half_width, layer, color, op_logic ); traceCircle( ux0, uy0, ux1, uy1, half_width, layer, aColor, op_logic );
break; else
drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, aColor, op_logic );
}
else if( aShape->GetShape() == SHAPE_T::ARC )
{
int ux0 = aShape->GetCenter().x - GetBrdCoordOrigin().x;
int uy0 = aShape->GetCenter().y - GetBrdCoordOrigin().y;
int ux1 = aShape->GetStart().x - GetBrdCoordOrigin().x;
int uy1 = aShape->GetStart().y - GetBrdCoordOrigin().y;
case SHAPE_T::SEGMENT: traceArc( ux0, uy0, ux1, uy1, aShape->GetArcAngle(), half_width, layer, aColor, op_logic );
drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
default:
break;
} }
} }

View File

@ -108,7 +108,7 @@ public:
DIST_CELL GetDist( int aRow, int aCol, int aSide ); DIST_CELL GetDist( int aRow, int aCol, int aSide );
void SetDist( int aRow, int aCol, int aSide, DIST_CELL ); void SetDist( int aRow, int aCol, int aSide, DIST_CELL );
void TraceSegmentPcb( PCB_SHAPE* pt_segm, int color, int marge, AR_MATRIX::CELL_OP op_logic ); void TraceSegmentPcb( PCB_SHAPE* aShape, int aColor, int aMargin, AR_MATRIX::CELL_OP op_logic );
void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut, void CreateKeepOutRectangle( int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut,
LSET aLayerMask ); LSET aLayerMask );

View File

@ -28,6 +28,7 @@
#include <wx/debug.h> #include <wx/debug.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <i18n_utility.h> #include <i18n_utility.h>
#include <macros.h>
#include <board.h> #include <board.h>
#include <pcb_group.h> #include <pcb_group.h>
@ -167,7 +168,7 @@ std::shared_ptr<SHAPE> BOARD_ITEM::GetEffectiveShape( PCB_LAYER_ID aLayer ) cons
{ {
std::shared_ptr<SHAPE> shape; std::shared_ptr<SHAPE> shape;
wxFAIL_MSG( "GetEffectiveShape() not implemented for " + GetClass() ); UNIMPLEMENTED_FOR( GetClass() );
return shape; return shape;
} }

View File

@ -23,6 +23,7 @@
*/ */
#include <vector> #include <vector>
#include <macros.h>
#include <bezier_curves.h> #include <bezier_curves.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <trigo.h> #include <trigo.h>
@ -465,12 +466,12 @@ void EDA_SHAPE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuf
} }
case SHAPE_T::ARC: case SHAPE_T::ARC:
TransformArcToPolygon( aCornerBuffer, GetArcStart(), GetArcMid(), GetArcEnd(), width, TransformArcToPolygon( aCornerBuffer, GetStart(), GetArcMid(), GetEnd(), width, aError,
aError, aErrorLoc ); aErrorLoc );
break; break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
TransformOvalToPolygon( aCornerBuffer, m_start, m_end, width, aError, aErrorLoc ); TransformOvalToPolygon( aCornerBuffer, GetStart(), GetEnd(), width, aError, aErrorLoc );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -518,8 +519,8 @@ void EDA_SHAPE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuf
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
{ {
std::vector<wxPoint> ctrlPoints = { m_start, m_bezierC1, m_bezierC2, m_end }; std::vector<wxPoint> ctrlPts = { GetStart(), GetBezierC1(), GetBezierC2(), GetEnd() };
BEZIER_POLY converter( ctrlPoints ); BEZIER_POLY converter( ctrlPts );
std::vector< wxPoint> poly; std::vector< wxPoint> poly;
converter.GetPoly( poly, m_width ); converter.GetPoly( poly, m_width );
@ -533,8 +534,7 @@ void EDA_SHAPE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuf
} }
default: default:
wxFAIL_MSG( "EDA_SHAPE::TransformShapeWithClearanceToPolygon not implemented for " UNIMPLEMENTED_FOR( SHAPE_T_asString() );
+ SHAPE_T_asString() );
break; break;
} }
} }

View File

@ -95,18 +95,8 @@ static PCB_SHAPE* findNext( PCB_SHAPE* aShape, const wxPoint& aPoint,
if( graphic == aShape || ( graphic->GetFlags() & SKIP_STRUCT ) != 0 ) if( graphic == aShape || ( graphic->GetFlags() & SKIP_STRUCT ) != 0 )
continue; continue;
switch( graphic->GetShape() ) if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() )
{ return graphic;
case SHAPE_T::ARC:
if( aPoint == graphic->GetArcStart() || aPoint == graphic->GetArcEnd() )
return graphic;
break;
default:
if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() )
return graphic;
}
} }
// Search again for anything that's close, even something already used. (The latter is // Search again for anything that's close, even something already used. (The latter is
@ -121,42 +111,20 @@ static PCB_SHAPE* findNext( PCB_SHAPE* aShape, const wxPoint& aPoint,
if( graphic == aShape ) if( graphic == aShape )
continue; continue;
switch( graphic->GetShape() ) d_sq = ( pt - graphic->GetStart() ).SquaredEuclideanNorm();
if( d_sq < closest_dist_sq )
{ {
case SHAPE_T::ARC: closest_dist_sq = d_sq;
d_sq = ( pt - graphic->GetArcStart() ).SquaredEuclideanNorm(); closest_graphic = graphic;
}
if( d_sq < closest_dist_sq ) d_sq = ( pt - graphic->GetEnd() ).SquaredEuclideanNorm();
{
closest_dist_sq = d_sq;
closest_graphic = graphic;
}
d_sq = ( pt - graphic->GetArcEnd() ).SquaredEuclideanNorm(); if( d_sq < closest_dist_sq )
{
if( d_sq < closest_dist_sq ) closest_dist_sq = d_sq;
{ closest_graphic = graphic;
closest_dist_sq = d_sq;
closest_graphic = graphic;
}
break;
default:
d_sq = ( pt - graphic->GetStart() ).SquaredEuclideanNorm();
if( d_sq < closest_dist_sq )
{
closest_dist_sq = d_sq;
closest_graphic = graphic;
}
d_sq = ( pt - graphic->GetEnd() ).SquaredEuclideanNorm();
if( d_sq < closest_dist_sq )
{
closest_dist_sq = d_sq;
closest_graphic = graphic;
}
} }
} }
@ -221,9 +189,9 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
case SHAPE_T::ARC: case SHAPE_T::ARC:
{ {
wxPoint pstart = graphic->GetArcStart(); wxPoint pstart = graphic->GetStart();
wxPoint center = graphic->GetCenter(); wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle(); double angle = -graphic->GetArcAngle();
double radius = graphic->GetRadius(); double radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 ); int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
wxPoint pt; wxPoint pt;
@ -389,8 +357,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Polygon start point. Arbitrarily chosen end of the // Polygon start point. Arbitrarily chosen end of the
// segment and build the poly from here. // segment and build the poly from here.
wxPoint startPt = graphic->GetShape() == SHAPE_T::ARC ? graphic->GetArcEnd() wxPoint startPt = graphic->GetEnd();
: graphic->GetEnd();
prevPt = startPt; prevPt = startPt;
aPolygons.NewOutline(); aPolygons.NewOutline();
@ -443,16 +410,16 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// We do not support arcs in polygons, so approximate an arc with a series of // We do not support arcs in polygons, so approximate an arc with a series of
// short lines and put those line segments into the !same! PATH. // short lines and put those line segments into the !same! PATH.
wxPoint pstart = graphic->GetArcStart(); wxPoint pstart = graphic->GetStart();
wxPoint pend = graphic->GetArcEnd(); wxPoint pend = graphic->GetEnd();
wxPoint pcenter = graphic->GetCenter(); wxPoint pcenter = graphic->GetCenter();
double angle = -graphic->GetAngle(); double angle = -graphic->GetArcAngle();
double radius = graphic->GetRadius(); double radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 ); int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
if( !close_enough( prevPt, pstart, aChainingEpsilon ) ) if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
{ {
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aChainingEpsilon ) ); wxASSERT( close_enough( prevPt, graphic->GetEnd(), aChainingEpsilon ) );
angle = -angle; angle = -angle;
std::swap( pstart, pend ); std::swap( pstart, pend );
@ -535,8 +502,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
break; break;
default: default:
wxFAIL_MSG( "ConvertOutlineToPolygon not implemented for " UNIMPLEMENTED_FOR( graphic->SHAPE_T_asString() );
+ graphic->SHAPE_T_asString() );
return false; return false;
} }
@ -668,8 +634,8 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// Polygon start point. Arbitrarily chosen end of the segment and build the poly // Polygon start point. Arbitrarily chosen end of the segment and build the poly
// from here. // from here.
wxPoint startPt( graphic->GetEnd() ); wxPoint startPt = graphic->GetEnd();
prevPt = graphic->GetEnd(); prevPt = startPt;
aPolygons.Append( prevPt, -1, hole ); aPolygons.Append( prevPt, -1, hole );
// do not append the other end point yet, this first 'graphic' might be an arc // do not append the other end point yet, this first 'graphic' might be an arc
@ -700,17 +666,16 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
// We do not support arcs in polygons, so approximate an arc with a series of // We do not support arcs in polygons, so approximate an arc with a series of
// short lines and put those line segments into the !same! PATH. // short lines and put those line segments into the !same! PATH.
{ {
wxPoint pstart = graphic->GetArcStart(); wxPoint pstart = graphic->GetStart();
wxPoint pend = graphic->GetArcEnd(); wxPoint pend = graphic->GetEnd();
wxPoint pcenter = graphic->GetCenter(); wxPoint pcenter = graphic->GetCenter();
double angle = -graphic->GetAngle(); double angle = -graphic->GetArcAngle();
int radius = graphic->GetRadius(); int radius = graphic->GetRadius();
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 ); int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
if( !close_enough( prevPt, pstart, aChainingEpsilon ) ) if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
{ {
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), wxASSERT( close_enough( prevPt, graphic->GetEnd(), aChainingEpsilon ) );
aChainingEpsilon ) );
angle = -angle; angle = -angle;
std::swap( pstart, pend ); std::swap( pstart, pend );

View File

@ -189,7 +189,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
case SHAPE_T::ARC: case SHAPE_T::ARC:
SetTitle( _( "Arc Properties" ) ); SetTitle( _( "Arc Properties" ) );
m_AngleValue = m_item->GetAngle() / 10.0; m_AngleValue = m_item->GetArcAngle() / 10.0;
m_filledCtrl->Show( false ); m_filledCtrl->Show( false );
break; break;
@ -220,12 +220,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
break; break;
} }
if( m_item->GetShape() == SHAPE_T::ARC ) if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
{
m_startX.SetValue( m_item->GetArcStart().x );
m_startY.SetValue( m_item->GetArcStart().y );
}
else if( m_flipStartEnd )
{ {
m_startX.SetValue( m_item->GetEnd().x ); m_startX.SetValue( m_item->GetEnd().x );
m_startY.SetValue( m_item->GetEnd().y ); m_startY.SetValue( m_item->GetEnd().y );
@ -240,12 +235,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
{ {
m_endX.SetValue( m_item->GetRadius() ); m_endX.SetValue( m_item->GetRadius() );
} }
else if( m_item->GetShape() == SHAPE_T::ARC ) else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
{
m_endX.SetValue( m_item->GetArcEnd().x );
m_endY.SetValue( m_item->GetArcEnd().y );
}
else if( m_flipStartEnd )
{ {
m_endX.SetValue( m_item->GetStart().x ); m_endX.SetValue( m_item->GetStart().x );
m_endY.SetValue( m_item->GetStart().y ); m_endY.SetValue( m_item->GetStart().y );
@ -292,11 +282,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
BOARD_COMMIT commit( m_parent ); BOARD_COMMIT commit( m_parent );
commit.Modify( m_item ); commit.Modify( m_item );
if( m_item->GetShape() == SHAPE_T::ARC ) if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
{
m_item->SetArcStart( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
}
else if( m_flipStartEnd )
{ {
m_item->SetEndX( m_startX.GetValue() ); m_item->SetEndX( m_startX.GetValue() );
m_item->SetEndY( m_startY.GetValue() ); m_item->SetEndY( m_startY.GetValue() );
@ -311,11 +297,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
{ {
m_item->SetEnd( m_item->GetStart() + wxPoint( m_endX.GetValue(), 0 ) ); m_item->SetEnd( m_item->GetStart() + wxPoint( m_endX.GetValue(), 0 ) );
} }
else if( m_item->GetShape() == SHAPE_T::ARC ) else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
{
m_item->SetArcEnd( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) );
}
else if( m_flipStartEnd )
{ {
m_item->SetStartX( m_endX.GetValue() ); m_item->SetStartX( m_endX.GetValue() );
m_item->SetStartY( m_endY.GetValue() ); m_item->SetStartY( m_endY.GetValue() );
@ -329,14 +311,14 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
// For Bezier curve: Set the two control points // For Bezier curve: Set the two control points
if( m_item->GetShape() == SHAPE_T::BEZIER ) if( m_item->GetShape() == SHAPE_T::BEZIER )
{ {
m_item->SetBezierC1( wxPoint( m_bezierCtrl1X.GetValue(), m_bezierCtrl1Y.GetValue())); m_item->SetBezierC1( wxPoint( m_bezierCtrl1X.GetValue(), m_bezierCtrl1Y.GetValue() ) );
m_item->SetBezierC2( wxPoint( m_bezierCtrl2X.GetValue(), m_bezierCtrl2Y.GetValue())); m_item->SetBezierC2( wxPoint( m_bezierCtrl2X.GetValue(), m_bezierCtrl2Y.GetValue() ) );
} }
if( m_item->GetShape() == SHAPE_T::ARC ) if( m_item->GetShape() == SHAPE_T::ARC )
{ {
m_item->SetArcCenter( GetArcCenter( m_item->GetArcStart(), m_item->GetArcEnd(), m_AngleValue )); m_item->SetCenter( CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue ) );
m_item->SetAngle( m_AngleValue * 10.0, false ); m_item->SetArcAngle( m_AngleValue * 10.0 );
} }
if( m_fp_item ) if( m_fp_item )
@ -345,10 +327,13 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
m_fp_item->SetStart0( m_fp_item->GetStart() ); m_fp_item->SetStart0( m_fp_item->GetStart() );
m_fp_item->SetEnd0( m_fp_item->GetEnd() ); m_fp_item->SetEnd0( m_fp_item->GetEnd() );
if( m_fp_item->GetShape() == SHAPE_T::BEZIER ) if( m_item->GetShape() == SHAPE_T::ARC )
m_fp_item->SetCenter0( m_fp_item->GetCenter() );
if( m_item->GetShape() == SHAPE_T::BEZIER )
{ {
m_fp_item->SetBezierC1_0( wxPoint( m_bezierCtrl1X.GetValue(), m_bezierCtrl1Y.GetValue())); m_fp_item->SetBezierC1_0( m_fp_item->GetBezierC1() );
m_fp_item->SetBezierC2_0( wxPoint( m_bezierCtrl2X.GetValue(), m_bezierCtrl2Y.GetValue())); m_fp_item->SetBezierC2_0( m_fp_item->GetBezierC2() );
} }
} }
@ -408,8 +393,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::Validate()
break; break;
default: default:
wxFAIL_MSG( "DIALOG_GRAPHIC_ITEM_PROPERTIES::Validate not implemented for shape " UNIMPLEMENTED_FOR( m_item->SHAPE_T_asString() );
+ m_item->SHAPE_T_asString() );
break; break;
} }

View File

@ -112,14 +112,14 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
case SHAPE_T::ARC: case SHAPE_T::ARC:
SetTitle( _( "Arc" ) ); SetTitle( _( "Arc" ) );
m_startX.SetValue( m_shape->GetEnd().x ); // confusingly, the start point of the arc m_startX.SetValue( m_shape->GetStart().x );
m_startY.SetValue( m_shape->GetEnd().y ); m_startY.SetValue( m_shape->GetStart().y );
m_staticTextPosEnd->SetLabel( _( "Center" ) ); m_staticTextPosEnd->SetLabel( _( "Center" ) );
m_endX.SetValue( m_shape->GetStart().x ); // arc center m_endX.SetValue( m_shape->GetCenter().x );
m_endY.SetValue( m_shape->GetStart().y ); m_endY.SetValue( m_shape->GetCenter().y );
m_radiusLabel->SetLabel( _( "Angle:" ) ); m_radiusLabel->SetLabel( _( "Angle:" ) );
m_radius.SetUnits( EDA_UNITS::DEGREES ); m_radius.SetUnits( EDA_UNITS::DEGREES );
m_radius.SetValue( m_shape->GetAngle() ); m_radius.SetValue( m_shape->GetArcAngle() );
m_ctrl1X.Show( false, true ); m_ctrl1X.Show( false, true );
m_ctrl1Y.Show( false, true ); m_ctrl1Y.Show( false, true );
m_ctrl2X.Show( false, true ); m_ctrl2X.Show( false, true );
@ -199,13 +199,9 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataFromWindow()
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
// NB: we store the center of the arc in m_Start, and, confusingly, m_shape->SetCenter( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) );
// the start point in m_End m_shape->SetStart( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
m_shape->SetStart( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) ); m_shape->SetArcAngleAndEnd( m_radius.GetValue() );
m_shape->SetEnd( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
// arc angle
m_shape->SetAngle( m_radius.GetValue() );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:

View File

@ -711,9 +711,8 @@ void DIALOG_PAD_PROPERTIES::displayPrimitivesList()
case SHAPE_T::ARC: case SHAPE_T::ARC:
bs_info[0] = _( "Arc" ); bs_info[0] = _( "Arc" );
bs_info[1] = _( "center" ) + wxS( " " )+ formatCoord( m_units, primitive->GetCenter() ); bs_info[1] = _( "center" ) + wxS( " " )+ formatCoord( m_units, primitive->GetCenter() );
bs_info[2] = _( "start" ) + wxS( " " )+ formatCoord( m_units, bs_info[2] = _( "start" ) + wxS( " " )+ formatCoord( m_units, primitive->GetStart() );
primitive->GetArcStart() ); bs_info[3] = _( "angle" ) + wxS( " " )+ FormatAngle( primitive->GetArcAngle() );
bs_info[3] = _( "angle" ) + wxS( " " )+ FormatAngle( primitive->GetAngle() );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:

View File

@ -1255,23 +1255,14 @@ static void FootprintWriteShape( FILE* aFile, FOOTPRINT* aFootprint, const wxStr
} }
case SHAPE_T::ARC: case SHAPE_T::ARC:
{
int arcendx, arcendy;
arcendx = shape->GetEnd0().x - shape->GetStart0().x;
arcendy = shape->GetEnd0().y - shape->GetStart0().y;
RotatePoint( &arcendx, &arcendy, -shape->GetAngle() );
arcendx += shape->GetStart0().x;
arcendy += shape->GetStart0().y;
fprintf( aFile, "ARC %g %g %g %g %g %g\n", fprintf( aFile, "ARC %g %g %g %g %g %g\n",
shape->GetStart0().x / SCALE_FACTOR,
-shape->GetStart0().y / SCALE_FACTOR,
shape->GetEnd0().x / SCALE_FACTOR, shape->GetEnd0().x / SCALE_FACTOR,
-shape->GetEnd0().y / SCALE_FACTOR, -shape->GetEnd0().y / SCALE_FACTOR,
arcendx / SCALE_FACTOR, shape->GetCenter0().x / SCALE_FACTOR,
-arcendy / SCALE_FACTOR, -shape->GetCenter0().y / SCALE_FACTOR );
shape->GetStart0().x / SCALE_FACTOR,
-shape->GetStart0().y / SCALE_FACTOR );
break; break;
}
case SHAPE_T::POLY: case SHAPE_T::POLY:
// Not exported (TODO) // Not exported (TODO)

View File

@ -91,11 +91,8 @@ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
{ {
if( ( graphic->GetStart().x == graphic->GetEnd().x ) if( graphic->GetStart() == graphic->GetEnd() )
&& ( graphic->GetStart().y == graphic->GetEnd().y ) )
{
break; break;
}
sp.x = graphic->GetStart().x * scale + offX; sp.x = graphic->GetStart().x * scale + offX;
sp.y = -graphic->GetStart().y * scale + offY; sp.y = -graphic->GetStart().y * scale + offY;
@ -111,11 +108,8 @@ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
case SHAPE_T::RECT: case SHAPE_T::RECT:
{ {
if( ( graphic->GetStart().x == graphic->GetEnd().x ) if( graphic->GetStart() == graphic->GetEnd() )
&& ( graphic->GetStart().y == graphic->GetEnd().y ) )
{
break; break;
}
double top = graphic->GetStart().y * scale + offY; double top = graphic->GetStart().y * scale + offY;
double left = graphic->GetStart().x * scale + offX; double left = graphic->GetStart().x * scale + offX;
@ -137,17 +131,14 @@ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
case SHAPE_T::ARC: case SHAPE_T::ARC:
{ {
if( ( graphic->GetCenter().x == graphic->GetArcStart().x ) if( graphic->GetCenter() == graphic->GetStart() )
&& ( graphic->GetCenter().y == graphic->GetArcStart().y ) )
{
break; break;
}
sp.x = graphic->GetCenter().x * scale + offX; sp.x = graphic->GetCenter().x * scale + offX;
sp.y = -graphic->GetCenter().y * scale + offY; sp.y = -graphic->GetCenter().y * scale + offY;
ep.x = graphic->GetArcStart().x * scale + offX; ep.x = graphic->GetStart().x * scale + offX;
ep.y = -graphic->GetArcStart().y * scale + offY; ep.y = -graphic->GetStart().y * scale + offY;
IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, -graphic->GetAngle() / 10.0, true ); IDF_SEGMENT* seg = new IDF_SEGMENT( sp, ep, -graphic->GetArcAngle() / 10.0, true );
if( seg ) if( seg )
lines.push_back( seg ); lines.push_back( seg );

View File

@ -57,7 +57,7 @@ void FP_SHAPE::SetLocalCoord()
{ {
m_start0 = m_start; m_start0 = m_start;
m_end0 = m_end; m_end0 = m_end;
m_thirdPoint0 = m_thirdPoint; m_arcCenter0 = m_arcCenter;
m_bezierC1_0 = m_bezierC1; m_bezierC1_0 = m_bezierC1;
m_bezierC2_0 = m_bezierC2; m_bezierC2_0 = m_bezierC2;
return; return;
@ -65,13 +65,13 @@ void FP_SHAPE::SetLocalCoord()
m_start0 = m_start - fp->GetPosition(); m_start0 = m_start - fp->GetPosition();
m_end0 = m_end - fp->GetPosition(); m_end0 = m_end - fp->GetPosition();
m_thirdPoint0 = m_thirdPoint - fp->GetPosition(); m_arcCenter0 = m_arcCenter - fp->GetPosition();
m_bezierC1_0 = m_bezierC1 - fp->GetPosition(); m_bezierC1_0 = m_bezierC1 - fp->GetPosition();
m_bezierC2_0 = m_bezierC2 - fp->GetPosition(); m_bezierC2_0 = m_bezierC2 - fp->GetPosition();
double angle = fp->GetOrientation(); double angle = fp->GetOrientation();
RotatePoint( &m_start0.x, &m_start0.y, -angle ); RotatePoint( &m_start0.x, &m_start0.y, -angle );
RotatePoint( &m_end0.x, &m_end0.y, -angle ); RotatePoint( &m_end0.x, &m_end0.y, -angle );
RotatePoint( &m_thirdPoint0.x, &m_thirdPoint0.y, -angle ); RotatePoint( &m_arcCenter0.x, &m_arcCenter0.y, -angle );
RotatePoint( &m_bezierC1_0.x, &m_bezierC1_0.y, -angle ); RotatePoint( &m_bezierC1_0.x, &m_bezierC1_0.y, -angle );
RotatePoint( &m_bezierC2_0.x, &m_bezierC2_0.y, -angle ); RotatePoint( &m_bezierC2_0.x, &m_bezierC2_0.y, -angle );
} }
@ -83,7 +83,7 @@ void FP_SHAPE::SetDrawCoord()
m_start = m_start0; m_start = m_start0;
m_end = m_end0; m_end = m_end0;
m_thirdPoint = m_thirdPoint0; m_arcCenter = m_arcCenter0;
m_bezierC1 = m_bezierC1_0; m_bezierC1 = m_bezierC1_0;
m_bezierC2 = m_bezierC2_0; m_bezierC2 = m_bezierC2_0;
@ -91,13 +91,13 @@ void FP_SHAPE::SetDrawCoord()
{ {
RotatePoint( &m_start.x, &m_start.y, fp->GetOrientation() ); RotatePoint( &m_start.x, &m_start.y, fp->GetOrientation() );
RotatePoint( &m_end.x, &m_end.y, fp->GetOrientation() ); RotatePoint( &m_end.x, &m_end.y, fp->GetOrientation() );
RotatePoint( &m_thirdPoint.x, &m_thirdPoint.y, fp->GetOrientation() ); RotatePoint( &m_arcCenter.x, &m_arcCenter.y, fp->GetOrientation() );
RotatePoint( &m_bezierC1.x, &m_bezierC1.y, fp->GetOrientation() ); RotatePoint( &m_bezierC1.x, &m_bezierC1.y, fp->GetOrientation() );
RotatePoint( &m_bezierC2.x, &m_bezierC2.y, fp->GetOrientation() ); RotatePoint( &m_bezierC2.x, &m_bezierC2.y, fp->GetOrientation() );
m_start += fp->GetPosition(); m_start += fp->GetPosition();
m_end += fp->GetPosition(); m_end += fp->GetPosition();
m_thirdPoint += fp->GetPosition(); m_arcCenter += fp->GetPosition();
m_bezierC1 += fp->GetPosition(); m_bezierC1 += fp->GetPosition();
m_bezierC2 += fp->GetPosition(); m_bezierC2 += fp->GetPosition();
} }
@ -137,22 +137,57 @@ EDA_ITEM* FP_SHAPE::Clone() const
} }
void FP_SHAPE::SetAngle( double aAngle, bool aUpdateEnd ) wxPoint FP_SHAPE::GetCenter0() const
{ {
// Mark as depreciated. switch( m_shape )
// m_Angle does not define the arc anymore
// Update the parent class (updates the global m_ThirdPoint)
PCB_SHAPE::SetAngle( aAngle, aUpdateEnd );
// Also update the local m_thirdPoint0 if requested
if( aUpdateEnd )
{ {
m_thirdPoint0 = m_end0; case SHAPE_T::ARC:
RotatePoint( &m_thirdPoint0, m_start0, -m_angle ); return m_arcCenter0;
case SHAPE_T::CIRCLE:
return m_start0;
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
return wxPoint();
} }
} }
void FP_SHAPE::SetCenter0( const wxPoint& aCenter )
{
switch( m_shape )
{
case SHAPE_T::ARC:
m_arcCenter0 = aCenter;
break;
case SHAPE_T::CIRCLE:
m_start0 = aCenter;
break;
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
}
}
void FP_SHAPE::SetArcAngle( double aAngle )
{
PCB_SHAPE::SetArcAngle( aAngle );
}
void FP_SHAPE::SetArcAngleAndEnd0( double aAngle )
{
PCB_SHAPE::SetArcAngle( aAngle );
wxPoint end = GetStart0();
RotatePoint( &end, GetCenter0(), -m_arcAngle );
SetEnd0( end );
}
void FP_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight ) void FP_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{ {
wxPoint pt( 0, 0 ); wxPoint pt( 0, 0 );
@ -160,9 +195,9 @@ void FP_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
switch( GetShape() ) switch( GetShape() )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
// Update arc angle but do not yet update m_ThirdPoint0 and m_thirdPoint, // Update arc angle but do not yet update m_arcCenter0 and m_arcCenter,
// arc center and start point must be updated before calculation arc end. // arc center and start point must be updated before calculation arc end.
SetAngle( -GetAngle(), false ); SetArcAngle( -GetArcAngle() );
KI_FALLTHROUGH; KI_FALLTHROUGH;
default: default:
@ -177,12 +212,12 @@ void FP_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{ {
MIRROR( m_start.x, aCentre.x ); MIRROR( m_start.x, aCentre.x );
MIRROR( m_end.x, aCentre.x ); MIRROR( m_end.x, aCentre.x );
MIRROR( m_thirdPoint.x, aCentre.x ); MIRROR( m_arcCenter.x, aCentre.x );
MIRROR( m_bezierC1.x, aCentre.x ); MIRROR( m_bezierC1.x, aCentre.x );
MIRROR( m_bezierC2.x, aCentre.x ); MIRROR( m_bezierC2.x, aCentre.x );
MIRROR( m_start0.x, pt.x ); MIRROR( m_start0.x, pt.x );
MIRROR( m_end0.x, pt.x ); MIRROR( m_end0.x, pt.x );
MIRROR( m_thirdPoint0.x, pt.x ); MIRROR( m_arcCenter0.x, pt.x );
MIRROR( m_bezierC1_0.x, pt.x ); MIRROR( m_bezierC1_0.x, pt.x );
MIRROR( m_bezierC2_0.x, pt.x ); MIRROR( m_bezierC2_0.x, pt.x );
} }
@ -190,12 +225,12 @@ void FP_SHAPE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{ {
MIRROR( m_start.y, aCentre.y ); MIRROR( m_start.y, aCentre.y );
MIRROR( m_end.y, aCentre.y ); MIRROR( m_end.y, aCentre.y );
MIRROR( m_thirdPoint.y, aCentre.y ); MIRROR( m_arcCenter.y, aCentre.y );
MIRROR( m_bezierC1.y, aCentre.y ); MIRROR( m_bezierC1.y, aCentre.y );
MIRROR( m_bezierC2.y, aCentre.y ); MIRROR( m_bezierC2.y, aCentre.y );
MIRROR( m_start0.y, pt.y ); MIRROR( m_start0.y, pt.y );
MIRROR( m_end0.y, pt.y ); MIRROR( m_end0.y, pt.y );
MIRROR( m_thirdPoint0.y, pt.y ); MIRROR( m_arcCenter0.y, pt.y );
MIRROR( m_bezierC1_0.y, pt.y ); MIRROR( m_bezierC1_0.y, pt.y );
MIRROR( m_bezierC2_0.y, pt.y ); MIRROR( m_bezierC2_0.y, pt.y );
} }
@ -227,9 +262,9 @@ void FP_SHAPE::Mirror( const wxPoint& aCentre, bool aMirrorAroundXAxis )
switch( GetShape() ) switch( GetShape() )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
// Update arc angle but do not yet update m_ThirdPoint0 and m_thirdPoint, // Update arc angle but do not yet update m_arcCenter0 and m_arcCenter,
// arc center and start point must be updated before calculation arc end. // arc center and start point must be updated before calculation arc end.
SetAngle( -GetAngle(), false ); SetArcAngle( -GetArcAngle() );
KI_FALLTHROUGH; KI_FALLTHROUGH;
default: default:
@ -239,7 +274,7 @@ void FP_SHAPE::Mirror( const wxPoint& aCentre, bool aMirrorAroundXAxis )
{ {
MIRROR( m_start0.y, aCentre.y ); MIRROR( m_start0.y, aCentre.y );
MIRROR( m_end0.y, aCentre.y ); MIRROR( m_end0.y, aCentre.y );
MIRROR( m_thirdPoint0.y, aCentre.y ); MIRROR( m_arcCenter0.y, aCentre.y );
MIRROR( m_bezierC1_0.y, aCentre.y ); MIRROR( m_bezierC1_0.y, aCentre.y );
MIRROR( m_bezierC2_0.y, aCentre.y ); MIRROR( m_bezierC2_0.y, aCentre.y );
} }
@ -247,7 +282,7 @@ void FP_SHAPE::Mirror( const wxPoint& aCentre, bool aMirrorAroundXAxis )
{ {
MIRROR( m_start0.x, aCentre.x ); MIRROR( m_start0.x, aCentre.x );
MIRROR( m_end0.x, aCentre.x ); MIRROR( m_end0.x, aCentre.x );
MIRROR( m_thirdPoint0.x, aCentre.x ); MIRROR( m_arcCenter0.x, aCentre.x );
MIRROR( m_bezierC1_0.x, aCentre.x ); MIRROR( m_bezierC1_0.x, aCentre.x );
MIRROR( m_bezierC2_0.x, aCentre.x ); MIRROR( m_bezierC2_0.x, aCentre.x );
} }
@ -290,7 +325,7 @@ void FP_SHAPE::Move( const wxPoint& aMoveVector )
// This is a footprint shape modification. // This is a footprint shape modification.
m_start0 += aMoveVector; m_start0 += aMoveVector;
m_end0 += aMoveVector; m_end0 += aMoveVector;
m_thirdPoint0 += aMoveVector; m_arcCenter0 += aMoveVector;
m_bezierC1_0 += aMoveVector; m_bezierC1_0 += aMoveVector;
m_bezierC2_0 += aMoveVector; m_bezierC2_0 += aMoveVector;

View File

@ -70,10 +70,9 @@ public:
/** /**
* Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees. * Sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
* @param aAngle is tenths of degrees, but will soon be degrees. * @param aAngle is tenths of degrees, but will soon be degrees.
* @param aUpdateEnd = true to update also arc end coordinates m_thirdPoint and
* m_thirdPoint0, so must be called after setting m_Start, m_start0, m_End and m_end0
*/ */
void SetAngle( double aAngle, bool aUpdateEnd = true ) override; void SetArcAngle( double aAngle ) override;
void SetArcAngleAndEnd0( double aAngle );
/** /**
* Move an edge of the footprint. * Move an edge of the footprint.
@ -114,15 +113,15 @@ public:
void SetEnd0( const wxPoint& aPoint ) { m_end0 = aPoint; } void SetEnd0( const wxPoint& aPoint ) { m_end0 = aPoint; }
const wxPoint& GetEnd0() const { return m_end0; } const wxPoint& GetEnd0() const { return m_end0; }
void SetThirdPoint0( const wxPoint& aPoint ){ m_thirdPoint0 = aPoint; }
const wxPoint& GetThirdPoint0() const { return m_thirdPoint0; }
void SetBezierC1_0( const wxPoint& aPoint ) { m_bezierC1_0 = aPoint; } void SetBezierC1_0( const wxPoint& aPoint ) { m_bezierC1_0 = aPoint; }
const wxPoint& GetBezierC1_0() const { return m_bezierC1_0; } const wxPoint& GetBezierC1_0() const { return m_bezierC1_0; }
void SetBezierC2_0( const wxPoint& aPoint ) { m_bezierC2_0 = aPoint; } void SetBezierC2_0( const wxPoint& aPoint ) { m_bezierC2_0 = aPoint; }
const wxPoint& GetBezierC2_0() const { return m_bezierC2_0; } const wxPoint& GetBezierC2_0() const { return m_bezierC2_0; }
wxPoint GetCenter0() const;
void SetCenter0( const wxPoint& aPt );
/** /**
* Set relative coordinates from draw coordinates. * Set relative coordinates from draw coordinates.
* Call in only when the geometry or the footprint is modified and therefore the relative * Call in only when the geometry or the footprint is modified and therefore the relative
@ -160,7 +159,7 @@ public:
protected: protected:
wxPoint m_start0; ///< Start point or circle center, relative to footprint origin, orient 0. wxPoint m_start0; ///< Start point or circle center, relative to footprint origin, orient 0.
wxPoint m_end0; ///< End point or circle edge, relative to footprint origin, orient 0. wxPoint m_end0; ///< End point or circle edge, relative to footprint origin, orient 0.
wxPoint m_thirdPoint0; ///< End point for an arc. wxPoint m_arcCenter0; ///< Center of arc, relative to footprint origin, orient 0.
wxPoint m_bezierC1_0; ///< Bezier Control Point 1, relative to footprint origin, orient 0. wxPoint m_bezierC1_0; ///< Bezier Control Point 1, relative to footprint origin, orient 0.
wxPoint m_bezierC2_0; ///< Bezier Control Point 2, relative to footprint origin, orient 0. wxPoint m_bezierC2_0; ///< Bezier Control Point 2, relative to footprint origin, orient 0.
}; };

View File

@ -24,6 +24,7 @@
*/ */
#include <reporter.h> #include <reporter.h>
#include <macros.h>
#include <board_commit.h> #include <board_commit.h>
#include <cleanup_item.h> #include <cleanup_item.h>
#include <pcb_shape.h> #include <pcb_shape.h>
@ -71,14 +72,12 @@ bool GRAPHICS_CLEANER::isNullShape( PCB_SHAPE* aShape )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
case SHAPE_T::RECT: case SHAPE_T::RECT:
case SHAPE_T::ARC:
return aShape->GetStart() == aShape->GetEnd(); return aShape->GetStart() == aShape->GetEnd();
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
return aShape->GetRadius() == 0; return aShape->GetRadius() == 0;
case SHAPE_T::ARC:
return aShape->GetCenter() == aShape->GetArcStart();
case SHAPE_T::POLY: case SHAPE_T::POLY:
return aShape->GetPointCount() == 0; return aShape->GetPointCount() == 0;
@ -87,8 +86,7 @@ bool GRAPHICS_CLEANER::isNullShape( PCB_SHAPE* aShape )
return aShape->GetBezierPoints().empty(); return aShape->GetBezierPoints().empty();
default: default:
wxFAIL_MSG( "GRAPHICS_CLEANER::isNullSegment unsupported PCB_SHAPE shape: " UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() );
+ aShape->SHAPE_T_asString() );
return false; return false;
} }
} }
@ -113,8 +111,8 @@ bool GRAPHICS_CLEANER::areEquivalent( PCB_SHAPE* aShape1, PCB_SHAPE* aShape2 )
case SHAPE_T::ARC: case SHAPE_T::ARC:
return aShape1->GetCenter() == aShape2->GetCenter() return aShape1->GetCenter() == aShape2->GetCenter()
&& aShape1->GetArcStart() == aShape2->GetArcStart() && aShape1->GetStart() == aShape2->GetStart()
&& aShape1->GetAngle() == aShape2->GetAngle(); && aShape1->GetArcAngle() == aShape2->GetArcAngle();
case SHAPE_T::POLY: case SHAPE_T::POLY:
// TODO // TODO

View File

@ -82,8 +82,8 @@ void GRAPHICS_IMPORTER_PCBNEW::AddCircle( const VECTOR2D& aCenter, double aRadiu
circle->SetFilled( aFilled ); circle->SetFilled( aFilled );
circle->SetLayer( GetLayer() ); circle->SetLayer( GetLayer() );
circle->SetWidth( MapLineWidth( aWidth ) ); circle->SetWidth( MapLineWidth( aWidth ) );
circle->SetArcCenter( MapCoordinate( aCenter )); circle->SetStart( MapCoordinate( aCenter ));
circle->SetArcStart( MapCoordinate( VECTOR2D( aCenter.x + aRadius, aCenter.y ) ) ); circle->SetEnd( MapCoordinate( VECTOR2D( aCenter.x + aRadius, aCenter.y ) ) );
if( circle->Type() == PCB_FP_SHAPE_T ) if( circle->Type() == PCB_FP_SHAPE_T )
static_cast<FP_SHAPE*>( circle.get() )->SetLocalCoord(); static_cast<FP_SHAPE*>( circle.get() )->SetLocalCoord();
@ -99,9 +99,9 @@ void GRAPHICS_IMPORTER_PCBNEW::AddArc( const VECTOR2D& aCenter, const VECTOR2D&
arc->SetShape( SHAPE_T::ARC ); arc->SetShape( SHAPE_T::ARC );
arc->SetLayer( GetLayer() ); arc->SetLayer( GetLayer() );
arc->SetWidth( MapLineWidth( aWidth ) ); arc->SetWidth( MapLineWidth( aWidth ) );
arc->SetArcCenter( MapCoordinate( aCenter )); arc->SetCenter( MapCoordinate( aCenter ));
arc->SetArcStart( MapCoordinate( aStart ) ); arc->SetStart( MapCoordinate( aStart ) );
arc->SetAngle( aAngle * 10.0 ); // Pcbnew uses the decidegree arc->SetArcAngleAndEnd( aAngle * 10.0 ); // Pcbnew uses the decidegree
if( arc->Type() == PCB_FP_SHAPE_T ) if( arc->Type() == PCB_FP_SHAPE_T )
static_cast<FP_SHAPE*>( arc.get() )->SetLocalCoord(); static_cast<FP_SHAPE*>( arc.get() )->SetLocalCoord();

View File

@ -424,8 +424,7 @@ FOOTPRINT* MICROWAVE_TOOL::createMicrowaveInductor( MICROWAVE_INDUCTOR_PATTERN&
// Generate segments // Generate segments
for( unsigned jj = 1; jj < buffer.size(); jj++ ) for( unsigned jj = 1; jj < buffer.size(); jj++ )
{ {
FP_SHAPE* seg; FP_SHAPE* seg = new FP_SHAPE( footprint, SHAPE_T::SEGMENT );
seg = new FP_SHAPE( footprint, SHAPE_T::SEGMENT );
seg->SetStart( buffer[jj - 1] ); seg->SetStart( buffer[jj - 1] );
seg->SetEnd( buffer[jj] ); seg->SetEnd( buffer[jj] );
seg->SetWidth( aInductorPattern.m_Width ); seg->SetWidth( aInductorPattern.m_Width );

View File

@ -85,9 +85,9 @@ void PAD::AddPrimitiveArc( const wxPoint& aCenter, const wxPoint& aStart, int aA
{ {
PCB_SHAPE* item = new PCB_SHAPE( nullptr, SHAPE_T::ARC ); PCB_SHAPE* item = new PCB_SHAPE( nullptr, SHAPE_T::ARC );
item->SetFilled( false ); item->SetFilled( false );
item->SetArcCenter( aCenter ); item->SetCenter( aCenter );
item->SetArcStart( aStart ); item->SetStart( aStart );
item->SetAngle( aArcAngle ); item->SetArcAngleAndEnd( aArcAngle );
item->SetWidth( aThickness ); item->SetWidth( aThickness );
item->SetParent( this ); item->SetParent( this );
m_editPrimitives.emplace_back( item ); m_editPrimitives.emplace_back( item );

View File

@ -1340,8 +1340,6 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
const COLOR4D& color = m_pcbSettings.GetColor( aShape, aShape->GetLayer() ); const COLOR4D& color = m_pcbSettings.GetColor( aShape, aShape->GetLayer() );
bool sketch = m_pcbSettings.m_sketchGraphics; bool sketch = m_pcbSettings.m_sketchGraphics;
int thickness = getLineThickness( aShape->GetWidth() ); int thickness = getLineThickness( aShape->GetWidth() );
VECTOR2D start( aShape->GetStart() );
VECTOR2D end( aShape->GetEnd() );
if( sketch ) if( sketch )
{ {
@ -1358,14 +1356,14 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
if( sketch ) if( sketch )
{ {
m_gal->DrawSegment( start, end, thickness ); m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
} }
else else
{ {
m_gal->SetIsFill( true ); m_gal->SetIsFill( true );
m_gal->SetIsStroke( false ); m_gal->SetIsStroke( false );
m_gal->DrawSegment( start, end, thickness ); m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
} }
break; break;
@ -1412,28 +1410,28 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
case SHAPE_T::ARC: case SHAPE_T::ARC:
if( sketch ) if( sketch )
{ {
m_gal->DrawArcSegment( start, aShape->GetRadius(), m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
DECIDEG2RAD( aShape->GetArcAngleStart() ), DECIDEG2RAD( aShape->GetArcAngleStart() ),
DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetAngle() ), // Change this DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetArcAngle() ), // Change this
thickness, m_maxError ); thickness, m_maxError );
} }
else else
{ {
m_gal->SetIsFill( true ); m_gal->SetIsFill( true );
m_gal->SetIsStroke( false ); m_gal->SetIsStroke( false );
m_gal->DrawArcSegment( start, aShape->GetRadius(), m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
DECIDEG2RAD( aShape->GetArcAngleStart() ), DECIDEG2RAD( aShape->GetArcAngleStart() ),
DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetAngle() ), // Change this DECIDEG2RAD( aShape->GetArcAngleStart() + aShape->GetArcAngle() ), // Change this
thickness, m_maxError ); thickness, m_maxError );
} }
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
if( sketch ) if( sketch )
{ {
m_gal->DrawCircle( start, aShape->GetRadius() - thickness / 2 ); m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() - thickness / 2 );
m_gal->DrawCircle( start, aShape->GetRadius() + thickness / 2 ); m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() + thickness / 2 );
} }
else else
{ {
@ -1441,7 +1439,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
m_gal->SetIsStroke( thickness > 0 ); m_gal->SetIsStroke( thickness > 0 );
m_gal->SetLineWidth( thickness ); m_gal->SetLineWidth( thickness );
m_gal->DrawCircle( start, aShape->GetRadius() ); m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() );
} }
break; break;

View File

@ -255,7 +255,7 @@ static struct PCB_SHAPE_DESC
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::DISTANCE ) ); &EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::DISTANCE ) );
// TODO show certain properties depending on the shape // TODO show certain properties depending on the shape
//propMgr.AddProperty( new PROPERTY<PCB_SHAPE, double>( _HKI( "Angle" ), //propMgr.AddProperty( new PROPERTY<PCB_SHAPE, double>( _HKI( "Angle" ),
// &PCB_SHAPE::SetAngle, &PCB_SHAPE::GetAngle, PROPERTY_DISPLAY::DECIDEGREE ) ); // &PCB_SHAPE::SetArcAngle, &PCB_SHAPE::GetAngle, PROPERTY_DISPLAY::DECIDEGREE ) );
// TODO or may have different names (arcs) // TODO or may have different names (arcs)
// TODO type? // TODO type?
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End X" ), propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End X" ),

View File

@ -73,8 +73,8 @@ public:
return false; return false;
} }
void SetPosition( const wxPoint& aPos ) override { SetShapePos( aPos ); } void SetPosition( const wxPoint& aPos ) override { setPosition( aPos ); }
wxPoint GetPosition() const override { return GetShapePos(); } wxPoint GetPosition() const override { return getPosition(); }
wxPoint GetCenter() const override { return getCenter(); } wxPoint GetCenter() const override { return getCenter(); }

View File

@ -956,13 +956,13 @@ void PCB_VIA::SwapData( BOARD_ITEM* aImage )
wxPoint PCB_ARC::GetPosition() const wxPoint PCB_ARC::GetPosition() const
{ {
auto center = GetArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ) ); auto center = CalcArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ));
return wxPoint( center.x, center.y ); return wxPoint( center.x, center.y );
} }
double PCB_ARC::GetRadius() const double PCB_ARC::GetRadius() const
{ {
auto center = GetArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ) ); auto center = CalcArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ));
return GetLineLength( wxPoint( center ), m_Start ); return GetLineLength( wxPoint( center ), m_Start );
} }

View File

@ -541,10 +541,8 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( const FP_SHAPE* aShape )
m_plotter->SetColor( getColor( aShape->GetLayer() ) ); m_plotter->SetColor( getColor( aShape->GetLayer() ) );
bool sketch = GetPlotMode() == SKETCH; bool sketch = GetPlotMode() == SKETCH;
int thickness = aShape->GetWidth(); int thickness = aShape->GetWidth();
wxPoint pos( aShape->GetStart() );
wxPoint end( aShape->GetEnd() );
GBR_METADATA gbr_metadata; GBR_METADATA gbr_metadata;
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP ); gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
@ -568,7 +566,8 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( const FP_SHAPE* aShape )
switch( aShape->GetShape() ) switch( aShape->GetShape() )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
m_plotter->ThickSegment( pos, end, thickness, GetPlotMode(), &gbr_metadata ); m_plotter->ThickSegment( aShape->GetStart(), aShape->GetEnd(), thickness, GetPlotMode(),
&gbr_metadata );
break; break;
case SHAPE_T::RECT: case SHAPE_T::RECT:
@ -596,30 +595,38 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( const FP_SHAPE* aShape )
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
radius = KiROUND( GetLineLength( end, pos ) ); radius = KiROUND( GetLineLength( aShape->GetStart(), aShape->GetEnd() ) );
if( aShape->IsFilled() ) if( aShape->IsFilled() )
m_plotter->FilledCircle( pos, radius * 2 + thickness, GetPlotMode(), &gbr_metadata ); {
m_plotter->FilledCircle( aShape->GetStart(), radius * 2 + thickness, GetPlotMode(),
&gbr_metadata );
}
else else
m_plotter->ThickCircle( pos, radius * 2, thickness, GetPlotMode(), &gbr_metadata ); {
m_plotter->ThickCircle( aShape->GetStart(), radius * 2, thickness, GetPlotMode(),
&gbr_metadata );
}
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
{ {
radius = KiROUND( GetLineLength( end, pos ) ); radius = KiROUND( GetLineLength( aShape->GetCenter(), aShape->GetStart() ) );
double startAngle = ArcTangente( end.y - pos.y, end.x - pos.x ); double startAngle = ArcTangente( aShape->GetStart().y - aShape->GetCenter().y,
double endAngle = startAngle + aShape->GetAngle(); aShape->GetStart().x - aShape->GetCenter().x );
double endAngle = startAngle + aShape->GetArcAngle();
// when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg // when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
if( std::abs( aShape->GetAngle() ) == 3600.0 ) if( std::abs( aShape->GetArcAngle() ) == 3600.0 )
{ {
m_plotter->ThickCircle( pos, radius * 2, thickness, GetPlotMode(), &gbr_metadata ); m_plotter->ThickCircle( aShape->GetCenter(), radius * 2, thickness, GetPlotMode(),
&gbr_metadata );
} }
else else
{ {
m_plotter->ThickArc( pos, -endAngle, -startAngle, radius, thickness, GetPlotMode(), m_plotter->ThickArc( aShape->GetCenter(), -endAngle, -startAngle, radius, thickness,
&gbr_metadata ); GetPlotMode(), &gbr_metadata );
} }
} }
break; break;
@ -865,16 +872,11 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
if( !m_layerMask[aShape->GetLayer()] ) if( !m_layerMask[aShape->GetLayer()] )
return; return;
int radius = 0;
double StAngle = 0, EndAngle = 0;
bool sketch = GetPlotMode() == SKETCH; bool sketch = GetPlotMode() == SKETCH;
int thickness = aShape->GetWidth(); int thickness = aShape->GetWidth();
m_plotter->SetColor( getColor( aShape->GetLayer() ) ); m_plotter->SetColor( getColor( aShape->GetLayer() ) );
wxPoint start( aShape->GetStart() );
wxPoint end( aShape->GetEnd() );
GBR_METADATA gbr_metadata; GBR_METADATA gbr_metadata;
if( aShape->GetLayer() == Edge_Cuts ) if( aShape->GetLayer() == Edge_Cuts )
@ -889,34 +891,42 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
switch( aShape->GetShape() ) switch( aShape->GetShape() )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
m_plotter->ThickSegment( start, end, thickness, GetPlotMode(), &gbr_metadata ); m_plotter->ThickSegment( aShape->GetStart(), aShape->GetEnd(), thickness, GetPlotMode(),
&gbr_metadata );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
radius = KiROUND( GetLineLength( end, start ) );
if( aShape->IsFilled() ) if( aShape->IsFilled() )
m_plotter->FilledCircle( start, radius * 2 + thickness, GetPlotMode(), &gbr_metadata ); {
m_plotter->FilledCircle( aShape->GetStart(), aShape->GetRadius() * 2 + thickness,
GetPlotMode(), &gbr_metadata );
}
else else
m_plotter->ThickCircle( start, radius * 2, thickness, GetPlotMode(), &gbr_metadata ); {
m_plotter->ThickCircle( aShape->GetStart(), aShape->GetRadius() * 2, thickness,
GetPlotMode(), &gbr_metadata );
}
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
radius = KiROUND( GetLineLength( end, start ) ); {
StAngle = ArcTangente( end.y - start.y, end.x - start.x ); double startAngle = ArcTangente( aShape->GetStart().y - aShape->GetCenter().y,
EndAngle = StAngle + aShape->GetAngle(); aShape->GetStart().x - aShape->GetCenter().x );
double endAngle = startAngle + aShape->GetArcAngle();
// when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg // when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
if( std::abs( aShape->GetAngle() ) == 3600.0 ) if( std::abs( aShape->GetArcAngle() ) == 3600.0 )
{ {
m_plotter->ThickCircle( start, radius * 2, thickness, GetPlotMode(), &gbr_metadata ); m_plotter->ThickCircle( aShape->GetCenter(), aShape->GetRadius() * 2, thickness,
GetPlotMode(), &gbr_metadata );
} }
else else
{ {
m_plotter->ThickArc( start, -EndAngle, -StAngle, radius, thickness, GetPlotMode(), m_plotter->ThickArc( aShape->GetCenter(), -endAngle, -startAngle, aShape->GetRadius(),
&gbr_metadata ); thickness, GetPlotMode(), &gbr_metadata );
} }
}
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
@ -984,8 +994,7 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
} }
default: default:
wxASSERT_MSG( false, "Unhandled PCB_SHAPE shape" ); UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() );
m_plotter->ThickSegment( start, end, thickness, GetPlotMode(), &gbr_metadata );
} }
} }

View File

@ -862,24 +862,25 @@ void ALTIUM_PCB::HelperCreateBoardOutline( const std::vector<ALTIUM_VERTICE>& aV
else if( cur->isRound ) else if( cur->isRound )
{ {
shape->SetShape( SHAPE_T::ARC ); shape->SetShape( SHAPE_T::ARC );
shape->SetAngle( -NormalizeAngleDegreesPos( cur->endangle - cur->startangle ) * 10. );
double includedAngle = cur->endangle - cur->startangle;
double startradiant = DEG2RAD( cur->startangle ); double startradiant = DEG2RAD( cur->startangle );
wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * cur->radius ), wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * cur->radius ),
-KiROUND( std::sin( startradiant ) * cur->radius ) ); -KiROUND( std::sin( startradiant ) * cur->radius ) );
wxPoint arcStart = cur->center + arcStartOffset; wxPoint arcStart = cur->center + arcStartOffset;
shape->SetArcCenter( cur->center );
shape->SetArcStart( arcStart ); shape->SetCenter( cur->center );
shape->SetStart( arcStart );
shape->SetArcAngleAndEnd( -NormalizeAngleDegreesPos( includedAngle ) * 10.0 );
if( !last->isRound ) if( !last->isRound )
{ {
double endradiant = DEG2RAD( cur->endangle ); double endradiant = DEG2RAD( cur->endangle );
wxPoint arcEndOffset = wxPoint( KiROUND( std::cos( endradiant ) * cur->radius ), wxPoint arcEndOffset = wxPoint( KiROUND( std::cos( endradiant ) * cur->radius ),
-KiROUND( std::sin( endradiant ) * cur->radius ) ); -KiROUND( std::sin( endradiant ) * cur->radius ) );
wxPoint arcEnd = cur->center + arcEndOffset; wxPoint arcEnd = cur->center + arcEndOffset;
PCB_SHAPE* shape2 = new PCB_SHAPE( m_board ); PCB_SHAPE* shape2 = new PCB_SHAPE( m_board, SHAPE_T::SEGMENT );
shape2->SetShape( SHAPE_T::SEGMENT );
m_board->Add( shape2, ADD_MODE::APPEND ); m_board->Add( shape2, ADD_MODE::APPEND );
shape2->SetWidth( m_board->GetDesignSettings().GetLineThickness( Edge_Cuts ) ); shape2->SetWidth( m_board->GetDesignSettings().GetLineThickness( Edge_Cuts ) );
shape2->SetLayer( Edge_Cuts ); shape2->SetLayer( Edge_Cuts );
@ -888,14 +889,11 @@ void ALTIUM_PCB::HelperCreateBoardOutline( const std::vector<ALTIUM_VERTICE>& aV
// TODO: this is more of a hack than the real solution // TODO: this is more of a hack than the real solution
double lineLengthStart = GetLineLength( last->position, arcStart ); double lineLengthStart = GetLineLength( last->position, arcStart );
double lineLengthEnd = GetLineLength( last->position, arcEnd ); double lineLengthEnd = GetLineLength( last->position, arcEnd );
if( lineLengthStart > lineLengthEnd ) if( lineLengthStart > lineLengthEnd )
{
shape2->SetEnd( cur->center + arcEndOffset ); shape2->SetEnd( cur->center + arcEndOffset );
}
else else
{
shape2->SetEnd( cur->center + arcStartOffset ); shape2->SetEnd( cur->center + arcStartOffset );
}
} }
} }
last = cur; last = cur;
@ -1922,22 +1920,25 @@ void ALTIUM_PCB::ParseArcs6Data( const CFB::CompoundFileReader& aReader,
{ {
PCB_SHAPE shape( nullptr ); // just a helper to get the graphic PCB_SHAPE shape( nullptr ); // just a helper to get the graphic
shape.SetWidth( elem.width ); shape.SetWidth( elem.width );
shape.SetArcCenter( elem.center );
if( elem.startangle == 0. && elem.endangle == 360. ) if( elem.startangle == 0. && elem.endangle == 360. )
{ // TODO: other variants to define circle? { // TODO: other variants to define circle?
shape.SetShape( SHAPE_T::CIRCLE ); shape.SetShape( SHAPE_T::CIRCLE );
shape.SetArcStart( elem.center - wxPoint( 0, elem.radius ) ); shape.SetStart( elem.center );
shape.SetEnd( elem.center - wxPoint( 0, elem.radius ) );
} }
else else
{ {
shape.SetShape( SHAPE_T::ARC ); shape.SetShape( SHAPE_T::ARC );
double includedAngle = elem.endangle - elem.startangle;
double startradiant = DEG2RAD( elem.startangle ); double startradiant = DEG2RAD( elem.startangle );
wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * elem.radius ), wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * elem.radius ),
-KiROUND( std::sin( startradiant ) * elem.radius ) ); -KiROUND( std::sin( startradiant ) * elem.radius ) );
shape.SetArcStart( elem.center + arcStartOffset );
shape.SetAngle( -NormalizeAngleDegreesPos( elem.endangle - elem.startangle ) * 10. ); shape.SetCenter( elem.center );
shape.SetStart( elem.center + arcStartOffset );
shape.SetArcAngleAndEnd( -NormalizeAngleDegreesPos( includedAngle ) * 10.0 );
} }
ZONE* zone = new ZONE( m_board ); ZONE* zone = new ZONE( m_board );
@ -2023,24 +2024,27 @@ void ALTIUM_PCB::ParseArcs6Data( const CFB::CompoundFileReader& aReader,
else else
{ {
PCB_SHAPE* shape = HelperCreateAndAddShape( elem.component ); PCB_SHAPE* shape = HelperCreateAndAddShape( elem.component );
shape->SetArcCenter( elem.center );
shape->SetWidth( elem.width ); shape->SetWidth( elem.width );
shape->SetLayer( klayer ); shape->SetLayer( klayer );
if( elem.startangle == 0. && elem.endangle == 360. ) if( elem.startangle == 0. && elem.endangle == 360. )
{ // TODO: other variants to define circle? { // TODO: other variants to define circle?
shape->SetShape( SHAPE_T::CIRCLE ); shape->SetShape( SHAPE_T::CIRCLE );
shape->SetArcStart( elem.center - wxPoint( 0, elem.radius ) ); shape->SetStart( elem.center );
shape->SetEnd( elem.center - wxPoint( 0, elem.radius ) );
} }
else else
{ {
shape->SetShape( SHAPE_T::ARC ); shape->SetShape( SHAPE_T::ARC );
shape->SetAngle( -NormalizeAngleDegreesPos( elem.endangle - elem.startangle ) * 10. );
double includedAngle = elem.endangle - elem.startangle;
double startradiant = DEG2RAD( elem.startangle ); double startradiant = DEG2RAD( elem.startangle );
wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * elem.radius ), wxPoint arcStartOffset = wxPoint( KiROUND( std::cos( startradiant ) * elem.radius ),
-KiROUND( std::sin( startradiant ) * elem.radius ) ); -KiROUND( std::sin( startradiant ) * elem.radius ) );
shape->SetArcStart( elem.center + arcStartOffset );
shape->SetCenter( elem.center );
shape->SetStart( elem.center + arcStartOffset );
shape->SetArcAngleAndEnd( -NormalizeAngleDegreesPos( includedAngle ) * 10.0 );
} }
HelperShapeSetLocalCoord( shape, elem.component ); HelperShapeSetLocalCoord( shape, elem.component );
@ -2363,9 +2367,9 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
// circle // circle
shape->SetShape( SHAPE_T::CIRCLE ); shape->SetShape( SHAPE_T::CIRCLE );
shape->SetFilled( true ); shape->SetFilled( true );
shape->SetArcCenter( aElem.position ); shape->SetStart( aElem.position );
shape->SetEnd( aElem.position - wxPoint( 0, aElem.topsize.x / 4 ) );
shape->SetWidth( aElem.topsize.x / 2 ); shape->SetWidth( aElem.topsize.x / 2 );
shape->SetArcStart( aElem.position - wxPoint( 0, aElem.topsize.x / 4 ) );
} }
else if( aElem.topsize.x < aElem.topsize.y ) else if( aElem.topsize.x < aElem.topsize.y )
{ {
@ -2396,9 +2400,9 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
shape->SetShape( SHAPE_T::CIRCLE ); shape->SetShape( SHAPE_T::CIRCLE );
shape->SetFilled( true ); shape->SetFilled( true );
shape->SetLayer( klayer ); shape->SetLayer( klayer );
shape->SetArcCenter( aElem.position ); shape->SetStart( aElem.position );
shape->SetEnd( aElem.position - wxPoint( 0, aElem.topsize.x / 4 ) );
shape->SetWidth( aElem.topsize.x / 2 ); shape->SetWidth( aElem.topsize.x / 2 );
shape->SetArcStart( aElem.position - wxPoint( 0, aElem.topsize.x / 4 ) );
HelperShapeSetLocalCoord( shape, aElem.component ); HelperShapeSetLocalCoord( shape, aElem.component );
} }
else else

View File

@ -2818,8 +2818,8 @@ PCB_SHAPE* CADSTAR_PCB_ARCHIVE_LOADER::getShapeFromVertex( const POINT& aCadstar
else else
shape = new PCB_SHAPE( aContainer, SHAPE_T::ARC ); shape = new PCB_SHAPE( aContainer, SHAPE_T::ARC );
shape->SetArcStart( startPoint ); shape->SetCenter( centerPoint );
shape->SetArcCenter( centerPoint ); shape->SetStart( startPoint );
arcStartAngle = getPolarAngle( startPoint - centerPoint ); arcStartAngle = getPolarAngle( startPoint - centerPoint );
arcEndAngle = getPolarAngle( endPoint - centerPoint ); arcEndAngle = getPolarAngle( endPoint - centerPoint );
@ -2828,9 +2828,9 @@ PCB_SHAPE* CADSTAR_PCB_ARCHIVE_LOADER::getShapeFromVertex( const POINT& aCadstar
// with opposite start/end points and same centre point) // with opposite start/end points and same centre point)
if( cw ) if( cw )
shape->SetAngle( NormalizeAnglePos( arcAngle ) ); shape->SetArcAngleAndEnd( NormalizeAnglePos( arcAngle ) );
else else
shape->SetAngle( NormalizeAngleNeg( arcAngle ) ); shape->SetArcAngleAndEnd( NormalizeAngleNeg( arcAngle ) );
break; break;
} }
@ -2960,12 +2960,12 @@ SHAPE_LINE_CHAIN CADSTAR_PCB_ARCHIVE_LOADER::getLineChainFromShapes( const std::
if( shape->GetClass() == wxT( "MGRAPHIC" ) ) if( shape->GetClass() == wxT( "MGRAPHIC" ) )
{ {
FP_SHAPE* fp_shape = (FP_SHAPE*) shape; FP_SHAPE* fp_shape = (FP_SHAPE*) shape;
SHAPE_ARC arc( fp_shape->GetStart0(), fp_shape->GetEnd0(), (double) fp_shape->GetAngle() / 10.0 ); SHAPE_ARC arc( fp_shape->GetCenter0(), fp_shape->GetStart0(), fp_shape->GetArcAngle() / 10.0 );
lineChain.Append( arc ); lineChain.Append( arc );
} }
else else
{ {
SHAPE_ARC arc( shape->GetCenter(), shape->GetArcStart(), (double) shape->GetAngle() / 10.0 ); SHAPE_ARC arc( shape->GetCenter(), shape->GetStart(), shape->GetArcAngle() / 10.0 );
lineChain.Append( arc ); lineChain.Append( arc );
} }
} }
@ -3041,15 +3041,13 @@ std::vector<PCB_TRACK*> CADSTAR_PCB_ARCHIVE_LOADER::makeTracksFromShapes(
if( shape->GetClass() == wxT( "MGRAPHIC" ) ) if( shape->GetClass() == wxT( "MGRAPHIC" ) )
{ {
FP_SHAPE* fp_shape = (FP_SHAPE*) shape; FP_SHAPE* fp_shape = (FP_SHAPE*) shape;
SHAPE_ARC arc( fp_shape->GetStart0(), fp_shape->GetEnd0(), SHAPE_ARC arc( fp_shape->GetCenter0(), fp_shape->GetStart0(),
(double) fp_shape->GetAngle() / 10.0 ); fp_shape->GetArcAngle() / 10.0 );
SHAPE_ARC arc( fp_shape->GetStart0(), fp_shape->GetEnd0(),
fp_shape->GetAngle() / 10.0 );
track = new PCB_ARC( aParentContainer, &arc ); track = new PCB_ARC( aParentContainer, &arc );
} }
else else
{ {
SHAPE_ARC arc( shape->GetCenter(), shape->GetArcStart(), (double) shape->GetAngle() / 10.0 ); SHAPE_ARC arc( shape->GetCenter(), shape->GetStart(), shape->GetArcAngle() / 10.0 );
track = new PCB_ARC( aParentContainer, &arc ); track = new PCB_ARC( aParentContainer, &arc );
} }
break; break;

View File

@ -715,6 +715,7 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
if( !w.curve ) if( !w.curve )
{ {
shape->SetShape( SHAPE_T::SEGMENT );
shape->SetStart( start ); shape->SetStart( start );
shape->SetEnd( end ); shape->SetEnd( end );
} }
@ -723,9 +724,9 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
wxPoint center = ConvertArcCenter( start, end, *w.curve ); wxPoint center = ConvertArcCenter( start, end, *w.curve );
shape->SetShape( SHAPE_T::ARC ); shape->SetShape( SHAPE_T::ARC );
shape->SetStart( center ); shape->SetCenter( center );
shape->SetEnd( start ); shape->SetStart( start );
shape->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way shape->SetArcAngleAndEnd( *w.curve * -10.0 ); // KiCad rotates the other way
} }
shape->SetLayer( layer ); shape->SetLayer( layer );
@ -1773,9 +1774,9 @@ void EAGLE_PLUGIN::packageWire( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
dwg = new FP_SHAPE( aFootprint, SHAPE_T::ARC ); dwg = new FP_SHAPE( aFootprint, SHAPE_T::ARC );
wxPoint center = ConvertArcCenter( start, end, *w.curve ); wxPoint center = ConvertArcCenter( start, end, *w.curve );
dwg->SetStart0( center ); dwg->SetCenter0( center );
dwg->SetEnd0( start ); dwg->SetStart0( start );
dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way dwg->SetArcAngleAndEnd0( *w.curve * -10.0 ); // KiCad rotates the other way
} }
dwg->SetLayer( layer ); dwg->SetLayer( layer );

View File

@ -2120,16 +2120,16 @@ bool FABMASTER::loadFootprints( BOARD* aBoard )
if( src->mirror ) if( src->mirror )
{ {
arc->SetLayer( FlipLayer( layer ) ); arc->SetLayer( FlipLayer( layer ) );
arc->SetArcCenter( wxPoint( lsrc->center_x, 2 * src->y - lsrc->center_y )); arc->SetCenter( wxPoint( lsrc->center_x, 2 * src->y - lsrc->center_y ) );
arc->SetArcStart( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) ); arc->SetStart( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
arc->SetAngle( lsrc->result.GetCentralAngle() * 10.0 ); arc->SetArcAngleAndEnd0( lsrc->result.GetCentralAngle() * 10.0 );
} }
else else
{ {
arc->SetLayer( layer ); arc->SetLayer( layer );
arc->SetArcCenter( wxPoint( lsrc->center_x, lsrc->center_y )); arc->SetCenter( wxPoint( lsrc->center_x, lsrc->center_y ) );
arc->SetArcStart( wxPoint( lsrc->end_x, lsrc->end_y ) ); arc->SetStart( wxPoint( lsrc->end_x, lsrc->end_y ) );
arc->SetAngle( -lsrc->result.GetCentralAngle() * 10.0 ); arc->SetArcAngleAndEnd0( -lsrc->result.GetCentralAngle() * 10.0 );
} }
arc->SetWidth( lsrc->width ); arc->SetWidth( lsrc->width );
@ -2773,9 +2773,9 @@ bool FABMASTER::loadOutline( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRA
PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC ); PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC );
arc->SetLayer( layer ); arc->SetLayer( layer );
arc->SetArcCenter( wxPoint( src->center_x, src->center_y )); arc->SetCenter( wxPoint( src->center_x, src->center_y ) );
arc->SetArcStart( wxPoint( src->start_x, src->start_y ) ); arc->SetStart( wxPoint( src->start_x, src->start_y ) );
arc->SetAngle( src->result.GetCentralAngle() * 10.0 ); arc->SetArcAngleAndEnd( src->result.GetCentralAngle() * 10.0 );
arc->SetWidth( src->width ); arc->SetWidth( src->width );
if( arc->GetWidth() == 0 ) if( arc->GetWidth() == 0 )
@ -2888,9 +2888,9 @@ bool FABMASTER::loadGraphics( BOARD* aBoard )
PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC ); PCB_SHAPE* arc = new PCB_SHAPE( aBoard, SHAPE_T::ARC );
arc->SetLayer( layer ); arc->SetLayer( layer );
arc->SetArcCenter( wxPoint( src->center_x, src->center_y )); arc->SetCenter( wxPoint( src->center_x, src->center_y ) );
arc->SetArcStart( wxPoint( src->start_x, src->start_y ) ); arc->SetStart( wxPoint( src->start_x, src->start_y ) );
arc->SetAngle( src->result.GetCentralAngle() * 10.0 ); arc->SetArcAngleAndEnd( src->result.GetCentralAngle() * 10.0 );
arc->SetWidth( src->width ); arc->SetWidth( src->width );
aBoard->Add( arc, ADD_MODE::APPEND ); aBoard->Add( arc, ADD_MODE::APPEND );

View File

@ -497,7 +497,7 @@ FOOTPRINT* GPCB_FPL_CACHE::parseFOOTPRINT( LINE_READER* aLineReader )
wxPoint centre( parseInt( parameters[2], conv_unit ), wxPoint centre( parseInt( parameters[2], conv_unit ),
parseInt( parameters[3], conv_unit ) ); parseInt( parameters[3], conv_unit ) );
shape->SetStart0( centre ); shape->SetCenter0( centre );
// Pcbnew start angles are inverted and 180 degrees from Geda PCB angles. // Pcbnew start angles are inverted and 180 degrees from Geda PCB angles.
double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0; double start_angle = parseInt( parameters[6], -10.0 ) + 1800.0;
@ -509,14 +509,14 @@ FOOTPRINT* GPCB_FPL_CACHE::parseFOOTPRINT( LINE_READER* aLineReader )
if( sweep_angle == -3600.0 ) if( sweep_angle == -3600.0 )
shape->SetShape( SHAPE_T::CIRCLE ); shape->SetShape( SHAPE_T::CIRCLE );
// Angle value is clockwise in gpcb and Pcbnew.
shape->SetAngle( sweep_angle );
shape->SetEnd0( wxPoint( radius, 0 ) );
// Calculate start point coordinate of arc // Calculate start point coordinate of arc
wxPoint arcStart( shape->GetEnd0() ); wxPoint arcStart( radius, 0 );
RotatePoint( &arcStart, -start_angle ); RotatePoint( &arcStart, -start_angle );
shape->SetEnd0( centre + arcStart ); shape->SetStart0( arcStart + centre );
// Angle value is clockwise in gpcb and Pcbnew.
shape->SetArcAngleAndEnd0( sweep_angle );
shape->SetWidth( parseInt( parameters[8], conv_unit ) ); shape->SetWidth( parseInt( parameters[8], conv_unit ) );
shape->SetDrawCoord(); shape->SetDrawCoord();
continue; continue;

View File

@ -803,10 +803,6 @@ void PCB_IO::format( const PCB_SHAPE* aShape, int aNestLevel ) const
locked.c_str(), locked.c_str(),
FormatInternalUnits( aShape->GetStart() ).c_str(), FormatInternalUnits( aShape->GetStart() ).c_str(),
FormatInternalUnits( aShape->GetEnd() ).c_str() ); FormatInternalUnits( aShape->GetEnd() ).c_str() );
if( aShape->GetAngle() != 0.0 )
m_out->Print( 0, " (angle %s)", FormatAngle( aShape->GetAngle() ).c_str() );
break; break;
case SHAPE_T::RECT: case SHAPE_T::RECT:
@ -826,9 +822,9 @@ void PCB_IO::format( const PCB_SHAPE* aShape, int aNestLevel ) const
case SHAPE_T::ARC: case SHAPE_T::ARC:
m_out->Print( aNestLevel, "(gr_arc%s (start %s) (end %s) (angle %s)", m_out->Print( aNestLevel, "(gr_arc%s (start %s) (end %s) (angle %s)",
locked.c_str(), locked.c_str(),
FormatInternalUnits( aShape->GetCenter() ).c_str(),
FormatInternalUnits( aShape->GetStart() ).c_str(), FormatInternalUnits( aShape->GetStart() ).c_str(),
FormatInternalUnits( aShape->GetEnd() ).c_str(), FormatAngle( aShape->GetArcAngle() ).c_str() );
FormatAngle( aShape->GetAngle() ).c_str() );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -905,7 +901,7 @@ void PCB_IO::format( const PCB_SHAPE* aShape, int aNestLevel ) const
break; break;
default: default:
wxFAIL_MSG( "PCB_IO::format not implemented for " + aShape->SHAPE_T_asString() ); UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() );
return; return;
}; };
@ -960,9 +956,9 @@ void PCB_IO::format( const FP_SHAPE* aFPShape, int aNestLevel ) const
case SHAPE_T::ARC: case SHAPE_T::ARC:
m_out->Print( aNestLevel, "(fp_arc%s (start %s) (end %s) (angle %s)", m_out->Print( aNestLevel, "(fp_arc%s (start %s) (end %s) (angle %s)",
locked.c_str(), locked.c_str(),
FormatInternalUnits( aFPShape->GetCenter0() ).c_str(),
FormatInternalUnits( aFPShape->GetStart0() ).c_str(), FormatInternalUnits( aFPShape->GetStart0() ).c_str(),
FormatInternalUnits( aFPShape->GetEnd0() ).c_str(), FormatAngle( aFPShape->GetArcAngle() ).c_str() );
FormatAngle( aFPShape->GetAngle() ).c_str() );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -1635,9 +1631,9 @@ void PCB_IO::format( const PAD* aPad, int aNestLevel ) const
case SHAPE_T::ARC: case SHAPE_T::ARC:
m_out->Print( nested_level, "(gr_arc (start %s) (end %s) (angle %s)", m_out->Print( nested_level, "(gr_arc (start %s) (end %s) (angle %s)",
FormatInternalUnits( primitive->GetCenter() ).c_str(),
FormatInternalUnits( primitive->GetStart() ).c_str(), FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(), FormatAngle( primitive->GetArcAngle() ).c_str() );
FormatAngle( primitive->GetAngle() ).c_str() );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:

View File

@ -2392,7 +2392,7 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
pt.x = parseBoardUnits( "X coordinate" ); pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" ); pt.y = parseBoardUnits( "Y coordinate" );
shape->SetArcCenter( pt ); shape->SetCenter( pt );
NeedRIGHT(); NeedRIGHT();
NeedLEFT(); NeedLEFT();
token = NextTok(); token = NextTok();
@ -2402,7 +2402,7 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
pt.x = parseBoardUnits( "X coordinate" ); pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" ); pt.y = parseBoardUnits( "Y coordinate" );
shape->SetArcStart( pt ); shape->SetStart( pt );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -2426,7 +2426,7 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
pt.x = parseBoardUnits( "X coordinate" ); pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" ); pt.y = parseBoardUnits( "Y coordinate" );
shape->SetArcCenter( pt ); shape->SetStart( pt );
NeedRIGHT(); NeedRIGHT();
NeedLEFT(); NeedLEFT();
@ -2570,7 +2570,8 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, or gp_rect" ); Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, or gp_rect" );
} }
bool foundFill = false; bool foundFill = false;
double angle;
for( token = NextTok(); token != T_RIGHT; token = NextTok() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
@ -2582,7 +2583,11 @@ PCB_SHAPE* PCB_PARSER::parsePCB_SHAPE()
switch( token ) switch( token )
{ {
case T_angle: case T_angle:
shape->SetAngle( parseDouble( "segment angle" ) * 10.0 ); angle = parseDouble( "segment angle" ) * 10.0;
if( shape->GetShape() == SHAPE_T::ARC )
shape->SetArcAngleAndEnd( angle );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -3419,7 +3424,7 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
FP_SHAPE* shape = parseFP_SHAPE(); FP_SHAPE* shape = parseFP_SHAPE();
// Drop 0 and NaN angles as these can corrupt/crash the schematic // Drop 0 and NaN angles as these can corrupt/crash the schematic
if( std::isnormal( shape->GetAngle() ) ) if( std::isnormal( shape->GetArcAngle() ) )
{ {
shape->SetParent( footprint.get() ); shape->SetParent( footprint.get() );
shape->SetDrawCoord(); shape->SetDrawCoord();
@ -3654,7 +3659,7 @@ FP_SHAPE* PCB_PARSER::parseFP_SHAPE()
pt.x = parseBoardUnits( "X coordinate" ); pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" ); pt.y = parseBoardUnits( "Y coordinate" );
shape->SetStart0( pt ); shape->SetCenter0( pt );
NeedRIGHT(); NeedRIGHT();
NeedLEFT(); NeedLEFT();
token = NextTok(); token = NextTok();
@ -3664,7 +3669,7 @@ FP_SHAPE* PCB_PARSER::parseFP_SHAPE()
pt.x = parseBoardUnits( "X coordinate" ); pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" ); pt.y = parseBoardUnits( "Y coordinate" );
shape->SetEnd0( pt ); shape->SetStart0( pt );
NeedRIGHT(); NeedRIGHT();
NeedLEFT(); NeedLEFT();
token = NextTok(); token = NextTok();
@ -3672,9 +3677,7 @@ FP_SHAPE* PCB_PARSER::parseFP_SHAPE()
if( token != T_angle ) if( token != T_angle )
Expecting( T_angle ); Expecting( T_angle );
// Setting angle will set m_thirdPoint0, so must be done after setting shape->SetArcAngleAndEnd0( parseDouble( "segment angle" ) * 10.0 );
// m_start0 and m_end0
shape->SetAngle( parseDouble( "segment angle" ) * 10.0 );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -4346,8 +4349,8 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
{ {
case T_gr_arc: case T_gr_arc:
dummyShape = parsePCB_SHAPE(); dummyShape = parsePCB_SHAPE();
pad->AddPrimitiveArc( dummyShape->GetCenter(), dummyShape->GetArcStart(), pad->AddPrimitiveArc( dummyShape->GetCenter(), dummyShape->GetStart(),
dummyShape->GetAngle(), dummyShape->GetWidth() ); dummyShape->GetArcAngle(), dummyShape->GetWidth() );
break; break;
case T_gr_line: case T_gr_line:

View File

@ -1582,21 +1582,18 @@ void LEGACY_PLUGIN::loadFP_SHAPE( FOOTPRINT* aFootprint )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
{ {
BIU start0_x = biuParse( line + SZ( "DA" ), &data ); BIU center0_x = biuParse( line + SZ( "DA" ), &data );
BIU start0_y = biuParse( data, &data ); BIU center0_y = biuParse( data, &data );
BIU end0_x = biuParse( data, &data ); BIU start0_x = biuParse( data, &data );
BIU end0_y = biuParse( data, &data ); BIU start0_y = biuParse( data, &data );
double angle = degParse( data, &data ); double angle = degParse( data, &data );
width = biuParse( data, &data ); width = biuParse( data, &data );
layer = layerParse( data ); layer = layerParse( data );
dwg->SetCenter0( wxPoint( center0_x, center0_y ) );
dwg->SetStart0( wxPoint( start0_x, start0_y ) ); dwg->SetStart0( wxPoint( start0_x, start0_y ) );
dwg->SetEnd0( wxPoint( end0_x, end0_y ) ); dwg->SetArcAngleAndEnd0( angle );
// Setting angle will set m_thirdPoint0, so must be done after setting
// m_start0 and m_end0
dwg->SetAngle( angle );
break; break;
} }
@ -1882,7 +1879,7 @@ void LEGACY_PLUGIN::loadPCB_LINE()
case 2: case 2:
double angle; double angle;
angle = degParse( data ); angle = degParse( data );
dseg->SetAngle( angle ); // m_Angle dseg->SetArcAngleAndEnd( angle ); // m_Angle
break; break;
case 3: case 3:
const_cast<KIID&>( dseg->m_Uuid ) = KIID( data ); const_cast<KIID&>( dseg->m_Uuid ) = KIID( data );

View File

@ -174,12 +174,9 @@ void PCB_ARC::AddToFootprint( FOOTPRINT* aFootprint )
FP_SHAPE* arc = new FP_SHAPE( aFootprint, IsCircle() ? SHAPE_T::CIRCLE : SHAPE_T::ARC ); FP_SHAPE* arc = new FP_SHAPE( aFootprint, IsCircle() ? SHAPE_T::CIRCLE : SHAPE_T::ARC );
aFootprint->Add( arc ); aFootprint->Add( arc );
arc->SetStart0( wxPoint( m_positionX, m_positionY ) ); arc->SetCenter0( wxPoint( m_positionX, m_positionY ) );
arc->SetEnd0( wxPoint( m_StartX, m_StartY ) ); arc->SetStart0( wxPoint( m_StartX, m_StartY ) );
arc->SetArcAngleAndEnd0( -m_Angle );
// Setting angle will set m_thirdPoint0, so must be done after setting
// m_start0 and m_end0
arc->SetAngle( -m_Angle );
arc->SetWidth( m_Width ); arc->SetWidth( m_Width );
arc->SetLayer( m_KiCadLayer ); arc->SetLayer( m_KiCadLayer );
@ -197,9 +194,9 @@ void PCB_ARC::AddToBoard()
arc->SetFilled( false ); arc->SetFilled( false );
arc->SetLayer( m_KiCadLayer ); arc->SetLayer( m_KiCadLayer );
arc->SetStart( wxPoint( m_positionX, m_positionY ) ); arc->SetCenter( wxPoint( m_positionX, m_positionY ) );
arc->SetEnd( wxPoint( m_StartX, m_StartY ) ); arc->SetStart( wxPoint( m_StartX, m_StartY ) );
arc->SetAngle( -m_Angle ); arc->SetArcAngleAndEnd( -m_Angle );
arc->SetWidth( m_Width ); arc->SetWidth( m_Width );
} }

View File

@ -150,7 +150,7 @@ void PCB_LINE::AddToBoard()
} }
else else
{ {
PCB_SHAPE* segment = new PCB_SHAPE( m_board ); PCB_SHAPE* segment = new PCB_SHAPE( m_board, SHAPE_T::SEGMENT );
m_board->Add( segment, ADD_MODE::APPEND ); m_board->Add( segment, ADD_MODE::APPEND );
segment->SetLayer( m_KiCadLayer ); segment->SetLayer( m_KiCadLayer );

View File

@ -802,10 +802,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
path->SetAperture( 0 );//scale( graphic->GetWidth() ) ); path->SetAperture( 0 );//scale( graphic->GetWidth() ) );
path->SetLayerId( "signal" ); path->SetLayerId( "signal" );
wxPoint arc_centre = graphic->GetStart0(); wxPoint arc_centre = graphic->GetCenter0();
double radius = graphic->GetRadius() + graphic->GetWidth() / 2; double radius = graphic->GetRadius() + graphic->GetWidth()/2;
double arcStartDeg = graphic->GetArcAngleStart() / 10.0; double arcStartDeg = graphic->GetArcAngleStart() / 10.0;
double arcAngleDeg = graphic->GetAngle() / 10.0; double arcAngleDeg = graphic->GetArcAngle() / 10.0;
// For some obscure reason, FreeRouter does not show the same polygonal // For some obscure reason, FreeRouter does not show the same polygonal
// shape for polygons CW and CCW. So used only the order of corners // shape for polygons CW and CCW. So used only the order of corners
@ -841,10 +841,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
wxPoint move = graphic->GetCenter() - arc_centre; wxPoint move = graphic->GetCenter() - arc_centre;
TransformCircleToPolygon( polyBuffer, graphic->GetArcStart() - move, TransformCircleToPolygon( polyBuffer, graphic->GetStart() - move,
graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE ); graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE );
TransformCircleToPolygon( polyBuffer, graphic->GetArcEnd() - move, TransformCircleToPolygon( polyBuffer, graphic->GetEnd() - move,
graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE ); graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE );
polyBuffer.Simplify( SHAPE_POLY_SET::PM_FAST ); polyBuffer.Simplify( SHAPE_POLY_SET::PM_FAST );

View File

@ -321,7 +321,7 @@ SHAPE_POLY_SET CONVERT_TOOL::makePolysFromSegs( const std::deque<EDA_ITEM*>& aIt
else else
{ {
PCB_SHAPE* ps = static_cast<PCB_SHAPE*>( aItem ); PCB_SHAPE* ps = static_cast<PCB_SHAPE*>( aItem );
arc = SHAPE_ARC( ps->GetArcStart(), ps->GetArcMid(), ps->GetArcEnd(), arc = SHAPE_ARC( ps->GetStart(), ps->GetArcMid(), ps->GetEnd(),
ps->GetWidth() ); ps->GetWidth() );
} }
@ -653,8 +653,8 @@ int CONVERT_TOOL::CreateLines( const TOOL_EVENT& aEvent )
PCB_ARC* arc = new PCB_ARC( parent ); PCB_ARC* arc = new PCB_ARC( parent );
arc->SetLayer( targetLayer ); arc->SetLayer( targetLayer );
arc->SetStart( graphic->GetArcStart() ); arc->SetStart( graphic->GetStart() );
arc->SetEnd( graphic->GetArcEnd() ); arc->SetEnd( graphic->GetEnd() );
arc->SetMid( graphic->GetArcMid() ); arc->SetMid( graphic->GetArcMid() );
commit.Add( arc ); commit.Add( arc );
@ -804,20 +804,19 @@ int CONVERT_TOOL::SegmentToArc( const TOOL_EVENT& aEvent )
if( source->Type() == PCB_SHAPE_T || source->Type() == PCB_FP_SHAPE_T ) if( source->Type() == PCB_SHAPE_T || source->Type() == PCB_FP_SHAPE_T )
{ {
PCB_SHAPE* line = static_cast<PCB_SHAPE*>( source ); PCB_SHAPE* line = static_cast<PCB_SHAPE*>( source );
PCB_SHAPE* arc = new PCB_SHAPE( parent ); PCB_SHAPE* arc = new PCB_SHAPE( parent, SHAPE_T::ARC );
VECTOR2I center = GetArcCenter( start, mid, end ); VECTOR2I center = CalcArcCenter( start, mid, end );
arc->SetShape( SHAPE_T::ARC );
arc->SetFilled( false ); arc->SetFilled( false );
arc->SetLayer( layer ); arc->SetLayer( layer );
arc->SetWidth( line->GetWidth() ); arc->SetWidth( line->GetWidth() );
arc->SetArcCenter( wxPoint( center )); arc->SetCenter( wxPoint( center ) );
arc->SetArcStart( wxPoint( start ) ); arc->SetStart( wxPoint( start ) );
arc->SetAngle( GetArcAngle( start, mid, end ) ); arc->SetEnd( wxPoint( end ) );
arc->SetArcAngle( CalcArcAngle( start, mid, end ) );
arc->SetArcEnd( wxPoint( end ) );
commit.Add( arc ); commit.Add( arc );
} }
else else
@ -848,21 +847,13 @@ OPT<SEG> CONVERT_TOOL::getStartEndPoints( EDA_ITEM* aItem, int* aWidth )
case PCB_SHAPE_T: case PCB_SHAPE_T:
case PCB_FP_SHAPE_T: case PCB_FP_SHAPE_T:
{ {
PCB_SHAPE* line = static_cast<PCB_SHAPE*>( aItem ); PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
if( aWidth ) if( aWidth )
*aWidth = line->GetWidth(); *aWidth = shape->GetWidth();
if( line->GetShape() == SHAPE_T::SEGMENT ) return boost::make_optional<SEG>( { VECTOR2I( shape->GetStart() ),
{ VECTOR2I( shape->GetEnd() ) } );
return boost::make_optional<SEG>( { VECTOR2I( line->GetStart() ),
VECTOR2I( line->GetEnd() ) } );
}
else
{
return boost::make_optional<SEG>( { VECTOR2I( line->GetArcStart() ),
VECTOR2I( line->GetArcEnd() ) } );
}
} }
case PCB_TRACE_T: case PCB_TRACE_T:

View File

@ -1713,17 +1713,16 @@ bool DRAWING_TOOL::drawSegment( const std::string& aTool, PCB_SHAPE** aGraphic,
static void updateArcFromConstructionMgr( const KIGFX::PREVIEW::ARC_GEOM_MANAGER& aMgr, static void updateArcFromConstructionMgr( const KIGFX::PREVIEW::ARC_GEOM_MANAGER& aMgr,
PCB_SHAPE& aArc ) PCB_SHAPE& aArc )
{ {
auto vec = aMgr.GetOrigin(); VECTOR2I vec = aMgr.GetOrigin();
aArc.SetArcCenter( { vec.x, vec.y } ); aArc.SetCenter( (wxPoint) vec );
vec = aMgr.GetStartRadiusEnd(); vec = aMgr.GetStartRadiusEnd();
aArc.SetArcStart( { vec.x, vec.y } ); aArc.SetStart( (wxPoint) vec );
aArc.SetAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
vec = aMgr.GetEndRadiusEnd(); vec = aMgr.GetEndRadiusEnd();
aArc.SetArcEnd( { vec.x, vec.y } ); aArc.SetEnd( (wxPoint) vec );
aArc.SetArcAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
} }
@ -1892,7 +1891,7 @@ bool DRAWING_TOOL::drawArc( const std::string& aTool, PCB_SHAPE** aGraphic, bool
{ {
if( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_START ) if( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_START )
{ {
graphic->SetAngle( 900, true ); graphic->SetArcAngleAndEnd( 900 );
frame()->OnEditItemRequest( graphic ); frame()->OnEditItemRequest( graphic );
m_view->Update( &preview ); m_view->Update( &preview );
frame()->SetMsgPanel( graphic ); frame()->SetMsgPanel( graphic );

View File

@ -555,7 +555,7 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent )
VECTOR2I newCenter = circlehelper.Center; VECTOR2I newCenter = circlehelper.Center;
VECTOR2I newStart = cSegTanStart.LineProject( newCenter ); VECTOR2I newStart = cSegTanStart.LineProject( newCenter );
VECTOR2I newEnd = cSegTanEnd.LineProject( newCenter ); VECTOR2I newEnd = cSegTanEnd.LineProject( newCenter );
VECTOR2I newMid = GetArcMid( newStart, newEnd, newCenter ); VECTOR2I newMid = CalcArcMid( newStart, newEnd, newCenter );
// Update objects // Update objects
theArc->SetStart( (wxPoint) newStart ); theArc->SetStart( (wxPoint) newStart );

View File

@ -23,6 +23,7 @@
#include "pad_tool.h" #include "pad_tool.h"
#include <macros.h>
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <view/view.h> #include <view/view.h>
@ -612,12 +613,38 @@ PCB_LAYER_ID PAD_TOOL::explodePad( PAD* aPad )
shape->SetShape( primitive->GetShape() ); shape->SetShape( primitive->GetShape() );
shape->SetFilled( primitive->IsFilled() ); shape->SetFilled( primitive->IsFilled() );
shape->SetWidth( primitive->GetWidth() ); shape->SetWidth( primitive->GetWidth() );
shape->SetStart( primitive->GetStart() );
shape->SetEnd( primitive->GetEnd() ); switch( shape->GetShape() )
shape->SetBezierC1( primitive->GetBezierC1()); {
shape->SetBezierC2( primitive->GetBezierC2()); case SHAPE_T::SEGMENT:
shape->SetAngle( primitive->GetAngle() ); case SHAPE_T::RECT:
shape->SetPolyShape( primitive->GetPolyShape() ); case SHAPE_T::CIRCLE:
shape->SetStart( primitive->GetStart() );
shape->SetEnd( primitive->GetEnd() );
break;
case SHAPE_T::ARC:
shape->SetStart( primitive->GetStart() );
shape->SetEnd( primitive->GetEnd() );
shape->SetCenter( primitive->GetCenter() );
shape->SetArcAngle( primitive->GetArcAngle() );
break;
case SHAPE_T::BEZIER:
shape->SetStart( primitive->GetStart() );
shape->SetEnd( primitive->GetEnd() );
shape->SetBezierC1( primitive->GetBezierC1() );
shape->SetBezierC2( primitive->GetBezierC2() );
break;
case SHAPE_T::POLY:
shape->SetPolyShape( primitive->GetPolyShape() );
break;
default:
UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
}
shape->SetLocalCoord(); shape->SetLocalCoord();
shape->Move( aPad->GetPosition() ); shape->Move( aPad->GetPosition() );
shape->Rotate( aPad->GetPosition(), aPad->GetOrientation() ); shape->Rotate( aPad->GetPosition(), aPad->GetOrientation() );
@ -724,12 +751,38 @@ void PAD_TOOL::recombinePad( PAD* aPad )
pcbShape->SetShape( fpShape->GetShape() ); pcbShape->SetShape( fpShape->GetShape() );
pcbShape->SetFilled( fpShape->IsFilled() ); pcbShape->SetFilled( fpShape->IsFilled() );
pcbShape->SetWidth( fpShape->GetWidth() ); pcbShape->SetWidth( fpShape->GetWidth() );
pcbShape->SetStart( fpShape->GetStart() );
pcbShape->SetEnd( fpShape->GetEnd() );
pcbShape->SetBezierC1( fpShape->GetBezierC1()); switch( pcbShape->GetShape() )
pcbShape->SetBezierC2( fpShape->GetBezierC2()); {
pcbShape->SetAngle( fpShape->GetAngle() ); case SHAPE_T::SEGMENT:
pcbShape->SetPolyShape( fpShape->GetPolyShape() ); case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
pcbShape->SetStart( fpShape->GetStart() );
pcbShape->SetEnd( fpShape->GetEnd() );
break;
case SHAPE_T::ARC:
pcbShape->SetStart( fpShape->GetStart() );
pcbShape->SetEnd( fpShape->GetEnd() );
pcbShape->SetCenter( fpShape->GetCenter() );
pcbShape->SetArcAngle( fpShape->GetArcAngle() );
break;
case SHAPE_T::BEZIER:
pcbShape->SetStart( fpShape->GetStart() );
pcbShape->SetEnd( fpShape->GetEnd() );
pcbShape->SetBezierC1( fpShape->GetBezierC1() );
pcbShape->SetBezierC2( fpShape->GetBezierC2() );
break;
case SHAPE_T::POLY:
pcbShape->SetPolyShape( fpShape->GetPolyShape() );
break;
default:
UNIMPLEMENTED_FOR( pcbShape->SHAPE_T_asString() );
}
pcbShape->Move( - aPad->GetPosition() ); pcbShape->Move( - aPad->GetPosition() );
pcbShape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() ); pcbShape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() );

View File

@ -543,8 +543,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
} }
case SHAPE_T::ARC: case SHAPE_T::ARC:
addAnchor( shape->GetArcStart(), CORNER | SNAPPABLE, shape ); addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
addAnchor( shape->GetArcEnd(), CORNER | SNAPPABLE, shape ); addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape ); addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape ); addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
break; break;
@ -598,7 +598,7 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos
KI_FALLTHROUGH; KI_FALLTHROUGH;
default: default:
addAnchor( shape->GetStart(), ORIGIN | SNAPPABLE, shape ); addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
break; break;
} }
break; break;

View File

@ -215,9 +215,9 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
case SHAPE_T::ARC: case SHAPE_T::ARC:
points->AddPoint( shape->GetCenter() ); points->AddPoint( shape->GetCenter() );
points->AddPoint( shape->GetArcStart() ); points->AddPoint( shape->GetStart() );
points->AddPoint( shape->GetArcMid() ); points->AddPoint( shape->GetArcMid() );
points->AddPoint( shape->GetArcEnd() ); points->AddPoint( shape->GetEnd() );
points->Point( ARC_MID ).SetGridConstraint( IGNORE_GRID ); points->Point( ARC_MID ).SetGridConstraint( IGNORE_GRID );
points->Point( ARC_START ).SetGridConstraint( SNAP_TO_GRID ); points->Point( ARC_START ).SetGridConstraint( SNAP_TO_GRID );
@ -613,7 +613,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
VECTOR2I p1, p2, p3; VECTOR2I p1, p2, p3;
// p1 does not move, p2 does. // p1 does not move, p2 does.
if( aStart != aArc->GetArcStart() ) if( aStart != aArc->GetStart() )
{ {
start = aCursor; start = aCursor;
p1 = aEnd; p1 = aEnd;
@ -621,7 +621,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
p3 = aMid; p3 = aMid;
movingStart = true; movingStart = true;
} }
else if( aEnd != aArc->GetArcEnd() ) else if( aEnd != aArc->GetEnd() )
{ {
end = aCursor; end = aCursor;
p1 = aStart; p1 = aStart;
@ -736,7 +736,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
// v4 is the new center // v4 is the new center
v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) : VECTOR2D( 2 * R + delta, 0 ); v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) : VECTOR2D( 2 * R + delta, 0 );
clockwise = aArc->GetAngle() > 0; clockwise = aArc->GetArcAngle() > 0;
if( transformCircle ) if( transformCircle )
clockwise = !clockwise; clockwise = !clockwise;
@ -759,13 +759,13 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
if( arcValid ) if( arcValid )
{ {
aArc->SetAngle( newAngle, false ); aArc->SetCenter( (wxPoint) aCenter );
aArc->SetArcCenter( ( wxPoint ) center ); aArc->SetArcAngle( newAngle );
if( movingStart ) if( movingStart )
aArc->SetArcStart( ( wxPoint ) start ); aArc->SetStart( (wxPoint) aStart );
else else
aArc->SetArcEnd( ( wxPoint ) end ); aArc->SetEnd( (wxPoint) aEnd );
} }
} }
} }
@ -886,7 +886,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepCenter( PCB_SHAPE* aArc, const VECTOR2
// p1 does not move, p2 does. // p1 does not move, p2 does.
if( aStart != aArc->GetArcStart() ) if( aStart != aArc->GetStart() )
{ {
p1 = aEnd; p1 = aEnd;
p2 = aStart; p2 = aStart;
@ -932,7 +932,7 @@ void PCB_POINT_EDITOR::editArcEndpointKeepCenter( PCB_SHAPE* aArc, const VECTOR2
p1 = p1 + aCenter; p1 = p1 + aCenter;
p2 = p2 + aCenter; p2 = p2 + aCenter;
clockwise = aArc->GetAngle() > 0; clockwise = aArc->GetArcAngle() > 0;
VECTOR2D startLine = aStart - aCenter; VECTOR2D startLine = aStart - aCenter;
VECTOR2D endLine = aEnd - aCenter; VECTOR2D endLine = aEnd - aCenter;
@ -943,13 +943,13 @@ void PCB_POINT_EDITOR::editArcEndpointKeepCenter( PCB_SHAPE* aArc, const VECTOR2
else if( !clockwise && newAngle > 0.0 ) else if( !clockwise && newAngle > 0.0 )
newAngle -= 3600.0; newAngle -= 3600.0;
aArc->SetAngle( newAngle, false ); aArc->SetCenter( (wxPoint) aCenter );
aArc->SetArcCenter((wxPoint) aCenter ); aArc->SetArcAngle( newAngle );
if( movingStart ) if( movingStart )
aArc->SetArcStart( (wxPoint) aStart ); aArc->SetStart( (wxPoint) aStart );
else else
aArc->SetArcEnd( (wxPoint) aEnd ); aArc->SetEnd( (wxPoint) aEnd );
} }
@ -1009,8 +1009,8 @@ void PCB_POINT_EDITOR::editArcMidKeepCenter( PCB_SHAPE* aArc, const VECTOR2I& aC
start = start + aCenter; start = start + aCenter;
end = end + aCenter; end = end + aCenter;
aArc->SetArcStart( (wxPoint) start ); aArc->SetStart( (wxPoint) start );
aArc->SetArcEnd( (wxPoint) end ); aArc->SetEnd( (wxPoint) end );
} }
@ -1577,9 +1577,9 @@ void PCB_POINT_EDITOR::updatePoints()
case SHAPE_T::ARC: case SHAPE_T::ARC:
m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetCenter() ); m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetCenter() );
m_editPoints->Point( ARC_START ).SetPosition( shape->GetArcStart() ); m_editPoints->Point( ARC_START ).SetPosition( shape->GetStart() );
m_editPoints->Point( ARC_MID ).SetPosition( shape->GetArcMid() ); m_editPoints->Point( ARC_MID ).SetPosition( shape->GetArcMid() );
m_editPoints->Point( ARC_END ).SetPosition( shape->GetArcEnd() ); m_editPoints->Point( ARC_END ).SetPosition( shape->GetEnd() );
break; break;
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:

View File

@ -51,7 +51,6 @@ set( QA_EESCHEMA_SRCS
sch_plugins/altium/test_altium_parser_sch.cpp sch_plugins/altium/test_altium_parser_sch.cpp
test_eagle_plugin.cpp test_eagle_plugin.cpp
test_lib_arc.cpp
test_lib_part.cpp test_lib_part.cpp
test_netlists.cpp test_netlists.cpp
test_sch_pin.cpp test_sch_pin.cpp

View File

@ -1,120 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see AUTHORS.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for LIB_ARC
*/
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <trigo.h>
#include <convert_to_biu.h>
// Code under test
#include <lib_arc.h>
class TEST_LIB_ARC_FIXTURE
{
public:
TEST_LIB_ARC_FIXTURE() :
m_arc( nullptr )
{
}
///> Part with no extra data set
LIB_ARC m_arc;
};
/**
* Declare the test suite
*/
BOOST_FIXTURE_TEST_SUITE( LibArc, TEST_LIB_ARC_FIXTURE )
/**
* Check that we can get the default properties out as expected
*/
BOOST_AUTO_TEST_CASE( DefaultProperties )
{
BOOST_CHECK_EQUAL( m_arc.Type(), LIB_ARC_T );
BOOST_CHECK_EQUAL( m_arc.GetClass(), "LIB_ARC" );
BOOST_CHECK_EQUAL( m_arc.GetPosition(), wxPoint( 0, 0 ) );
}
/**
* Test the function that calculates the radius angles based on the center, start, and end points.
*/
BOOST_AUTO_TEST_CASE( TestCalcRadiusAngles )
{
double radius = 5.0; // Use millimeters and convert to internal units.
int startX = Millimeter2iu( radius * cos( DEG2RAD( 10.0 ) ) );
int startY = Millimeter2iu( radius * sin( DEG2RAD( 10.0 ) ) );
int endX = Millimeter2iu( radius * cos( DEG2RAD( 45.0 ) ) );
int endY = Millimeter2iu( radius * sin( DEG2RAD( 45.0 ) ) );
m_arc.SetStart( wxPoint( startX, startY ) );
m_arc.SetEnd( wxPoint( endX, endY ) );
m_arc.CalcRadiusAngles();
BOOST_CHECK_EQUAL( m_arc.GetFirstRadiusAngle(), 100 );
BOOST_CHECK_EQUAL( m_arc.GetSecondRadiusAngle(), 450 );
// Set arc end point in the second quadrant.
endX = Millimeter2iu( radius * cos( DEG2RAD( 145.0 ) ) );
endY = Millimeter2iu( radius * sin( DEG2RAD( 145.0 ) ) );
m_arc.SetEnd( wxPoint( endX, endY ) );
m_arc.CalcRadiusAngles();
BOOST_CHECK_EQUAL( m_arc.GetFirstRadiusAngle(), 100 );
BOOST_CHECK_EQUAL( m_arc.GetSecondRadiusAngle(), 1450 );
}
/**
* Test the function that calculates the mid point based on the start and end angles and
* radius length.
*/
BOOST_AUTO_TEST_CASE( TestCalcMidPoint )
{
// Midpoint angle is 77.5 degrees.
m_arc.SetRadius( Millimeter2iu( 5.0 ) );
m_arc.SetFirstRadiusAngle( 100 );
m_arc.SetSecondRadiusAngle( 1450 );
BOOST_CHECK_EQUAL( m_arc.CalcMidPoint(), VECTOR2I( 10822, 48815 ) );
m_arc.SetFirstRadiusAngle( 850 );
m_arc.SetSecondRadiusAngle( 950 );
BOOST_CHECK_EQUAL( m_arc.CalcMidPoint(), VECTOR2I( 0, 50000 ) );
m_arc.SetFirstRadiusAngle( 1700 );
m_arc.SetSecondRadiusAngle( 1900 );
BOOST_CHECK_EQUAL( m_arc.CalcMidPoint(), VECTOR2I( -50000, 0 ) );
m_arc.SetFirstRadiusAngle( 2500 );
m_arc.SetSecondRadiusAngle( 2900 );
BOOST_CHECK_EQUAL( m_arc.CalcMidPoint(), VECTOR2I( 0, -50000 ) );
m_arc.SetFirstRadiusAngle( 3500 );
m_arc.SetSecondRadiusAngle( 100 );
BOOST_CHECK_EQUAL( m_arc.CalcMidPoint(), VECTOR2I( 50000, 0 ) );
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -61,9 +61,9 @@ void DrawArc( FOOTPRINT& aFootprint, const VECTOR2I& aCentre, const VECTOR2I& aS
{ {
auto seg = std::make_unique<FP_SHAPE>( &aFootprint, SHAPE_T::ARC ); auto seg = std::make_unique<FP_SHAPE>( &aFootprint, SHAPE_T::ARC );
seg->SetStart0( (wxPoint) aCentre ); seg->SetCenter0( (wxPoint) aCentre );
seg->SetEnd0( (wxPoint) aStart ); seg->SetStart0( (wxPoint) aStart );
seg->SetAngle( aAngle * 10 ); seg->SetArcAngleAndEnd0( aAngle * 10 );
seg->SetWidth( aWidth ); seg->SetWidth( aWidth );
seg->SetLayer( aLayer ); seg->SetLayer( aLayer );