diff --git a/common/lset.cpp b/common/lset.cpp index 2ecd17dd2c..8d255c9577 100644 --- a/common/lset.cpp +++ b/common/lset.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck - * 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 * modify it under the terms of the GNU General Public License @@ -30,7 +30,7 @@ #include #include // for Clamp -#include // for LSET, PCB_LAYER_ID, LSEQ +#include // for LSET, PCB_LAYER_ID, LSEQ #include // for arrayDim #include // for wxASSERT, wxASSERT_MSG #include @@ -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 ret; diff --git a/include/layer_ids.h b/include/layer_ids.h index c03394c0cd..30a6f61275 100644 --- a/include/layer_ids.h +++ b/include/layer_ids.h @@ -731,6 +731,8 @@ public: */ 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 * element will be in the same sequence as in PCB_LAYER_ID and only present diff --git a/pcbnew/dialogs/dialog_export_svg.cpp b/pcbnew/dialogs/dialog_export_svg.cpp index 49e6eb2f1b..f420281886 100644 --- a/pcbnew/dialogs/dialog_export_svg.cpp +++ b/pcbnew/dialogs/dialog_export_svg.cpp @@ -218,7 +218,8 @@ void DIALOG_EXPORT_SVG::OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) boardFilePath = wxPathOnly( 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 ); } @@ -360,10 +361,7 @@ bool DIALOG_EXPORT_SVG::CreateSVGFile( const wxString& aFullFileName ) if( plotter ) { plotter->SetColorMode( !m_printBW ); - - for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq ) - PlotOneBoardLayer( m_board, plotter, *seq, plot_opts ); - + PlotBoardLayers( m_board, plotter, m_printMaskLayer.SeqStackupBottom2Top(), plot_opts ); plotter->EndPlot(); } diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index a5d436cbb3..21b00b6a5f 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -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 ) { // 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. LSET disabledCopperLayers = LSET::AllCuMask() & ~m_parent->GetBoard()->GetEnabledLayers(); + // Enable all of the disabled copper layers. // If someone enables more copper layers they will be selected by default. selectedLayers = selectedLayers | disabledCopperLayers; @@ -871,6 +870,14 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) 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; // All copper layers that are disabled are actually selected @@ -896,14 +903,15 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) 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: wxString msg; if( plotter ) { - PlotOneBoardLayer( board, plotter, layer, m_plotOpts ); + PlotBoardLayers( board, plotter, plotSequence, m_plotOpts ); plotter->EndPlot(); delete plotter->RenderSettings(); delete plotter; @@ -924,6 +932,7 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event ) { // Pick the basename from the board file wxFileName fn( boardFilename ); + // Build gerber job file from basename BuildPlotFileName( &fn, outputDir.GetPath(), wxT( "job" ), GerberJobFileExtension ); jobfile_writer.CreateJobFile( fn.GetFullPath() ); diff --git a/pcbnew/pcbplot.h b/pcbnew/pcbplot.h index 8f7b525eba..8bda1314a3 100644 --- a/pcbnew/pcbplot.h +++ b/pcbnew/pcbplot.h @@ -1,7 +1,7 @@ /* * 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 * 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, 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. * diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 272e734ced..ae9d1e710a 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -30,6 +30,7 @@ #include +#include #include #include #include @@ -65,6 +66,16 @@ static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMa 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, 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. LSET layer_mask( aLayer ); - if( !aPlotOpt.GetExcludeEdgeLayer() ) - layer_mask.set( Edge_Cuts ); - if( IsCopperLayer( aLayer ) ) { // 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 F_Mask: plotOpt.SetSkipPlotNPTH_Pads( false ); + // Disable plot pad holes 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 F_Paste: plotOpt.SetSkipPlotNPTH_Pads( false ); + // Disable plot pad holes 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 PAD_SHAPE padShape = pad->GetShape(); - VECTOR2I padSize = pad->GetSize(); + VECTOR2I padSize = pad->GetSize(); 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. // 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. */ @@ -724,7 +666,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, 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; @@ -752,8 +694,9 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, // Plot pad holes if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) { - int smallDrill = (aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE) - ? Millimeter2iu( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) : INT_MAX; + int smallDrill = ( aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE ) + ? Millimeter2iu( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) : + INT_MAX; 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 // 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 ); 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 item->TransformShapeWithClearanceToPolygon( initialPolys, layer, 0, maxError, ERROR_OUTSIDE ); + // add shapes inflated by aMinThickness/2 in areas item->TransformShapeWithClearanceToPolygon( areas, layer, inflate, maxError, ERROR_OUTSIDE ); @@ -907,6 +851,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask, // add shapes with their exact mask layer size in initialPolys via->TransformShapeWithClearanceToPolygon( initialPolys, layer, clearance, maxError, ERROR_OUTSIDE ); + // add shapes inflated by aMinThickness/2 in areas via->TransformShapeWithClearanceToPolygon( areas, layer, clearance + inflate, maxError, ERROR_OUTSIDE );