Commit 699c76cc authored by jean-pierre charras's avatar jean-pierre charras
Browse files

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)
parent 569c2be3
Loading
Loading
Loading
Loading
+110 −0
Original line number Original line Diff line number Diff line
'''
    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 );
+3 −3
Original line number Original line Diff line number Diff line
/*
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 * 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 <stambaughw@verizon.net>
 * Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
 * 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
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * modify it under the terms of the GNU General Public License
@@ -548,7 +548,7 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
        return;
        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(),
                nameList.GetCount(),
                GetChars( lib->GetName() ) );
                GetChars( lib->GetName() ) );


+1 −0
Original line number Original line Diff line number Diff line
@@ -353,6 +353,7 @@ if( KICAD_SCRIPTING )


        DEPENDS pcbcommon
        DEPENDS pcbcommon
        DEPENDS plotcontroller.h
        DEPENDS plotcontroller.h
        DEPENDS exporters/gendrill_Excellon_writer.h
        DEPENDS scripting/pcbnew.i
        DEPENDS scripting/pcbnew.i
        DEPENDS scripting/board.i
        DEPENDS scripting/board.i
        DEPENDS scripting/board_item.i
        DEPENDS scripting/board_item.i
+17 −194
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
 */
 */


#include <fctsys.h>
#include <fctsys.h>
//#include <pgm_base.h>
#include <kiface_i.h>
#include <kiface_i.h>
#include <pcbnew.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
#include <wxPcbStruct.h>
@@ -41,6 +40,7 @@


#include <dialog_gendrill.h>
#include <dialog_gendrill.h>
#include <wildcards_and_files_ext.h>
#include <wildcards_and_files_ext.h>
#include <reporter.h>




// Keywords for read and write config
// Keywords for read and write config
@@ -351,93 +351,12 @@ void DIALOG_GENDRILL::SetParams()


void DIALOG_GENDRILL::GenDrillAndMapFiles(bool aGenDrill, bool aGenMap)
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
    UpdateConfig();     // set params and Save drill options


    m_parent->ClearMsgPanel();
    m_parent->ClearMsgPanel();

    if( m_microViasCount || m_blindOrBuriedViasCount )
        hasBuriedVias = true;

    EXCELLON_WRITER excellonWriter( m_parent->GetBoard() );
    excellonWriter.SetFormat( !m_UnitDrillIsInch,
                              (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 );

    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() );
    wxString defaultPath = Prj().AbsolutePath( m_plotOpts.GetOutputDirectory() );
    WX_TEXT_CTRL_REPORTER reporter( m_messagesBox );


            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] =
    const PlotFormat filefmt[6] =
    {   // Keep these format ids in the same order than m_Choice_Drill_Map choices
    {   // 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_HPGL, PLOT_FORMAT_POST, PLOT_FORMAT_GERBER,
@@ -445,45 +364,18 @@ void DIALOG_GENDRILL::GenDrillAndMapFiles(bool aGenDrill, bool aGenMap)
    };
    };
    unsigned choice = (unsigned) m_Choice_Drill_Map->GetSelection();
    unsigned choice = (unsigned) m_Choice_Drill_Map->GetSelection();


                if( choice >= m_Choice_Drill_Map->GetCount() )
    if( choice >= DIM( filefmt ) )
        choice = 1;
        choice = 1;


                fn.SetExt( wxEmptyString ); // Will be added by GenDrillMap
    EXCELLON_WRITER excellonWriter( m_parent->GetBoard() );
                wxString fullfilename = fn.GetFullPath() + wxT( "-drl_map" );
    excellonWriter.SetFormat( !m_UnitDrillIsInch,

                              (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat,
                GenDrillMap( fullfilename, excellonWriter, filefmt[choice] );
                              m_Precision.m_lhs, m_Precision.m_rhs );
            }
    excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH );
        }
    excellonWriter.SetMapFileFormat( 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() );
    EXCELLON_WRITER excellonWriter( m_parent->GetBoard() );
    excellonWriter.SetFormat( !m_UnitDrillIsInch,
    excellonWriter.SetFormat( !m_UnitDrillIsInch,
                              (EXCELLON_WRITER::zeros_fmt) m_ZerosFormat,
                              (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat,
                              m_Precision.m_lhs, m_Precision.m_rhs );
                              m_Precision.m_lhs, m_Precision.m_rhs );
    excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH );
    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 );
        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 );
    }
}
+1 −6
Original line number Original line Diff line number Diff line
@@ -98,14 +98,9 @@ private:
     */
     */
    void            GenDrillAndMapFiles( bool aGenDrill, bool aGenMap );
    void            GenDrillAndMapFiles( bool aGenDrill, bool aGenMap );


    void            GenDrillMap( const wxString  aFileName,
                                 EXCELLON_WRITER& aExcellonWriter,
                                 PlotFormat      format );

    void            UpdatePrecisionOptions();
    void            UpdatePrecisionOptions();
    void            UpdateConfig();
    void            UpdateConfig();
    int             Create_Drill_File_EXCELLON( FILE*  aFile,
    int             Create_Drill_File_EXCELLON( FILE* aFile, wxPoint aOffset );
                                                wxPoint aOffset );
    int             Gen_Liste_Tools( std::vector<DRILL_TOOL>& buffer,
    int             Gen_Liste_Tools( std::vector<DRILL_TOOL>& buffer,
                                     bool print_header );
                                     bool print_header );


Loading