Gerber plotter: fix broken plot of SHAPE_LINE_CHAIN with arcs.

Also simplify SHAPE_T::POLY plot.
Fixes #10989
https://gitlab.com/kicad/code/kicad/issues/10989
This commit is contained in:
jean-pierre charras 2022-02-28 15:32:10 +01:00
parent 5503afc09a
commit aa0787f2b4
2 changed files with 33 additions and 13 deletions

View File

@ -843,8 +843,16 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
VECTOR2I start( aArc.GetP0() ); VECTOR2I start( aArc.GetP0() );
VECTOR2I end( aArc.GetP1() ); VECTOR2I end( aArc.GetP1() );
VECTOR2I center( aArc.GetCenter() ); VECTOR2I center( aArc.GetCenter() );
EDA_ANGLE start_angle = aArc.GetStartAngle(); EDA_ANGLE startAngle = aArc.GetStartAngle();
EDA_ANGLE end_angle = aArc.GetEndAngle(); EDA_ANGLE endAngle = aArc.GetEndAngle();
if( startAngle > endAngle )
{
if( endAngle < ANGLE_0 )
endAngle.Normalize();
else
startAngle = startAngle.Normalize() - ANGLE_360;
}
if( !aPlotInRegion ) if( !aPlotInRegion )
MoveTo( start); MoveTo( start);
@ -856,7 +864,7 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
if( start_angle < end_angle ) if( startAngle > endAngle )
fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW
else else
fprintf( m_outputFile, "G02*\n" ); // Active circular interpolation, CW fprintf( m_outputFile, "G02*\n" ); // Active circular interpolation, CW
@ -1011,6 +1019,10 @@ void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int
const SHAPE_ARC& arc = aPoly.Arc( arcindex ); const SHAPE_ARC& arc = aPoly.Arc( arcindex );
plotArc( arc, ii > 0 ); plotArc( arc, ii > 0 );
// skip points on arcs, since we plot the arc itself
while( ii+1 < aPoly.PointCount() && arcindex == aPoly.ArcIndex( ii+1 ) )
ii++;
} }
} }
@ -1041,12 +1053,17 @@ void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int
const SHAPE_ARC& arc = aPoly.Arc( arcindex ); const SHAPE_ARC& arc = aPoly.Arc( arcindex );
plotArc( arc, ii > 0 ); plotArc( arc, ii > 0 );
// skip points on arcs, since we plot the arc itself
while( ii+1 < aPoly.PointCount() && arcindex == aPoly.ArcIndex( ii+1 ) )
ii++;
} }
} }
// Ensure the thick outline is closed for filled polygons // Ensure the thick outline is closed for filled polygons
// (if not filled, could be only a polyline) // (if not filled, could be only a polyline)
if( aFill != FILL_T::NO_FILL && ( aPoly.CPoint( 0 ) != aPoly.CPoint( -1 ) ) ) if( ( aPoly.CPoint( 0 ) != aPoly.CPoint( -1 ) )
&& ( aPoly.IsClosed() || aFill != FILL_T::NO_FILL ) )
LineTo( VECTOR2I( aPoly.CPoint( 0 ) ) ); LineTo( VECTOR2I( aPoly.CPoint( 0 ) ) );
PenFinish(); PenFinish();

View File

@ -707,7 +707,7 @@ void BRDITEMS_PLOTTER::PlotFootprintShape( const FP_SHAPE* aShape )
} }
} }
if( sketch || thickness > 0 ) if( sketch )
{ {
for( size_t i = 1; i < cornerList.size(); i++ ) for( size_t i = 1; i < cornerList.size(); i++ )
{ {
@ -719,8 +719,7 @@ void BRDITEMS_PLOTTER::PlotFootprintShape( const FP_SHAPE* aShape )
GetPlotMode(), &gbr_metadata ); GetPlotMode(), &gbr_metadata );
} }
else
if( !sketch && aShape->IsFilled() )
{ {
// This must be simplified and fractured to prevent overlapping polygons // This must be simplified and fractured to prevent overlapping polygons
// from generating invalid Gerber files // from generating invalid Gerber files
@ -966,7 +965,7 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
case SHAPE_T::POLY: case SHAPE_T::POLY:
if( aShape->IsPolyShapeValid() ) if( aShape->IsPolyShapeValid() )
{ {
if( sketch || thickness > 0 ) if( sketch )
{ {
for( auto it = aShape->GetPolyShape().CIterateSegments( 0 ); it; it++ ) for( auto it = aShape->GetPolyShape().CIterateSegments( 0 ); it; it++ )
{ {
@ -975,8 +974,7 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
&gbr_metadata ); &gbr_metadata );
} }
} }
else
if( !sketch && aShape->IsFilled() )
{ {
m_plotter->SetCurrentLineWidth( thickness, &gbr_metadata ); m_plotter->SetCurrentLineWidth( thickness, &gbr_metadata );
@ -985,13 +983,18 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
// ( for the future or to show a non expected shape ) // ( for the future or to show a non expected shape )
// This must be simplified and fractured to prevent overlapping polygons // This must be simplified and fractured to prevent overlapping polygons
// from generating invalid Gerber files // from generating invalid Gerber files
auto tmpPoly = SHAPE_POLY_SET( aShape->GetPolyShape() ); SHAPE_POLY_SET tmpPoly = SHAPE_POLY_SET( aShape->GetPolyShape() );
tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST ); tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
FILL_T fill = aShape->IsFilled() ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj ) for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj )
{ {
SHAPE_LINE_CHAIN& poly = tmpPoly.Outline( jj ); SHAPE_LINE_CHAIN& poly = tmpPoly.Outline( jj );
m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, thickness, &gbr_metadata );
// Ensure the polygon is closed:
poly.SetClosed( true );
m_plotter->PlotPoly( poly, fill, thickness, &gbr_metadata );
} }
} }
} }