CLI: Allow controlling layer order for multilayer plots

This commit is contained in:
Jon Evans 2023-09-28 10:59:11 -04:00
parent dc47d251f5
commit 0b136ae0df
14 changed files with 63 additions and 45 deletions

View File

@ -47,7 +47,7 @@ public:
bool m_plotBorderTitleBlocks;
DXF_UNITS m_dxfUnits;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
};
#endif

View File

@ -49,7 +49,7 @@ public:
int m_precision;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
};
#endif

View File

@ -44,7 +44,7 @@ public:
bool m_plotRefDes;
bool m_plotBorderTitleBlocks;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
// How holes in pads/vias are plotted:
// 0 = no hole, 1 = small shape, 2 = actual shape

View File

@ -43,7 +43,7 @@ public:
bool m_plotDrawingSheet;
int m_pageSizeMode;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
// How holes in pads/vias are plotted:
// 0 = no hole, 1 = small shape, 2 = actual shape

View File

@ -39,7 +39,7 @@ public:
wxString m_colorTheme;
bool m_blackAndWhite;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
};
#endif

View File

@ -74,6 +74,13 @@ LSET::LSET( unsigned aIdCount, int aFirst, ... ) :
}
LSET::LSET( const LSEQ& aSeq )
{
for( PCB_LAYER_ID layer : aSeq )
set( layer );
}
/**
* NOTE: These names must not be translated or changed. They are used as tokens in the board
* file format because the ordinal value of the PCB_LAYER_ID enum was not stable over time.
@ -475,23 +482,16 @@ LSEQ LSET::Seq() const
LSEQ LSET::SeqStackupBottom2Top() const
{
// bottom-to-top stack-up layers
// Note that the bottom technical layers are flipped so that when plotting a bottom-side view,
// they appear in the correct sequence.
static const PCB_LAYER_ID sequence[] = {
User_9,
User_8,
User_7,
User_6,
User_5,
User_4,
User_3,
User_2,
User_1,
B_Fab,
B_CrtYd,
B_Adhes,
B_SilkS,
B_Paste,
B_Mask,
B_Cu,
B_Mask,
B_Paste,
B_SilkS,
B_Adhes,
B_CrtYd,
B_Fab,
In30_Cu,
In29_Cu,
In28_Cu,
@ -533,6 +533,15 @@ LSEQ LSET::SeqStackupBottom2Top() const
Cmts_User,
Eco1_User,
Eco2_User,
User_1,
User_2,
User_3,
User_4,
User_5,
User_6,
User_7,
User_8,
User_9,
Margin,
Edge_Cuts,
};

View File

@ -524,6 +524,10 @@ public:
BASE_SEQ( aStart, aEnd ), m_index( 0 )
{}
LSEQ( std::initializer_list<PCB_LAYER_ID> aLayers ) :
BASE_SEQ( aLayers )
{}
void Rewind() { m_index = 0; }
void operator ++ () { ++m_index; } // returns nothing, used in simple statements only.
@ -613,6 +617,8 @@ public:
*/
LSET( unsigned aIdCount, int aFirst, ... ); // args chosen to prevent LSET( int ) from compiling
LSET( const LSEQ& aSeq );
/**
* See if the layer set contains a PCB layer.
*

View File

@ -77,10 +77,10 @@ int CLI::FP_EXPORT_SVG_COMMAND::doPerform( KIWAY& aKiway )
svgJob->m_colorTheme = From_UTF8( m_argParser.get<std::string>( ARG_THEME ).c_str() );
if( m_selectedLayers.count() > 0 )
if( !m_selectedLayers.empty() )
svgJob->m_printMaskLayer = m_selectedLayers;
else
svgJob->m_printMaskLayer = LSET::AllLayersMask();
svgJob->m_printMaskLayer = LSET::AllLayersMask().SeqStackupBottom2Top();
int exitCode = aKiway.ProcessJob( KIWAY::FACE_PCB, svgJob.get() );

View File

@ -72,13 +72,12 @@ CLI::PCB_EXPORT_BASE_COMMAND::PCB_EXPORT_BASE_COMMAND( const std::string& aName,
}
LSET CLI::PCB_EXPORT_BASE_COMMAND::convertLayerStringList( wxString& aLayerString, bool& aLayerArgSet ) const
LSEQ CLI::PCB_EXPORT_BASE_COMMAND::convertLayerStringList( wxString& aLayerString, bool& aLayerArgSet ) const
{
LSET layerMask;
LSEQ layerMask;
if( !aLayerString.IsEmpty() )
{
layerMask.reset();
wxStringTokenizer layerTokens( aLayerString, "," );
while( layerTokens.HasMoreTokens() )
@ -88,13 +87,17 @@ LSET CLI::PCB_EXPORT_BASE_COMMAND::convertLayerStringList( wxString& aLayerStrin
// Search for a layer name in canonical layer name used in .kicad_pcb files:
if( m_layerMasks.count( token ) )
{
layerMask |= m_layerMasks.at(token);
for( PCB_LAYER_ID layer : m_layerMasks.at( token ).Seq() )
layerMask.push_back( layer );
aLayerArgSet = true;
}
// Search for a layer name in canonical layer name used in GUI (not translated):
else if( m_layerGuiMasks.count( token ) )
{
layerMask |= m_layerGuiMasks.at(token);
for( PCB_LAYER_ID layer : m_layerGuiMasks.at( token ).Seq() )
layerMask.push_back( layer );
aLayerArgSet = true;
}
else
@ -128,8 +131,9 @@ int CLI::PCB_EXPORT_BASE_COMMAND::doPerform( KIWAY& aKiway )
{
wxString layers = From_UTF8( m_argParser.get<std::string>( ARG_LAYERS ).c_str() );
LSET layerMask = convertLayerStringList( layers, m_selectedLayersSet );
if( m_requireLayers && layerMask.Seq().size() < 1 )
LSEQ layerMask = convertLayerStringList( layers, m_selectedLayersSet );
if( m_requireLayers && layerMask.size() < 1 )
{
wxFprintf( stderr, _( "At least one layer must be specified\n" ) );
return EXIT_CODES::ERR_ARGS;

View File

@ -46,7 +46,7 @@ struct PCB_EXPORT_BASE_COMMAND : public COMMAND
protected:
int doPerform( KIWAY& aKiway ) override;
LSET convertLayerStringList( wxString& aLayerString, bool& aLayerArgSet ) const;
LSEQ convertLayerStringList( wxString& aLayerString, bool& aLayerArgSet ) const;
void addLayerArg( bool aRequire );
// The list of canonical layer names used in .kicad_pcb files:
@ -55,7 +55,7 @@ protected:
// The list of canonical layer names used in GUI (not translated):
std::map<std::string, LSET> m_layerGuiMasks;
LSET m_selectedLayers;
LSEQ m_selectedLayers;
bool m_selectedLayersSet;
bool m_hasLayerArg;

View File

@ -50,7 +50,7 @@ public:
private:
BOARD* m_board;
PCB_EDIT_FRAME* m_parent;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
// the list of existing board layers in wxCheckListBox, with the
// board layers id:
std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
@ -326,10 +326,10 @@ void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
wxString svgPath = fn.GetFullPath();
m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
m_printMaskLayer = aOnlyOneFile ? all_selected.SeqStackupBottom2Top() : LSEQ( { layer } );
if( m_checkboxEdgesOnAllPages->GetValue() )
m_printMaskLayer.set( Edge_Cuts );
m_printMaskLayer.push_back( Edge_Cuts );
svgPlotOptions.m_outputFile = svgPath;
svgPlotOptions.m_printMaskLayer = m_printMaskLayer;

View File

@ -35,7 +35,7 @@ bool EXPORT_SVG::Plot( BOARD* aBoard, const PCB_PLOT_SVG_OPTIONS& aSvgPlotOption
plot_opts.SetPlotFrameRef( aSvgPlotOptions.m_plotFrame );
// Adding drill marks, for copper layers
if( ( aSvgPlotOptions.m_printMaskLayer & LSET::AllCuMask() ).any() )
if( ( LSET( aSvgPlotOptions.m_printMaskLayer ) & LSET::AllCuMask() ).any() )
{
switch( aSvgPlotOptions.m_drillShapeOption )
{
@ -97,7 +97,7 @@ bool EXPORT_SVG::Plot( BOARD* aBoard, const PCB_PLOT_SVG_OPTIONS& aSvgPlotOption
if( plotter )
{
plotter->SetColorMode( !aSvgPlotOptions.m_blackAndWhite );
PlotBoardLayers( aBoard, plotter, aSvgPlotOptions.m_printMaskLayer.SeqStackupBottom2Top(),
PlotBoardLayers( aBoard, plotter, aSvgPlotOptions.m_printMaskLayer,
plot_opts );
plotter->EndPlot();
}

View File

@ -33,7 +33,7 @@ struct PCB_PLOT_SVG_OPTIONS
int m_pageSizeMode;
LSET m_printMaskLayer;
LSEQ m_printMaskLayer;
// How holes in pads/vias are plotted:
// 0 = no hole, 1 = small shape, 2 = actual shape

View File

@ -263,7 +263,7 @@ int PCBNEW_JOBS_HANDLER::JobExportDxf( JOB* aJob )
if( plotter )
{
PlotBoardLayers( brd, plotter, aDxfJob->m_printMaskLayer.SeqStackupBottom2Top(), plotOpts );
PlotBoardLayers( brd, plotter, aDxfJob->m_printMaskLayer, plotOpts );
plotter->EndPlot();
}
@ -332,7 +332,7 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob )
if( plotter )
{
PlotBoardLayers( brd, plotter, aPdfJob->m_printMaskLayer.SeqStackupBottom2Top(), plotOpts );
PlotBoardLayers( brd, plotter, aPdfJob->m_printMaskLayer, plotOpts );
PlotInteractiveLayer( brd, plotter, plotOpts );
plotter->EndPlot();
}
@ -365,20 +365,20 @@ int PCBNEW_JOBS_HANDLER::JobExportGerbers( JOB* aJob )
if( aGerberJob->m_useBoardPlotParams )
{
aGerberJob->m_printMaskLayer = boardPlotOptions.GetLayerSelection();
aGerberJob->m_printMaskLayer = boardPlotOptions.GetLayerSelection().SeqStackupBottom2Top();
aGerberJob->m_layersIncludeOnAll = boardPlotOptions.GetPlotOnAllLayersSelection();
}
else
{
// default to the board enabled layers
if( aGerberJob->m_printMaskLayer == 0 )
aGerberJob->m_printMaskLayer = brd->GetEnabledLayers();
aGerberJob->m_printMaskLayer = brd->GetEnabledLayers().SeqStackupBottom2Top();
if( aGerberJob->m_layersIncludeOnAllSet )
aGerberJob->m_layersIncludeOnAll = plotOnAllLayersSelection;
}
for( LSEQ seq = aGerberJob->m_printMaskLayer.UIOrder(); seq; ++seq )
for( LSEQ seq = LSET( aGerberJob->m_printMaskLayer ).UIOrder(); seq; ++seq )
{
LSEQ plotSequence;
@ -499,13 +499,12 @@ int PCBNEW_JOBS_HANDLER::JobExportGerber( JOB* aJob )
// We are feeding it one layer at the start here to silence a logic check
GERBER_PLOTTER* plotter = (GERBER_PLOTTER*) StartPlotBoard(
brd, &plotOpts, aGerberJob->m_printMaskLayer.Seq().front(), aGerberJob->m_outputFile,
brd, &plotOpts, aGerberJob->m_printMaskLayer.front(), aGerberJob->m_outputFile,
wxEmptyString, wxEmptyString );
if( plotter )
{
PlotBoardLayers( brd, plotter, aGerberJob->m_printMaskLayer.SeqStackupBottom2Top(),
plotOpts );
PlotBoardLayers( brd, plotter, aGerberJob->m_printMaskLayer, plotOpts );
plotter->EndPlot();
}
else