Improve moving, rendering and plotting of very small angle arcs.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17110
This commit is contained in:
Alex Shvartzkop 2024-04-03 00:39:55 +03:00
parent 8260c174e9
commit b905b4eac8
5 changed files with 42 additions and 12 deletions

View File

@ -1075,9 +1075,21 @@ void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius,
if( seg_count % 2 != 0 ) if( seg_count % 2 != 0 )
seg_count += 1; seg_count += 1;
// Our shaders have trouble rendering null line quads, so delegate this task to DrawSegment.
if( seg_count == 0 )
{
VECTOR2D p_start( aCenterPoint.x + cos( startAngle ) * aRadius,
aCenterPoint.y + sin( startAngle ) * aRadius );
VECTOR2D p_end( aCenterPoint.x + cos( endAngle ) * aRadius,
aCenterPoint.y + sin( endAngle ) * aRadius );
DrawSegment( p_start, p_end, aWidth );
return;
}
// Recalculate alphaIncrement with a even integer number of segment // Recalculate alphaIncrement with a even integer number of segment
if( seg_count ) alphaIncrement = ( endAngle - startAngle ) / seg_count;
alphaIncrement = ( endAngle - startAngle ) / seg_count;
Save(); Save();
m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 ); m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );

View File

@ -833,10 +833,21 @@ void GERBER_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
{ {
SetCurrentLineWidth( aWidth ); SetCurrentLineWidth( aWidth );
EDA_ANGLE endAngle = aStartAngle + aAngle; double arcLength = std::abs( aRadius * aAngle.AsRadians() );
// aFill is not used here. if( arcLength < 100 || std::abs( aAngle.AsDegrees() ) < 0.1 )
plotArc( aCenter, aStartAngle, endAngle, aRadius, false ); {
// Prevent plotting very short arcs as full circles, especially with 4.5 mm precision.
// Also reduce the risk of integer overflow issues.
polyArc( aCenter, aStartAngle, aAngle, aRadius, aFill, aWidth );
}
else
{
EDA_ANGLE endAngle = aStartAngle + aAngle;
// aFill is not used here.
plotArc( aCenter, aStartAngle, endAngle, aRadius, false );
}
} }

View File

@ -565,6 +565,13 @@ void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
if( aRadius <= 0 ) if( aRadius <= 0 )
return; return;
// Avoid integer overflow when calculating the center point
if( std::abs( aAngle.AsDegrees() ) < 5 )
{
polyArc( aCenter, aStartAngle, aAngle, aRadius, aFill, aWidth );
return;
}
double const radius_device = userToDeviceSize( aRadius ); double const radius_device = userToDeviceSize( aRadius );
double const circumf_device = 2.0 * M_PI * radius_device; double const circumf_device = 2.0 * M_PI * radius_device;
double const target_chord_length = m_arcTargetChordLength; double const target_chord_length = m_arcTargetChordLength;

View File

@ -191,8 +191,8 @@ void PLOTTER::polyArc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
SetCurrentLineWidth( aWidth ); SetCurrentLineWidth( aWidth );
start.x = aCenter.x + KiROUND( aRadius * startAngle.Cos() ); start.x = KiROUND( aCenter.x + aRadius * startAngle.Cos() );
start.y = aCenter.y + sign * KiROUND( aRadius * startAngle.Sin() ); start.y = KiROUND( aCenter.y + sign * aRadius * startAngle.Sin() );
if( aFill != FILL_T::NO_FILL ) if( aFill != FILL_T::NO_FILL )
{ {
@ -206,13 +206,13 @@ void PLOTTER::polyArc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
for( EDA_ANGLE ii = startAngle + delta; ii < endAngle; ii += delta ) for( EDA_ANGLE ii = startAngle + delta; ii < endAngle; ii += delta )
{ {
end.x = aCenter.x + KiROUND( aRadius * ii.Cos() ); end.x = KiROUND( aCenter.x + aRadius * ii.Cos() );
end.y = aCenter.y + sign * KiROUND( aRadius * ii.Sin() ); end.y = KiROUND( aCenter.y + sign * aRadius * ii.Sin() );
LineTo( end ); LineTo( end );
} }
end.x = aCenter.x + KiROUND( aRadius * endAngle.Cos() ); end.x = KiROUND( aCenter.x + aRadius * endAngle.Cos() );
end.y = aCenter.y + sign * KiROUND( aRadius * endAngle.Sin() ); end.y = KiROUND( aCenter.y + sign * aRadius * endAngle.Sin() );
if( aFill != FILL_T::NO_FILL ) if( aFill != FILL_T::NO_FILL )
{ {

View File

@ -141,7 +141,7 @@ protected:
double Distance( const VECTOR2I& aP ) const double Distance( const VECTOR2I& aP ) const
{ {
return ( aP - pos ).EuclideanNorm(); return VECTOR2D( (double) aP.x - pos.x, (double) aP.y - pos.y ).EuclideanNorm();
} }
}; };