From 6eeca9aa90cbb5550f9030cf280af16cd1e3aede Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 13 Sep 2023 17:54:57 +0200 Subject: [PATCH] Pcbnew: fix some issues with very small arcs (size a few internal units) these very small arcs do not allow to calculate a reliable center position, and therefore a reliable radius. So handle them as a very small segments to fix plotting/drawing issues. From master branch. Fixes #15639 https://gitlab.com/kicad/code/kicad/-/issues/15639 --- .../3d_canvas/create_3Dgraphic_brd_items.cpp | 13 ++++++++++ pcbnew/pcb_track.cpp | 11 ++++++++ pcbnew/pcb_track.h | 8 ++++++ pcbnew/plot_board_layers.cpp | 25 +++++++++++++------ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index 21abc51d43..f11799c6db 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -261,6 +261,19 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs { const PCB_ARC* arc = static_cast( aTrack ); + if( arc->IsDegenerated() ) + { + // Draw this very small arc like a track segment (a PCB_TRACE_T) + PCB_TRACK track( arc->GetParent() ); + track.SetStart( arc->GetStart() ); + track.SetEnd( arc->GetEnd() ); + track.SetWidth( arc->GetWidth() ); + track.SetLayer( arc->GetLayer() ); + + createTrack( &track, aDstContainer ); + return; + } + VECTOR2D center( arc->GetCenter() ); EDA_ANGLE arc_angle = arc->GetAngle(); double radius = arc->GetRadius(); diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 84a9089919..425ad6a9aa 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -1170,6 +1170,17 @@ EDA_ANGLE PCB_ARC::GetArcAngleEnd() const return angleEnd.Normalize(); } +bool PCB_ARC::IsDegenerated( int aThreshold ) const +{ + // Too small arcs cannot be really handled: arc center (and arc radius) + // cannot be safely computed if the distance between mid and end points + // is too small (a few internal units) + + // len of both segments must be < aThreshold to be a very small degenerated arc + return ( GetMid() - GetStart() ).EuclideanNorm() < aThreshold + && ( GetMid() - GetEnd() ).EuclideanNorm() < aThreshold; +} + bool PCB_TRACK::cmp_tracks::operator() ( const PCB_TRACK* a, const PCB_TRACK* b ) const { diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index d65e03443d..43edbe782f 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -357,6 +357,14 @@ public: EDA_ITEM* Clone() const override; + /** + * @return true if the arc is too small to allow a safe calculation + * of center position and arc angles i.e if distance between m_Mid and each arc end + * is only a few internal units. + * @param aThreshold is the minimal dist in internal units. Default id 5 IU + */ + bool IsDegenerated( int aThreshold = 5 ) const; + protected: virtual void swapData( BOARD_ITEM* aImage ) override; diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index a1580764a3..f23d1eca5e 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -638,17 +638,28 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, { const PCB_ARC* arc = static_cast( track ); - // ThickArc expects only positive angle arcs, so flip start/end if - // we are negative - if( arc->GetAngle() < ANGLE_0 ) + // Too small arcs cannot be really handled: arc center (and arc radius) + // cannot be safely computed + if( arc->IsDegenerated( 10 /* in IU */ ) ) { - aPlotter->ThickArc( arc->GetCenter(), arc->GetEnd(), arc->GetStart(), - width, plotMode, &gbr_metadata ); + // Approximate this very small arc by a segment. + aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode, + &gbr_metadata ); } else { - aPlotter->ThickArc( arc->GetCenter(), arc->GetStart(), arc->GetEnd(), - width, plotMode, &gbr_metadata ); + // ThickArc expects only positive angle arcs, so flip start/end if + // we are negative + if( arc->GetAngle() < ANGLE_0 ) + { + aPlotter->ThickArc( arc->GetCenter(), arc->GetEnd(), arc->GetStart(), + width, plotMode, &gbr_metadata ); + } + else + { + aPlotter->ThickArc( arc->GetCenter(), arc->GetStart(), arc->GetEnd(), + width, plotMode, &gbr_metadata ); + } } } else