From 699c76cceac9dac1d06ab8d19bf2c4cc99a107df Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 29 Apr 2015 17:37:37 +0200 Subject: [PATCH] Rework on EXCELLON_WRITER class, to allow gerber and drill files creation from a python script. added the example gen_gerber_and_drill_files_board.py in demos, which shows how to do that. Fix a Printf format issue (shown in Debug mode) in Libedit (%d used for a size_t, changed in %zu) --- .../gen_gerber_and_drill_files_board.py | 110 +++++++++ eeschema/libedit.cpp | 6 +- pcbnew/CMakeLists.txt | 1 + pcbnew/dialogs/dialog_gendrill.cpp | 211 ++---------------- pcbnew/dialogs/dialog_gendrill.h | 7 +- pcbnew/exporters/gen_drill_report_files.cpp | 20 +- pcbnew/exporters/gendrill_Excellon_writer.cpp | 197 +++++++++++++++- pcbnew/exporters/gendrill_Excellon_writer.h | 86 ++++--- pcbnew/scripting/pcbnew.i | 2 + 9 files changed, 388 insertions(+), 252 deletions(-) create mode 100644 demos/python_scripts_examples/gen_gerber_and_drill_files_board.py diff --git a/demos/python_scripts_examples/gen_gerber_and_drill_files_board.py b/demos/python_scripts_examples/gen_gerber_and_drill_files_board.py new file mode 100644 index 0000000000..551c0ba9ce --- /dev/null +++ b/demos/python_scripts_examples/gen_gerber_and_drill_files_board.py @@ -0,0 +1,110 @@ +''' + A python script example to create plot files to build a board: + Gerber files + Drill files + Map dril files + + Important note: + this python script does not plot frame references (page layout). + the reason is it is not yet possible from a python script because plotting + plot frame references needs loading the corresponding page layout file + (.wks file) or the default template. + + This info (the page layout template) is not stored in the board, and therefore + not available. + + Do not try to change SetPlotFrameRef(False) to SetPlotFrameRef(true) + the result is the pcbnew lib will crash if you try to plot + the unknown frame references template. + + Anyway, in gerber and drill files the page layout is not plot +''' + +import sys + +from pcbnew import * +filename=sys.argv[1] + +board = LoadBoard(filename) + +plotDir = "plot/" + +pctl = PLOT_CONTROLLER(board) + +popt = pctl.GetPlotOptions() + +popt.SetOutputDirectory(plotDir) + +# Set some important plot options: +popt.SetPlotFrameRef(False) +popt.SetLineWidth(FromMM(0.35)) + +popt.SetAutoScale(False) +popt.SetScale(1) +popt.SetMirror(False) +popt.SetUseGerberAttributes(True) +popt.SetExcludeEdgeLayer(False); +popt.SetScale(1) +popt.SetUseAuxOrigin(True) + +# This by gerbers only (also the name is truly horrid!) +popt.SetSubtractMaskFromSilk(False) + +# Once the defaults are set it become pretty easy... +# I have a Turing-complete programming language here: I'll use it... +# param 0 is a string added to the file base name to identify the drawing +# param 1 is the layer ID +# param 2 is a comment +plot_plan = [ + ( "CuTop", F_Cu, "Top layer" ), + ( "CuBottom", B_Cu, "Bottom layer" ), + ( "PasteBottom", B_Paste, "Paste Bottom" ), + ( "PasteTop", F_Paste, "Paste top" ), + ( "SilkTop", F_SilkS, "Silk top" ), + ( "SilkBottom", B_SilkS, "Silk top" ), + ( "MaskBottom", B_Mask, "Mask bottom" ), + ( "MaskTop", F_Mask, "Mask top" ), + ( "EdgeCuts", Edge_Cuts, "Edges" ), +] + + +for layer_info in plot_plan: + pctl.SetLayer(layer_info[1]) + pctl.OpenPlotfile(layer_info[0], PLOT_FORMAT_GERBER, layer_info[2]) + pctl.PlotLayer() + +#generate internal copper layers, if any +lyrcnt = board.GetCopperLayerCount(); + +for innerlyr in range ( 1, lyrcnt-1 ): + pctl.SetLayer(innerlyr) + lyrname = 'inner%s' % innerlyr + pctl.OpenPlotfile(lyrname, PLOT_FORMAT_GERBER, "inner") + pctl.PlotLayer() + + +# At the end you have to close the last plot, otherwise you don't know when +# the object will be recycled! +pctl.ClosePlot() + +# Fabricators need drill files. +# sometimes a drill map file is asked (for verification purpose) +drlwriter = EXCELLON_WRITER( board ) +drlwriter.SetMapFileFormat( PLOT_FORMAT_PDF ) + +mirror = False +minimalHeader = False +offset = wxPoint(0,0) +mergeNPTH = False +drlwriter.SetOptions( mirror, minimalHeader, offset, mergeNPTH ) + +metricFmt = True +drlwriter.SetFormat( metricFmt ) + +genDrl = True +genMap = True +drlwriter.CreateDrillandMapFilesSet( plotDir, genDrl, genMap ); + +# One can create a text file to report drill statistics +rptfn = plotDir + '/drill_report.txt' +drlwriter.GenDrillReportFile( rptfn ); diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp index 6b2e2e41d2..cf15dccdaa 100644 --- a/eeschema/libedit.cpp +++ b/eeschema/libedit.cpp @@ -1,9 +1,9 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2008-2013 Wayne Stambaugh - * Copyright (C) 2004-2013 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2004-2015 KiCad Developers, see change_log.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 @@ -548,7 +548,7 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event ) return; } - msg.Printf( _( "Select 1 of %d components to delete\nfrom library '%s'." ), + msg.Printf( _( "Select one of %zu components to delete\nfrom library '%s'." ), nameList.GetCount(), GetChars( lib->GetName() ) ); diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index b16208bf65..77ce1a2b94 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -353,6 +353,7 @@ if( KICAD_SCRIPTING ) DEPENDS pcbcommon DEPENDS plotcontroller.h + DEPENDS exporters/gendrill_Excellon_writer.h DEPENDS scripting/pcbnew.i DEPENDS scripting/board.i DEPENDS scripting/board_item.i diff --git a/pcbnew/dialogs/dialog_gendrill.cpp b/pcbnew/dialogs/dialog_gendrill.cpp index c3291d4423..6657d446f4 100644 --- a/pcbnew/dialogs/dialog_gendrill.cpp +++ b/pcbnew/dialogs/dialog_gendrill.cpp @@ -27,7 +27,6 @@ */ #include -//#include #include #include #include @@ -41,6 +40,7 @@ #include #include +#include // Keywords for read and write config @@ -351,139 +351,31 @@ void DIALOG_GENDRILL::SetParams() void DIALOG_GENDRILL::GenDrillAndMapFiles(bool aGenDrill, bool aGenMap) { - wxString layername_extend; /* added to the Board FileName to - * create FullFileName (= Board - * FileName + layer pair names) - */ - wxString msg; - bool hasBuriedVias = false; /* If true, drill files are created - * layer pair by layer pair for - * buried vias - */ - UpdateConfig(); // set params and Save drill options m_parent->ClearMsgPanel(); + wxString defaultPath = Prj().AbsolutePath( m_plotOpts.GetOutputDirectory() ); + WX_TEXT_CTRL_REPORTER reporter( m_messagesBox ); - if( m_microViasCount || m_blindOrBuriedViasCount ) - hasBuriedVias = true; + const PlotFormat filefmt[6] = + { // Keep these format ids in the same order than m_Choice_Drill_Map choices + PLOT_FORMAT_HPGL, PLOT_FORMAT_POST, PLOT_FORMAT_GERBER, + PLOT_FORMAT_DXF, PLOT_FORMAT_SVG, PLOT_FORMAT_PDF + }; + unsigned choice = (unsigned) m_Choice_Drill_Map->GetSelection(); + + if( choice >= DIM( filefmt ) ) + choice = 1; EXCELLON_WRITER excellonWriter( m_parent->GetBoard() ); excellonWriter.SetFormat( !m_UnitDrillIsInch, - (EXCELLON_WRITER::zeros_fmt) m_ZerosFormat, + (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat, m_Precision.m_lhs, m_Precision.m_rhs ); excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH ); + excellonWriter.SetMapFileFormat( filefmt[choice] ); - wxFileName fn; - int layer1 = F_Cu; - int layer2 = B_Cu; - bool gen_through_holes = true; - bool gen_NPTH_holes = false; - - for( ; ; ) - { - excellonWriter.BuildHolesList( layer1, layer2, gen_through_holes ? false : true, - gen_NPTH_holes, m_Merge_PTH_NPTH ); - - if( excellonWriter.GetHolesCount() > 0 ) // has holes? - { - fn = m_parent->GetBoard()->GetFileName(); - layername_extend.Empty(); - - if( gen_NPTH_holes ) - { - layername_extend << wxT( "-NPTH" ); - } - else if( !gen_through_holes ) - { - if( layer1 == F_Cu ) - layername_extend << wxT( "-front" ); - else - layername_extend << wxT( "-inner" ) << layer1; - - if( layer2 == B_Cu ) - layername_extend << wxT( "-back" ); - else - layername_extend << wxT( "-inner" ) << layer2; - } - - fn.SetName( fn.GetName() + layername_extend ); - - wxString defaultPath = Prj().AbsolutePath( m_plotOpts.GetOutputDirectory() ); - - fn.SetPath( defaultPath ); - - if( aGenDrill ) - { - fn.SetExt( DrillFileExtension ); - wxString fullFilename = fn.GetFullPath(); - - FILE* file = wxFopen( fullFilename, wxT( "w" ) ); - - if( file == 0 ) - { - msg.Printf( _( "** Unable to create %s **\n" ), - GetChars( fullFilename ) ); - m_messagesBox->AppendText( msg ); - break; - } - else - { - msg.Printf( _( "Plot: %s OK\n" ), GetChars( fullFilename ) ); - m_messagesBox->AppendText( msg ); - } - - excellonWriter.CreateDrillFile( file ); - } - - if( aGenMap ) - { - const PlotFormat filefmt[6] = - { // Keep these format ids in the same order than m_Choice_Drill_Map choices - PLOT_FORMAT_HPGL, PLOT_FORMAT_POST, PLOT_FORMAT_GERBER, - PLOT_FORMAT_DXF, PLOT_FORMAT_SVG, PLOT_FORMAT_PDF - }; - unsigned choice = (unsigned) m_Choice_Drill_Map->GetSelection(); - - if( choice >= m_Choice_Drill_Map->GetCount() ) - choice = 1; - - fn.SetExt( wxEmptyString ); // Will be added by GenDrillMap - wxString fullfilename = fn.GetFullPath() + wxT( "-drl_map" ); - - GenDrillMap( fullfilename, excellonWriter, filefmt[choice] ); - } - } - - if( gen_NPTH_holes ) // The last drill file was created - break; - - if( !hasBuriedVias ) - gen_NPTH_holes = true; - else - { - if( gen_through_holes ) - layer2 = layer1 + 1; // done with through-board holes, prepare generation of first layer pair - else - { - if( layer2 >= B_Cu ) // no more layer pair to consider - { - layer1 = F_Cu; - layer2 = B_Cu; - gen_NPTH_holes = true; - continue; - } - - layer1++; - layer2++; // use next layer pair - - if( layer2 == m_parent->GetBoard()->GetCopperLayerCount() - 1 ) - layer2 = B_Cu; // the last layer is always the back layer - } - - gen_through_holes = false; - } - } + excellonWriter.CreateDrillandMapFilesSet( defaultPath, aGenDrill, aGenMap, + &reporter); } @@ -510,7 +402,7 @@ void DIALOG_GENDRILL::OnGenReportFile( wxCommandEvent& event ) EXCELLON_WRITER excellonWriter( m_parent->GetBoard() ); excellonWriter.SetFormat( !m_UnitDrillIsInch, - (EXCELLON_WRITER::zeros_fmt) m_ZerosFormat, + (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat, m_Precision.m_lhs, m_Precision.m_rhs ); excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH ); @@ -529,72 +421,3 @@ void DIALOG_GENDRILL::OnGenReportFile( wxCommandEvent& event ) m_messagesBox->AppendText( msg ); } } - - -// Generate the drill map of the board -void DIALOG_GENDRILL::GenDrillMap( const wxString aFullFileNameWithoutExt, - EXCELLON_WRITER& aExcellonWriter, - PlotFormat format ) -{ - wxString ext, wildcard; - - /* Init extension */ - switch( format ) - { - case PLOT_FORMAT_HPGL: - ext = HPGL_PLOTTER::GetDefaultFileExtension(); - wildcard = _( "HPGL plot files (.plt)|*.plt" ); - break; - - case PLOT_FORMAT_POST: - ext = PS_PLOTTER::GetDefaultFileExtension(); - wildcard = PSFileWildcard; - break; - - case PLOT_FORMAT_GERBER: - ext = GERBER_PLOTTER::GetDefaultFileExtension(); - wildcard = _( "Gerber files (.pho)|*.pho" ); - break; - - case PLOT_FORMAT_DXF: - ext = DXF_PLOTTER::GetDefaultFileExtension(); - wildcard = _( "DXF files (.dxf)|*.dxf" ); - break; - - case PLOT_FORMAT_SVG: - ext = SVG_PLOTTER::GetDefaultFileExtension(); - wildcard = SVGFileWildcard; - break; - - case PLOT_FORMAT_PDF: - ext = PDF_PLOTTER::GetDefaultFileExtension(); - wildcard = PdfFileWildcard; - break; - - default: - wxLogMessage( wxT( "DIALOG_GENDRILL::GenDrillMap() error, fmt % unknown" ), format ); - return; - } - - // Add file name extension - wxString fullFilename = aFullFileNameWithoutExt; - fullFilename << wxT(".") << ext; - - bool success = aExcellonWriter.GenDrillMapFile( fullFilename, - m_parent->GetPageSettings(), - format ); - - wxString msg; - - if( ! success ) - { - msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fullFilename ) ); - m_messagesBox->AppendText( msg ); - return; - } - else - { - msg.Printf( _( "Plot: %s OK\n" ), GetChars( fullFilename ) ); - m_messagesBox->AppendText( msg ); - } -} diff --git a/pcbnew/dialogs/dialog_gendrill.h b/pcbnew/dialogs/dialog_gendrill.h index 048f2f99cc..85a7087adc 100644 --- a/pcbnew/dialogs/dialog_gendrill.h +++ b/pcbnew/dialogs/dialog_gendrill.h @@ -98,14 +98,9 @@ private: */ void GenDrillAndMapFiles( bool aGenDrill, bool aGenMap ); - void GenDrillMap( const wxString aFileName, - EXCELLON_WRITER& aExcellonWriter, - PlotFormat format ); - void UpdatePrecisionOptions(); void UpdateConfig(); - int Create_Drill_File_EXCELLON( FILE* aFile, - wxPoint aOffset ); + int Create_Drill_File_EXCELLON( FILE* aFile, wxPoint aOffset ); int Gen_Liste_Tools( std::vector& buffer, bool print_header ); diff --git a/pcbnew/exporters/gen_drill_report_files.cpp b/pcbnew/exporters/gen_drill_report_files.cpp index 48922b29d6..1e62bc29b5 100644 --- a/pcbnew/exporters/gen_drill_report_files.cpp +++ b/pcbnew/exporters/gen_drill_report_files.cpp @@ -56,17 +56,19 @@ inline double diameter_in_mm( double ius ) bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, - const PAGE_INFO& aSheet, PlotFormat aFormat ) { double scale = 1.0; wxPoint offset; PLOTTER* plotter = NULL; + PAGE_INFO dummy( PAGE_INFO::A4, false ); PCB_PLOT_PARAMS plot_opts; // starts plotting with default options LOCALE_IO toggle; // use standard C notation for float numbers + const PAGE_INFO& page_info = m_pageInfo ? *m_pageInfo : dummy; + // Calculate dimensions and center of PCB EDA_RECT bbbox = m_pcb->ComputeBoundingBox( true ); @@ -88,7 +90,7 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, hpgl_plotter->SetPenNumber( plot_opts.GetHPGLPenNum() ); hpgl_plotter->SetPenSpeed( plot_opts.GetHPGLPenSpeed() ); hpgl_plotter->SetPenOverlap( 0 ); - plotter->SetPageSettings( aSheet ); + plotter->SetPageSettings( page_info ); plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); } break; @@ -140,7 +142,7 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, { DXF_PLOTTER* dxf_plotter = new DXF_PLOTTER; plotter = dxf_plotter; - plotter->SetPageSettings( aSheet ); + plotter->SetPageSettings( page_info ); plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); } break; @@ -149,7 +151,7 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, { SVG_PLOTTER* svg_plotter = new SVG_PLOTTER; plotter = svg_plotter; - plotter->SetPageSettings( aSheet ); + plotter->SetPageSettings( page_info ); plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); } break; @@ -289,14 +291,14 @@ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) unsigned totalHoleCount; char line[1024]; - LAYER_NUM layer1 = F_Cu; // First layer of the stack layer - LAYER_NUM layer2 = B_Cu; // Last layer of the stack layer + LAYER_NUM layer1 = F_Cu; // First layer of the layer stack + LAYER_NUM layer2 = B_Cu; // Last layer of the layer stack bool gen_through_holes = true; bool gen_NPTH_holes = false; wxString brdFilename = m_pcb->GetFileName(); fprintf( m_file, "Drill report for %s\n", TO_UTF8( brdFilename ) ); - fprintf( m_file, "Created on %s\n", TO_UTF8( DateAndTime() ) ); + fprintf( m_file, "Created on %s\n\n", TO_UTF8( DateAndTime() ) ); /* build hole lists: * 1 - through holes @@ -321,7 +323,7 @@ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) if( layer1 == F_Cu ) fputs( "Drill report for buried and blind vias :\n\n", m_file ); - sprintf( line, "Drill report for holes from layer %s to layer %s :\n", + sprintf( line, "Holes from layer %s to layer %s :\n", TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( layer1 ) ) ), TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( layer2 ) ) ) ); } @@ -332,7 +334,7 @@ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) { // List the tool number assigned to each drill, // in mm then in inches. - sprintf( line, "T%d %2.2fmm %2.3f\" ", + sprintf( line, " T%d %2.2fmm %2.3f\" ", ii + 1, diameter_in_mm( m_toolListBuffer[ii].m_Diameter ), diameter_in_inches( m_toolListBuffer[ii].m_Diameter ) ); diff --git a/pcbnew/exporters/gendrill_Excellon_writer.cpp b/pcbnew/exporters/gendrill_Excellon_writer.cpp index 6b302d85df..149f13ec50 100644 --- a/pcbnew/exporters/gendrill_Excellon_writer.cpp +++ b/pcbnew/exporters/gendrill_Excellon_writer.cpp @@ -53,8 +53,180 @@ #include #include #include +#include -#include // Dialog box for drill file generation +//#include // Dialog box for drill file generation + +EXCELLON_WRITER::EXCELLON_WRITER( BOARD* aPcb ) +{ + m_file = NULL; + m_pcb = aPcb; + m_zeroFormat = DECIMAL_FORMAT; + m_conversionUnits = 0.0001; + m_unitsDecimal = true; + m_mirror = false; + m_merge_PTH_NPTH = false; + m_minimalHeader = false; + m_ShortHeader = false; + m_mapFileFmt = PLOT_FORMAT_PDF; + m_pageInfo = NULL; +} + + +void EXCELLON_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory, + bool aGenDrill, bool aGenMap, + REPORTER * aReporter ) +{ + wxFileName fn; + wxString msg; + + wxString layername_extend; // added to the board filefame to create a full filename + //(board fileName + layer pair names) + + // If some buried/blind vias are found, drill files are created + // layer pair by layer pair for buried vias + bool hasBuriedVias = false; + + for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() ) + { + if( track->Type() == PCB_VIA_T ) + { + const VIA *via = static_cast( track ); + + if( via->GetViaType() == VIA_MICROVIA || + via->GetViaType() == VIA_BLIND_BURIED ) + { + hasBuriedVias = true; + break; + } + } + } + + + int layer1 = F_Cu; + int layer2 = B_Cu; + bool gen_through_holes = true; + bool gen_NPTH_holes = false; + + for( ; ; ) + { + BuildHolesList( layer1, layer2, gen_through_holes ? false : true, + gen_NPTH_holes, m_merge_PTH_NPTH ); + + if( GetHolesCount() > 0 ) // has holes? + { + fn = m_pcb->GetFileName(); + layername_extend.Empty(); + + if( gen_NPTH_holes ) + { + layername_extend << wxT( "-NPTH" ); + } + else if( !gen_through_holes ) + { + if( layer1 == F_Cu ) + layername_extend << wxT( "-front" ); + else + layername_extend << wxT( "-inner" ) << layer1; + + if( layer2 == B_Cu ) + layername_extend << wxT( "-back" ); + else + layername_extend << wxT( "-inner" ) << layer2; + } + + fn.SetName( fn.GetName() + layername_extend ); + + fn.SetPath( aPlotDirectory ); + + if( aGenDrill ) + { + fn.SetExt( DrillFileExtension ); + wxString fullFilename = fn.GetFullPath(); + + FILE* file = wxFopen( fullFilename, wxT( "w" ) ); + + if( file == NULL ) + { + if( aReporter ) + { + msg.Printf( _( "** Unable to create %s **\n" ), + GetChars( fullFilename ) ); + aReporter->Report( msg ); + } + break; + } + else + { + if( aReporter ) + { + msg.Printf( _( "Create file %s\n" ), GetChars( fullFilename ) ); + aReporter->Report( msg ); + } + } + + CreateDrillFile( file ); + } + + if( aGenMap ) + { + fn.SetExt( wxEmptyString ); // Will be added by GenDrillMap + wxString fullfilename = fn.GetFullPath() + wxT( "-drl_map" ); + fullfilename << wxT(".") << GetDefaultPlotExtension( m_mapFileFmt ); + + bool success = GenDrillMapFile( fullfilename, m_mapFileFmt ); + + if( ! success ) + { + if( aReporter ) + { + msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fullfilename ) ); + aReporter->Report( msg ); + } + + return; + } + else + { + if( aReporter ) + { + msg.Printf( _( "Create file %s\n" ), GetChars( fullfilename ) ); + aReporter->Report( msg ); + } + } + } + } + + if( gen_NPTH_holes ) // The last drill file was created + break; + + if( !hasBuriedVias ) + gen_NPTH_holes = true; + else + { + if( gen_through_holes ) + layer2 = layer1 + 1; // done with through-board holes, prepare generation of first layer pair + else + { + if( layer2 >= B_Cu ) // no more layer pair to consider + { + layer1 = F_Cu; + layer2 = B_Cu; + gen_NPTH_holes = true; + continue; + } + + layer1++; + layer2++; // use next layer pair + + if( layer2 == m_pcb->GetCopperLayerCount() - 1 ) + layer2 = B_Cu; // the last layer is always the back layer + } + + gen_through_holes = false; + } + } +} /* @@ -67,8 +239,6 @@ * - Decimal * - Metric */ - - int EXCELLON_WRITER::CreateDrillFile( FILE* aFile ) { m_file = aFile; @@ -78,7 +248,7 @@ int EXCELLON_WRITER::CreateDrillFile( FILE* aFile ) double xt, yt; char line[1024]; - SetLocaleTo_C_standard(); // Use the standard notation for double numbers + LOCALE_IO dummy; // Use the standard notation for double numbers WriteEXCELLONHeader(); @@ -212,14 +382,12 @@ int EXCELLON_WRITER::CreateDrillFile( FILE* aFile ) WriteEXCELLONEndOfFile(); - SetLocaleTo_Default(); // Revert to locale double notation - return holes_count; } void EXCELLON_WRITER::SetFormat( bool aMetric, - zeros_fmt aZerosFmt, + ZEROS_FMT aZerosFmt, int aLeftDigits, int aRightDigits ) { @@ -228,9 +396,17 @@ void EXCELLON_WRITER::SetFormat( bool aMetric, /* Set conversion scale depending on drill file units */ if( m_unitsDecimal ) - m_conversionUnits = 1.0 / IU_PER_MM; // EXCELLON units = mm + m_conversionUnits = 1.0 / IU_PER_MM; // EXCELLON units = mm else - m_conversionUnits = 0.001 / IU_PER_MILS; // EXCELLON units = INCHES + m_conversionUnits = 0.001 / IU_PER_MILS; // EXCELLON units = INCHES + + // Set the zero counts. if aZerosFmt == DECIMAL_FORMAT, these values + // will be set, but not used. + if( aLeftDigits <= 0 ) + aLeftDigits = m_unitsDecimal ? 3 : 2; + + if( aRightDigits <= 0 ) + aRightDigits = m_unitsDecimal ? 3 : 4; m_precision.m_lhs = aLeftDigits; m_precision.m_rhs = aRightDigits; @@ -344,7 +520,8 @@ void EXCELLON_WRITER::WriteEXCELLONHeader() if( !m_minimalHeader ) { // The next 2 lines in EXCELLON files are comments: - wxString msg = Pgm().App().GetAppName() + wxT( " " ) + GetBuildVersion(); + wxString msg; + msg << wxT("KiCad") << wxT( " " ) << GetBuildVersion(); fprintf( m_file, ";DRILL file {%s} date %s\n", TO_UTF8( msg ), TO_UTF8( DateAndTime() ) ); diff --git a/pcbnew/exporters/gendrill_Excellon_writer.h b/pcbnew/exporters/gendrill_Excellon_writer.h index 676057c9d9..80ce9c7c33 100644 --- a/pcbnew/exporters/gendrill_Excellon_writer.h +++ b/pcbnew/exporters/gendrill_Excellon_writer.h @@ -6,8 +6,8 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2012 Jean_Pierre Charras - * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 1992-2015 Jean_Pierre Charras + * Copyright (C) 1992-2015 KiCad Developers, see change_log.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 @@ -120,12 +120,11 @@ public: DRILL_PRECISION( int l = 2, int r = 4 ) class EXCELLON_WRITER { public: - enum zeros_fmt { - // Zero format in coordinates - DECIMAL_FORMAT, - SUPPRESS_LEADING, - SUPPRESS_TRAILING, - KEEP_ZEROS + enum ZEROS_FMT { // Zero format in coordinates + DECIMAL_FORMAT, // Floating point coordinates + SUPPRESS_LEADING, // Suppress leading zeros + SUPPRESS_TRAILING, // Suppress trainling zeros + KEEP_ZEROS // keep zeros }; wxPoint m_Offset; // offset coordinates @@ -137,7 +136,7 @@ private: bool m_minimalHeader; // True to use minimal header // in excellon file (strip comments) bool m_unitsDecimal; // true = decimal, false = inches - zeros_fmt m_zeroFormat; // the zero format option for output file + ZEROS_FMT m_zeroFormat; // the zero format option for output file DRILL_PRECISION m_precision; // The current coordinate precision (not used in decimal format) double m_conversionUnits; // scaling factor to convert the board unites to Excellon units // (i.e inches or mm) @@ -147,20 +146,13 @@ private: std::vector m_holeListBuffer; // Buffer containing holes std::vector m_toolListBuffer; // Buffer containing tools -public: - EXCELLON_WRITER( BOARD* aPcb ) - { - m_file = NULL; - m_pcb = aPcb; - m_zeroFormat = DECIMAL_FORMAT; - m_conversionUnits = 0.0001; - m_unitsDecimal = false; - m_mirror = false; - m_merge_PTH_NPTH = false; - m_minimalHeader = false; - m_ShortHeader = false; - } + PlotFormat m_mapFileFmt; // the format of the map drill file, + // if this map is needed + const PAGE_INFO* m_pageInfo; // the page info used to plot drill maps + // If NULL, use a A4 page format +public: + EXCELLON_WRITER( BOARD* aPcb ); ~EXCELLON_WRITER() { @@ -178,9 +170,30 @@ public: * @param aMetric = true for metric coordinates, false for imperial units * @param aZerosFmt = DECIMAL_FORMAT, SUPPRESS_LEADING, SUPPRESS_TRAILING, KEEP_ZEROS * @param aLeftDigits = number of digits for integer part of coordinates + * if <= 0 (default), a suitable value will be used, depending on units * @param aRightDigits = number of digits for mantissa part of coordinates + * if <= 0 (default), a suitable value will be used, depending on units */ - void SetFormat( bool aMetric, zeros_fmt aZerosFmt, int aLeftDigits, int aRightDigits ); + void SetFormat( bool aMetric, ZEROS_FMT aZerosFmt = DECIMAL_FORMAT, + int aLeftDigits = 0, int aRightDigits = 0 ); + + /** + * Sets the page info used to plot drill maps + * If NULL, a A4 page format will be used + * @param aPageInfo = a reference to the page info, usually used to plot/display the board + */ + void SetPageInfo( const PAGE_INFO* aPageInfo ) { m_pageInfo = aPageInfo; } + + /** + * Function SetMapFileFormat + * Initialize the format for the drill map file + * @param SetMapFileFormat = a PlotFormat value (one of + * PLOT_FORMAT_HPGL, PLOT_FORMAT_POST, PLOT_FORMAT_GERBER, + * PLOT_FORMAT_DXF, PLOT_FORMAT_SVG, PLOT_FORMAT_PDF + * the most useful are PLOT_FORMAT_PDF and PLOT_FORMAT_POST + */ + void SetMapFileFormat( PlotFormat aMapFmt ) { m_mapFileFmt = aMapFmt; } + /** * Function SetOptions @@ -219,6 +232,19 @@ public: int GetHolesCount() const { return m_holeListBuffer.size(); } + /** + * Function CreateDrillandMapFilesSet + * Creates the full set of Excellon drill file for the board + * filenames are computed from the board name, and layers id + * @param aPlotDirectory = the output folder + * @param aGenDrill = true to generate the EXCELLON drill file + * @param aGenMap = true to generate a drill map file + * @param aReporter = a REPORTER to return activity or any message (can be NULL) + */ + void CreateDrillandMapFilesSet( const wxString& aPlotDirectory, + bool aGenDrill, bool aGenMap, + REPORTER * aReporter = NULL ); + /** * Function CreateDrillFile * Creates an Excellon drill file @@ -275,7 +301,7 @@ public: * Total unplated holes count 1 * * @param aFullFileName : the name of the file to create - * m_unitsDecimal = false tu use inches, true to use mm in report file + * m_unitsDecimal = false to use inches, true to use mm in report file * * @return success if the file is created */ @@ -284,14 +310,14 @@ public: /** * Function GenDrillMapFile * Plot a map of drill marks for holes. - * @param aFullFileNameWithoutExt : the full filename of the file to create, - * without extension (will be added according to the format) - * @param aSheet : the paper sheet to use for plot + * the paper sheet to use to plot the map is set in m_pageInfo + * ( calls SetPageInfo() to set it ) + * if NULL, A4 format will be used + * @param aFullFileName : the full filename of the map file to create, * @param aFormat : one of the supported plot formats (see enum PlotFormat ) */ - bool GenDrillMapFile( const wxString& aFullFileNameWithoutExt, - const PAGE_INFO& aSheet, - PlotFormat aFormat ); + bool GenDrillMapFile( const wxString& aFullFileName, PlotFormat aFormat ); + private: /* Print the DRILL file header. The full header is: * M48 diff --git a/pcbnew/scripting/pcbnew.i b/pcbnew/scripting/pcbnew.i index dcb791f3ea..bf2278a703 100644 --- a/pcbnew/scripting/pcbnew.i +++ b/pcbnew/scripting/pcbnew.i @@ -108,6 +108,7 @@ #include #include + #include #include BOARD *GetBoard(); /* get current editor board */ @@ -145,6 +146,7 @@ %include %include %include +%include %include %include "board_item.i"