diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp index 09d6650376..ecb96cd484 100644 --- a/common/plotters/GERBER_plotter.cpp +++ b/common/plotters/GERBER_plotter.cpp @@ -826,6 +826,35 @@ void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAn } +void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion ) +{ + wxPoint start( aArc.GetP0() ); + wxPoint end( aArc.GetP1() ); + wxPoint center( aArc.GetCenter() ); + double start_angle = aArc.GetStartAngle(); + double end_angle = aArc.GetEndAngle(); + + if( !aPlotInRegion ) + MoveTo( start); + else + LineTo( start ); + + DPOINT devEnd = userToDeviceCoordinates( end ); + DPOINT devCenter = userToDeviceCoordinates( center ) - userToDeviceCoordinates( start ); + + if( start_angle < end_angle ) + fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW + else + fprintf( m_outputFile, "G02*\n" ); // Active circular interpolation, CW + + fprintf( m_outputFile, "X%dY%dI%dJ%dD01*\n", + KiROUND( devEnd.x ), KiROUND( devEnd.y ), + KiROUND( devCenter.x ), KiROUND( devCenter.y ) ); + + fprintf( m_outputFile, "G01*\n" ); // Back to linear interpol (perhaps useless here). +} + + void GERBER_PLOTTER::plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle, int aRadius, bool aPlotInRegion ) { @@ -858,8 +887,46 @@ void GERBER_PLOTTER::plotArc( const wxPoint& aCenter, double aStAngle, double aE } +void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, + void* aData ) +{ + if( aPoly.PointCount() <= 2 ) + return; + + GBR_METADATA* gbr_metadata = static_cast( aData ); + + bool clearTA_AperFunction = false; // true if a TA.AperFunction is used + + if( gbr_metadata ) + { + std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format ); + + if( !attrib.empty() ) + { + fputs( attrib.c_str(), m_outputFile ); + clearTA_AperFunction = true; + } + } + + PlotPoly( aPoly, FILL_TYPE::FILLED_SHAPE, 0 , gbr_metadata ); + + // Clear the TA attribute, to avoid the next item to inherit it: + if( clearTA_AperFunction ) + { + if( m_useX2format ) + { + fputs( "%TD.AperFunction*%\n", m_outputFile ); + } + else + { + fputs( "G04 #@! TD.AperFunction*\n", m_outputFile ); + } + } +} + + void GERBER_PLOTTER::PlotGerberRegion( const std::vector< wxPoint >& aCornerList, - void * aData ) + void* aData ) { if( aCornerList.size() <= 2 ) return; @@ -895,6 +962,84 @@ void GERBER_PLOTTER::PlotGerberRegion( const std::vector< wxPoint >& aCornerList } } +void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, + FILL_TYPE aFill, int aWidth, void* aData ) +{ + if( aPoly.CPoints().size() <= 1 ) + return; + + // Gerber format does not know filled polygons with thick outline + // Therefore, to plot a filled polygon with outline having a thickness, + // one should plot outline as thick segments + GBR_METADATA* gbr_metadata = static_cast( aData ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + if( aFill != FILL_TYPE::NO_FILL ) + { + fputs( "G36*\n", m_outputFile ); + + MoveTo( wxPoint( aPoly.CPoint( 0 ) ) ); + + fputs( "G01*\n", m_outputFile ); // Set linear interpolation. + + for( int ii = 1; ii < aPoly.PointCount(); ii++ ) + { + int arcindex = aPoly.ArcIndex( ii ); + + if( arcindex < 0 ) + { + /// Plain point + LineTo( wxPoint( aPoly.CPoint( ii ) ) ); + } + else + { + const SHAPE_ARC& arc = aPoly.Arc( arcindex ); + + plotArc( arc, ii > 0 ); + } + } + + // If the polygon is not closed, close it: + if( aPoly.CPoint( 0 ) != aPoly.CPoint( -1 ) ) + FinishTo( wxPoint( aPoly.CPoint( 0 ) ) ); + + fputs( "G37*\n", m_outputFile ); + } + + if( aWidth > 0 ) // Draw the polyline/polygon outline + { + SetCurrentLineWidth( aWidth, gbr_metadata ); + + MoveTo( wxPoint( aPoly.CPoint( 0 ) ) ); + + for( int ii = 1; ii < aPoly.PointCount(); ii++ ) + { + int arcindex = aPoly.ArcIndex( ii ); + + if( arcindex < 0 ) + { + /// Plain point + LineTo( wxPoint( aPoly.CPoint( ii ) ) ); + } + else + { + const SHAPE_ARC& arc = aPoly.Arc( arcindex ); + + plotArc( arc, ii > 0 ); + } + } + + // Ensure the thick outline is closed for filled polygons + // (if not filled, could be only a polyline) + if( aFill != FILL_TYPE::NO_FILL && ( aPoly.CPoint( 0 ) != aPoly.CPoint( -1 ) ) ) + LineTo( wxPoint( aPoly.CPoint( 0 ) ) ); + + PenFinish(); + } +} + void GERBER_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_TYPE aFill, int aWidth, void * aData ) { diff --git a/common/plotters/plotter_gerber.h b/common/plotters/plotter_gerber.h index 0e02d880f3..e65162a568 100644 --- a/common/plotters/plotter_gerber.h +++ b/common/plotters/plotter_gerber.h @@ -33,6 +33,7 @@ #include #include "gbr_plotter_apertures.h" +class SHAPE_ARC; class GERBER_PLOTTER : public PLOTTER { @@ -97,6 +98,9 @@ public: FILL_TYPE aFill, int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override; + virtual void PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_TYPE aFill, + int aWidth = USE_DEFAULT_LINE_WIDTH, void * aData = NULL ) override; + virtual void PenTo( const wxPoint& pos, char plume ) override; virtual void Text( const wxPoint& aPos, @@ -166,6 +170,9 @@ public: void PlotGerberRegion( const std::vector< wxPoint >& aCornerList, void * aData = NULL ); + void PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, + void * aData = NULL ); + /** * Change the plot polarity and begin a new layer * Used to 'scratch off' silk screen away from solder mask @@ -262,6 +269,7 @@ protected: */ void plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle, int aRadius, bool aPlotInRegion ); + void plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion ); /** * Pick an existing aperture or create a new one, matching the diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 09a8a19b87..c4b0965551 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -657,14 +657,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, cornerList.clear(); const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 ); - for( int jj = 0; jj < path.PointCount(); jj++ ) - cornerList.emplace_back( (wxPoint) path.CPoint( jj ) ); - - // Ensure the polygon is closed - if( cornerList[0] != cornerList[cornerList.size() - 1] ) - cornerList.push_back( cornerList[0] ); - - aPlotter->PlotPoly( cornerList, FILL_TYPE::NO_FILL ); + aPlotter->PlotPoly( path, FILL_TYPE::NO_FILL ); } } @@ -905,12 +898,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask, // Plot each initial shape (pads and polygons on mask layer), with suitable attributes: PlotStandardLayer( aBoard, aPlotter, aLayerMask, aPlotOpt ); - // Add shapes corresponding to areas having too small thickness. - std::vector cornerList; - for( int ii = 0; ii < areas.OutlineCount(); ii++ ) { - cornerList.clear(); const SHAPE_LINE_CHAIN& path = areas.COutline( ii ); // polygon area in mm^2 : @@ -924,14 +913,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask, if( curr_area < poly_min_area_mm2 ) continue; - for( int jj = 0; jj < path.PointCount(); jj++ ) - cornerList.emplace_back( (wxPoint) path.CPoint( jj ) ); - - // Ensure the polygon is closed - if( cornerList[0] != cornerList[cornerList.size() - 1] ) - cornerList.push_back( cornerList[0] ); - - aPlotter->PlotPoly( cornerList, FILL_TYPE::FILLED_SHAPE ); + aPlotter->PlotPoly( path, FILL_TYPE::FILLED_SHAPE ); } #endif } diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index ac9e9dd01b..3ab422043a 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -779,9 +779,6 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET& } } - // We need a buffer to store corners coordinates: - std::vector< wxPoint > cornerList; - m_plotter->SetColor( getColor( aZone->GetLayer() ) ); m_plotter->StartBlock( nullptr ); // Clean current object attributes @@ -798,55 +795,42 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET& { const SHAPE_LINE_CHAIN& outline = polysList.Outline( idx ); - cornerList.clear(); - cornerList.reserve( outline.PointCount() ); - - for( int ic = 0; ic < outline.PointCount(); ++ic ) + // Plot the current filled area (as region for Gerber plotter + // to manage attributes) and its outline for thick outline + if( GetPlotMode() == FILLED ) { - cornerList.emplace_back( wxPoint( outline.CPoint( ic ) ) ); - } - - if( cornerList.size() ) // Plot the current filled area outline - { - // First, close the outline - if( cornerList[0] != cornerList[cornerList.size() - 1] ) - cornerList.push_back( cornerList[0] ); - - // Plot the current filled area (as region for Gerber plotter - // to manage attributes) and its outline for thick outline - if( GetPlotMode() == FILLED ) + if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER ) { - if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER ) + if( outline_thickness > 0 ) { - if( outline_thickness > 0 ) - { - m_plotter->PlotPoly( cornerList, FILL_TYPE::NO_FILL, outline_thickness, - &gbr_metadata ); - } + m_plotter->PlotPoly( outline, FILL_TYPE::NO_FILL, + outline_thickness, &gbr_metadata ); + } - static_cast( m_plotter )->PlotGerberRegion( cornerList, - &gbr_metadata ); - } - else - { - m_plotter->PlotPoly( cornerList, FILL_TYPE::FILLED_SHAPE, outline_thickness, - &gbr_metadata ); - } + static_cast( m_plotter )->PlotGerberRegion( + outline, &gbr_metadata ); } else { - if( outline_thickness ) - { - for( unsigned jj = 1; jj < cornerList.size(); jj++ ) - { - m_plotter->ThickSegment( cornerList[jj -1], cornerList[jj], - outline_thickness, GetPlotMode(), &gbr_metadata ); - } - } - - m_plotter->SetCurrentLineWidth( -1 ); + m_plotter->PlotPoly( outline, FILL_TYPE::FILLED_SHAPE, + outline_thickness, &gbr_metadata ); } } + else + { + if( outline_thickness ) + { + for( int jj = 1; jj < outline.PointCount(); jj++ ) + { + m_plotter->ThickSegment( wxPoint( outline.CPoint( jj - 1) ), + wxPoint( outline.CPoint( jj ) ), + outline_thickness, + GetPlotMode(), &gbr_metadata ); + } + } + + m_plotter->SetCurrentLineWidth( -1 ); + } } m_plotter->EndBlock( nullptr ); // Clear object attributes