Plot on all layers prep work.

We only need one bottom to top layer sequence definition.

Plot a sequence of layer IDs (LSEQ) in the order of the sequence.

Add helper method to layer set (LSET) to create a sequence of layer IDs
using another sequence for ordering.
This commit is contained in:
Wayne Stambaugh 2022-03-29 16:08:02 -04:00
parent 91ea0903d0
commit c0d8657d97
6 changed files with 68 additions and 89 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2014-2020 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -30,7 +30,7 @@
#include <core/arraydim.h> #include <core/arraydim.h>
#include <math/util.h> // for Clamp #include <math/util.h> // for Clamp
#include <layer_ids.h> // for LSET, PCB_LAYER_ID, LSEQ #include <layer_ids.h> // for LSET, PCB_LAYER_ID, LSEQ
#include <macros.h> // for arrayDim #include <macros.h> // for arrayDim
#include <wx/debug.h> // for wxASSERT, wxASSERT_MSG #include <wx/debug.h> // for wxASSERT, wxASSERT_MSG
#include <wx/string.h> #include <wx/string.h>
@ -442,6 +442,20 @@ LSEQ LSET::Seq( const PCB_LAYER_ID* aWishListSequence, unsigned aCount ) const
} }
LSEQ LSET::Seq( const LSEQ& aSequence ) const
{
LSEQ ret;
for( LSEQ seq = aSequence; seq; ++seq )
{
if( test( *seq ) )
ret.push_back( *seq );
}
return ret;
}
LSEQ LSET::Seq() const LSEQ LSET::Seq() const
{ {
LSEQ ret; LSEQ ret;

View File

@ -731,6 +731,8 @@ public:
*/ */
LSEQ Seq( const PCB_LAYER_ID* aWishListSequence, unsigned aCount ) const; LSEQ Seq( const PCB_LAYER_ID* aWishListSequence, unsigned aCount ) const;
LSEQ Seq( const LSEQ& aSequence ) const;
/** /**
* Return a LSEQ from this LSET in ascending PCB_LAYER_ID order. Each LSEQ * Return a LSEQ from this LSET in ascending PCB_LAYER_ID order. Each LSEQ
* element will be in the same sequence as in PCB_LAYER_ID and only present * element will be in the same sequence as in PCB_LAYER_ID and only present

View File

@ -218,7 +218,8 @@ void DIALOG_EXPORT_SVG::OnOutputDirectoryBrowseClicked( wxCommandEvent& event )
boardFilePath = wxPathOnly( boardFilePath ); boardFilePath = wxPathOnly( boardFilePath );
if( !dirName.MakeRelativeTo( boardFilePath ) ) if( !dirName.MakeRelativeTo( boardFilePath ) )
wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ), wxMessageBox( _( "Cannot make path relative (target volume different from board "
"file volume)!" ),
_( "Plot Output Directory" ), wxOK | wxICON_ERROR ); _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
} }
@ -360,10 +361,7 @@ bool DIALOG_EXPORT_SVG::CreateSVGFile( const wxString& aFullFileName )
if( plotter ) if( plotter )
{ {
plotter->SetColorMode( !m_printBW ); plotter->SetColorMode( !m_printBW );
PlotBoardLayers( m_board, plotter, m_printMaskLayer.SeqStackupBottom2Top(), plot_opts );
for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq )
PlotOneBoardLayer( m_board, plotter, *seq, plot_opts );
plotter->EndPlot(); plotter->EndPlot();
} }

View File

@ -415,8 +415,6 @@ PLOT_FORMAT DIALOG_PLOT::getPlotFormat()
} }
// Enable or disable widgets according to the plot format selected
// and clear also some optional values
void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event )
{ {
// this option exist only in DXF format: // this option exist only in DXF format:
@ -745,6 +743,7 @@ void DIALOG_PLOT::applyPlotSettings()
// Get a list of copper layers that aren't being used by inverting enabled layers. // Get a list of copper layers that aren't being used by inverting enabled layers.
LSET disabledCopperLayers = LSET::AllCuMask() & ~m_parent->GetBoard()->GetEnabledLayers(); LSET disabledCopperLayers = LSET::AllCuMask() & ~m_parent->GetBoard()->GetEnabledLayers();
// Enable all of the disabled copper layers. // Enable all of the disabled copper layers.
// If someone enables more copper layers they will be selected by default. // If someone enables more copper layers they will be selected by default.
selectedLayers = selectedLayers | disabledCopperLayers; selectedLayers = selectedLayers | disabledCopperLayers;
@ -871,6 +870,14 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event )
for( LSEQ seq = m_plotOpts.GetLayerSelection().UIOrder(); seq; ++seq ) for( LSEQ seq = m_plotOpts.GetLayerSelection().UIOrder(); seq; ++seq )
{ {
LSEQ plotSequence;
// Base layer always gets plotted first.
plotSequence.push_back( *seq );
if( ( *seq != Edge_Cuts ) && !m_plotOpts.GetExcludeEdgeLayer() )
plotSequence.push_back( Edge_Cuts );
PCB_LAYER_ID layer = *seq; PCB_LAYER_ID layer = *seq;
// All copper layers that are disabled are actually selected // All copper layers that are disabled are actually selected
@ -896,14 +903,15 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event )
LOCALE_IO toggle; LOCALE_IO toggle;
PLOTTER* plotter = StartPlotBoard( board, &m_plotOpts, layer, fn.GetFullPath(), wxEmptyString ); PLOTTER* plotter = StartPlotBoard( board, &m_plotOpts, layer, fn.GetFullPath(),
wxEmptyString );
// Print diags in messages box: // Print diags in messages box:
wxString msg; wxString msg;
if( plotter ) if( plotter )
{ {
PlotOneBoardLayer( board, plotter, layer, m_plotOpts ); PlotBoardLayers( board, plotter, plotSequence, m_plotOpts );
plotter->EndPlot(); plotter->EndPlot();
delete plotter->RenderSettings(); delete plotter->RenderSettings();
delete plotter; delete plotter;
@ -924,6 +932,7 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event )
{ {
// Pick the basename from the board file // Pick the basename from the board file
wxFileName fn( boardFilename ); wxFileName fn( boardFilename );
// Build gerber job file from basename // Build gerber job file from basename
BuildPlotFileName( &fn, outputDir.GetPath(), wxT( "job" ), GerberJobFileExtension ); BuildPlotFileName( &fn, outputDir.GetPath(), wxT( "job" ), GerberJobFileExtension );
jobfile_writer.CreateJobFile( fn.GetFullPath() ); jobfile_writer.CreateJobFile( fn.GetFullPath() );

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -145,6 +145,17 @@ private:
PLOTTER* StartPlotBoard( BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, int aLayer, PLOTTER* StartPlotBoard( BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, int aLayer,
const wxString& aFullFileName, const wxString& aSheetDesc ); const wxString& aFullFileName, const wxString& aSheetDesc );
/**
* Plot a sequence of board layer IDs.
*
* @param aBoard is the board to plot.
* @param aPlotter is the plotter to use.
* @param aLayerSequence is the sequence of layer IDs to plot.
* @param aPlotOptions are the plot options (files, sketch). Has meaning for some formats only.
*/
void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayerSequence,
const PCB_PLOT_PARAMS& aPlotOptions );
/** /**
* Plot one copper or technical layer. * Plot one copper or technical layer.
* *

View File

@ -30,6 +30,7 @@
#include <eda_item.h> #include <eda_item.h>
#include <layer_ids.h>
#include <geometry/geometry_utils.h> #include <geometry/geometry_utils.h>
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <pcb_base_frame.h> #include <pcb_base_frame.h>
@ -65,6 +66,16 @@ static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMa
const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness ); const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness );
void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
const PCB_PLOT_PARAMS& aPlotOptions )
{
wxCHECK( aBoard && aPlotter && aLayers.size(), /* void */ );
for( LSEQ seq = aLayers; seq; ++seq )
PlotOneBoardLayer( aBoard, aPlotter, *seq, aPlotOptions );
}
void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer, void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
const PCB_PLOT_PARAMS& aPlotOpt ) const PCB_PLOT_PARAMS& aPlotOpt )
{ {
@ -79,9 +90,6 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
// contents of the currently specified layer. // contents of the currently specified layer.
LSET layer_mask( aLayer ); LSET layer_mask( aLayer );
if( !aPlotOpt.GetExcludeEdgeLayer() )
layer_mask.set( Edge_Cuts );
if( IsCopperLayer( aLayer ) ) if( IsCopperLayer( aLayer ) )
{ {
// Skip NPTH pads on copper layers ( only if hole size == pad size ): // Skip NPTH pads on copper layers ( only if hole size == pad size ):
@ -104,6 +112,7 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
case B_Mask: case B_Mask:
case F_Mask: case F_Mask:
plotOpt.SetSkipPlotNPTH_Pads( false ); plotOpt.SetSkipPlotNPTH_Pads( false );
// Disable plot pad holes // Disable plot pad holes
plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE ); plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE );
@ -128,6 +137,7 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
case B_Paste: case B_Paste:
case F_Paste: case F_Paste:
plotOpt.SetSkipPlotNPTH_Pads( false ); plotOpt.SetSkipPlotNPTH_Pads( false );
// Disable plot pad holes // Disable plot pad holes
plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE ); plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE );
@ -304,9 +314,9 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// Store these parameters that can be modified to plot inflated/deflated pads shape // Store these parameters that can be modified to plot inflated/deflated pads shape
PAD_SHAPE padShape = pad->GetShape(); PAD_SHAPE padShape = pad->GetShape();
VECTOR2I padSize = pad->GetSize(); VECTOR2I padSize = pad->GetSize();
VECTOR2I padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads VECTOR2I padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads
double padCornerRadius = pad->GetRoundRectCornerRadius(); double padCornerRadius = pad->GetRoundRectCornerRadius();
// Don't draw a 0 sized pad. // Don't draw a 0 sized pad.
// Note: a custom pad can have its pad anchor with size = 0 // Note: a custom pad can have its pad anchor with size = 0
@ -645,74 +655,6 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
} }
// Seems like we want to plot from back to front?
static const PCB_LAYER_ID plot_seq[] = {
User_9,
User_8,
User_7,
User_6,
User_5,
User_4,
User_3,
User_2,
User_1,
B_Adhes,
F_Adhes,
B_Paste,
F_Paste,
B_SilkS,
B_Mask,
F_Mask,
Dwgs_User,
Cmts_User,
Eco1_User,
Eco2_User,
Edge_Cuts,
Margin,
F_CrtYd, // CrtYd & Body are footprint only
B_CrtYd,
F_Fab,
B_Fab,
B_Cu,
In30_Cu,
In29_Cu,
In28_Cu,
In27_Cu,
In26_Cu,
In25_Cu,
In24_Cu,
In23_Cu,
In22_Cu,
In21_Cu,
In20_Cu,
In19_Cu,
In18_Cu,
In17_Cu,
In16_Cu,
In15_Cu,
In14_Cu,
In13_Cu,
In12_Cu,
In11_Cu,
In10_Cu,
In9_Cu,
In8_Cu,
In7_Cu,
In6_Cu,
In5_Cu,
In4_Cu,
In3_Cu,
In2_Cu,
In1_Cu,
F_Cu,
F_SilkS,
};
/** /**
* Plot outlines of copper layer. * Plot outlines of copper layer.
*/ */
@ -724,7 +666,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
SHAPE_POLY_SET outlines; SHAPE_POLY_SET outlines;
for( LSEQ seq = aLayerMask.Seq( plot_seq, arrayDim( plot_seq ) ); seq; ++seq ) for( LSEQ seq = aLayerMask.Seq( aLayerMask.SeqStackupBottom2Top() ); seq; ++seq )
{ {
PCB_LAYER_ID layer = *seq; PCB_LAYER_ID layer = *seq;
@ -752,8 +694,9 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// Plot pad holes // Plot pad holes
if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE )
{ {
int smallDrill = (aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE) int smallDrill = ( aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE )
? Millimeter2iu( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) : INT_MAX; ? Millimeter2iu( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) :
INT_MAX;
for( FOOTPRINT* footprint : aBoard->Footprints() ) for( FOOTPRINT* footprint : aBoard->Footprints() )
{ {
@ -838,7 +781,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater // We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
// than or equal comparison in the shape separation (boolean add) // than or equal comparison in the shape separation (boolean add)
int inflate = aMinThickness/2 - 1; int inflate = aMinThickness / 2 - 1;
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
itemplotter.SetLayerSet( aLayerMask ); itemplotter.SetLayerSet( aLayerMask );
@ -882,6 +825,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// add shapes with their exact mask layer size in initialPolys // add shapes with their exact mask layer size in initialPolys
item->TransformShapeWithClearanceToPolygon( initialPolys, layer, 0, maxError, item->TransformShapeWithClearanceToPolygon( initialPolys, layer, 0, maxError,
ERROR_OUTSIDE ); ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas // add shapes inflated by aMinThickness/2 in areas
item->TransformShapeWithClearanceToPolygon( areas, layer, inflate, maxError, item->TransformShapeWithClearanceToPolygon( areas, layer, inflate, maxError,
ERROR_OUTSIDE ); ERROR_OUTSIDE );
@ -907,6 +851,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// add shapes with their exact mask layer size in initialPolys // add shapes with their exact mask layer size in initialPolys
via->TransformShapeWithClearanceToPolygon( initialPolys, layer, clearance, maxError, via->TransformShapeWithClearanceToPolygon( initialPolys, layer, clearance, maxError,
ERROR_OUTSIDE ); ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas // add shapes inflated by aMinThickness/2 in areas
via->TransformShapeWithClearanceToPolygon( areas, layer, clearance + inflate, maxError, via->TransformShapeWithClearanceToPolygon( areas, layer, clearance + inflate, maxError,
ERROR_OUTSIDE ); ERROR_OUTSIDE );