From b905b4eac84b51757285f27f508fe76d162fbe3d Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Wed, 3 Apr 2024 00:39:55 +0300 Subject: [PATCH] Improve moving, rendering and plotting of very small angle arcs. Fixes https://gitlab.com/kicad/code/kicad/-/issues/17110 --- common/gal/opengl/opengl_gal.cpp | 16 ++++++++++++++-- common/plotters/GERBER_plotter.cpp | 17 ++++++++++++++--- common/plotters/HPGL_plotter.cpp | 7 +++++++ common/plotters/plotter.cpp | 12 ++++++------ include/tool/grid_helper.h | 2 +- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 2565ffcf0b..3f0198119a 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -1075,9 +1075,21 @@ void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, if( seg_count % 2 != 0 ) 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 - if( seg_count ) - alphaIncrement = ( endAngle - startAngle ) / seg_count; + alphaIncrement = ( endAngle - startAngle ) / seg_count; Save(); m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 ); diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp index b59ad9fa44..d7702d17bf 100644 --- a/common/plotters/GERBER_plotter.cpp +++ b/common/plotters/GERBER_plotter.cpp @@ -833,10 +833,21 @@ void GERBER_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle, { SetCurrentLineWidth( aWidth ); - EDA_ANGLE endAngle = aStartAngle + aAngle; + double arcLength = std::abs( aRadius * aAngle.AsRadians() ); - // aFill is not used here. - plotArc( aCenter, aStartAngle, endAngle, aRadius, false ); + if( arcLength < 100 || std::abs( aAngle.AsDegrees() ) < 0.1 ) + { + // 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 ); + } } diff --git a/common/plotters/HPGL_plotter.cpp b/common/plotters/HPGL_plotter.cpp index 5d9e07cd70..806ddf0905 100644 --- a/common/plotters/HPGL_plotter.cpp +++ b/common/plotters/HPGL_plotter.cpp @@ -565,6 +565,13 @@ void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle, if( aRadius <= 0 ) 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 circumf_device = 2.0 * M_PI * radius_device; double const target_chord_length = m_arcTargetChordLength; diff --git a/common/plotters/plotter.cpp b/common/plotters/plotter.cpp index ffa378b5f5..34e72cf877 100644 --- a/common/plotters/plotter.cpp +++ b/common/plotters/plotter.cpp @@ -191,8 +191,8 @@ void PLOTTER::polyArc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle, SetCurrentLineWidth( aWidth ); - start.x = aCenter.x + KiROUND( aRadius * startAngle.Cos() ); - start.y = aCenter.y + sign * KiROUND( aRadius * startAngle.Sin() ); + start.x = KiROUND( aCenter.x + aRadius * startAngle.Cos() ); + start.y = KiROUND( aCenter.y + sign * aRadius * startAngle.Sin() ); 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 ) { - end.x = aCenter.x + KiROUND( aRadius * ii.Cos() ); - end.y = aCenter.y + sign * KiROUND( aRadius * ii.Sin() ); + end.x = KiROUND( aCenter.x + aRadius * ii.Cos() ); + end.y = KiROUND( aCenter.y + sign * aRadius * ii.Sin() ); LineTo( end ); } - end.x = aCenter.x + KiROUND( aRadius * endAngle.Cos() ); - end.y = aCenter.y + sign * KiROUND( aRadius * endAngle.Sin() ); + end.x = KiROUND( aCenter.x + aRadius * endAngle.Cos() ); + end.y = KiROUND( aCenter.y + sign * aRadius * endAngle.Sin() ); if( aFill != FILL_T::NO_FILL ) { diff --git a/include/tool/grid_helper.h b/include/tool/grid_helper.h index 5e87222591..a8af1a2a55 100644 --- a/include/tool/grid_helper.h +++ b/include/tool/grid_helper.h @@ -141,7 +141,7 @@ protected: double Distance( const VECTOR2I& aP ) const { - return ( aP - pos ).EuclideanNorm(); + return VECTOR2D( (double) aP.x - pos.x, (double) aP.y - pos.y ).EuclideanNorm(); } };