ADDED: sketch-pads-on-fab-layers to CLI PDF & SVG export.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18091
This commit is contained in:
Jeff Young 2024-05-27 20:56:16 +01:00
parent 0881fc8aa9
commit b88d3b13ac
21 changed files with 144 additions and 25 deletions

View File

@ -34,6 +34,7 @@ JOB_EXPORT_PCB_PDF::JOB_EXPORT_PCB_PDF( bool aIsCli ) :
m_plotRefDes( true ),
m_plotBorderTitleBlocks( false ),
m_printMaskLayer(),
m_sketchPadsOnFabLayers( false ),
m_drillShapeOption( 2 )
{
}

View File

@ -46,9 +46,10 @@ public:
LSEQ m_printMaskLayer;
bool m_sketchPadsOnFabLayers;
// How holes in pads/vias are plotted:
// 0 = no hole, 1 = small shape, 2 = actual shape
// Not used in some plotters (Gerber)
int m_drillShapeOption;
};

View File

@ -33,6 +33,7 @@ JOB_EXPORT_PCB_SVG::JOB_EXPORT_PCB_SVG( bool aIsCli ) :
m_plotDrawingSheet( true ),
m_pageSizeMode( 0 ),
m_printMaskLayer(),
m_sketchPadsOnFabLayers( false ),
m_drillShapeOption( 2 )
{
}

View File

@ -44,10 +44,10 @@ public:
int m_pageSizeMode;
LSEQ m_printMaskLayer;
bool m_sketchPadsOnFabLayers;
// How holes in pads/vias are plotted:
// 0 = no hole, 1 = small shape, 2 = actual shape
// Not used in some plotters (Gerber)
int m_drillShapeOption;
};

View File

@ -26,6 +26,7 @@ JOB_FP_EXPORT_SVG::JOB_FP_EXPORT_SVG( bool aIsCli ) :
m_libraryPath(),
m_footprint(),
m_outputDirectory(),
m_blackAndWhite( false )
m_blackAndWhite( false ),
m_sketchPadsOnFabLayers( false )
{
}

View File

@ -39,6 +39,7 @@ public:
wxString m_colorTheme;
bool m_blackAndWhite;
bool m_sketchPadsOnFabLayers;
LSEQ m_printMaskLayer;
};

View File

@ -28,6 +28,7 @@ pdf_metadata
plotframeref
plotfptext
plotinvisibletext
plotpadnumbers
plotreference
plotvalue
psa4output

View File

@ -34,6 +34,7 @@
#include <gal/color4d.h>
#include <stroke_params.h>
#include <render_settings.h>
#include <font/font.h>
class COLOR_SETTINGS;
@ -441,8 +442,8 @@ public:
const COLOR4D& aColor,
const wxString& aText,
const TEXT_ATTRIBUTES& aAttributes,
KIFONT::FONT* aFont,
const KIFONT::METRICS& aFontMetrics,
KIFONT::FONT* aFont = nullptr,
const KIFONT::METRICS& aFontMetrics = KIFONT::METRICS::Default(),
void* aData = nullptr );
/**
* Create a clickable hyperlink with a rectangular click area

View File

@ -50,6 +50,10 @@ CLI::FP_EXPORT_SVG_COMMAND::FP_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND( "
.help( UTF8STDSTR( _( "Specific footprint to export within the library" ) ) )
.metavar( "FOOTPRINT_NAME" );
m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
.help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
.flag();
m_argParser.add_argument( ARG_BLACKANDWHITE )
.help( UTF8STDSTR( _( ARG_BLACKANDWHITE_DESC ) ) )
.flag();
@ -67,6 +71,7 @@ int CLI::FP_EXPORT_SVG_COMMAND::doPerform( KIWAY& aKiway )
svgJob->m_libraryPath = m_argInput;
svgJob->m_outputDirectory = m_argOutput;
svgJob->m_blackAndWhite = m_argParser.get<bool>( ARG_BLACKANDWHITE );
svgJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
svgJob->m_footprint = From_UTF8( m_argParser.get<std::string>( ARG_FOOTPRINT ).c_str() );
svgJob->SetVarOverrides( m_argDefineVars );

View File

@ -29,6 +29,12 @@ namespace CLI
#define ARG_BLACKANDWHITE "--black-and-white"
#define ARG_BLACKANDWHITE_DESC "Black and white only"
#define ARG_SKETCH_PADS_ON_FAB_LAYERS "--sketch-pads-on-fab-layers"
#define ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC "Draw pad outlines and their numbers on front and back fab layers"
#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
#define ARG_DRILL_SHAPE_OPTION_DESC "Set pad/via drill shape option (0 = no shape, 1 = small shape, 2 = actual shape)"
#define ARG_NEGATIVE "--negative"
#define ARG_NEGATIVE_SHORT "-n"
#define ARG_NEGATIVE_DESC "Plot as negative (useful for directly etching from the export)"

View File

@ -26,13 +26,8 @@
#include <string_utils.h>
#include <wx/crt.h>
#include <macros.h>
#include <wx/tokenzr.h>
#include <locale_io.h>
#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND( "pdf" )
{
@ -58,6 +53,10 @@ CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND(
.help( UTF8STDSTR( _( "Include the border and title block" ) ) )
.flag();
m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
.help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
.flag();
m_argParser.add_argument( ARG_NEGATIVE_SHORT, ARG_NEGATIVE )
.help( UTF8STDSTR( _( ARG_NEGATIVE_DESC ) ) )
.flag();
@ -72,8 +71,7 @@ CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND(
.metavar( "THEME_NAME" );
m_argParser.add_argument( ARG_DRILL_SHAPE_OPTION )
.help( UTF8STDSTR( _( "Set pad/via drill shape option (0 = no shape, 1 = "
"small shape, 2 = actual shape)" ) ) )
.help( UTF8STDSTR( _( ARG_DRILL_SHAPE_OPTION_DESC ) ) )
.scan<'i', int>()
.default_value( 2 );
}
@ -109,6 +107,7 @@ int CLI::PCB_EXPORT_PDF_COMMAND::doPerform( KIWAY& aKiway )
pdfJob->m_colorTheme = From_UTF8( m_argParser.get<std::string>( ARG_THEME ).c_str() );
pdfJob->m_negative = m_argParser.get<bool>( ARG_NEGATIVE );
pdfJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
pdfJob->m_drillShapeOption = m_argParser.get<int>( ARG_DRILL_SHAPE_OPTION );
pdfJob->m_printMaskLayer = m_selectedLayers;

View File

@ -29,12 +29,9 @@
#include <regex>
#include <wx/crt.h>
#include <macros.h>
#include <wx/tokenzr.h>
#define ARG_EXCLUDE_DRAWING_SHEET "--exclude-drawing-sheet"
#define ARG_PAGE_SIZE "--page-size-mode"
#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND( "svg" )
@ -62,6 +59,10 @@ CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND(
.help( UTF8STDSTR( _( ARG_BLACKANDWHITE_DESC ) ) )
.flag();
m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
.help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
.flag();
m_argParser.add_argument( ARG_PAGE_SIZE )
.help( UTF8STDSTR( _( "Set page sizing mode (0 = page with frame and title block, 1 = "
"current page size, 2 = board area only)" ) ) )
@ -74,8 +75,7 @@ CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND(
.flag();
m_argParser.add_argument( ARG_DRILL_SHAPE_OPTION )
.help( UTF8STDSTR( _( "Set pad/via drill shape option (0 = no shape, 1 = "
"small shape, 2 = actual shape)" ) ) )
.help( UTF8STDSTR( _( ARG_DRILL_SHAPE_OPTION_DESC ) ) )
.scan<'i', int>()
.default_value( 2 )
.metavar( "SHAPE_OPTION" );
@ -94,6 +94,7 @@ int CLI::PCB_EXPORT_SVG_COMMAND::doPerform( KIWAY& aKiway )
svgJob->m_blackAndWhite = m_argParser.get<bool>( ARG_BLACKANDWHITE );
svgJob->m_pageSizeMode = m_argParser.get<int>( ARG_PAGE_SIZE );
svgJob->m_negative = m_argParser.get<bool>( ARG_NEGATIVE );
svgJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
svgJob->m_drillShapeOption = m_argParser.get<int>( ARG_DRILL_SHAPE_OPTION );
svgJob->m_drawingSheet = m_argDrawingSheet;

View File

@ -106,6 +106,7 @@ std::string g_previewBoard =
" (plotreference true)\n"
" (plotvalue true)\n"
" (plotinvisibletext false)\n"
" (plotpadnumbers false)\n"
" (sketchpadsonfab false)\n"
" (subtractmaskfromsilk false)\n"
" (outputformat 1)\n"

View File

@ -20,7 +20,6 @@
#include "board.h"
#include "locale_io.h"
#include "pcb_plot_params.h"
#include "export_svg.h"
#include "pcbplot.h"
#include "pgm_base.h"
@ -34,6 +33,12 @@ bool EXPORT_SVG::Plot( BOARD* aBoard, const PCB_PLOT_SVG_OPTIONS& aSvgPlotOption
plot_opts.SetPlotFrameRef( aSvgPlotOptions.m_plotFrame );
if( aSvgPlotOptions.m_sketchPadsOnFabLayers )
{
plot_opts.SetSketchPadsOnFabLayers( true );
plot_opts.SetPlotPadNumbers( true );
}
// Adding drill marks, for copper layers
if( ( LSET( aSvgPlotOptions.m_printMaskLayer ) & LSET::AllCuMask() ).any() )
{

View File

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

View File

@ -118,6 +118,7 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS()
m_plotFPText = true;
m_plotInvisibleText = false;
m_sketchPadsOnFabLayers = false;
m_plotPadNumbers = false;
m_subtractMaskFromSilk = false;
m_format = PLOT_FORMAT::GERBER;
m_mirror = false;
@ -244,12 +245,10 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter,
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotreference", m_plotReference );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotvalue", m_plotValue );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotfptext", m_plotFPText );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotinvisibletext",
m_plotInvisibleText );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "sketchpadsonfab",
m_sketchPadsOnFabLayers );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "subtractmaskfromsilk",
m_subtractMaskFromSilk );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotinvisibletext", m_plotInvisibleText );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "sketchpadsonfab", m_sketchPadsOnFabLayers );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotpadnumbers", m_plotPadNumbers );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "subtractmaskfromsilk", m_subtractMaskFromSilk );
aFormatter->Print( aNestLevel+1, "(outputformat %d)\n", static_cast<int>( m_format ) );
KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "mirror", m_mirror );
aFormatter->Print( aNestLevel+1, "(drillshape %d)\n", (int)m_drillMarks );
@ -359,6 +358,9 @@ bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams ) const
if( m_sketchPadsOnFabLayers != aPcbPlotParams.m_sketchPadsOnFabLayers )
return false;
if( m_plotPadNumbers != aPcbPlotParams.m_plotPadNumbers )
return false;
if( m_subtractMaskFromSilk != aPcbPlotParams.m_subtractMaskFromSilk )
return false;
@ -630,6 +632,10 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
aPcbPlotParams->m_sketchPadsOnFabLayers= parseBool();
break;
case T_plotpadnumbers:
aPcbPlotParams->m_plotPadNumbers = parseBool();
break;
case T_subtractmaskfromsilk:
aPcbPlotParams->m_subtractMaskFromSilk = parseBool();
break;

View File

@ -71,6 +71,9 @@ public:
void SetPlotMode( OUTLINE_MODE aPlotMode ) { m_plotMode = aPlotMode; }
OUTLINE_MODE GetPlotMode() const { return m_plotMode; }
void SetPlotPadNumbers( bool aFlag ) { m_plotPadNumbers = aFlag; }
bool GetPlotPadNumbers() const { return m_plotPadNumbers; }
void SetDXFPlotPolygonMode( bool aFlag ) { m_DXFPolygonMode = aFlag; }
bool GetDXFPlotPolygonMode() const { return m_DXFPolygonMode; }
@ -203,6 +206,7 @@ private:
bool m_skipNPTH_Pads; /// Used to disable NPTH pads plotting on copper layers
OUTLINE_MODE m_plotMode; /// FILLED or SKETCH for filled objects.
bool m_plotPadNumbers; /// Plot pad numbers when sketching pads on fab layers
DRILL_MARKS m_drillMarks; /// Holes can be not plotted, have a small mark, or be
/// plotted in actual size
PLOT_TEXT_MODE m_textMode;

View File

@ -438,6 +438,7 @@ int PCBNEW_JOBS_HANDLER::JobExportSvg( JOB* aJob )
svgPlotOptions.m_pageSizeMode = aSvgJob->m_pageSizeMode;
svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
svgPlotOptions.m_plotFrame = aSvgJob->m_plotDrawingSheet;
svgPlotOptions.m_sketchPadsOnFabLayers = aSvgJob->m_sketchPadsOnFabLayers;
svgPlotOptions.m_drillShapeOption = aSvgJob->m_drillShapeOption;
if( aJob->IsCli() )
@ -571,6 +572,12 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob )
plotOpts.SetBlackAndWhite( aPdfJob->m_blackAndWhite );
plotOpts.SetNegative( aPdfJob->m_negative );
if( aPdfJob->m_sketchPadsOnFabLayers )
{
plotOpts.SetSketchPadsOnFabLayers( true );
plotOpts.SetPlotPadNumbers( true );
}
switch( aPdfJob->m_drillShapeOption )
{
default:
@ -1246,12 +1253,12 @@ int PCBNEW_JOBS_HANDLER::doFpExportSvg( JOB_FP_EXPORT_SVG* aSvgJob, const FOOTPR
svgPlotOptions.m_mirror = false;
svgPlotOptions.m_pageSizeMode = 2; // board bounding box
svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
svgPlotOptions.m_sketchPadsOnFabLayers = aSvgJob->m_sketchPadsOnFabLayers;
svgPlotOptions.m_plotFrame = false;
if( !EXPORT_SVG::Plot( brd.get(), svgPlotOptions ) )
m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
return CLI::EXIT_CODES::OK;
}

View File

@ -102,6 +102,8 @@ public:
*/
void PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_MODE aPlotMode );
void PlotPadNumber( const PAD* aPad, const COLOR4D& aColor );
/**
* Plot items like text and graphics but not tracks and footprints.
*/

View File

@ -333,6 +333,14 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
}
if( sketchPads &&
( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
{
if( aPlotOpt.GetPlotPadNumbers() )
itemplotter.PlotPadNumber( pad, color );
}
VECTOR2I margin;
int width_adj = 0;

View File

@ -72,6 +72,73 @@ COLOR4D BRDITEMS_PLOTTER::getColor( int aLayer ) const
}
void BRDITEMS_PLOTTER::PlotPadNumber( const PAD* aPad, const COLOR4D& aColor )
{
wxString padNumber = UnescapeString( aPad->GetNumber() );
if( padNumber.IsEmpty() )
return;
BOX2I padBBox = aPad->GetBoundingBox();
VECTOR2I position = padBBox.Centre();
VECTOR2I padsize = padBBox.GetSize();
if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
{
// See if we have a number box
for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
{
if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE )
{
position = primitive->GetCenter();
RotatePoint( position, aPad->GetOrientation() );
position += aPad->ShapePos();
padsize.x = abs( primitive->GetBotRight().x - primitive->GetTopLeft().x );
padsize.y = abs( primitive->GetBotRight().y - primitive->GetTopLeft().y );
break;
}
}
}
if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
{
// Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
int limit = KiROUND( std::min( aPad->GetSize().x, aPad->GetSize().y ) * 1.1 );
if( padsize.x > limit && padsize.y > limit )
{
padsize.x = limit;
padsize.y = limit;
}
}
TEXT_ATTRIBUTES textAttrs;
if( padsize.x < ( padsize.y * 0.95 ) )
{
textAttrs.m_Angle = ANGLE_90;
std::swap( padsize.x, padsize.y );
}
// approximate the size of the pad number text:
// We use a size for at least 3 chars, to give a good look even for short numbers
int tsize = KiROUND( padsize.x / std::max( PrintableCharCount( padNumber ), 3 ) );
tsize = std::min( tsize, padsize.y );
// enforce a max size
tsize = std::min( tsize, pcbIUScale.mmToIU( 5.0 ) );
textAttrs.m_Size = VECTOR2I( tsize, tsize );
// use a somewhat spindly font to go with the outlined pads
textAttrs.m_StrokeWidth = KiROUND( tsize / 12.0 );
m_plotter->PlotText( position, aColor, padNumber, textAttrs );
}
void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_MODE aPlotMode )
{
VECTOR2I shape_pos = aPad->ShapePos();