From 213a74cbe64eace7b2c1b4f86de22dcecd8a48b5 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 10 Oct 2020 14:39:54 +0200 Subject: [PATCH] Gerber, Dialog plot: add option to disable Aperture Macro use. Some broken Gerber readers cannot handle Aperture Macros without errors although this feature exists since the beginning of RS274X format. --- common/pcb_plot_params.keywords | 1 + common/plotters/GERBER_plotter.cpp | 90 +++++++++++++++++------------ common/plotters/plotter_gerber.h | 9 +++ pcbnew/dialogs/dialog_plot.cpp | 6 +- pcbnew/dialogs/dialog_plot_base.cpp | 7 ++- pcbnew/dialogs/dialog_plot_base.fbp | 69 +++++++++++++++++++++- pcbnew/dialogs/dialog_plot_base.h | 1 + pcbnew/pcb_plot_params.cpp | 10 ++++ pcbnew/pcb_plot_params.h | 7 +++ pcbnew/plot_board_layers.cpp | 1 + 10 files changed, 162 insertions(+), 39 deletions(-) diff --git a/common/pcb_plot_params.keywords b/common/pcb_plot_params.keywords index 066a40f799..0c8991c5d0 100644 --- a/common/pcb_plot_params.keywords +++ b/common/pcb_plot_params.keywords @@ -1,4 +1,5 @@ creategerberjobfile +disableapertmacros drillshape excludeedgelayer false diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp index eb8d1b9fcd..0870e49ee6 100644 --- a/common/plotters/GERBER_plotter.cpp +++ b/common/plotters/GERBER_plotter.cpp @@ -40,6 +40,10 @@ // if GBR_USE_MACROS is defined, pads having a shape that is not a Gerber primitive // will use a macro when possible // Old code will be removed only after many tests +// +// Note also: setting m_gerberDisableApertMacros to true disable all aperture macros +// in Gerber files +// #define GBR_USE_MACROS_FOR_CHAMFERED_RECT #define GBR_USE_MACROS_FOR_ROUNDRECT #define GBR_USE_MACROS_FOR_TRAPEZOID @@ -64,6 +68,7 @@ GERBER_PLOTTER::GERBER_PLOTTER() m_gerberUnitFmt = 6; m_useX2format = true; m_useNetAttributes = true; + m_gerberDisableApertMacros = false; m_hasApertureRoundRect = false; // true is at least one round rect aperture is in use m_hasApertureRotOval = false; // true is at least one oval rotated aperture is in use @@ -1024,34 +1029,37 @@ void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, doub if( trace_mode == FILLED ) { #ifdef GBR_USE_MACROS_FOR_ROTATED_OVAL - m_hasApertureRotOval = true; - // We are using a aperture macro that expect size.y < size.x - // i.e draw a horizontal line for rotation = 0.0 - // size.x = length, size.y = width - if( size.x < size.y ) + if( !m_gerberDisableApertMacros ) + #endif { - std::swap( size.x, size.y ); - orient += 900; + m_hasApertureRotOval = true; + // We are using a aperture macro that expect size.y < size.x + // i.e draw a horizontal line for rotation = 0.0 + // size.x = length, size.y = width + if( size.x < size.y ) + { + std::swap( size.x, size.y ); + orient += 900; - if( orient > 1800 ) - orient -= 1800; + if( orient > 1800 ) + orient -= 1800; + } + + DPOINT pos_dev = userToDeviceCoordinates( pos ); + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( size, 0, orient/10.0, APERTURE::AM_ROTATED_OVAL, aperture_attrib ); + + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + + emitDcode( pos_dev, 3 ); + return; } - - DPOINT pos_dev = userToDeviceCoordinates( pos ); - int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, 0, orient/10.0, APERTURE::AM_ROTATED_OVAL, aperture_attrib ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - emitDcode( pos_dev, 3 ); - #else // Draw the oval as round rect pad with a radius = 50% min size) // In gerber file, it will be drawn as a region with arcs, and can be // detected as pads (similar to a flashed pad) FlashPadRoundRect( pos, aSize, std::min( aSize.x, aSize.y ) /2, orient, FILLED, aData ); - #endif } else // Non filled shape: plot outlines: { @@ -1116,7 +1124,7 @@ void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize, default: #ifdef GBR_USE_MACROS_FOR_ROTATED_RECT - if( trace_mode != SKETCH ) + if( trace_mode != SKETCH && !m_gerberDisableApertMacros ) { m_hasApertureRotRect = true; DPOINT pos_dev = userToDeviceCoordinates( pos ); @@ -1187,18 +1195,22 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS else { #ifdef GBR_USE_MACROS_FOR_ROUNDRECT - m_hasApertureRoundRect = true; + if( !m_gerberDisableApertMacros ) + #endif + { + m_hasApertureRoundRect = true; - DPOINT pos_dev = userToDeviceCoordinates( aPadPos ); - int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( aSize, aCornerRadius, aOrient/10.0, - APERTURE::AM_ROUND_RECT, aperture_attrib ); + DPOINT pos_dev = userToDeviceCoordinates( aPadPos ); + int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; + selectAperture( aSize, aCornerRadius, aOrient/10.0, + APERTURE::AM_ROUND_RECT, aperture_attrib ); - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); + if( gbr_metadata ) + formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - emitDcode( pos_dev, 3 ); - #else + emitDcode( pos_dev, 3 ); + return; + } // A Pad RoundRect is plotted as a Gerber region. // Initialize region metadata: bool clearTA_AperFunction = false; // true if a TA.AperFunction is used @@ -1226,7 +1238,6 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS else fputs( "G04 #@! TD.AperFunction*\n", outputFile ); } - #endif } } @@ -1420,7 +1431,8 @@ void GERBER_PLOTTER::FlashPadChamferRoundRect( const wxPoint& aShapePos, const w bool hasRoundedCorner = aCornerRadius != 0 && aChamferPositions != 15; #ifdef GBR_USE_MACROS_FOR_CHAMFERED_RECT - if( aPlotMode != FILLED || hasRoundedCorner ) // Sketch mode or round rect shape + // Sketch mode or round rect shape or Apert Macros disabled + if( aPlotMode != FILLED || hasRoundedCorner || m_gerberDisableApertMacros ) #endif { TransformRoundChamferedRectToPolygon( outline, aShapePos, aPadSize, @@ -1525,9 +1537,15 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo metadata = *gbr_metadata; if( aTrace_Mode == SKETCH ) + { PlotPoly( cornerList, NO_FILL, GetCurrentLineWidth(), &metadata ); - else + return; + } + + // Plot a filled polygon: #ifdef GBR_USE_MACROS_FOR_TRAPEZOID + if( !m_gerberDisableApertMacros ) + #endif { m_hasApertureOutline4P = true; DPOINT pos_dev = userToDeviceCoordinates( aPadPos ); @@ -1540,10 +1558,10 @@ void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCo formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); emitDcode( pos_dev, 3 ); + return; } - #else - PlotGerberRegion( cornerList, &metadata ); - #endif + + PlotGerberRegion( cornerList, &metadata ); } diff --git a/common/plotters/plotter_gerber.h b/common/plotters/plotter_gerber.h index 6ccf2f9044..bece1713d5 100644 --- a/common/plotters/plotter_gerber.h +++ b/common/plotters/plotter_gerber.h @@ -197,6 +197,12 @@ public: void UseX2format( bool aEnable ) { m_useX2format = aEnable; } void UseX2NetAttributes( bool aEnable ) { m_useNetAttributes = aEnable; } + /** Disable Aperture Macro (AM) command, only for broken Gerber Readers + * Regions will be used instead of AM shapes to draw complex shapes + * @param aDisable = true to disable Aperture Macro (AM) command. + */ + void DisableApertMacros( bool aDisable ) { m_gerberDisableApertMacros = aDisable; } + /** * calling this function allows one to define the beginning of a group * of drawing items (used in X2 format with netlist attributes) @@ -351,6 +357,9 @@ protected: bool m_gerberUnitInch; // true if the gerber units are inches, false for mm int m_gerberUnitFmt; // number of digits in mantissa. // usually 6 in Inches and 5 or 6 in mm + bool m_gerberDisableApertMacros; // True to disable Aperture Macro (AM) command, + // for broken Gerber Readers + // Regions will be used instead of AM shapes bool m_useX2format; // Add X2 file header attributes. If false, attributes // will be added as comments. bool m_useNetAttributes; // In recent gerber files, netlist info can be added. diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index 77c02e8f81..87d9f05b1a 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -136,6 +136,9 @@ void DIALOG_PLOT::init_Dialog() m_layerCheckListBox->Check( checkIndex ); } + // Option for disabling Gerber Aperture Macro (for broken Gerber readers) + m_disableApertMacros->SetValue( m_plotOpts.GetDisableGerberMacros() ); + // Option for using proper Gerber extensions. Note also Protel extensions are // a broken feature. However, for now, we need to handle it. m_useGerberExtensions->SetValue( m_plotOpts.GetUseGerberProtelExtensions() ); @@ -720,6 +723,7 @@ void DIALOG_PLOT::applyPlotSettings() tempOptions.SetFormat( getPlotFormat() ); + tempOptions.SetDisableGerberMacros( m_disableApertMacros->GetValue() ); tempOptions.SetUseGerberProtelExtensions( m_useGerberExtensions->GetValue() ); tempOptions.SetUseGerberX2format( m_useGerberX2Format->GetValue() ); tempOptions.SetIncludeGerberNetlistInfo( m_useGerberNetAttributes->GetValue() ); @@ -881,7 +885,7 @@ 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; diff --git a/pcbnew/dialogs/dialog_plot_base.cpp b/pcbnew/dialogs/dialog_plot_base.cpp index 2939eaee64..8523e4ec54 100644 --- a/pcbnew/dialogs/dialog_plot_base.cpp +++ b/pcbnew/dialogs/dialog_plot_base.cpp @@ -228,7 +228,7 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr m_coordFormatCtrl->SetSelection( 0 ); gbSizer2->Add( m_coordFormatCtrl, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxEXPAND|wxRIGHT|wxLEFT, 5 ); - m_useGerberX2Format = new wxCheckBox( m_GerberOptionsSizer->GetStaticBox(), wxID_ANY, _("Use extended X2 format"), wxDefaultPosition, wxDefaultSize, 0 ); + m_useGerberX2Format = new wxCheckBox( m_GerberOptionsSizer->GetStaticBox(), wxID_ANY, _("Use extended X2 format (recommended)"), wxDefaultPosition, wxDefaultSize, 0 ); m_useGerberX2Format->SetToolTip( _("Use X2 Gerber file format.\nInclude mainly X2 attributes in Gerber headers.\nIf not checked, use X1 format.\nIn X1 format, these attributes are included as comments in files.") ); gbSizer2->Add( m_useGerberX2Format, wxGBPosition( 1, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 30 ); @@ -238,6 +238,11 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr gbSizer2->Add( m_useGerberNetAttributes, wxGBPosition( 2, 1 ), wxGBSpan( 1, 2 ), wxLEFT|wxALIGN_CENTER_VERTICAL, 30 ); + m_disableApertMacros = new wxCheckBox( m_GerberOptionsSizer->GetStaticBox(), wxID_ANY, _("Disable aperture macros (non recommended)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_disableApertMacros->SetToolTip( _("Disable aperture macros in Gerber files\nUse *only* for broken Gerber viewers.") ); + + gbSizer2->Add( m_disableApertMacros, wxGBPosition( 3, 1 ), wxGBSpan( 1, 2 ), wxLEFT|wxALIGN_CENTER_VERTICAL, 30 ); + gbSizer2->AddGrowableCol( 2 ); diff --git a/pcbnew/dialogs/dialog_plot_base.fbp b/pcbnew/dialogs/dialog_plot_base.fbp index 4825263a0d..288e2d06a8 100644 --- a/pcbnew/dialogs/dialog_plot_base.fbp +++ b/pcbnew/dialogs/dialog_plot_base.fbp @@ -2345,7 +2345,7 @@ 0 0 wxID_ANY - Use extended X2 format + Use extended X2 format (recommended) 0 @@ -2444,6 +2444,73 @@ + + 30 + 2 + 1 + wxLEFT|wxALIGN_CENTER_VERTICAL + 3 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Disable aperture macros (non recommended) + + 0 + + + 0 + + 1 + m_disableApertMacros + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Disable aperture macros in Gerber files Use *only* for broken Gerber viewers. + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/pcbnew/dialogs/dialog_plot_base.h b/pcbnew/dialogs/dialog_plot_base.h index 587cddce27..89e6e69c82 100644 --- a/pcbnew/dialogs/dialog_plot_base.h +++ b/pcbnew/dialogs/dialog_plot_base.h @@ -99,6 +99,7 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM wxChoice* m_coordFormatCtrl; wxCheckBox* m_useGerberX2Format; wxCheckBox* m_useGerberNetAttributes; + wxCheckBox* m_disableApertMacros; wxStaticBoxSizer* m_HPGLOptionsSizer; wxStaticText* m_hpglPenLabel; wxTextCtrl* m_hpglPenCtrl; diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp index f41ca02292..8eef01eb45 100644 --- a/pcbnew/pcb_plot_params.cpp +++ b/pcbnew/pcb_plot_params.cpp @@ -98,6 +98,7 @@ static bool setDouble( double* aTarget, double aValue, double aMin, double aMax PCB_PLOT_PARAMS::PCB_PLOT_PARAMS() { m_useGerberProtelExtensions = false; + m_gerberDisableApertMacros = false; m_useGerberX2format = true; m_includeGerberNetlistInfo = true; m_createGerberJobFile = true; @@ -176,6 +177,9 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter, aFormatter->Print( aNestLevel+1, "(%s 0x%s)\n", getTokenName( T_layerselection ), m_layerSelection.FmtHex().c_str() ); + aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_disableapertmacros ), + m_gerberDisableApertMacros ? trueStr : falseStr ); + aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberextensions ), m_useGerberProtelExtensions ? trueStr : falseStr ); @@ -262,6 +266,8 @@ bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams, bool aCom return false; if( m_useGerberProtelExtensions != aPcbPlotParams.m_useGerberProtelExtensions ) return false; + if( m_gerberDisableApertMacros != aPcbPlotParams.m_gerberDisableApertMacros ) + return false; if( m_useGerberX2format != aPcbPlotParams.m_useGerberX2format ) return false; if( m_includeGerberNetlistInfo != aPcbPlotParams.m_includeGerberNetlistInfo ) @@ -419,6 +425,10 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams ) } break; + case T_disableapertmacros: + aPcbPlotParams->m_gerberDisableApertMacros = parseBool(); + break; + case T_usegerberextensions: aPcbPlotParams->m_useGerberProtelExtensions = parseBool(); break; diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h index 18365d073e..f9d03f2fa6 100644 --- a/pcbnew/pcb_plot_params.h +++ b/pcbnew/pcb_plot_params.h @@ -108,6 +108,10 @@ private: /// Include attributes from the Gerber X2 format (chapter 5 in revision J2) bool m_useGerberX2format; + /// Disable aperure macros in Gerber format (only for broken Gerber readers) + /// Ideally, should be never selected. + bool m_gerberDisableApertMacros; + /// Include netlist info (only in Gerber X2 format) (chapter ? in revision ?) bool m_includeGerberNetlistInfo; @@ -291,6 +295,9 @@ public: void SetOutputDirectory( wxString aDir ) { m_outputDirectory = aDir; } wxString GetOutputDirectory() const { return m_outputDirectory; } + void SetDisableGerberMacros( bool aDisable ) { m_gerberDisableApertMacros = aDisable; } + bool GetDisableGerberMacros() const { return m_gerberDisableApertMacros; } + void SetUseGerberX2format( bool aUse ) { m_useGerberX2format = aUse; } bool GetUseGerberX2format() const { return m_useGerberX2format; } diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 1e141b480b..e8fca1cb16 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -1143,6 +1143,7 @@ PLOTTER* StartPlotBoard( BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts, int aLayer, bool useX2mode = plotOpts.GetUseGerberX2format(); GERBER_PLOTTER* gbrplotter = static_cast ( plotter ); + gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() ); gbrplotter->UseX2format( useX2mode ); gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );