From b50872edca3f41d914f4250b99e0c78822446d7e Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 30 Jun 2014 12:00:21 +0200 Subject: [PATCH] Gerber output: Some changes after evaluation of Gerber files by Ucamco (the manager of GERBER format): * default file ext is now .gbr (the "official extension") * some outdated commands remoded. * mainly use mm and 4.5 format instead of inches and 3.4 format. this is mandatory, because the 3.4 format (comming from old pcbned internal units) creates truncations in coordinates. (with serious issues in polygons which can appear self-intersecting afer truncation) --- common/class_colors_design_settings.cpp | 17 +++++-- common/common_plotGERBER_functions.cpp | 63 ++++++++++++++++++------- gerbview/files.cpp | 6 ++- include/plot_common.h | 15 +++--- kicad/files-io.cpp | 2 +- kicad/tree_project_frame.cpp | 2 +- pcbnew/class_board.h | 6 ++- 7 files changed, 79 insertions(+), 32 deletions(-) diff --git a/common/class_colors_design_settings.cpp b/common/class_colors_design_settings.cpp index 42d8e79a71..19fa76ac4a 100644 --- a/common/class_colors_design_settings.cpp +++ b/common/class_colors_design_settings.cpp @@ -12,14 +12,21 @@ * in Eeschema, Pcbnew and GerbView */ -/* Initial colors values: optimized for Pcbnew, but are also Ok for Eeschema +/* Initial colors values: optimized for Pcbnew 64 layers. + * The table is not actually used by Eeschema. * these values are superseded by config reading */ static const EDA_COLOR_T default_layer_color[] = { - GREEN, BLUE, LIGHTGRAY, BROWN, - RED, MAGENTA, LIGHTGRAY, MAGENTA, - DARKGRAY, BLUE, GREEN, CYAN, - LIGHTRED, LIGHTMAGENTA, YELLOW, RED, + RED, YELLOW, LIGHTMAGENTA, LIGHTRED, + CYAN, GREEN, BLUE, DARKGRAY, + MAGENTA, LIGHTGRAY, MAGENTA, RED, + BROWN, LIGHTGRAY, BLUE, GREEN, + + RED, YELLOW, LIGHTMAGENTA, LIGHTRED, + CYAN, GREEN, BLUE, DARKGRAY, + MAGENTA, LIGHTGRAY, MAGENTA, RED, + BROWN, LIGHTGRAY, BLUE, GREEN, + BLUE, MAGENTA, LIGHTCYAN, RED, MAGENTA, CYAN, diff --git a/common/common_plotGERBER_functions.cpp b/common/common_plotGERBER_functions.cpp index 99e47c27bf..6937351149 100644 --- a/common/common_plotGERBER_functions.cpp +++ b/common/common_plotGERBER_functions.cpp @@ -23,10 +23,23 @@ void GERBER_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, wxASSERT( aMirror == false ); m_plotMirror = false; plotOffset = aOffset; - wxASSERT( aScale == 1 ); - plotScale = 1; + wxASSERT( aScale == 1 ); // aScale parameter is not used in Gerber + plotScale = 1; // Plot scale is *always* 1.0 + + m_gerberUnitInch = false; // Currently fixed, but could be an option + + // number of digits after the point (number of digits of the mantissa + // Be carefull: the coordinates are stored in an integer + // so 6 digits (inches) or 5 digits (mm) is the best value + // to avoid truncations and overflow + m_gerberUnitFmt = m_gerberUnitInch ? 6 : 5; + m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = 1.0 / aIusPerDecimil; + iuPerDeviceUnit = pow( 10.0, m_gerberUnitFmt ) / ( aIusPerDecimil * 10000.0 ); + + if( ! m_gerberUnitInch ) + iuPerDeviceUnit *= 25.4; // gerber output in mm + /* We don't handle the filmbox, and it's more useful to keep the * origin at the origin */ paperSize.x = 0; @@ -67,25 +80,38 @@ bool GERBER_PLOTTER::StartPlot() if( outputFile == NULL ) return false; - if( !attribFunction.IsEmpty() ) + if( ! m_attribFunction.IsEmpty() ) { - fputs( "%TF.GerberVersion,J1*%\n", outputFile ); - fprintf( outputFile, "%%TF.FileFunction,%s*%%\n", TO_UTF8( attribFunction ) ); + fprintf( outputFile, "%%TF.FileFunction,%s*%%\n", + TO_UTF8( m_attribFunction ) ); } - /* Set coordinate format to 3.4 absolute, leading zero omitted */ - fputs( "%FSLAX34Y34*%\n", outputFile ); - fputs( "G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*\n", outputFile ); + // Set coordinate format to 3.6 or 4.5 absolute, leading zero omitted + // the number of digits for the integer part of coordintes is needed + // in gerber format, but is not very important when omitting leading zeros + // It is fixed here to 3 (inch) or 4 (mm), but is not actually used + int leadingDigitCount = m_gerberUnitInch ? 3 : 4; + + fprintf( outputFile, "%%FSLAX%d%dY%d%d*%%\n", + leadingDigitCount, m_gerberUnitFmt, + leadingDigitCount, m_gerberUnitFmt ); + fprintf( outputFile, + "G04 Gerber Fmt %d.%d, Leading zero omitted, Abs format (unit %s)*\n", + leadingDigitCount, m_gerberUnitFmt, + m_gerberUnitInch ? "inch" : "mm" ); wxString Title = creator + wxT( " " ) + GetBuildVersion(); fprintf( outputFile, "G04 (created by %s) date %s*\n", TO_UTF8( Title ), TO_UTF8( DateAndTime() ) ); - /* Mass parameter: unit = INCHES */ - fputs( "%MOIN*%\n", outputFile ); + /* Mass parameter: unit = INCHES/MM */ + if( m_gerberUnitInch ) + fputs( "%MOIN*%\n", outputFile ); + else + fputs( "%MOMM*%\n", outputFile ); - /* Specify linear interpol (G01), unit = INCH (G70), abs format (G90) */ - fputs( "G01*\nG70*\nG90*\n", outputFile ); + /* Specify linear interpol (G01) */ + fputs( "G01*\n", outputFile ); fputs( "G04 APERTURE LIST*\n", outputFile ); /* Select the default aperture */ SetCurrentLineWidth( -1 ); @@ -191,7 +217,7 @@ void GERBER_PLOTTER::selectAperture( const wxSize& size, { // Pick an existing aperture or create a new one currentAperture = getAperture( size, type ); - fprintf( outputFile, "G54D%d*\n", currentAperture->DCode ); + fprintf( outputFile, "D%d*\n", currentAperture->DCode ); } } @@ -208,8 +234,13 @@ void GERBER_PLOTTER::writeApertureList() for( std::vector::iterator tool = apertures.begin(); tool != apertures.end(); tool++ ) { - const double fscale = 0.0001f * plotScale - * iuPerDeviceUnit ; + // apertude sizes are in inch or mm, regardless the + // coordinates format + double fscale = 0.0001 * plotScale / m_IUsPerDecimil; // inches + + if(! m_gerberUnitInch ) + fscale *= 25.4; // size in mm + char* text = cbuf + sprintf( cbuf, "%%ADD%d", tool->DCode ); /* Please note: the Gerber specs for mass parameters say that diff --git a/gerbview/files.cpp b/gerbview/files.cpp index 5b016e87a9..7daa9d9b80 100644 --- a/gerbview/files.cpp +++ b/gerbview/files.cpp @@ -109,15 +109,17 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName ) { /* Standard gerber filetypes * (See http://en.wikipedia.org/wiki/Gerber_File) - * the .pho extension is the default used in Pcbnew + * the .gbr (.pho in legacy files) extension is the default used in Pcbnew * However there are a lot of other extensions used for gerber files * Because the first letter is usually g, we accept g* as extension * (Mainly internal copper layers do not have specific extention, * and filenames are like *.g1, *.g2 *.gb1 ...). + * Now (2014) Ucamco (the company which manager the Gerber format) encourage + * use of .gbr only and the Gerber X2 file format. */ filetypes = _( "Gerber files (.g* .lgr .pho)" ); filetypes << wxT("|"); - filetypes += wxT("*.g*;*.G*;*.lgr;*.LGR;*.pho;*.PHO" ); + filetypes += wxT("*.g*;*.G*;*.pho;*.PHO" ); filetypes << wxT("|"); /* Special gerber filetypes */ diff --git a/include/plot_common.h b/include/plot_common.h index 1a259fa378..f7732db7cf 100644 --- a/include/plot_common.h +++ b/include/plot_common.h @@ -314,13 +314,13 @@ protected: /// Plot scale - chosen by the user (even implicitly with 'fit in a4') double plotScale; - /* Device scale (how many IUs in a decimil - always); it's a double + /* Caller scale (how many IUs in a decimil - always); it's a double * because in eeschema there are 0.1 IUs in a decimil (eeschema * always works in mils internally) while pcbnew can work in decimil * or nanometers, so this value would be >= 1 */ double m_IUsPerDecimil; - /// Device scale (from IUs to device units - usually decimils) + /// Device scale (from IUs to plotter device units - usually decimils) double iuPerDeviceUnit; /// Plot offset (in IUs) @@ -774,7 +774,6 @@ public: workFile = 0; finalFile = 0; currentAperture = apertures.end(); - attribFunction = wxEmptyString; } virtual PlotFormat GetPlotterType() const @@ -784,7 +783,7 @@ public: static wxString GetDefaultFileExtension() { - return wxString( wxT( "pho" ) ); + return wxString( wxT( "gbr" ) ); } virtual bool StartPlot(); @@ -821,7 +820,7 @@ public: virtual void SetLayerAttribFunction( const wxString& function ) { - attribFunction = function; + m_attribFunction = function; } protected: @@ -840,7 +839,11 @@ protected: std::vector apertures; std::vector::iterator currentAperture; - wxString attribFunction; /* the layer "function", it is linked with the layer id */ + wxString m_attribFunction; // the layer "function", in GERBER X2 extention + // it is linked with the layer id + 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 }; diff --git a/kicad/files-io.cpp b/kicad/files-io.cpp index 4943e359f3..f0eed253e2 100644 --- a/kicad/files-io.cpp +++ b/kicad/files-io.cpp @@ -133,7 +133,7 @@ void KICAD_MANAGER_FRAME::OnArchiveFiles( wxCommandEvent& event ) /* List of file extensions to save. */ static const wxChar* extentionList[] = { wxT( "*.sch" ), wxT( "*.lib" ), wxT( "*.mod" ), wxT( "*.cmp" ), - wxT( "*.brd" ), wxT( "*.kicad_pcb" ), + wxT( "*.brd" ), wxT( "*.kicad_pcb" ), wxT( "*.gbr" ), wxT( "*.net" ), wxT( "*.pro" ), wxT( "*.pho" ), wxT( "*.py" ), wxT( "*.pdf" ), wxT( "*.txt" ), wxT( "*.dcm" ), wxT( "*.kicad_wks" ), NULL diff --git a/kicad/tree_project_frame.cpp b/kicad/tree_project_frame.cpp index 0cc4add54d..e4e6d362af 100644 --- a/kicad/tree_project_frame.cpp +++ b/kicad/tree_project_frame.cpp @@ -69,7 +69,7 @@ static const wxChar* s_allowedExtensionsToList[] = wxT( "^[^$].*\\.kicad_wks$" ), // S format kicad page layout descr files wxT( "^.*\\.net$" ), wxT( "^.*\\.txt$" ), - wxT( "^.*\\.pho$" ), // Gerber file (Kicad extension) + wxT( "^.*\\.pho$" ), // Gerber file (Old Kicad extension) wxT( "^.*\\.gbr$" ), // Gerber file wxT( "^.*\\.gb[alops]$" ), // Gerber back (or bottom) layer file wxT( "^.*\\.gt[alops]$" ), // Gerber front (or top) layer file diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 0460e39445..07d2e41b49 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -1220,7 +1220,11 @@ public: * @param aLayerMask A layer or layers to mask the hit test. * @return A pointer to a D_PAD object if found or NULL if not found. */ - D_PAD* GetPad( const wxPoint& aPosition, LSET aLayerMask = LSET().set() ); + D_PAD* GetPad( const wxPoint& aPosition, LSET aLayerMask ); + D_PAD* GetPad( const wxPoint& aPosition ) + { + return GetPad( aPosition, LSET().set() ); + } /** * Function GetPad