From e5042a46ba95505f875aeab6711d2dca69deff4e Mon Sep 17 00:00:00 2001 From: Johannes Pfister Date: Mon, 20 Apr 2020 22:02:03 +0000 Subject: [PATCH] Add ability to set SVG plot units and precision ADDED: Ability to set SVG to metric or imperial units and made it possible to change the size of a step --- common/plotters/SVG_plotter.cpp | 31 ++- include/plotter.h | 48 +++-- pcbnew/dialogs/dialog_plot.cpp | 12 +- pcbnew/dialogs/dialog_plot_base.cpp | 52 ++++- pcbnew/dialogs/dialog_plot_base.fbp | 322 +++++++++++++++++++++++++++- pcbnew/dialogs/dialog_plot_base.h | 8 +- pcbnew/pcb_plot_params.cpp | 12 ++ pcbnew/pcb_plot_params.h | 12 ++ pcbnew/plot_board_layers.cpp | 2 + 9 files changed, 469 insertions(+), 30 deletions(-) diff --git a/common/plotters/SVG_plotter.cpp b/common/plotters/SVG_plotter.cpp index 512fa1a03b..9743ef154c 100644 --- a/common/plotters/SVG_plotter.cpp +++ b/common/plotters/SVG_plotter.cpp @@ -105,7 +105,6 @@ #include #include - /** * Function XmlEsc * translates '<' to "<", '>' to ">" and so on, according to the spec: @@ -171,6 +170,8 @@ SVG_PLOTTER::SVG_PLOTTER() m_pen_rgb_color = 0; // current color value (black) m_brush_rgb_color = 0; // current color value (black) m_dashed = PLOT_DASH_TYPE::SOLID; + m_useInch = true; // decimils is the default + m_precision = 4; // because there where used before it was changable } @@ -182,11 +183,28 @@ void SVG_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, plotOffset = aOffset; plotScale = aScale; m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = 1.0 / aIusPerDecimil; + /* Compute the paper size in IUs */ paperSize = pageInfo.GetSizeMils(); paperSize.x *= 10.0 * aIusPerDecimil; paperSize.y *= 10.0 * aIusPerDecimil; + + // set iuPerDeviceUnit, in 0.1mils ( 2.54um ) + // this was used before the format was changable, so we set is as default + SetSvgCoordinatesFormat( 4, true ); +} + +void SVG_PLOTTER::SetSvgCoordinatesFormat( unsigned aResolution, bool aUseInches ) +{ + m_useInch = aUseInches; + m_precision = aResolution; + + // gives now a default value to iuPerDeviceUnit (because the units of the caller is now known) + double iusPerMM = m_IUsPerDecimil / 2.54 * 1000; + iuPerDeviceUnit = pow( 10.0, m_precision ) / ( iusPerMM ); + + if( m_useInch ) + iuPerDeviceUnit /= 25.4; // convert to inch } @@ -702,13 +720,10 @@ bool SVG_PLOTTER::StartPlot() // Write viewport pos and size wxPoint origin; // TODO set to actual value - fprintf( outputFile, - " width=\"%gcm\" height=\"%gcm\" viewBox=\"%d %d %d %d\">\n", + fprintf( outputFile, " width=\"%gcm\" height=\"%gcm\" viewBox=\"%d %d %d %d\">\n", (double) paperSize.x / m_IUsPerDecimil * 2.54 / 10000, - (double) paperSize.y / m_IUsPerDecimil * 2.54 / 10000, - origin.x, origin.y, - (int) ( paperSize.x / m_IUsPerDecimil ), - (int) ( paperSize.y / m_IUsPerDecimil) ); + (double) paperSize.y / m_IUsPerDecimil * 2.54 / 10000, origin.x, origin.y, + (int) ( paperSize.x * iuPerDeviceUnit ), (int) ( paperSize.y * iuPerDeviceUnit) ); // Write title char date_buf[250]; diff --git a/include/plotter.h b/include/plotter.h index c725b783e1..8b45452500 100644 --- a/include/plotter.h +++ b/include/plotter.h @@ -452,6 +452,11 @@ public: // NOP for most plotters. Only for Gerber plotter } + virtual void SetSvgCoordinatesFormat( unsigned aResolution, bool aUseInches = false ) + { + // NOP for most plotters. Only for SVG plotter + } + /** * calling this function allows one to define the beginning of a group * of drawing items, for instance in SVG or Gerber format. @@ -962,6 +967,18 @@ public: virtual void PenTo( const wxPoint& pos, char plume ) override; + /** + * Function SetSvgCoordinatesFormat + * selection of SVG step size (number of digits needed for 1 mm or 1 inch ) + * @param aResolution = number of digits in mantissa of coordinate + * use a value from 3-6 + * do not use value > 6 to avoid overflow in PCBNEW + * do not use value > 4 to avoid overflow for other parts + * @param aUseInches = true to use inches, false to use mm (default) + * + * Should be called only after SetViewport() is called + */ + virtual void SetSvgCoordinatesFormat( unsigned aResolution, bool aUseInches = false ) override; /** * calling this function allows one to define the beginning of a group @@ -991,18 +1008,25 @@ public: void* aData = NULL ) override; protected: - FILL_T m_fillMode; // true if the current contour - // rect, arc, circle, polygon must be filled - long m_pen_rgb_color; // current rgb color value: each color has - // a value 0 ... 255, and the 3 colors are - // grouped in a 3x8 bits value - // (written in hex to svg files) - long m_brush_rgb_color; // same as m_pen_rgb_color, used to fill - // some contours. - bool m_graphics_changed; // true if a pen/brush parameter is modified - // color, pen size, fil mode ... - // the new SVG stype must be output on file - PLOT_DASH_TYPE m_dashed; // plot line style + FILL_T m_fillMode; // true if the current contour + // rect, arc, circle, polygon must be filled + long m_pen_rgb_color; // current rgb color value: each color has + // a value 0 ... 255, and the 3 colors are + // grouped in a 3x8 bits value + // (written in hex to svg files) + long m_brush_rgb_color; // same as m_pen_rgb_color, used to fill + // some contours. + bool m_graphics_changed; // true if a pen/brush parameter is modified + // color, pen size, fil mode ... + // the new SVG stype must be output on file + PLOT_DASH_TYPE m_dashed; // plot line style + bool m_useInch; // is 0 if the step size is 10**-n*mm + // is 1 if the step size is 10**-n*inch + // Where n is given from m_precision + unsigned m_precision; // How fine the step size is + // Use 3-6 (3 means um precision, 6 nm precision) in pcbnew + // 3-4 in other moduls (avoid values >4 to avoid overflow) + // see also comment for m_useInch. /** * function emitSetRGBColor() diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index 1e56a593eb..8bbe7932ff 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -155,6 +155,10 @@ void DIALOG_PLOT::init_Dialog() // Gerber precision for coordinates m_coordFormatCtrl->SetSelection( m_plotOpts.GetGerberPrecision() == 5 ? 0 : 1 ); + // SVG precision and units for coordinates + m_svgPrecsision->SetValue( m_plotOpts.GetSvgPrecision() ); + m_svgUnits->SetSelection( m_plotOpts.GetSvgUseInch() ); + // Option for excluding contents of "Edges Pcb" layer m_excludeEdgeLayerOpt->SetValue( m_plotOpts.GetExcludeEdgeLayer() ); @@ -396,8 +400,9 @@ void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) switch( getPlotFormat() ) { - case PLOT_FORMAT::PDF: case PLOT_FORMAT::SVG: + m_PlotOptionsSizer->Show( m_svgOptionsSizer ); + case PLOT_FORMAT::PDF: m_drillShapeOpt->Enable( true ); m_plotModeOpt->Enable( false ); setPlotModeChoiceSelection( FILLED ); @@ -442,6 +447,7 @@ void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer ); m_PlotOptionsSizer->Show( m_PSOptionsSizer ); m_PlotOptionsSizer->Hide( m_SizerDXF_options ); + m_PlotOptionsSizer->Hide( m_svgOptionsSizer ); break; case PLOT_FORMAT::GERBER: @@ -469,6 +475,7 @@ void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer ); m_PlotOptionsSizer->Hide( m_PSOptionsSizer ); m_PlotOptionsSizer->Hide( m_SizerDXF_options ); + m_PlotOptionsSizer->Hide( m_svgOptionsSizer ); break; case PLOT_FORMAT::HPGL: @@ -492,6 +499,7 @@ void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) m_PlotOptionsSizer->Show( m_HPGLOptionsSizer ); m_PlotOptionsSizer->Hide( m_PSOptionsSizer ); m_PlotOptionsSizer->Hide( m_SizerDXF_options ); + m_PlotOptionsSizer->Hide( m_svgOptionsSizer ); break; case PLOT_FORMAT::DXF: @@ -518,6 +526,7 @@ void DIALOG_PLOT::SetPlotFormat( wxCommandEvent& event ) m_PlotOptionsSizer->Hide( m_HPGLOptionsSizer ); m_PlotOptionsSizer->Hide( m_PSOptionsSizer ); m_PlotOptionsSizer->Show( m_SizerDXF_options ); + m_PlotOptionsSizer->Hide( m_svgOptionsSizer ); OnChangeDXFPlotMode( event ); break; @@ -693,6 +702,7 @@ void DIALOG_PLOT::applyPlotSettings() tempOptions.SetCreateGerberJobFile( m_generateGerberJobFile->GetValue() ); tempOptions.SetGerberPrecision( m_coordFormatCtrl->GetSelection() == 0 ? 5 : 6 ); + tempOptions.SetSvgPrecision( m_svgPrecsision->GetValue(), m_svgUnits->GetSelection() ); LSET selectedLayers; for( unsigned i = 0; i < m_layerList.size(); i++ ) diff --git a/pcbnew/dialogs/dialog_plot_base.cpp b/pcbnew/dialogs/dialog_plot_base.cpp index ca874e479a..dd4a36fb00 100644 --- a/pcbnew/dialogs/dialog_plot_base.cpp +++ b/pcbnew/dialogs/dialog_plot_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 26 2018) +// C++ code generated with wxFormBuilder (version Feb 18 2020) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -336,8 +336,56 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr m_PlotOptionsSizer->Add( m_SizerDXF_options, 0, wxEXPAND|wxALL, 5 ); + m_svgOptionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("SVG Options") ), wxHORIZONTAL ); - bmiddleSizer->Add( m_PlotOptionsSizer, 0, 0, 5 ); + wxGridBagSizer* gbSizer21; + gbSizer21 = new wxGridBagSizer( 3, 0 ); + gbSizer21->SetFlexibleDirection( wxHORIZONTAL ); + gbSizer21->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + wxGridSizer* gSizer1; + gSizer1 = new wxGridSizer( 0, 2, 0, 0 ); + + + gbSizer21->Add( gSizer1, wxGBPosition( 0, 3 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + + + gbSizer21->AddGrowableCol( 2 ); + + m_svgOptionsSizer->Add( gbSizer21, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxGridSizer* gSizer2; + gSizer2 = new wxGridSizer( 0, 4, 0, 0 ); + + svgUnitLabel = new wxStaticText( m_svgOptionsSizer->GetStaticBox(), wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 ); + svgUnitLabel->Wrap( -1 ); + gSizer2->Add( svgUnitLabel, 0, wxALL, 5 ); + + wxString m_svgUnitsChoices[] = { _("Millimeter"), _("Inch") }; + int m_svgUnitsNChoices = sizeof( m_svgUnitsChoices ) / sizeof( wxString ); + m_svgUnits = new wxChoice( m_svgOptionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_svgUnitsNChoices, m_svgUnitsChoices, 0 ); + m_svgUnits->SetSelection( 0 ); + m_svgUnits->SetToolTip( _("The units that are used for a SVG user units. Choose Millimeter when you are not sure.") ); + + gSizer2->Add( m_svgUnits, 0, wxALL, 5 ); + + svgPrecisionLabel = new wxStaticText( m_svgOptionsSizer->GetStaticBox(), wxID_ANY, _("Precision:"), wxDefaultPosition, wxDefaultSize, 0 ); + svgPrecisionLabel->Wrap( -1 ); + gSizer2->Add( svgPrecisionLabel, 0, wxALL, 5 ); + + m_svgPrecsision = new wxSpinCtrl( m_svgOptionsSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 3, 6, 6 ); + m_svgPrecsision->SetToolTip( _("How big a SVG user unit is. The number defines how many digits are exported that are below 1 mm or 1 inch. user unit is 10^- mm or 10^- inch. Choose 6 if you are not sure.") ); + + gSizer2->Add( m_svgPrecsision, 0, wxALL, 5 ); + + + m_svgOptionsSizer->Add( gSizer2, 1, wxEXPAND, 5 ); + + + m_PlotOptionsSizer->Add( m_svgOptionsSizer, 1, wxEXPAND, 5 ); + + + bmiddleSizer->Add( m_PlotOptionsSizer, 0, 0, 6 ); m_MainSizer->Add( bmiddleSizer, 0, wxEXPAND|wxALL, 5 ); diff --git a/pcbnew/dialogs/dialog_plot_base.fbp b/pcbnew/dialogs/dialog_plot_base.fbp index ffd57b7c54..04d1f31981 100644 --- a/pcbnew/dialogs/dialog_plot_base.fbp +++ b/pcbnew/dialogs/dialog_plot_base.fbp @@ -493,7 +493,7 @@ - 5 + 6 0 @@ -513,11 +513,11 @@ wxVERTICAL 1 none - + 5 wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 1 - + wxHORIZONTAL 0,2 @@ -1870,11 +1870,11 @@ wxHORIZONTAL 1 protected - + 5 wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 1 - + wxHORIZONTAL 2 @@ -2360,7 +2360,7 @@ 5 wxALL|wxEXPAND 0 - + wxID_ANY HPGL Options @@ -3397,6 +3397,316 @@ + + 5 + wxEXPAND + 1 + + wxID_ANY + SVG Options + + m_svgOptionsSizer + wxHORIZONTAL + 1 + protected + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + + wxHORIZONTAL + 2 + + 0 + + gbSizer21 + wxFLEX_GROWMODE_SPECIFIED + none + 3 + + 5 + 1 + 3 + wxEXPAND + 0 + 1 + + 2 + 0 + + gSizer1 + none + 0 + 0 + + + + + + 5 + wxEXPAND + 1 + + 4 + 0 + + gSizer2 + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Units: + 0 + + 0 + + + 0 + + 1 + svgUnitLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Millimeter" "Inch" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_svgUnits + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + The units that are used for a SVG user units. Choose Millimeter when you are not sure. + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Precision: + 0 + + 0 + + + 0 + + 1 + svgPrecisionLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 6 + 6 + + 0 + + 3 + + 0 + + 1 + m_svgPrecsision + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + ; ; forward_declare + 0 + How big a SVG user unit is. The number defines how many digits are exported that are below 1 mm or 1 inch. user unit is 10^-<N> mm or 10^-<N> inch. Choose 6 if you are not sure. + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_plot_base.h b/pcbnew/dialogs/dialog_plot_base.h index 0f1eb725cc..2321b8a7ca 100644 --- a/pcbnew/dialogs/dialog_plot_base.h +++ b/pcbnew/dialogs/dialog_plot_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 26 2018) +// C++ code generated with wxFormBuilder (version Feb 18 2020) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -31,6 +31,7 @@ class WX_HTML_REPORT_PANEL; #include #include #include +#include #include #include #include @@ -112,6 +113,11 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM wxCheckBox* m_DXF_plotTextStrokeFontOpt; wxStaticText* DXF_exportUnitsLabel; wxChoice* m_DXF_plotUnits; + wxStaticBoxSizer* m_svgOptionsSizer; + wxStaticText* svgUnitLabel; + wxChoice* m_svgUnits; + wxStaticText* svgPrecisionLabel; + wxSpinCtrl* m_svgPrecsision; WX_HTML_REPORT_PANEL* m_messagesPanel; wxBoxSizer* m_sizerButtons; wxButton* m_buttonDRC; diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp index 8dda7a725c..07a95e2cc1 100644 --- a/pcbnew/pcb_plot_params.cpp +++ b/pcbnew/pcb_plot_params.cpp @@ -101,6 +101,9 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS() m_includeGerberNetlistInfo = true; m_createGerberJobFile = true; m_gerberPrecision = gbrDefaultPrecision; + // we used 0.1mils for SVG step before, but nm precision is more accurate, so we use nm + m_svgPrecision = 6; + m_svgUseInch = false; m_excludeEdgeLayer = true; m_lineWidth = g_DrawDefaultLineThickness; m_plotFrameRef = false; @@ -161,6 +164,11 @@ void PCB_PLOT_PARAMS::SetGerberPrecision( int aPrecision ) gbrDefaultPrecision; } +void PCB_PLOT_PARAMS::SetSvgPrecision( unsigned aPrecision, bool aUseInch ) +{ + m_svgUseInch = aUseInch; + m_svgPrecision = Clamp( 3U, aPrecision, 6U ); +} // PLEASE NOTE: only plot dialog options are processed void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter, @@ -280,6 +288,10 @@ bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams, bool aCom return false; if( m_DXFplotUnits != aPcbPlotParams.m_DXFplotUnits ) return false; + if( m_svgPrecision != aPcbPlotParams.m_svgPrecision ) + return false; + if( m_svgUseInch != aPcbPlotParams.m_svgUseInch ) + return false; } if( m_useAuxOrigin != aPcbPlotParams.m_useAuxOrigin ) return false; diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h index 9c05b8fe94..1cee3199c2 100644 --- a/pcbnew/pcb_plot_params.h +++ b/pcbnew/pcb_plot_params.h @@ -123,6 +123,14 @@ private: /// 5 is the minimal value for professional boards. int m_gerberPrecision; + /// precision of coordinates in SVG files: accepted 3 - 6 + /// 6 is the internal resolution of Pcbnew + unsigned m_svgPrecision; + + /// units for SVG plot + /// false for metric, true for inch/mils + bool m_svgUseInch; + /// Plot gerbers using auxiliary (drill) origin instead of absolue coordinates bool m_useAuxOrigin; @@ -298,6 +306,10 @@ public: void SetGerberPrecision( int aPrecision ); int GetGerberPrecision() const { return m_gerberPrecision; } + void SetSvgPrecision( unsigned aPrecision, bool aUseInch ); + unsigned GetSvgPrecision() const { return m_svgPrecision; } + bool GetSvgUseInch() const { return m_svgUseInch; } + /** Default precision of coordinates in Gerber files. * when units are in mm (7 in inches, but Pcbnew uses mm). * 6 is the internal resolution of Pcbnew, so the default is 6 diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index c2f8cceb64..551a7272f3 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -1113,6 +1113,8 @@ static void initializePlotter( PLOTTER *aPlotter, BOARD * aBoard, aPlotter->SetViewport( offset, IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() ); // Has meaning only for gerber plotter. Must be called only after SetViewport aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() ); + // Has meaning only for SVG plotter. Must be called only after SetViewport + aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision(), aPlotOpts->GetSvgUseInch() ); aPlotter->SetCreator( wxT( "PCBNEW" ) ); aPlotter->SetColorMode( false ); // default is plot in Black and White.