Browse Source
Pcbnew: Add creation of Drill Files in Gerber X2 format.
Pcbnew: Add creation of Drill Files in Gerber X2 format.
Gerbview: add support of drill files in Gerber format. Fix also an issue in drill dialog: Axis choice is now common to plot a drill files.pull/3/merge
21 changed files with 1611 additions and 631 deletions
-
16common/gbr_metadata.cpp
-
38gerbview/class_X2_gerber_attributes.cpp
-
24gerbview/class_X2_gerber_attributes.h
-
9gerbview/class_gerber_file_image_list.cpp
-
3include/plot_auxiliary_data.h
-
2pcbnew/CMakeLists.txt
-
103pcbnew/dialogs/dialog_gendrill.cpp
-
9pcbnew/dialogs/dialog_gendrill.h
-
50pcbnew/dialogs/dialog_gendrill_base.cpp
-
204pcbnew/dialogs/dialog_gendrill_base.fbp
-
7pcbnew/dialogs/dialog_gendrill_base.h
-
27pcbnew/dialogs/dialog_plot.cpp
-
31pcbnew/exporters/gen_drill_report_files.cpp
-
297pcbnew/exporters/gendrill_Excellon_writer.cpp
-
259pcbnew/exporters/gendrill_Excellon_writer.h
-
340pcbnew/exporters/gendrill_file_writer_base.cpp
-
346pcbnew/exporters/gendrill_file_writer_base.h
-
328pcbnew/exporters/gendrill_gerber_writer.cpp
-
107pcbnew/exporters/gendrill_gerber_writer.h
-
14pcbnew/pcbplot.cpp
-
28pcbnew/pcbplot.h
@ -0,0 +1,340 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> |
|||
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> |
|||
* Copyright (C) 1992-2017 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 |
|||
* 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 <fctsys.h>
|
|||
|
|||
#include <class_board.h>
|
|||
#include <class_module.h>
|
|||
#include <collectors.h>
|
|||
#include <reporter.h>
|
|||
|
|||
#include <gendrill_file_writer_base.h>
|
|||
|
|||
|
|||
/* Helper function for sorting hole list.
|
|||
* Compare function used for sorting holes type type (plated then not plated) |
|||
* then by increasing diameter value and X value |
|||
*/ |
|||
static bool CmpHoleSorting( const HOLE_INFO& a, const HOLE_INFO& b ) |
|||
{ |
|||
if( a.m_Hole_NotPlated != b.m_Hole_NotPlated ) |
|||
return b.m_Hole_NotPlated; |
|||
|
|||
if( a.m_Hole_Diameter != b.m_Hole_Diameter ) |
|||
return a.m_Hole_Diameter < b.m_Hole_Diameter; |
|||
|
|||
// group by components when possible
|
|||
const D_PAD* pada = dyn_cast<const D_PAD*>( a.m_ItemParent ); |
|||
const D_PAD* padb = dyn_cast<const D_PAD*>( b.m_ItemParent ); |
|||
|
|||
if( pada && padb ) |
|||
{ |
|||
if( pada->GetParent()->GetReference().Cmp( padb->GetParent()->GetReference() ) != 0 ) |
|||
return pada->GetParent()->GetReference().Cmp( padb->GetParent()->GetReference() ) < 0; |
|||
} |
|||
else if( pada || padb ) |
|||
return true; |
|||
|
|||
// At this point, holes are via holes: sort by position
|
|||
|
|||
if( a.m_Hole_Pos.x != b.m_Hole_Pos.x ) |
|||
return a.m_Hole_Pos.x < b.m_Hole_Pos.x; |
|||
|
|||
return a.m_Hole_Pos.y < b.m_Hole_Pos.y; |
|||
} |
|||
|
|||
|
|||
void GENDRILL_WRITER_BASE::buildHolesList( DRILL_LAYER_PAIR aLayerPair, |
|||
bool aGenerateNPTH_list ) |
|||
{ |
|||
HOLE_INFO new_hole; |
|||
|
|||
m_holeListBuffer.clear(); |
|||
m_toolListBuffer.clear(); |
|||
|
|||
wxASSERT( aLayerPair.first < aLayerPair.second ); // fix the caller
|
|||
|
|||
// build hole list for vias
|
|||
if( ! aGenerateNPTH_list ) // vias are always plated !
|
|||
{ |
|||
for( VIA* via = GetFirstVia( m_pcb->m_Track ); via; via = GetFirstVia( via->Next() ) ) |
|||
{ |
|||
int hole_sz = via->GetDrillValue(); |
|||
|
|||
if( hole_sz == 0 ) // Should not occur.
|
|||
continue; |
|||
|
|||
new_hole.m_ItemParent = via; |
|||
new_hole.m_Tool_Reference = -1; // Flag value for Not initialized
|
|||
new_hole.m_Hole_Orient = 0; |
|||
new_hole.m_Hole_Diameter = hole_sz; |
|||
new_hole.m_Hole_NotPlated = false; |
|||
new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter; |
|||
|
|||
new_hole.m_Hole_Shape = 0; // hole shape: round
|
|||
new_hole.m_Hole_Pos = via->GetStart(); |
|||
|
|||
via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer ); |
|||
|
|||
// LayerPair() returns params with m_Hole_Bottom_Layer > m_Hole_Top_Layer
|
|||
// Remember: top layer = 0 and bottom layer = 31 for through hole vias
|
|||
// Any captured via should be from aLayerPair.first to aLayerPair.second exactly.
|
|||
if( new_hole.m_Hole_Top_Layer != aLayerPair.first || |
|||
new_hole.m_Hole_Bottom_Layer != aLayerPair.second ) |
|||
continue; |
|||
|
|||
m_holeListBuffer.push_back( new_hole ); |
|||
} |
|||
} |
|||
|
|||
if( aLayerPair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) ) |
|||
{ |
|||
// add holes for thru hole pads
|
|||
for( MODULE* module = m_pcb->m_Modules; module; module = module->Next() ) |
|||
{ |
|||
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) |
|||
{ |
|||
if( !m_merge_PTH_NPTH ) |
|||
{ |
|||
if( !aGenerateNPTH_list && pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED ) |
|||
continue; |
|||
|
|||
if( aGenerateNPTH_list && pad->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) |
|||
continue; |
|||
} |
|||
|
|||
if( pad->GetDrillSize().x == 0 ) |
|||
continue; |
|||
|
|||
new_hole.m_ItemParent = pad; |
|||
new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED); |
|||
new_hole.m_Tool_Reference = -1; // Flag is: Not initialized
|
|||
new_hole.m_Hole_Orient = pad->GetOrientation(); |
|||
new_hole.m_Hole_Shape = 0; // hole shape: round
|
|||
new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ); |
|||
new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter; |
|||
|
|||
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE ) |
|||
new_hole.m_Hole_Shape = 1; // oval flag set
|
|||
|
|||
new_hole.m_Hole_Size = pad->GetDrillSize(); |
|||
new_hole.m_Hole_Pos = pad->GetPosition(); // hole position
|
|||
new_hole.m_Hole_Bottom_Layer = B_Cu; |
|||
new_hole.m_Hole_Top_Layer = F_Cu; // pad holes are through holes
|
|||
m_holeListBuffer.push_back( new_hole ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Sort holes per increasing diameter value
|
|||
sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleSorting ); |
|||
|
|||
// build the tool list
|
|||
int last_hole = -1; // Set to not initialized (this is a value not used
|
|||
// for m_holeListBuffer[ii].m_Hole_Diameter)
|
|||
bool last_notplated_opt = false; |
|||
|
|||
DRILL_TOOL new_tool( 0, false ); |
|||
unsigned jj; |
|||
|
|||
for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) |
|||
{ |
|||
if( m_holeListBuffer[ii].m_Hole_Diameter != last_hole || |
|||
m_holeListBuffer[ii].m_Hole_NotPlated != last_notplated_opt ) |
|||
{ |
|||
new_tool.m_Diameter = m_holeListBuffer[ii].m_Hole_Diameter; |
|||
new_tool.m_Hole_NotPlated = m_holeListBuffer[ii].m_Hole_NotPlated; |
|||
m_toolListBuffer.push_back( new_tool ); |
|||
last_hole = new_tool.m_Diameter; |
|||
last_notplated_opt = new_tool.m_Hole_NotPlated; |
|||
} |
|||
|
|||
jj = m_toolListBuffer.size(); |
|||
|
|||
if( jj == 0 ) |
|||
continue; // Should not occurs
|
|||
|
|||
m_holeListBuffer[ii].m_Tool_Reference = jj; // Tool value Initialized (value >= 1)
|
|||
|
|||
m_toolListBuffer.back().m_TotalCount++; |
|||
|
|||
if( m_holeListBuffer[ii].m_Hole_Shape ) |
|||
m_toolListBuffer.back().m_OvalCount++; |
|||
} |
|||
} |
|||
|
|||
|
|||
std::vector<DRILL_LAYER_PAIR> GENDRILL_WRITER_BASE::getUniqueLayerPairs() const |
|||
{ |
|||
wxASSERT( m_pcb ); |
|||
|
|||
static const KICAD_T interesting_stuff_to_collect[] = { |
|||
PCB_VIA_T, |
|||
EOT |
|||
}; |
|||
|
|||
PCB_TYPE_COLLECTOR vias; |
|||
|
|||
vias.Collect( m_pcb, interesting_stuff_to_collect ); |
|||
|
|||
std::set< DRILL_LAYER_PAIR > unique; |
|||
|
|||
DRILL_LAYER_PAIR layer_pair; |
|||
|
|||
for( int i = 0; i < vias.GetCount(); ++i ) |
|||
{ |
|||
VIA* v = (VIA*) vias[i]; |
|||
|
|||
v->LayerPair( &layer_pair.first, &layer_pair.second ); |
|||
|
|||
// only make note of blind buried.
|
|||
// thru hole is placed unconditionally as first in fetched list.
|
|||
if( layer_pair != DRILL_LAYER_PAIR( F_Cu, B_Cu ) ) |
|||
{ |
|||
unique.insert( layer_pair ); |
|||
} |
|||
} |
|||
|
|||
std::vector<DRILL_LAYER_PAIR> ret; |
|||
|
|||
ret.push_back( DRILL_LAYER_PAIR( F_Cu, B_Cu ) ); // always first in returned list
|
|||
|
|||
for( std::set< DRILL_LAYER_PAIR >::const_iterator it = unique.begin(); it != unique.end(); ++it ) |
|||
ret.push_back( *it ); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
|
|||
const std::string GENDRILL_WRITER_BASE::layerName( PCB_LAYER_ID aLayer ) const |
|||
{ |
|||
// Generic names here.
|
|||
switch( aLayer ) |
|||
{ |
|||
case F_Cu: |
|||
return "front"; |
|||
case B_Cu: |
|||
return "back"; |
|||
default: |
|||
return StrPrintf( "in%d", aLayer ); |
|||
} |
|||
} |
|||
|
|||
|
|||
const std::string GENDRILL_WRITER_BASE::layerPairName( DRILL_LAYER_PAIR aPair ) const |
|||
{ |
|||
std::string ret = layerName( aPair.first ); |
|||
ret += '-'; |
|||
ret += layerName( aPair.second ); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
|
|||
const wxString GENDRILL_WRITER_BASE::getDrillFileName( DRILL_LAYER_PAIR aPair, bool aNPTH, |
|||
bool aMerge_PTH_NPTH ) const |
|||
{ |
|||
wxASSERT( m_pcb ); |
|||
|
|||
wxString extend; |
|||
|
|||
if( aNPTH ) |
|||
extend = "-NPTH"; |
|||
else if( aPair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) ) |
|||
{ |
|||
if( !aMerge_PTH_NPTH ) |
|||
extend = "-PTH"; |
|||
// if merged, extend with nothing
|
|||
} |
|||
else |
|||
{ |
|||
extend += '-'; |
|||
extend += layerPairName( aPair ); |
|||
} |
|||
|
|||
wxFileName fn = m_pcb->GetFileName(); |
|||
|
|||
fn.SetName( fn.GetName() + extend ); |
|||
fn.SetExt( m_drillFileExtension ); |
|||
|
|||
wxString ret = fn.GetFullName(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
void GENDRILL_WRITER_BASE::CreateMapFilesSet( const wxString& aPlotDirectory, |
|||
REPORTER * aReporter ) |
|||
{ |
|||
wxFileName fn; |
|||
wxString msg; |
|||
|
|||
std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs(); |
|||
|
|||
// append a pair representing the NPTH set of holes, for separate drill files.
|
|||
if( !m_merge_PTH_NPTH ) |
|||
hole_sets.push_back( DRILL_LAYER_PAIR( F_Cu, B_Cu ) ); |
|||
|
|||
for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin(); |
|||
it != hole_sets.end(); ++it ) |
|||
{ |
|||
DRILL_LAYER_PAIR pair = *it; |
|||
// For separate drill files, the last layer pair is the NPTH drill file.
|
|||
bool doing_npth = m_merge_PTH_NPTH ? false : ( it == hole_sets.end() - 1 ); |
|||
|
|||
buildHolesList( pair, doing_npth ); |
|||
|
|||
// The file is created if it has holes, or if it is the non plated drill file
|
|||
// to be sure the NPTH file is up to date in separate files mode.
|
|||
if( getHolesCount() > 0 || doing_npth ) |
|||
{ |
|||
fn = getDrillFileName( pair, doing_npth, m_merge_PTH_NPTH ); |
|||
fn.SetPath( aPlotDirectory ); |
|||
|
|||
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 ); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,346 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 1992-2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> |
|||
* Copyright (C) 1992-2017 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 |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file gendrill_file_writer_base.h |
|||
* @brief helper classes to handle hole info for drill files generators. |
|||
*/ |
|||
#ifndef GENDRILL_FILE_WRITER_BASE_H |
|||
#define GENDRILL_FILE_WRITER_BASE_H |
|||
|
|||
#include <vector> |
|||
|
|||
class BOARD_ITEM; |
|||
|
|||
|
|||
// the DRILL_TOOL class handles tools used in the excellon drill file: |
|||
class DRILL_TOOL |
|||
{ |
|||
public: |
|||
int m_Diameter; // the diameter of the used tool (for oblong, the smaller size) |
|||
int m_TotalCount; // how many times it is used (round and oblong) |
|||
int m_OvalCount; // oblong count |
|||
bool m_Hole_NotPlated; // Is the hole plated or not plated |
|||
|
|||
public: |
|||
DRILL_TOOL( int aDiameter, bool a_NotPlated ) |
|||
{ |
|||
m_TotalCount = 0; |
|||
m_OvalCount = 0; |
|||
m_Diameter = aDiameter; |
|||
m_Hole_NotPlated = a_NotPlated; |
|||
} |
|||
}; |
|||
|
|||
|
|||
/* the HOLE_INFO class handle hole which must be drilled (diameter, position and layers) |
|||
* For buried or micro vias, the hole is not on all layers. |
|||
* So we must generate a drill file for each layer pair (adjacent layers) |
|||
* Not plated holes are always through holes, and must be output on a specific drill file |
|||
* because they are drilled after the Pcb process is finished. |
|||
*/ |
|||
class HOLE_INFO |
|||
{ |
|||
public: |
|||
BOARD_ITEM* m_ItemParent; // The pad or via parent of this hole |
|||
int m_Hole_Diameter; // hole value, and for oblong: min(hole size x, hole size y) |
|||
int m_Tool_Reference; // Tool reference for this hole = 1 ... n (values <=0 must not be used) |
|||
wxSize m_Hole_Size; // hole size for oblong holes |
|||
double m_Hole_Orient; // Hole rotation (= pad rotation) for oblong holes |
|||
int m_Hole_Shape; // hole shape: round (0) or oval (1) |
|||
wxPoint m_Hole_Pos; // hole position |
|||
PCB_LAYER_ID m_Hole_Bottom_Layer; // hole ending layer (usually back layer) |
|||
PCB_LAYER_ID m_Hole_Top_Layer; // hole starting layer (usually front layer): |
|||
// m_Hole_Top_Layer < m_Hole_Bottom_Layer |
|||
bool m_Hole_NotPlated; // hole not plated. Must be in a specific drill file or section |
|||
|
|||
public: |
|||
HOLE_INFO() |
|||
{ |
|||
m_ItemParent = nullptr; |
|||
m_Hole_NotPlated = false; |
|||
m_Hole_Diameter = 0; |
|||
m_Tool_Reference = 0; |
|||
m_Hole_Orient = 0.0; |
|||
m_Hole_Shape = 0; |
|||
m_Hole_Bottom_Layer = B_Cu; |
|||
m_Hole_Top_Layer = F_Cu; |
|||
} |
|||
}; |
|||
|
|||
|
|||
/* the DRILL_PRECISION helper class to handle drill precision format in excellon files |
|||
*/ |
|||
class DRILL_PRECISION |
|||
{ |
|||
public: |
|||
int m_lhs; // Left digit number (integer value of coordinates) |
|||
int m_rhs; // Right digit number (decimal value of coordinates) |
|||
|
|||
public: |
|||
DRILL_PRECISION( int l = 2, int r = 4 ) |
|||
{ |
|||
m_lhs = l; m_rhs = r; |
|||
} |
|||
|
|||
|
|||
wxString GetPrecisionString() |
|||
{ |
|||
wxString text; |
|||
|
|||
text << m_lhs << wxT( ":" ) << m_rhs; |
|||
return text; |
|||
} |
|||
}; |
|||
|
|||
|
|||
typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> DRILL_LAYER_PAIR; |
|||
|
|||
/** |
|||
* GENDRILL_WRITER_BASE is a class to create drill maps and drill report, |
|||
* and a helper class to created drill files. |
|||
* drill files are created by specialized derived classes, depenfing on the |
|||
* file format. |
|||
*/ |
|||
class GENDRILL_WRITER_BASE |
|||
{ |
|||
public: |
|||
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 |
|||
}; |
|||
|
|||
protected: |
|||
BOARD* m_pcb; |
|||
wxString m_drillFileExtension; // .drl or .gbr, depending on format |
|||
bool m_unitsDecimal; // true = decimal, false = inches |
|||
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/Gerber units (i.e inches or mm) |
|||
wxPoint m_offset; // Drill offset coordinates |
|||
bool m_merge_PTH_NPTH; // True to generate only one drill file |
|||
std::vector<HOLE_INFO> m_holeListBuffer; // Buffer containing holes |
|||
std::vector<DRILL_TOOL> m_toolListBuffer; // Buffer containing tools |
|||
|
|||
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 |
|||
// This Ctor is protected. |
|||
// Use derived classes to build a fully initialized GENDRILL_WRITER_BASE class. |
|||
GENDRILL_WRITER_BASE( BOARD* aPcb ) |
|||
{ |
|||
m_pcb = aPcb; |
|||
m_conversionUnits = 1.0; |
|||
m_unitsDecimal = true; |
|||
m_mapFileFmt = PLOT_FORMAT_PDF; |
|||
m_pageInfo = NULL; |
|||
m_merge_PTH_NPTH = false; |
|||
} |
|||
|
|||
public: |
|||
~GENDRILL_WRITER_BASE() |
|||
{ |
|||
} |
|||
|
|||
/** |
|||
* set the option to make separate drill files for PTH and NPTH |
|||
* @param aMerge = true to make only one file containing PTH and NPTH |
|||
* = false to create 2 separate files |
|||
*/ |
|||
void SetMergeOption( bool aMerge ) { m_merge_PTH_NPTH = aMerge; } |
|||
|
|||
/** |
|||
* Return the plot offset (usually the position |
|||
* of the auxiliary axis |
|||
*/ |
|||
const wxPoint GetOffset() { return m_offset; } |
|||
|
|||
/** |
|||
* 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 CreateMapFilesSet |
|||
* Creates the full set of map files for the board, in PS, PDF ... format |
|||
* (use SetMapFileFormat() to select the format) |
|||
* filenames are computed from the board name, and layers id |
|||
* @param aPlotDirectory = the output folder |
|||
* @param aReporter = a REPORTER to return activity or any message (can be NULL) |
|||
*/ |
|||
void CreateMapFilesSet( const wxString& aPlotDirectory, |
|||
REPORTER* aReporter = NULL ); |
|||
|
|||
/** |
|||
* Function GenDrillReportFile |
|||
* Create a plain text report file giving a list of drill values and drill count |
|||
* for through holes, oblong holes, and for buried vias, |
|||
* drill values and drill count per layer pair |
|||
* there is only one report for all drill files even when buried or blinds vias exist |
|||
* |
|||
* Here is a sample created by this function: |
|||
* Drill report for F:/tmp/interf_u/interf_u.brd |
|||
* Created on 04/10/2012 20:48:38 |
|||
* Selected Drill Unit: Imperial (inches) |
|||
* |
|||
* Drill report for plated through holes : |
|||
* T1 0,025" 0,64mm (88 holes) |
|||
* T2 0,031" 0,79mm (120 holes) |
|||
* T3 0,032" 0,81mm (151 holes) (with 1 slot) |
|||
* T4 0,040" 1,02mm (43 holes) |
|||
* T5 0,079" 2,00mm (1 hole) (with 1 slot) |
|||
* T6 0,120" 3,05mm (1 hole) (with 1 slot) |
|||
* |
|||
* Total plated holes count 404 |
|||
* |
|||
* |
|||
* Drill report for buried and blind vias : |
|||
* |
|||
* Drill report for holes from layer Soudure to layer Interne1 : |
|||
* |
|||
* Total plated holes count 0 |
|||
* |
|||
* |
|||
* Drill report for holes from layer Interne1 to layer Interne2 : |
|||
* T1 0,025" 0,64mm (3 holes) |
|||
* |
|||
* Total plated holes count 3 |
|||
* |
|||
* |
|||
* Drill report for holes from layer Interne2 to layer Composant : |
|||
* T1 0,025" 0,64mm (1 hole) |
|||
* |
|||
* Total plated holes count 1 |
|||
* |
|||
* |
|||
* Drill report for unplated through holes : |
|||
* T1 0,120" 3,05mm (1 hole) (with 1 slot) |
|||
* |
|||
* Total unplated holes count 1 |
|||
* |
|||
* @param aFullFileName : the name of the file to create |
|||
* |
|||
* @return true if the file is created |
|||
*/ |
|||
bool GenDrillReportFile( const wxString& aFullFileName ); |
|||
|
|||
protected: |
|||
/** |
|||
* Function GenDrillMapFile |
|||
* Plot a map of drill marks for holes. |
|||
* Hole list must be created before calling this function, by buildHolesList() |
|||
* for the right holes set (PTH, NPTH, buried/blind vias ...) |
|||
* 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& aFullFileName, PlotFormat aFormat ); |
|||
|
|||
/** |
|||
* Function BuildHolesList |
|||
* Create the list of holes and tools for a given board |
|||
* The list is sorted by increasing drill size. |
|||
* Only holes included within aLayerPair are listed. |
|||
* If aLayerPair identifies with [F_Cu, B_Cu], then |
|||
* pad holes are always included also. |
|||
* |
|||
* @param aLayerPair is an inclusive range of layers. |
|||
* @param aGenerateNPTH_list : |
|||
* true to create NPTH only list (with no plated holes) |
|||
* false to created plated holes list (with no NPTH ) |
|||
*/ |
|||
void buildHolesList( DRILL_LAYER_PAIR aLayerPair, |
|||
bool aGenerateNPTH_list ); |
|||
|
|||
int getHolesCount() const { return m_holeListBuffer.size(); } |
|||
|
|||
/** Helper function. |
|||
* Writes the drill marks in HPGL, POSTSCRIPT or other supported formats |
|||
* Each hole size has a symbol (circle, cross X, cross + ...) up to |
|||
* PLOTTER::MARKER_COUNT different values. |
|||
* If more than PLOTTER::MARKER_COUNT different values, |
|||
* these other values share the same mark shape |
|||
* @param aPlotter = a PLOTTER instance (HPGL, POSTSCRIPT ... plotter). |
|||
*/ |
|||
bool plotDrillMarks( PLOTTER* aPlotter ); |
|||
|
|||
/// Get unique layer pairs by examining the micro and blind_buried vias. |
|||
std::vector<DRILL_LAYER_PAIR> getUniqueLayerPairs() const; |
|||
|
|||
/** |
|||
* Function printToolSummary |
|||
* prints m_toolListBuffer[] tools to aOut and returns total hole count. |
|||
* @param aOut = the current OUTPUTFORMATTER to print summary |
|||
* @param aSummaryNPTH = true to print summary for NPTH, false for PTH |
|||
*/ |
|||
unsigned printToolSummary( OUTPUTFORMATTER& aOut, bool aSummaryNPTH ) const; |
|||
|
|||
/** |
|||
* minor helper function. |
|||
* @return a string from aPair to identify the layer layer pair. |
|||
* string is "<layer1Name>"-"<layer2Name>" |
|||
* used to generate a filename for drill files and drill maps |
|||
*/ |
|||
const std::string layerPairName( DRILL_LAYER_PAIR aPair ) const; |
|||
|
|||
/** |
|||
* minor helper function. |
|||
* @return a string from aLayer to identify the layer. |
|||
* string are "front" "back" or "in<aLayer>" |
|||
*/ |
|||
const std::string layerName( PCB_LAYER_ID aLayer ) const; |
|||
|
|||
/** |
|||
* @return a filename which identify the drill file function. |
|||
* it is the board name with the layer pair names added, and for separate |
|||
* (PTH and NPTH) files, "-NPH" or "-NPTH" added |
|||
* @param aPair = the layer pair |
|||
* @param aNPTH = true to generate the filename of NPTH holes |
|||
* @param aMerge_PTH_NPTH = true to generate the filename of a file which containd both |
|||
* NPH and NPTH holes |
|||
*/ |
|||
virtual const wxString getDrillFileName( DRILL_LAYER_PAIR aPair, bool aNPTH, |
|||
bool aMerge_PTH_NPTH ) const; |
|||
}; |
|||
|
|||
#endif // #define GENDRILL_FILE_WRITER_BASE_H |
|||
|
@ -0,0 +1,328 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> |
|||
* Copyright (C) 1992-2017 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 |
|||
* 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 |
|||
*/ |
|||
|
|||
/**
|
|||
* @file gendrill_gerber_writer.cpp |
|||
* @brief Functions to create drill files in gerber X2 format. |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
|
|||
#include <vector>
|
|||
|
|||
#include <plot_common.h>
|
|||
#include <kicad_string.h>
|
|||
#include <wxPcbStruct.h>
|
|||
#include <pgm_base.h>
|
|||
#include <build_version.h>
|
|||
|
|||
#include <class_board.h>
|
|||
|
|||
#include <pcbplot.h>
|
|||
#include <pcbnew.h>
|
|||
#include <gendrill_gerber_writer.h>
|
|||
#include <wildcards_and_files_ext.h>
|
|||
#include <reporter.h>
|
|||
#include <plot_auxiliary_data.h>
|
|||
#include <class_module.h>
|
|||
|
|||
|
|||
GERBER_WRITER::GERBER_WRITER( BOARD* aPcb ) |
|||
: GENDRILL_WRITER_BASE( aPcb ) |
|||
{ |
|||
m_zeroFormat = SUPPRESS_LEADING; |
|||
m_conversionUnits = 1.0; |
|||
m_unitsDecimal = true; |
|||
m_drillFileExtension = "gbr"; |
|||
m_merge_PTH_NPTH = false; |
|||
} |
|||
|
|||
|
|||
void GERBER_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory, |
|||
bool aGenDrill, bool aGenMap, |
|||
REPORTER * aReporter ) |
|||
{ |
|||
// Note: In Gerber drill files, NPTH and PTH are always separate files
|
|||
m_merge_PTH_NPTH = false; |
|||
|
|||
wxFileName fn; |
|||
wxString msg; |
|||
|
|||
std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs(); |
|||
|
|||
// append a pair representing the NPTH set of holes, for separate drill files.
|
|||
// (Gerber drill files are separate files for PTH and NPTH)
|
|||
hole_sets.push_back( DRILL_LAYER_PAIR( F_Cu, B_Cu ) ); |
|||
|
|||
for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin(); |
|||
it != hole_sets.end(); ++it ) |
|||
{ |
|||
DRILL_LAYER_PAIR pair = *it; |
|||
// For separate drill files, the last layer pair is the NPTH drill file.
|
|||
bool doing_npth = ( it == hole_sets.end() - 1 ); |
|||
|
|||
buildHolesList( pair, doing_npth ); |
|||
|
|||
// The file is created if it has holes, or if it is the non plated drill file
|
|||
// to be sure the NPTH file is up to date in separate files mode.
|
|||
if( getHolesCount() > 0 || doing_npth ) |
|||
{ |
|||
fn = getDrillFileName( pair, doing_npth, false ); |
|||
fn.SetPath( aPlotDirectory ); |
|||
|
|||
if( aGenDrill ) |
|||
{ |
|||
wxString fullFilename = fn.GetFullPath(); |
|||
|
|||
int result = createDrillFile( fullFilename, doing_npth, pair.first, pair.second ); |
|||
|
|||
if( result < 0 ) |
|||
{ |
|||
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 ); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
if( aGenMap ) |
|||
CreateMapFilesSet( aPlotDirectory, aReporter ); |
|||
} |
|||
|
|||
// A helper class to transform an oblong hole to a segment
|
|||
static void convertOblong2Segment( wxSize aSize, double aOrient, wxPoint& aStart, wxPoint& aEnd ); |
|||
|
|||
int GERBER_WRITER::createDrillFile( wxString& aFullFilename, bool aIsNpth, |
|||
int aLayer1, int aLayer2 ) |
|||
{ |
|||
int holes_count; |
|||
|
|||
LOCALE_IO dummy; // Use the standard notation for double numbers
|
|||
|
|||
GERBER_PLOTTER plotter; |
|||
|
|||
// Gerber drill file imply X2 format:
|
|||
plotter.UseX2Attributes( true ); |
|||
plotter.UseX2NetAttributes( true ); |
|||
|
|||
// Add the standard X2 header, without FileFunction
|
|||
AddGerberX2Header( &plotter, m_pcb ); |
|||
plotter.SetViewport( m_offset, IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false ); |
|||
// has meaning only for gerber plotter. Must be called only after SetViewport
|
|||
plotter.SetGerberCoordinatesFormat( 6 ); |
|||
plotter.SetCreator( wxT( "PCBNEW" ) ); |
|||
|
|||
// Add the standard X2 FileFunction for drill files
|
|||
// %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Route][Mixed]*%
|
|||
wxString text( "%TF.FileFunction," ); |
|||
|
|||
if( aIsNpth ) |
|||
text << "NonPlated,"; |
|||
else |
|||
text << "Plated,"; |
|||
|
|||
// In Gerber files, layers num are 1 to copper layer count instead of F_Cu to B_Cu
|
|||
// (0 to copper layer count-1)
|
|||
// Note also for a n copper layers board, gerber layers num are 1 ... n
|
|||
aLayer1 += 1; |
|||
|
|||
if( aLayer2 == B_Cu ) |
|||
aLayer2 = m_pcb->GetCopperLayerCount(); |
|||
else |
|||
aLayer2 += 1; |
|||
|
|||
text << aLayer1 << ","; |
|||
text << aLayer2 << ","; |
|||
|
|||
// Now add PTH or NPTH or Blind or Buried attribute
|
|||
int toplayer = 1; |
|||
int bottomlayer = m_pcb->GetCopperLayerCount(); |
|||
|
|||
if( aIsNpth ) |
|||
text << "NPTH"; |
|||
else if( aLayer1 == toplayer && aLayer2 == bottomlayer ) |
|||
text << "PTH"; |
|||
else if( aLayer1 == toplayer || aLayer2 == bottomlayer ) |
|||
text << "Blind"; |
|||
else |
|||
text << "Buried"; |
|||
|
|||
// Now add Drill or Route or Mixed:
|
|||
// file containing only round holes have Drill attribute
|
|||
// file containing only oblong holes have Routed attribute
|
|||
// file containing both holes have Mixed attribute
|
|||
bool hasOblong = false; |
|||
bool hasDrill = false; |
|||
|
|||
for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) |
|||
{ |
|||
HOLE_INFO& hole_descr = m_holeListBuffer[ii]; |
|||
|
|||
if( hole_descr.m_Hole_Shape ) // m_Hole_Shape not 0 is an oblong hole)
|
|||
hasOblong = true; |
|||
else |
|||
hasDrill = true; |
|||
} |
|||
|
|||
if( hasOblong && hasDrill ) |
|||
text << ",Mixed"; |
|||
else if( hasDrill ) |
|||
text << ",Drill"; |
|||
else if( hasOblong ) |
|||
text << ",Route"; |
|||
|
|||
// else: empty file.
|
|||
|
|||
// End of attribute:
|
|||
text << "*%"; |
|||
|
|||
plotter.AddLineToHeader( text ); |
|||
|
|||
if( !plotter.OpenFile( aFullFilename ) ) |
|||
return -1; |
|||
|
|||
plotter.StartPlot(); |
|||
|
|||
holes_count = 0; |
|||
|
|||
wxPoint hole_pos; |
|||
|
|||
for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) |
|||
{ |
|||
HOLE_INFO& hole_descr = m_holeListBuffer[ii]; |
|||
hole_pos = hole_descr.m_Hole_Pos; |
|||
|
|||
// Manage the aperture attributes: in drill files 3 attributes can be used:
|
|||
// "ViaDrill", only for vias, not pads
|
|||
// "ComponentDrill", only for Through Holes pads
|
|||
// "Slot" for oblong holes;
|
|||
GBR_METADATA gbr_metadata; |
|||
|
|||
if( dyn_cast<const VIA*>(hole_descr.m_ItemParent ) ) |
|||
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_VIADRILL ); |
|||
else if( dyn_cast<const D_PAD*>( hole_descr.m_ItemParent ) ) |
|||
{ |
|||
if( hole_descr.m_Hole_Shape ) |
|||
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_SLOTDRILL ); |
|||
else |
|||
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_COMPONENTDRILL ); |
|||
|
|||
// Add object attribute: component reference to pads (mainly usefull for users)
|
|||
const D_PAD* pad = dyn_cast<const D_PAD*>( hole_descr.m_ItemParent ); |
|||
gbr_metadata.SetCmpReference( pad->GetParent()->GetReference() ); |
|||
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP ); |
|||
} |
|||
|
|||
if( hole_descr.m_Hole_Shape ) |
|||
{ |
|||
#if 0 // set to 1 to use flashed oblong holes.
|
|||
// Currently not possible for hole orient != 0 or 90 deg
|
|||
// Use flashed oblong hole
|
|||
plotter.FlashPadOval( hole_pos, hole_descr.m_Hole_Size, |
|||
hole_descr.m_Hole_Orient, FILLED, &gbr_metadata ); |
|||
#else
|
|||
// Use routing for oblong hole (Slots)
|
|||
wxPoint start, end; |
|||
convertOblong2Segment( hole_descr.m_Hole_Size, |
|||
hole_descr.m_Hole_Orient, start, end ); |
|||
int width = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y ); |
|||
plotter.ThickSegment( start+hole_pos, end+hole_pos, |
|||
width, FILLED, &gbr_metadata ); |
|||
#endif
|
|||
} |
|||
else |
|||
{ |
|||
int diam = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y ); |
|||
plotter.FlashPadCircle( hole_pos, diam, FILLED, &gbr_metadata ); |
|||
} |
|||
|
|||
holes_count++; |
|||
} |
|||
|
|||
plotter.EndPlot(); |
|||
|
|||
return holes_count; |
|||
} |
|||
|
|||
|
|||
void convertOblong2Segment( wxSize aSize, double aOrient, wxPoint& aStart, wxPoint& aEnd ) |
|||
{ |
|||
wxSize size( aSize ); |
|||
double orient = aOrient; |
|||
|
|||
/* The pad will be drawn as an oblong shape with size.y > size.x
|
|||
* (Oval vertical orientation 0) |
|||
*/ |
|||
if( size.x > size.y ) |
|||
{ |
|||
std::swap( size.x, size.y ); |
|||
orient = AddAngles( orient, 900 ); |
|||
} |
|||
|
|||
int deltaxy = size.y - size.x; // distance between centers of the oval
|
|||
|
|||
int cx = 0; |
|||
int cy = deltaxy / 2; |
|||
RotatePoint( &cx, &cy, orient ); |
|||
aStart = wxPoint( cx, cy ); |
|||
cx = 0; cy = -deltaxy / 2; |
|||
RotatePoint( &cx, &cy, orient ); |
|||
aEnd = wxPoint( cx, cy ); |
|||
} |
|||
|
|||
|
|||
void GERBER_WRITER::SetFormat( int aRightDigits ) |
|||
{ |
|||
/* Set conversion scale depending on drill file units */ |
|||
m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm
|
|||
|
|||
// Set precison (unit is mm).
|
|||
m_precision.m_lhs = 4; |
|||
m_precision.m_rhs = aRightDigits == 6 ? 6 : 5; |
|||
} |
|||
|
|||
|
|||
const wxString GERBER_WRITER::getDrillFileName( DRILL_LAYER_PAIR aPair, bool aNPTH, |
|||
bool aMerge_PTH_NPTH ) const |
|||
{ |
|||
// Gerber files extension is always .gbr.
|
|||
// Therefore, to mark drill files, add "-drl" to the filename.
|
|||
wxFileName fname( GENDRILL_WRITER_BASE::getDrillFileName( aPair, aNPTH, aMerge_PTH_NPTH ) ); |
|||
fname.SetName( fname.GetName() + "-drl" ); |
|||
|
|||
return fname.GetFullPath(); |
|||
} |
@ -0,0 +1,107 @@ |
|||
/** |
|||
* @file gendrill_gerber_writer.h |
|||
* @brief Classes used in drill files, map files and report files generation. |
|||
*/ |
|||
|
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 1992-2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> |
|||
* Copyright (C) 1992-2017 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 |
|||
* 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 |
|||
*/ |
|||
|
|||
#ifndef _GENDRILL_GERBER_WRITER_ |
|||
#define _GENDRILL_GERBER_WRITER_ |
|||
|
|||
#include <gendrill_file_writer_base.h> |
|||
|
|||
class BOARD; |
|||
|
|||
/** |
|||
* GERBER_WRITER is a class mainly used to create Gerber drill files |
|||
*/ |
|||
class GERBER_WRITER: public GENDRILL_WRITER_BASE |
|||
{ |
|||
public: |
|||
GERBER_WRITER( BOARD* aPcb ); |
|||
|
|||
~GERBER_WRITER() |
|||
{ |
|||
} |
|||
|
|||
/** |
|||
* Function SetFormat |
|||
* Initialize internal parameters to match the given format |
|||
* @param aRightDigits = number of digits for mantissa part of coordinates (5 or 6) |
|||
*/ |
|||
void SetFormat( int aRightDigits = 6 ); |
|||
|
|||
/** |
|||
* Function SetOptions |
|||
* Initialize internal parameters to match drill options |
|||
* note: PTH and NPTH are always separate files in Gerber format |
|||
* @param aOffset = drill coordinates offset |
|||
*/ |
|||
void SetOptions( wxPoint aOffset ) |
|||
{ |
|||
m_offset = aOffset; |
|||
m_merge_PTH_NPTH = false; |
|||
} |
|||
|
|||
/** |
|||
* 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 ); |
|||
|
|||
private: |
|||
/** |
|||
* Function createDrillFile |
|||
* Creates an Excellon drill file |
|||
* @param aFullFilename = the full filename |
|||
* @param aIsNpth = true for a NPTH file, false for a PTH file |
|||
* @param aLayer1 = the first board layer |
|||
* @param aLayer2 = the last board layer |
|||
* for blind buried vias, they are not always top and bottom layers |
|||
* @return hole count, or -1 if the file cannot be created |
|||
*/ |
|||
int createDrillFile( wxString& aFullFilename, bool aIsNpth, int aLayer1, int aLayer2 ); |
|||
|
|||
/** |
|||
* @return a filename which identify the drill file function. |
|||
* it is the board name with the layer pair names added, and for separate |
|||
* (PTH and NPTH) files, "-NPH" or "-NPTH" added |
|||
* @param aPair = the layer pair |
|||
* @param aNPTH = true to generate the filename of NPTH holes |
|||
* @param aMerge_PTH_NPTH = true to generate the filename of a file which containd both |
|||
* NPH and NPTH holes |
|||
*/ |
|||
virtual const wxString getDrillFileName( DRILL_LAYER_PAIR aPair, bool aNPTH, |
|||
bool aMerge_PTH_NPTH ) const override; |
|||
}; |
|||
|
|||
#endif // #ifndef _GENDRILL_GERBER_WRITER_ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue