Add Gerber plot for SHAPE_ARC and SHAPE_LINE_CHAIN
This commit is contained in:
parent
013209046b
commit
3d4ce0796e
|
@ -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,
|
void GERBER_PLOTTER::plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
|
||||||
int aRadius, bool aPlotInRegion )
|
int aRadius, bool aPlotInRegion )
|
||||||
{
|
{
|
||||||
|
@ -858,6 +887,44 @@ 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 GERBER_PLOTTER::PlotGerberRegion( const std::vector< wxPoint >& aCornerList,
|
||||||
void* aData )
|
void* aData )
|
||||||
{
|
{
|
||||||
|
@ -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,
|
void GERBER_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
|
||||||
FILL_TYPE aFill, int aWidth, void * aData )
|
FILL_TYPE aFill, int aWidth, void * aData )
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <plotter.h>
|
#include <plotter.h>
|
||||||
#include "gbr_plotter_apertures.h"
|
#include "gbr_plotter_apertures.h"
|
||||||
|
|
||||||
|
class SHAPE_ARC;
|
||||||
|
|
||||||
class GERBER_PLOTTER : public PLOTTER
|
class GERBER_PLOTTER : public PLOTTER
|
||||||
{
|
{
|
||||||
|
@ -97,6 +98,9 @@ public:
|
||||||
FILL_TYPE aFill, int aWidth = USE_DEFAULT_LINE_WIDTH,
|
FILL_TYPE aFill, int aWidth = USE_DEFAULT_LINE_WIDTH,
|
||||||
void* aData = nullptr ) override;
|
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 PenTo( const wxPoint& pos, char plume ) override;
|
||||||
|
|
||||||
virtual void Text( const wxPoint& aPos,
|
virtual void Text( const wxPoint& aPos,
|
||||||
|
@ -166,6 +170,9 @@ public:
|
||||||
void PlotGerberRegion( const std::vector< wxPoint >& aCornerList,
|
void PlotGerberRegion( const std::vector< wxPoint >& aCornerList,
|
||||||
void * aData = NULL );
|
void * aData = NULL );
|
||||||
|
|
||||||
|
void PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly,
|
||||||
|
void * aData = NULL );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the plot polarity and begin a new layer
|
* Change the plot polarity and begin a new layer
|
||||||
* Used to 'scratch off' silk screen away from solder mask
|
* Used to 'scratch off' silk screen away from solder mask
|
||||||
|
@ -262,6 +269,7 @@ protected:
|
||||||
*/
|
*/
|
||||||
void plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
|
void plotArc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
|
||||||
int aRadius, bool aPlotInRegion );
|
int aRadius, bool aPlotInRegion );
|
||||||
|
void plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pick an existing aperture or create a new one, matching the
|
* Pick an existing aperture or create a new one, matching the
|
||||||
|
|
|
@ -657,14 +657,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
cornerList.clear();
|
cornerList.clear();
|
||||||
const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 );
|
const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 );
|
||||||
|
|
||||||
for( int jj = 0; jj < path.PointCount(); jj++ )
|
aPlotter->PlotPoly( path, FILL_TYPE::NO_FILL );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
// Plot each initial shape (pads and polygons on mask layer), with suitable attributes:
|
||||||
PlotStandardLayer( aBoard, aPlotter, aLayerMask, aPlotOpt );
|
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++ )
|
for( int ii = 0; ii < areas.OutlineCount(); ii++ )
|
||||||
{
|
{
|
||||||
cornerList.clear();
|
|
||||||
const SHAPE_LINE_CHAIN& path = areas.COutline( ii );
|
const SHAPE_LINE_CHAIN& path = areas.COutline( ii );
|
||||||
|
|
||||||
// polygon area in mm^2 :
|
// polygon area in mm^2 :
|
||||||
|
@ -924,14 +913,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
if( curr_area < poly_min_area_mm2 )
|
if( curr_area < poly_min_area_mm2 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for( int jj = 0; jj < path.PointCount(); jj++ )
|
aPlotter->PlotPoly( path, FILL_TYPE::FILLED_SHAPE );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -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->SetColor( getColor( aZone->GetLayer() ) );
|
||||||
|
|
||||||
m_plotter->StartBlock( nullptr ); // Clean current object attributes
|
m_plotter->StartBlock( nullptr ); // Clean current object attributes
|
||||||
|
@ -798,20 +795,6 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET&
|
||||||
{
|
{
|
||||||
const SHAPE_LINE_CHAIN& outline = polysList.Outline( idx );
|
const SHAPE_LINE_CHAIN& outline = polysList.Outline( idx );
|
||||||
|
|
||||||
cornerList.clear();
|
|
||||||
cornerList.reserve( outline.PointCount() );
|
|
||||||
|
|
||||||
for( int ic = 0; ic < outline.PointCount(); ++ic )
|
|
||||||
{
|
|
||||||
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
|
// Plot the current filled area (as region for Gerber plotter
|
||||||
// to manage attributes) and its outline for thick outline
|
// to manage attributes) and its outline for thick outline
|
||||||
if( GetPlotMode() == FILLED )
|
if( GetPlotMode() == FILLED )
|
||||||
|
@ -820,34 +803,35 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET&
|
||||||
{
|
{
|
||||||
if( outline_thickness > 0 )
|
if( outline_thickness > 0 )
|
||||||
{
|
{
|
||||||
m_plotter->PlotPoly( cornerList, FILL_TYPE::NO_FILL, outline_thickness,
|
m_plotter->PlotPoly( outline, FILL_TYPE::NO_FILL,
|
||||||
&gbr_metadata );
|
outline_thickness, &gbr_metadata );
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion( cornerList,
|
static_cast<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion(
|
||||||
&gbr_metadata );
|
outline, &gbr_metadata );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_plotter->PlotPoly( cornerList, FILL_TYPE::FILLED_SHAPE, outline_thickness,
|
m_plotter->PlotPoly( outline, FILL_TYPE::FILLED_SHAPE,
|
||||||
&gbr_metadata );
|
outline_thickness, &gbr_metadata );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( outline_thickness )
|
if( outline_thickness )
|
||||||
{
|
{
|
||||||
for( unsigned jj = 1; jj < cornerList.size(); jj++ )
|
for( int jj = 1; jj < outline.PointCount(); jj++ )
|
||||||
{
|
{
|
||||||
m_plotter->ThickSegment( cornerList[jj -1], cornerList[jj],
|
m_plotter->ThickSegment( wxPoint( outline.CPoint( jj - 1) ),
|
||||||
outline_thickness, GetPlotMode(), &gbr_metadata );
|
wxPoint( outline.CPoint( jj ) ),
|
||||||
|
outline_thickness,
|
||||||
|
GetPlotMode(), &gbr_metadata );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_plotter->SetCurrentLineWidth( -1 );
|
m_plotter->SetCurrentLineWidth( -1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_plotter->EndBlock( nullptr ); // Clear object attributes
|
m_plotter->EndBlock( nullptr ); // Clear object attributes
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue