summaryrefslogtreecommitdiff
path: root/pcbnew/pcb_plot_params.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/pcb_plot_params.cpp')
-rw-r--r--pcbnew/pcb_plot_params.cpp579
1 files changed, 579 insertions, 0 deletions
diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp
new file mode 100644
index 0000000..6e23b1e
--- /dev/null
+++ b/pcbnew/pcb_plot_params.cpp
@@ -0,0 +1,579 @@
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2017 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+//#include <wx/wx.h>
+#include <pcb_plot_params_parser.h>
+#include <pcb_plot_params.h>
+#include <layers_id_colors_and_visibility.h>
+#include <plot_common.h>
+#include <macros.h>
+#include <convert_to_biu.h>
+
+
+#define PLOT_LINEWIDTH_MIN (0.02*IU_PER_MM) // min value for default line thickness
+#define PLOT_LINEWIDTH_MAX (2*IU_PER_MM) // max value for default line thickness
+#define PLOT_LINEWIDTH_DEFAULT (0.15*IU_PER_MM) // def. value for default line thickness
+#define HPGL_PEN_DIAMETER_MIN 0
+#define HPGL_PEN_DIAMETER_MAX 100 // Unit = mil
+#define HPGL_PEN_SPEED_MIN 1 // this param is always in cm/s
+#define HPGL_PEN_SPEED_MAX 99 // this param is always in cm/s
+#define HPGL_PEN_NUMBER_MIN 1
+#define HPGL_PEN_NUMBER_MAX 16
+#define HPGL_PEN_OVERLAP_MIN 0
+#define HPGL_PEN_OVERLAP_MAX 50 // Unit = mil
+
+
+/**
+ * Default line thickness in internal units used to draw or plot items using a
+ * default thickness line value (Frame references)
+ */
+int g_DrawDefaultLineThickness = PLOT_LINEWIDTH_DEFAULT;
+
+// default trailing digits in Gerber coordinates, when units are mm
+// This is also the max usable precision (i.e. internal Pcbnew Units)
+static const int gbrDefaultPrecision = 6;
+
+
+using namespace PCBPLOTPARAMS_T;
+
+
+static const char* getTokenName( T aTok )
+{
+ return PCB_PLOT_PARAMS_LEXER::TokenName( aTok );
+}
+
+
+static bool setInt( int* aInt, int aValue, int aMin, int aMax )
+{
+ int temp = aValue;
+
+ if( aValue < aMin )
+ temp = aMin;
+ else if( aValue > aMax )
+ temp = aMax;
+
+ *aInt = temp;
+ return (temp == aValue);
+}
+
+// PCB_PLOT_PARAMS
+
+PCB_PLOT_PARAMS::PCB_PLOT_PARAMS() :
+ m_layerSelection( 4, B_Cu, F_Cu, F_SilkS, B_SilkS )
+{
+ m_useGerberProtelExtensions = false;
+ m_useGerberAttributes = false;
+ m_gerberPrecision = gbrDefaultPrecision;
+ m_excludeEdgeLayer = true;
+ m_lineWidth = g_DrawDefaultLineThickness;
+ m_plotFrameRef = false;
+ m_plotViaOnMaskLayer = false;
+ m_plotMode = FILLED;
+ m_DXFplotPolygonMode = true;
+ m_useAuxOrigin = false;
+ m_HPGLPenNum = 1;
+ m_HPGLPenSpeed = 20; // this param is always in cm/s
+ m_HPGLPenDiam = 15; // in mils
+ m_HPGLPenOvr = 2; // in mils
+ m_negative = false;
+ m_A4Output = false;
+ m_plotReference = true;
+ m_plotValue = true;
+ m_plotInvisibleText = false;
+ m_plotPadsOnSilkLayer = false;
+ m_subtractMaskFromSilk = false;
+ m_format = PLOT_FORMAT_GERBER;
+ m_mirror = false;
+ m_drillMarks = SMALL_DRILL_SHAPE;
+ m_autoScale = false;
+ m_scale = 1.0;
+ m_scaleSelection = 1;
+ m_fineScaleAdjustX = 1.0;
+ m_fineScaleAdjustY = 1.0;
+ m_widthAdjust = 0.;
+ m_outputDirectory.clear();
+ m_color = BLACK;
+ m_textMode = PLOTTEXTMODE_DEFAULT;
+
+ // This parameter controls if the NPTH pads will be plotted or not
+ // it is a "local" parameter
+ m_skipNPTH_Pads = false;
+}
+
+void PCB_PLOT_PARAMS::SetGerberPrecision( int aPrecision )
+{
+ // Currently geber files use mm.
+ // accepted precision is only 6 (max value, this is the resolution of Pcbnew)
+ // or 5, min value for professional boards, when 6 creates problems
+ // to board makers.
+
+ m_gerberPrecision = aPrecision == gbrDefaultPrecision-1 ? gbrDefaultPrecision-1 :
+ gbrDefaultPrecision;
+}
+
+
+// PLEASE NOTE: only plot dialog options are processed
+void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter,
+ int aNestLevel, int aControl ) const throw( IO_ERROR )
+{
+ const char* falseStr = getTokenName( T_false );
+ const char* trueStr = getTokenName( T_true );
+
+ aFormatter->Print( aNestLevel, "(%s\n", getTokenName( T_pcbplotparams ) );
+
+ 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_usegerberextensions ),
+ m_useGerberProtelExtensions ? trueStr : falseStr );
+
+ if( m_useGerberAttributes ) // save this option only if active,
+ // to avoid incompatibility with older Pcbnew version
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_usegerberattributes ), trueStr );
+
+ if( m_gerberPrecision != gbrDefaultPrecision ) // save this option only if it is not the default value,
+ // to avoid incompatibility with older Pcbnew version
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n",
+ getTokenName( T_gerberprecision ), m_gerberPrecision );
+
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_excludeedgelayer ),
+ m_excludeEdgeLayer ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %f)\n", getTokenName( T_linewidth ),
+ m_lineWidth / IU_PER_MM );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_plotframeref ),
+ m_plotFrameRef ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_viasonmask ),
+ m_plotViaOnMaskLayer ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_mode ),
+ GetPlotMode() == SKETCH ? 2 : 1 ); // Value 0 (LINE mode) no more used
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_useauxorigin ),
+ m_useAuxOrigin ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_hpglpennumber ),
+ m_HPGLPenNum );
+
+ // Obsolete parameter, pen speed is no more managed, because hpgl format
+ // is now an export format, and for this, pen speed has no meaning
+ // aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_hpglpenspeed ),
+ // m_HPGLPenSpeed );
+
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_hpglpenspeed ),
+ m_HPGLPenSpeed );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_hpglpendiameter ),
+ m_HPGLPenDiam );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_hpglpenoverlay ),
+ m_HPGLPenOvr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_psnegative ),
+ m_negative ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_psa4output ),
+ m_A4Output ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_plotreference ),
+ m_plotReference ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_plotvalue ),
+ m_plotValue ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_plotinvisibletext ),
+ m_plotInvisibleText ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_padsonsilk ),
+ m_plotPadsOnSilkLayer ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_subtractmaskfromsilk ),
+ m_subtractMaskFromSilk ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_outputformat ),
+ m_format );
+ aFormatter->Print( aNestLevel+1, "(%s %s)\n", getTokenName( T_mirror ),
+ m_mirror ? trueStr : falseStr );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_drillshape ),
+ m_drillMarks );
+ aFormatter->Print( aNestLevel+1, "(%s %d)\n", getTokenName( T_scaleselection ),
+ m_scaleSelection );
+ aFormatter->Print( aNestLevel+1, "(%s %s)", getTokenName( T_outputdirectory ),
+ aFormatter->Quotew( m_outputDirectory ).c_str() );
+ aFormatter->Print( 0, ")\n" );
+}
+
+
+void PCB_PLOT_PARAMS::Parse( PCB_PLOT_PARAMS_PARSER* aParser )
+ throw( PARSE_ERROR, IO_ERROR )
+{
+ aParser->Parse( this );
+}
+
+
+bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams, bool aCompareOnlySavedPrms ) const
+{
+ if( m_layerSelection != aPcbPlotParams.m_layerSelection )
+ return false;
+ if( m_useGerberProtelExtensions != aPcbPlotParams.m_useGerberProtelExtensions )
+ return false;
+ if( m_useGerberAttributes != aPcbPlotParams.m_useGerberAttributes )
+ return false;
+ if( m_gerberPrecision != aPcbPlotParams.m_gerberPrecision )
+ return false;
+ if( m_excludeEdgeLayer != aPcbPlotParams.m_excludeEdgeLayer )
+ return false;
+ if( m_lineWidth != aPcbPlotParams.m_lineWidth )
+ return false;
+ if( m_plotFrameRef != aPcbPlotParams.m_plotFrameRef )
+ return false;
+ if( m_plotViaOnMaskLayer != aPcbPlotParams.m_plotViaOnMaskLayer )
+ return false;
+ if( m_plotMode != aPcbPlotParams.m_plotMode )
+ return false;
+
+ if( !aCompareOnlySavedPrms )
+ {
+ if( m_DXFplotPolygonMode != aPcbPlotParams.m_DXFplotPolygonMode )
+ return false;
+ }
+
+ if( m_useAuxOrigin != aPcbPlotParams.m_useAuxOrigin )
+ return false;
+ if( m_HPGLPenNum != aPcbPlotParams.m_HPGLPenNum )
+ return false;
+ if( m_HPGLPenSpeed != aPcbPlotParams.m_HPGLPenSpeed )
+ return false;
+ if( m_HPGLPenDiam != aPcbPlotParams.m_HPGLPenDiam )
+ return false;
+ if( m_HPGLPenOvr != aPcbPlotParams.m_HPGLPenOvr )
+ return false;
+ if( m_negative != aPcbPlotParams.m_negative )
+ return false;
+ if( m_A4Output != aPcbPlotParams.m_A4Output )
+ return false;
+ if( m_plotReference != aPcbPlotParams.m_plotReference )
+ return false;
+ if( m_plotValue != aPcbPlotParams.m_plotValue )
+ return false;
+ if( m_plotInvisibleText != aPcbPlotParams.m_plotInvisibleText )
+ return false;
+ if( m_plotPadsOnSilkLayer != aPcbPlotParams.m_plotPadsOnSilkLayer )
+ return false;
+ if( m_subtractMaskFromSilk != aPcbPlotParams.m_subtractMaskFromSilk )
+ return false;
+ if( m_format != aPcbPlotParams.m_format )
+ return false;
+ if( m_mirror != aPcbPlotParams.m_mirror )
+ return false;
+ if( m_drillMarks != aPcbPlotParams.m_drillMarks )
+ return false;
+ if( m_scaleSelection != aPcbPlotParams.m_scaleSelection )
+ return false;
+ if( m_autoScale != aPcbPlotParams.m_autoScale )
+ return false;
+ if( m_scale != aPcbPlotParams.m_scale )
+ return false;
+ if( m_fineScaleAdjustX != aPcbPlotParams.m_fineScaleAdjustX )
+ return false;
+ if( m_fineScaleAdjustY != aPcbPlotParams.m_fineScaleAdjustY )
+ return false;
+ if( m_widthAdjust != aPcbPlotParams.m_widthAdjust )
+ return false;
+
+ if( !aCompareOnlySavedPrms )
+ {
+ if( m_color != aPcbPlotParams.m_color )
+ return false;
+ }
+
+ if( m_textMode != aPcbPlotParams.m_textMode )
+ return false;
+ if( !m_outputDirectory.IsSameAs( aPcbPlotParams.m_outputDirectory ) )
+ return false;
+ return true;
+}
+
+
+bool PCB_PLOT_PARAMS::SetHPGLPenDiameter( int aValue )
+{
+ return setInt( &m_HPGLPenDiam, aValue, HPGL_PEN_DIAMETER_MIN, HPGL_PEN_DIAMETER_MAX );
+}
+
+
+bool PCB_PLOT_PARAMS::SetHPGLPenSpeed( int aValue )
+{
+ return setInt( &m_HPGLPenSpeed, aValue, HPGL_PEN_SPEED_MIN, HPGL_PEN_SPEED_MAX );
+}
+
+
+bool PCB_PLOT_PARAMS::SetHPGLPenOverlay( int aValue )
+{
+ return setInt( &m_HPGLPenOvr, aValue, HPGL_PEN_OVERLAP_MIN, HPGL_PEN_OVERLAP_MAX );
+}
+
+
+bool PCB_PLOT_PARAMS::SetLineWidth( int aValue )
+{
+ return setInt( &m_lineWidth, aValue, PLOT_LINEWIDTH_MIN, PLOT_LINEWIDTH_MAX );
+}
+
+// PCB_PLOT_PARAMS_PARSER
+
+PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader ) :
+ PCB_PLOT_PARAMS_LEXER( aReader )
+{
+}
+
+
+PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( char* aLine, const wxString& aSource ) :
+ PCB_PLOT_PARAMS_LEXER( aLine, aSource )
+{
+}
+
+
+void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
+ throw( PARSE_ERROR, IO_ERROR )
+{
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ Unexpected( T_EOF );
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ if( token == T_pcbplotparams )
+ continue;
+
+ bool skip_right = false;
+
+ switch( token )
+ {
+ case T_layerselection:
+ {
+ token = NeedSYMBOLorNUMBER();
+
+ const std::string& cur = CurStr();
+
+ if( token == T_NUMBER ) // pretty 3 format had legacy Cu stack.
+ {
+ // unsigned legacy_mask = atol( cur.c_str() );
+
+ /* It's not possible to convert a legacy Cu layer number to a new
+ Cu layer number without knowing the number or total Cu layers
+ in the legacy board. We do not have that information here.
+ So simply set all layers ON. User can turn them off in the UI.
+ This is one of the superiorities of the new Cu sequence.
+ aPcbPlotParams->m_layerSelection = LEGACY_PLUGIN::leg_mask2new( cu_count, legacy_mask );
+ */
+
+ // sorry, use the UI once to fix:
+ aPcbPlotParams->m_layerSelection = LSET( 4, B_Cu, F_Cu, F_SilkS, B_SilkS );
+ }
+ else if( cur.find_first_of( "0x" ) == 0 ) // pretty ver. 4.
+ {
+ // skip the leading 2 0x bytes.
+ aPcbPlotParams->m_layerSelection.ParseHex( cur.c_str()+2, cur.size()-2 );
+ }
+ else
+ Expecting( "integer or hex layerSelection" );
+ }
+ break;
+
+ case T_usegerberextensions:
+ aPcbPlotParams->m_useGerberProtelExtensions = parseBool();
+ break;
+
+ case T_usegerberattributes:
+ aPcbPlotParams->m_useGerberAttributes = parseBool();
+ break;
+
+ case T_gerberprecision:
+ aPcbPlotParams->m_gerberPrecision =
+ parseInt( gbrDefaultPrecision-1, gbrDefaultPrecision);
+ break;
+
+ case T_psa4output:
+ aPcbPlotParams->m_A4Output = parseBool();
+ break;
+
+ case T_excludeedgelayer:
+ aPcbPlotParams->m_excludeEdgeLayer = parseBool();
+ break;
+
+ case T_linewidth:
+ {
+ // Due to a bug, this (minor) parameter was saved in biu
+ // and now is saved in mm
+ // If the read value is outside bounds, force a default value
+ double tmp = parseDouble();
+ if( !aPcbPlotParams->SetLineWidth( KiROUND( tmp * IU_PER_MM ) ) )
+ aPcbPlotParams->SetLineWidth( PLOT_LINEWIDTH_DEFAULT );
+ }
+ break;
+
+ case T_plotframeref:
+ aPcbPlotParams->m_plotFrameRef = parseBool();
+ break;
+
+ case T_viasonmask:
+ aPcbPlotParams->m_plotViaOnMaskLayer = parseBool();
+ break;
+
+ case T_mode:
+ aPcbPlotParams->SetPlotMode( parseInt( 0, 2 ) > 1 ? SKETCH : FILLED );
+ break;
+
+ case T_useauxorigin:
+ aPcbPlotParams->m_useAuxOrigin = parseBool();
+ break;
+
+ case T_hpglpennumber:
+ aPcbPlotParams->m_HPGLPenNum = parseInt( HPGL_PEN_NUMBER_MIN,
+ HPGL_PEN_NUMBER_MAX );
+ break;
+ case T_hpglpenspeed:
+ aPcbPlotParams->m_HPGLPenSpeed = parseInt( HPGL_PEN_SPEED_MIN,
+ HPGL_PEN_SPEED_MAX );
+ break;
+ case T_hpglpendiameter:
+ aPcbPlotParams->m_HPGLPenDiam = parseInt( HPGL_PEN_DIAMETER_MIN,
+ HPGL_PEN_DIAMETER_MAX );
+ break;
+ case T_hpglpenoverlay:
+ aPcbPlotParams->m_HPGLPenOvr = parseInt( HPGL_PEN_OVERLAP_MIN,
+ HPGL_PEN_OVERLAP_MAX );
+ break;
+ case T_pscolor:
+ NeedSYMBOL(); // This actually was never used...
+ break;
+
+ case T_psnegative:
+ aPcbPlotParams->m_negative = parseBool();
+ break;
+
+ case T_plotreference:
+ aPcbPlotParams->m_plotReference = parseBool();
+ break;
+
+ case T_plotvalue:
+ aPcbPlotParams->m_plotValue = parseBool();
+ break;
+
+ case T_plotinvisibletext:
+ aPcbPlotParams->m_plotInvisibleText = parseBool();
+ break;
+
+ case T_padsonsilk:
+ aPcbPlotParams->m_plotPadsOnSilkLayer= parseBool();
+ break;
+
+ case T_subtractmaskfromsilk:
+ aPcbPlotParams->m_subtractMaskFromSilk = parseBool();
+ break;
+
+ case T_outputformat:
+ aPcbPlotParams->m_format = static_cast<PlotFormat>(
+ parseInt( PLOT_FIRST_FORMAT, PLOT_LAST_FORMAT ) );
+ break;
+
+ case T_mirror:
+ aPcbPlotParams->m_mirror = parseBool();
+ break;
+
+ case T_drillshape:
+ aPcbPlotParams->m_drillMarks = static_cast<PCB_PLOT_PARAMS::DrillMarksType>
+ ( parseInt( 0, 2 ) );
+ break;
+
+ case T_scaleselection:
+ aPcbPlotParams->m_scaleSelection = parseInt( 0, 4 );
+ break;
+
+ case T_outputdirectory:
+ NeedSYMBOL();
+ aPcbPlotParams->m_outputDirectory = FROM_UTF8( CurText() );
+ break;
+
+ default:
+ skipCurrent(); // skip unknown or outdated plot parameter
+ skip_right = true; // the closing right token is already read.
+ break;
+ }
+
+ if( ! skip_right )
+ NeedRIGHT();
+ }
+}
+
+
+bool PCB_PLOT_PARAMS_PARSER::parseBool()
+{
+ T token = NeedSYMBOL();
+
+ if( token != T_false && token != T_true )
+ Expecting( "true|false" );
+
+ return token == T_true;
+}
+
+
+int PCB_PLOT_PARAMS_PARSER::parseInt( int aMin, int aMax )
+{
+ T token = NextTok();
+
+ if( token != T_NUMBER )
+ Expecting( T_NUMBER );
+
+ int val = atoi( CurText() );
+
+ if( val < aMin )
+ val = aMin;
+ else if( val > aMax )
+ val = aMax;
+
+ return val;
+}
+
+
+double PCB_PLOT_PARAMS_PARSER::parseDouble()
+{
+ T token = NextTok();
+
+ if( token != T_NUMBER )
+ Expecting( T_NUMBER );
+
+ double val = strtod( CurText(), NULL );
+
+ return val;
+}
+
+void PCB_PLOT_PARAMS_PARSER::skipCurrent() throw( IO_ERROR, PARSE_ERROR )
+{
+ int curr_level = 0;
+ T token;
+
+ while( ( token = NextTok() ) != T_EOF )
+ {
+ if( token == T_LEFT )
+ curr_level--;
+
+ if( token == T_RIGHT )
+ {
+ curr_level++;
+
+ if( curr_level > 0 )
+ return;
+ }
+ }
+}