Validate arc output when editing

Handles checking output of the arc to ensure we don't end up generating
an invalid arc.  Also keeps the limit of the arc angle to be (360,360)
excluding 0.

Fixes https://gitlab.com/kicad/code/kicad/issues/10070
This commit is contained in:
Seth Hillbrand 2022-02-06 17:16:28 -08:00
parent aa5b6c70a7
commit 8fc831cbc2
4 changed files with 37 additions and 14 deletions

View File

@ -109,7 +109,7 @@ void RotatePoint( double *pX, double *pY, double cx, double cy, double angle );
const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd );
const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd );
const wxPoint CalcArcCenter( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd );
const wxPoint CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle );
const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd, double aAngle );
/**
* Return the subtended angle for a given arc.

View File

@ -359,10 +359,10 @@ void RotatePoint( double* pX, double* pY, double angle )
}
const wxPoint CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle )
const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd, double aAngle )
{
VECTOR2I start = aStart;
VECTOR2I end = aEnd;
VECTOR2D start = aStart;
VECTOR2D end = aEnd;
if( aAngle < 0 )
{
@ -376,14 +376,14 @@ const wxPoint CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, doubl
aAngle = 360 - aAngle;
}
int chord = ( start - end ).EuclideanNorm();
int r = ( chord / 2 ) / sin( aAngle * M_PI / 360.0 );
double chord = ( start - end ).EuclideanNorm();
double r = chord / ( 2.0 * sin( ( aAngle / 2.0 ) * M_PI / 180.0 ) );
VECTOR2I vec = end - start;
VECTOR2D vec = end - start;
vec = vec.Resize( r );
vec = vec.Rotate( ( 180.0 - aAngle ) * M_PI / 360.0 );
vec = vec.Rotate( ( 90.0 - aAngle / 2.0 ) * M_PI / 180.0 );
return (wxPoint) ( start + vec );
return start + vec;
}

View File

@ -113,7 +113,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FR
m_bezierCtrl2Y.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
m_angle.SetUnits( EDA_UNITS::DEGREES );
m_AngleValidator.SetRange( -360.0, 360.0 );
m_AngleValidator.SetRange( -359.9, 359.9 );
m_angleCtrl->SetValidator( m_AngleValidator );
m_AngleValidator.SetWindow( m_angleCtrl );
@ -316,8 +316,11 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
}
if( m_item->GetShape() == SHAPE_T::ARC )
m_item->SetCenter( CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue ) );
{
VECTOR2D center = CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue );
m_item->SetCenter( wxPoint( KiROUND( center.x ), KiROUND( center.y ) ) );
}
if( m_fp_item )
{
// We are editing a footprint; init the item coordinates relative to the footprint anchor.
@ -371,10 +374,28 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::Validate()
error_msgs.Add( _( "The arc angle cannot be zero." ) );
if( m_startX.GetValue() == m_endX.GetValue() && m_startY.GetValue() == m_endY.GetValue() )
error_msgs.Add( _( "The radius cannot be zero." ) );
{
error_msgs.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ),
0.0, m_angle.GetDoubleValue() ) );
}
else
{
VECTOR2D start( m_startX.GetValue(), m_startY.GetValue() );
VECTOR2D end( m_endX.GetValue(), m_endY.GetValue() );
VECTOR2D center = CalcArcCenter( start, end, m_angle.GetDoubleValue() );
double radius = ( center - start ).EuclideanNorm();
double max_offset = std::max( std::abs( center.x ) + radius,
std::abs( center.y ) + radius );
if( max_offset >= ( std::numeric_limits<VECTOR2I::coord_type>::max() / 2 )
|| center == start || center == end )
{
error_msgs.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ),
radius, m_angle.GetDoubleValue() ) );
}
}
break;
case SHAPE_T::CIRCLE:
// Check radius.
if( m_endX.GetValue() == 0 )

View File

@ -1929,7 +1929,9 @@ bool DRAWING_TOOL::drawArc( const std::string& aTool, PCB_SHAPE** aGraphic, bool
frame()->SetMsgPanel( graphic );
break;
}
else if( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
// Don't show the edit panel if we can't represent the arc with it
else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
&& ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
{
frame()->OnEditItemRequest( graphic );
m_view->Update( &preview );