Add Gerber plot for SHAPE_ARC and SHAPE_LINE_CHAIN

This commit is contained in:
Seth Hillbrand 2021-06-03 13:31:25 -07:00
parent 013209046b
commit 3d4ce0796e
4 changed files with 183 additions and 64 deletions

View File

@ -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<GBR_METADATA*>( 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<GBR_METADATA*>( 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 )
{

View File

@ -33,6 +33,7 @@
#include <plotter.h>
#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

View File

@ -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<wxPoint> 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
}

View File

@ -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<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion( cornerList,
&gbr_metadata );
}
else
{
m_plotter->PlotPoly( cornerList, FILL_TYPE::FILLED_SHAPE, outline_thickness,
&gbr_metadata );
}
static_cast<GERBER_PLOTTER*>( 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