KiCad PCB EDA Suite
EXCELLON_WRITER Class Reference

Create Excellon drill, drill map, and drill report files. More...

#include <gendrill_Excellon_writer.h>

Inheritance diagram for EXCELLON_WRITER:
GENDRILL_WRITER_BASE

Public Types

enum  ZEROS_FMT { DECIMAL_FORMAT, SUPPRESS_LEADING, SUPPRESS_TRAILING, KEEP_ZEROS }
 
enum  TYPE_FILE { PTH_FILE, NPTH_FILE, MIXED_FILE }
 

Public Member Functions

 EXCELLON_WRITER (BOARD *aPcb)
 
virtual ~EXCELLON_WRITER ()
 
wxPoint GetOffset ()
 Return the plot offset (usually the position of the auxiliary axis. More...
 
void SetRouteModeForOvalHoles (bool aUseRouteModeForOvalHoles)
 
void SetFormat (bool aMetric, ZEROS_FMT aZerosFmt=DECIMAL_FORMAT, int aLeftDigits=0, int aRightDigits=0)
 Initialize internal parameters to match the given format. More...
 
void SetOptions (bool aMirror, bool aMinimalHeader, const wxPoint &aOffset, bool aMerge_PTH_NPTH)
 Initialize internal parameters to match drill options. More...
 
void CreateDrillandMapFilesSet (const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
 Create the full set of Excellon drill file for the board. More...
 
void SetMergeOption (bool aMerge)
 Set the option to make separate drill files for PTH and NPTH. More...
 
void SetPageInfo (const PAGE_INFO *aPageInfo)
 Set the page info used to plot drill maps. More...
 
void SetMapFileFormat (PLOT_FORMAT aMapFmt)
 Initialize the format for the drill map file. More...
 
void CreateMapFilesSet (const wxString &aPlotDirectory, REPORTER *aReporter=nullptr)
 Create the full set of map files for the board, in PS, PDF ... More...
 
bool GenDrillReportFile (const wxString &aFullFileName)
 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. More...
 

Protected Member Functions

bool genDrillMapFile (const wxString &aFullFileName, PLOT_FORMAT aFormat)
 Plot a map of drill marks for holes. More...
 
void buildHolesList (DRILL_LAYER_PAIR aLayerPair, bool aGenerateNPTH_list)
 Create the list of holes and tools for a given board. More...
 
int getHolesCount () const
 
bool plotDrillMarks (PLOTTER *aPlotter)
 Write the drill marks in HPGL, POSTSCRIPT or other supported formats/. More...
 
std::vector< DRILL_LAYER_PAIRgetUniqueLayerPairs () const
 Get unique layer pairs by examining the micro and blind_buried vias. More...
 
unsigned printToolSummary (OUTPUTFORMATTER &aOut, bool aSummaryNPTH) const
 Print m_toolListBuffer[] tools to aOut and returns total hole count. More...
 
const std::string layerPairName (DRILL_LAYER_PAIR aPair) const
 
const std::string layerName (PCB_LAYER_ID aLayer) const
 
virtual const wxString getDrillFileName (DRILL_LAYER_PAIR aPair, bool aNPTH, bool aMerge_PTH_NPTH) const
 
const wxString BuildFileFunctionAttributeString (DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHoleType, bool aCompatNCdrill=false) const
 

Protected Attributes

BOARDm_pcb
 
wxString m_drillFileExtension
 
bool m_unitsMetric
 
ZEROS_FMT m_zeroFormat
 
DRILL_PRECISION m_precision
 
double m_conversionUnits
 
wxPoint m_offset
 
bool m_merge_PTH_NPTH
 
std::vector< HOLE_INFOm_holeListBuffer
 
std::vector< DRILL_TOOLm_toolListBuffer
 
PLOT_FORMAT m_mapFileFmt
 
const PAGE_INFOm_pageInfo
 

Private Member Functions

int createDrillFile (FILE *aFile, DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHolesType)
 Create an Excellon drill file. More...
 
void writeEXCELLONHeader (DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHolesType)
 Print the DRILL file header. More...
 
void writeEXCELLONEndOfFile ()
 
void writeCoordinates (char *aLine, double aCoordX, double aCoordY)
 Create a line like according to the selected format. More...
 
void writeHoleAttribute (HOLE_ATTRIBUTE aAttribute)
 Write a comment string giving the hole attribute. More...
 

Private Attributes

FILE * m_file
 
bool m_minimalHeader
 
bool m_mirror
 
bool m_useRouteModeForOval
 

Detailed Description

Create Excellon drill, drill map, and drill report files.

Definition at line 44 of file gendrill_Excellon_writer.h.

Member Enumeration Documentation

◆ TYPE_FILE

Enumerator
PTH_FILE 
NPTH_FILE 
MIXED_FILE 

Definition at line 162 of file gendrill_file_writer_base.h.

162  { // type of holes in file: PTH, NPTH, mixed
163  PTH_FILE, // PTH only, this is the default also for blind/buried holes
164  NPTH_FILE, // NPTH only
165  MIXED_FILE // PHT+NPTH (mixed)
166  };

◆ ZEROS_FMT

Enumerator
DECIMAL_FORMAT 
SUPPRESS_LEADING 
SUPPRESS_TRAILING 
KEEP_ZEROS 

Definition at line 155 of file gendrill_file_writer_base.h.

155  { // Zero format in coordinates
156  DECIMAL_FORMAT, // Floating point coordinates
157  SUPPRESS_LEADING, // Suppress leading zeros
158  SUPPRESS_TRAILING, // Suppress trailing zeros
159  KEEP_ZEROS // keep zeros
160  };

Constructor & Destructor Documentation

◆ EXCELLON_WRITER()

EXCELLON_WRITER::EXCELLON_WRITER ( BOARD aPcb)
See also
for EXCELLON format, see: http://www.excellon.com/manuals/program.htm and the CNC-7 manual.

Definition at line 62 of file gendrill_Excellon_writer.cpp.

References GENDRILL_WRITER_BASE::DECIMAL_FORMAT, DrillFileExtension, GENDRILL_WRITER_BASE::m_conversionUnits, GENDRILL_WRITER_BASE::m_drillFileExtension, m_file, GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, m_minimalHeader, m_mirror, m_useRouteModeForOval, and GENDRILL_WRITER_BASE::m_zeroFormat.

◆ ~EXCELLON_WRITER()

virtual EXCELLON_WRITER::~EXCELLON_WRITER ( )
inlinevirtual

Definition at line 49 of file gendrill_Excellon_writer.h.

50  {
51  }

Member Function Documentation

◆ BuildFileFunctionAttributeString()

const wxString GENDRILL_WRITER_BASE::BuildFileFunctionAttributeString ( DRILL_LAYER_PAIR  aLayerPair,
TYPE_FILE  aHoleType,
bool  aCompatNCdrill = false 
) const
protectedinherited
Parameters
aLayerPairis the layer pair (Drill from rom first layer to second layer)
aHoleTypeis type of drill file (PTH, NPTH, mixed)
aCompatNCdrillis true when generating NC (Excellon) compatible drill file
Returns
a wxString containing the .FileFunction attribute. the standard X2 FileFunction for drill files is TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried], Drill[Route][Mixed]*% There is no X1 version, as the Gerber drill files uses only X2 format There is a compatible NC drill version.

Definition at line 363 of file gendrill_file_writer_base.cpp.

366 {
367 // Build a wxString containing the .FileFunction attribute for drill files.
368 // %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Route][Mixed]*%
369  wxString text;
370 
371  if( aCompatNCdrill )
372  text = wxT( "; #@! " );
373  else
374  text = wxT( "%" );
375 
376  text << wxT( "TF.FileFunction," );
377 
378  if( aHoleType == NPTH_FILE )
379  text << wxT( "NonPlated," );
380  else if( aHoleType == MIXED_FILE ) // only for Excellon format
381  text << wxT( "MixedPlating," );
382  else
383  text << wxT( "Plated," );
384 
385  int layer1 = aLayerPair.first;
386  int layer2 = aLayerPair.second;
387  // In Gerber files, layers num are 1 to copper layer count instead of F_Cu to B_Cu
388  // (0 to copper layer count-1)
389  // Note also for a n copper layers board, gerber layers num are 1 ... n
390  layer1 += 1;
391 
392  if( layer2 == B_Cu )
393  layer2 = m_pcb->GetCopperLayerCount();
394  else
395  layer2 += 1;
396 
397  text << layer1 << wxT( "," ) << layer2;
398 
399  // Now add PTH or NPTH or Blind or Buried attribute
400  int toplayer = 1;
401  int bottomlayer = m_pcb->GetCopperLayerCount();
402 
403  if( aHoleType == NPTH_FILE )
404  text << wxT( ",NPTH" );
405  else if( aHoleType == MIXED_FILE ) // only for Excellon format
406  {
407  // write nothing
408  }
409  else if( layer1 == toplayer && layer2 == bottomlayer )
410  text << wxT( ",PTH" );
411  else if( layer1 == toplayer || layer2 == bottomlayer )
412  text << wxT( ",Blind" );
413  else
414  text << wxT( ",Buried" );
415 
416  // In NC drill file, these previous parameters should be enough:
417  if( aCompatNCdrill )
418  return text;
419 
420 
421  // Now add Drill or Route or Mixed:
422  // file containing only round holes have Drill attribute
423  // file containing only oblong holes have Routed attribute
424  // file containing both holes have Mixed attribute
425  bool hasOblong = false;
426  bool hasDrill = false;
427 
428  for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
429  {
430  const HOLE_INFO& hole_descr = m_holeListBuffer[ii];
431 
432  if( hole_descr.m_Hole_Shape ) // m_Hole_Shape not 0 is an oblong hole)
433  hasOblong = true;
434  else
435  hasDrill = true;
436  }
437 
438  if( hasOblong && hasDrill )
439  text << wxT( ",Mixed" );
440  else if( hasDrill )
441  text << wxT( ",Drill" );
442  else if( hasOblong )
443  text << wxT( ",Route" );
444 
445  // else: empty file.
446 
447  // End of .FileFunction attribute:
448  text << wxT( "*%" );
449 
450  return text;
451 }
Handle hole which must be drilled (diameter, position and layers).
int GetCopperLayerCount() const
Definition: board.cpp:455
std::vector< HOLE_INFO > m_holeListBuffer

References B_Cu, BOARD::GetCopperLayerCount(), HOLE_INFO::m_Hole_Shape, GENDRILL_WRITER_BASE::m_holeListBuffer, GENDRILL_WRITER_BASE::m_pcb, GENDRILL_WRITER_BASE::MIXED_FILE, GENDRILL_WRITER_BASE::NPTH_FILE, and text.

Referenced by GERBER_WRITER::createDrillFile(), and writeEXCELLONHeader().

◆ buildHolesList()

void GENDRILL_WRITER_BASE::buildHolesList ( DRILL_LAYER_PAIR  aLayerPair,
bool  aGenerateNPTH_list 
)
protectedinherited

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.

Parameters
aLayerPairis an inclusive range of layers.
aGenerateNPTH_list: true to create NPTH only list (with no plated holes) false to created plated holes list (with no NPTH )

Definition at line 66 of file gendrill_file_writer_base.cpp.

68 {
69  HOLE_INFO new_hole;
70 
71  m_holeListBuffer.clear();
72  m_toolListBuffer.clear();
73 
74  wxASSERT( aLayerPair.first < aLayerPair.second ); // fix the caller
75 
76  // build hole list for vias
77  if( ! aGenerateNPTH_list ) // vias are always plated !
78  {
79  for( auto track : m_pcb->Tracks() )
80  {
81  if( track->Type() != PCB_VIA_T )
82  continue;
83 
84  PCB_VIA* via = static_cast<PCB_VIA*>( track );
85  int hole_sz = via->GetDrillValue();
86 
87  if( hole_sz == 0 ) // Should not occur.
88  continue;
89 
90  new_hole.m_ItemParent = via;
91 
92  if( aLayerPair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
94  else
96 
97  new_hole.m_Tool_Reference = -1; // Flag value for Not initialized
98  new_hole.m_Hole_Orient = 0;
99  new_hole.m_Hole_Diameter = hole_sz;
100  new_hole.m_Hole_NotPlated = false;
101  new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;
102 
103  new_hole.m_Hole_Shape = 0; // hole shape: round
104  new_hole.m_Hole_Pos = via->GetStart();
105 
106  via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer );
107 
108  // LayerPair() returns params with m_Hole_Bottom_Layer > m_Hole_Top_Layer
109  // Remember: top layer = 0 and bottom layer = 31 for through hole vias
110  // Any captured via should be from aLayerPair.first to aLayerPair.second exactly.
111  if( new_hole.m_Hole_Top_Layer != aLayerPair.first ||
112  new_hole.m_Hole_Bottom_Layer != aLayerPair.second )
113  continue;
114 
115  m_holeListBuffer.push_back( new_hole );
116  }
117  }
118 
119  if( aLayerPair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
120  {
121  // add holes for thru hole pads
122  for( FOOTPRINT* footprint : m_pcb->Footprints() )
123  {
124  for( PAD* pad : footprint->Pads() )
125  {
126  if( !m_merge_PTH_NPTH )
127  {
128  if( !aGenerateNPTH_list && pad->GetAttribute() == PAD_ATTRIB::NPTH )
129  continue;
130 
131  if( aGenerateNPTH_list && pad->GetAttribute() != PAD_ATTRIB::NPTH )
132  continue;
133  }
134 
135  if( pad->GetDrillSize().x == 0 )
136  continue;
137 
138  new_hole.m_ItemParent = pad;
139  new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_ATTRIB::NPTH);
140  new_hole.m_HoleAttribute = new_hole.m_Hole_NotPlated
143  new_hole.m_Tool_Reference = -1; // Flag is: Not initialized
144  new_hole.m_Hole_Orient = pad->GetOrientation();
145  new_hole.m_Hole_Shape = 0; // hole shape: round
146  new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
147  new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter;
148 
149  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
150  new_hole.m_Hole_Shape = 1; // oval flag set
151 
152  new_hole.m_Hole_Size = pad->GetDrillSize();
153  new_hole.m_Hole_Pos = pad->GetPosition(); // hole position
154  new_hole.m_Hole_Bottom_Layer = B_Cu;
155  new_hole.m_Hole_Top_Layer = F_Cu; // pad holes are through holes
156  m_holeListBuffer.push_back( new_hole );
157  }
158  }
159  }
160 
161  // Sort holes per increasing diameter value (and for each dimater, by position)
162  sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), cmpHoleSorting );
163 
164  // build the tool list
165  int last_hole = -1; // Set to not initialized (this is a value not used
166  // for m_holeListBuffer[ii].m_Hole_Diameter)
167  bool last_notplated_opt = false;
169 
170  DRILL_TOOL new_tool( 0, false );
171  unsigned jj;
172 
173  for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
174  {
175  if( m_holeListBuffer[ii].m_Hole_Diameter != last_hole
176  || m_holeListBuffer[ii].m_Hole_NotPlated != last_notplated_opt
178  || m_holeListBuffer[ii].m_HoleAttribute != last_attribute
179 #endif
180  )
181  {
182  new_tool.m_Diameter = m_holeListBuffer[ii].m_Hole_Diameter;
183  new_tool.m_Hole_NotPlated = m_holeListBuffer[ii].m_Hole_NotPlated;
184  new_tool.m_HoleAttribute = m_holeListBuffer[ii].m_HoleAttribute;
185  m_toolListBuffer.push_back( new_tool );
186  last_hole = new_tool.m_Diameter;
187  last_notplated_opt = new_tool.m_Hole_NotPlated;
188  last_attribute = new_tool.m_HoleAttribute;
189  }
190 
191  jj = m_toolListBuffer.size();
192 
193  if( jj == 0 )
194  continue; // Should not occurs
195 
196  m_holeListBuffer[ii].m_Tool_Reference = jj; // Tool value Initialized (value >= 1)
197 
198  m_toolListBuffer.back().m_TotalCount++;
199 
200  if( m_holeListBuffer[ii].m_Hole_Shape )
201  m_toolListBuffer.back().m_OvalCount++;
202  }
203 }
BOARD_ITEM * m_ItemParent
#define USE_ATTRIB_FOR_HOLES
std::vector< DRILL_TOOL > m_toolListBuffer
like PAD_PTH, but not plated
FOOTPRINTS & Footprints()
Definition: board.h:234
Handle hole which must be drilled (diameter, position and layers).
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
PCB_LAYER_ID m_Hole_Bottom_Layer
HOLE_ATTRIBUTE m_HoleAttribute
PCB_LAYER_ID m_Hole_Top_Layer
Definition: layer_ids.h:71
static bool cmpHoleSorting(const HOLE_INFO &a, const HOLE_INFO &b)
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
Definition: pad.h:57
std::vector< HOLE_INFO > m_holeListBuffer
TRACKS & Tracks()
Definition: board.h:231

References B_Cu, cmpHoleSorting(), F_Cu, BOARD::Footprints(), HOLE_MECHANICAL, HOLE_PAD, HOLE_UNKNOWN, HOLE_VIA_BURIED, HOLE_VIA_THROUGH, DRILL_TOOL::m_Diameter, HOLE_INFO::m_Hole_Bottom_Layer, HOLE_INFO::m_Hole_Diameter, DRILL_TOOL::m_Hole_NotPlated, HOLE_INFO::m_Hole_NotPlated, HOLE_INFO::m_Hole_Orient, HOLE_INFO::m_Hole_Pos, HOLE_INFO::m_Hole_Shape, HOLE_INFO::m_Hole_Size, HOLE_INFO::m_Hole_Top_Layer, DRILL_TOOL::m_HoleAttribute, HOLE_INFO::m_HoleAttribute, GENDRILL_WRITER_BASE::m_holeListBuffer, HOLE_INFO::m_ItemParent, GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, GENDRILL_WRITER_BASE::m_pcb, HOLE_INFO::m_Tool_Reference, GENDRILL_WRITER_BASE::m_toolListBuffer, NPTH, pad, PAD_DRILL_SHAPE_CIRCLE, PCB_VIA_T, BOARD::Tracks(), USE_ATTRIB_FOR_HOLES, and via.

Referenced by GERBER_WRITER::CreateDrillandMapFilesSet(), CreateDrillandMapFilesSet(), GENDRILL_WRITER_BASE::CreateMapFilesSet(), and GENDRILL_WRITER_BASE::GenDrillReportFile().

◆ CreateDrillandMapFilesSet()

void EXCELLON_WRITER::CreateDrillandMapFilesSet ( const wxString &  aPlotDirectory,
bool  aGenDrill,
bool  aGenMap,
REPORTER aReporter = nullptr 
)

Create the full set of Excellon drill file for the board.

File names are computed from the board name and layer ID.

Parameters
aPlotDirectoryis the output folder.
aGenDrillset to true to generate the EXCELLON drill file.
aGenMapset to true to generate a drill map file.
aReporteris a REPORTER to return activity or any message (can be NULL)

Definition at line 76 of file gendrill_Excellon_writer.cpp.

78 {
79  wxFileName fn;
80  wxString msg;
81 
82  std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();
83 
84  // append a pair representing the NPTH set of holes, for separate drill files.
85  if( !m_merge_PTH_NPTH )
86  hole_sets.emplace_back( F_Cu, B_Cu );
87 
88  for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin();
89  it != hole_sets.end(); ++it )
90  {
91  DRILL_LAYER_PAIR pair = *it;
92  // For separate drill files, the last layer pair is the NPTH drill file.
93  bool doing_npth = m_merge_PTH_NPTH ? false : ( it == hole_sets.end() - 1 );
94 
95  buildHolesList( pair, doing_npth );
96 
97  // The file is created if it has holes, or if it is the non plated drill file to be
98  // sure the NPTH file is up to date in separate files mode.
99  // Also a PTH drill/map file is always created, to be sure at least one plated hole
100  // drill file is created (do not create any PTH drill file can be seen as not working
101  // drill generator).
102  if( getHolesCount() > 0 || doing_npth || pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
103  {
104  fn = getDrillFileName( pair, doing_npth, m_merge_PTH_NPTH );
105  fn.SetPath( aPlotDirectory );
106 
107  if( aGenDrill )
108  {
109  wxString fullFilename = fn.GetFullPath();
110 
111  FILE* file = wxFopen( fullFilename, wxT( "w" ) );
112 
113  if( file == nullptr )
114  {
115  if( aReporter )
116  {
117  msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
118  aReporter->Report( msg, RPT_SEVERITY_ERROR );
119  }
120 
121  break;
122  }
123  else
124  {
125  if( aReporter )
126  {
127  msg.Printf( _( "Created file '%s'" ), fullFilename );
128  aReporter->Report( msg, RPT_SEVERITY_ACTION );
129  }
130  }
131 
132  TYPE_FILE file_type = TYPE_FILE::PTH_FILE;
133 
134  // Only external layer pair can have non plated hole
135  // internal layers have only plated via holes
136  if( pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
137  {
138  if( m_merge_PTH_NPTH )
139  file_type = TYPE_FILE::MIXED_FILE;
140  else if( doing_npth )
141  file_type = TYPE_FILE::NPTH_FILE;
142  }
143 
144  createDrillFile( file, pair, file_type );
145  }
146  }
147  }
148 
149  if( aGenMap )
150  CreateMapFilesSet( aPlotDirectory, aReporter );
151 
152  if( aReporter )
153  aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
154 }
virtual const wxString getDrillFileName(DRILL_LAYER_PAIR aPair, bool aNPTH, bool aMerge_PTH_NPTH) const
void CreateMapFilesSet(const wxString &aPlotDirectory, REPORTER *aReporter=nullptr)
Create the full set of map files for the board, in PS, PDF ...
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition: reporter.h:99
std::vector< DRILL_LAYER_PAIR > getUniqueLayerPairs() const
Get unique layer pairs by examining the micro and blind_buried vias.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
#define _(s)
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
void buildHolesList(DRILL_LAYER_PAIR aLayerPair, bool aGenerateNPTH_list)
Create the list of holes and tools for a given board.
int createDrillFile(FILE *aFile, DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHolesType)
Create an Excellon drill file.
Definition: layer_ids.h:71

References _, B_Cu, GENDRILL_WRITER_BASE::buildHolesList(), createDrillFile(), GENDRILL_WRITER_BASE::CreateMapFilesSet(), F_Cu, GENDRILL_WRITER_BASE::getDrillFileName(), GENDRILL_WRITER_BASE::getHolesCount(), GENDRILL_WRITER_BASE::getUniqueLayerPairs(), GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, REPORTER::Report(), REPORTER::ReportTail(), RPT_SEVERITY_ACTION, RPT_SEVERITY_ERROR, and RPT_SEVERITY_INFO.

Referenced by DIALOG_GENDRILL::GenDrillAndMapFiles().

◆ createDrillFile()

int EXCELLON_WRITER::createDrillFile ( FILE *  aFile,
DRILL_LAYER_PAIR  aLayerPair,
TYPE_FILE  aHolesType 
)
private

Create an Excellon drill file.

Parameters
aFileis an opened file to write to will be closed by CreateDrillFile.
aLayerPairis the layer pair for the current holes.
aHolesTypeis the holes type (PTH, NPTH, mixed).
Returns
the hole count.

Definition at line 190 of file gendrill_Excellon_writer.cpp.

192 {
193  m_file = aFile;
194 
195  int diam, holes_count;
196  int x0, y0, xf, yf, xc, yc;
197  double xt, yt;
198  char line[1024];
199 
200  LOCALE_IO dummy; // Use the standard notation for double numbers
201 
202  writeEXCELLONHeader( aLayerPair, aHolesType );
203 
204  holes_count = 0;
205 
206  /* Write the tool list */
207  for( unsigned ii = 0; ii < m_toolListBuffer.size(); ii++ )
208  {
209  DRILL_TOOL& tool_descr = m_toolListBuffer[ii];
210 
211 #if USE_ATTRIB_FOR_HOLES
212  writeHoleAttribute( tool_descr.m_HoleAttribute );
213 #endif
214 
215  // if units are mm, the resolution is 0.001 mm (3 digits in mantissa)
216  // if units are inches, the resolution is 0.1 mil (4 digits in mantissa)
217  if( m_unitsMetric )
218  fprintf( m_file, "T%dC%.3f\n", ii + 1, tool_descr.m_Diameter * m_conversionUnits );
219  else
220  fprintf( m_file, "T%dC%.4f\n", ii + 1, tool_descr.m_Diameter * m_conversionUnits );
221  }
222 
223  fputs( "%\n", m_file ); // End of header info
224  fputs( "G90\n", m_file ); // Absolute mode
225  fputs( "G05\n", m_file ); // Drill mode
226 
227  /* Read the hole list and generate data for normal holes (oblong
228  * holes will be created later) */
229  int tool_reference = -2;
230 
231  for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
232  {
233  HOLE_INFO& hole_descr = m_holeListBuffer[ii];
234 
235  if( hole_descr.m_Hole_Shape )
236  continue; // oblong holes will be created later
237 
238  if( tool_reference != hole_descr.m_Tool_Reference )
239  {
240  tool_reference = hole_descr.m_Tool_Reference;
241  fprintf( m_file, "T%d\n", tool_reference );
242  }
243 
244  x0 = hole_descr.m_Hole_Pos.x - m_offset.x;
245  y0 = hole_descr.m_Hole_Pos.y - m_offset.y;
246 
247  if( !m_mirror )
248  y0 *= -1;
249 
250  xt = x0 * m_conversionUnits;
251  yt = y0 * m_conversionUnits;
252  writeCoordinates( line, xt, yt );
253 
254  fputs( line, m_file );
255  holes_count++;
256  }
257 
258  /* Read the hole list and generate data for oblong holes
259  */
260  tool_reference = -2; // set to a value not used for
261  // m_holeListBuffer[ii].m_Tool_Reference
262 
263  for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
264  {
265  HOLE_INFO& hole_descr = m_holeListBuffer[ii];
266 
267  if( hole_descr.m_Hole_Shape == 0 )
268  continue; // wait for oblong holes
269 
270  if( tool_reference != hole_descr.m_Tool_Reference )
271  {
272  tool_reference = hole_descr.m_Tool_Reference;
273  fprintf( m_file, "T%d\n", tool_reference );
274  }
275 
276  diam = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y );
277 
278  if( diam == 0 )
279  continue;
280 
281  /* Compute the hole coordinates: */
282  xc = x0 = xf = hole_descr.m_Hole_Pos.x - m_offset.x;
283  yc = y0 = yf = hole_descr.m_Hole_Pos.y - m_offset.y;
284 
285  /* Compute the start and end coordinates for the shape */
286  if( hole_descr.m_Hole_Size.x < hole_descr.m_Hole_Size.y )
287  {
288  int delta = ( hole_descr.m_Hole_Size.y - hole_descr.m_Hole_Size.x ) / 2;
289  y0 -= delta;
290  yf += delta;
291  }
292  else
293  {
294  int delta = ( hole_descr.m_Hole_Size.x - hole_descr.m_Hole_Size.y ) / 2;
295  x0 -= delta;
296  xf += delta;
297  }
298 
299  RotatePoint( &x0, &y0, xc, yc, hole_descr.m_Hole_Orient );
300  RotatePoint( &xf, &yf, xc, yc, hole_descr.m_Hole_Orient );
301 
302  if( !m_mirror )
303  {
304  y0 *= -1;
305  yf *= -1;
306  }
307 
308  xt = x0 * m_conversionUnits;
309  yt = y0 * m_conversionUnits;
310 
312  fputs( "G00", m_file ); // Select the routing mode
313 
314  writeCoordinates( line, xt, yt );
315 
316  if( !m_useRouteModeForOval )
317  {
318  /* remove the '\n' from end of line, because we must add the "G85"
319  * command to the line: */
320  for( int kk = 0; line[kk] != 0; kk++ )
321  {
322  if( line[kk] < ' ' )
323  line[kk] = 0;
324  }
325 
326  fputs( line, m_file );
327  fputs( "G85", m_file ); // add the "G85" command
328  }
329  else
330  {
331  fputs( line, m_file );
332  fputs( "M15\nG01", m_file ); // tool down and linear routing from last coordinates
333  }
334 
335  xt = xf * m_conversionUnits;
336  yt = yf * m_conversionUnits;
337  writeCoordinates( line, xt, yt );
338 
339  fputs( line, m_file );
340 
342  fputs( "M16\n", m_file ); // Tool up (end routing)
343 
344  fputs( "G05\n", m_file ); // Select drill mode
345  holes_count++;
346  }
347 
349 
350  return holes_count;
351 }
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
HOLE_ATTRIBUTE m_HoleAttribute
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
std::vector< DRILL_TOOL > m_toolListBuffer
void writeCoordinates(char *aLine, double aCoordX, double aCoordY)
Create a line like according to the selected format.
Handle hole which must be drilled (diameter, position and layers).
void writeHoleAttribute(HOLE_ATTRIBUTE aAttribute)
Write a comment string giving the hole attribute.
void writeEXCELLONHeader(DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHolesType)
Print the DRILL file header.
constexpr int delta
std::vector< HOLE_INFO > m_holeListBuffer

References delta, dummy(), GENDRILL_WRITER_BASE::m_conversionUnits, DRILL_TOOL::m_Diameter, m_file, HOLE_INFO::m_Hole_Orient, HOLE_INFO::m_Hole_Pos, HOLE_INFO::m_Hole_Shape, HOLE_INFO::m_Hole_Size, DRILL_TOOL::m_HoleAttribute, GENDRILL_WRITER_BASE::m_holeListBuffer, m_mirror, GENDRILL_WRITER_BASE::m_offset, HOLE_INFO::m_Tool_Reference, GENDRILL_WRITER_BASE::m_toolListBuffer, GENDRILL_WRITER_BASE::m_unitsMetric, m_useRouteModeForOval, RotatePoint(), writeCoordinates(), writeEXCELLONEndOfFile(), writeEXCELLONHeader(), and writeHoleAttribute().

Referenced by CreateDrillandMapFilesSet().

◆ CreateMapFilesSet()

void GENDRILL_WRITER_BASE::CreateMapFilesSet ( const wxString &  aPlotDirectory,
REPORTER aReporter = nullptr 
)
inherited

Create the full set of map files for the board, in PS, PDF ...

format (use SetMapFileFormat() to select the format).

File names are computed from the board name and layer ID.

Parameters
aPlotDirectoryis the output folder.
aReporteris a REPORTER to return activity or any message (can be NULL)

Definition at line 304 of file gendrill_file_writer_base.cpp.

306 {
307  wxFileName fn;
308  wxString msg;
309 
310  std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();
311 
312  // append a pair representing the NPTH set of holes, for separate drill files.
313  if( !m_merge_PTH_NPTH )
314  hole_sets.emplace_back( F_Cu, B_Cu );
315 
316  for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin();
317  it != hole_sets.end(); ++it )
318  {
319  DRILL_LAYER_PAIR pair = *it;
320  // For separate drill files, the last layer pair is the NPTH drill file.
321  bool doing_npth = m_merge_PTH_NPTH ? false : ( it == hole_sets.end() - 1 );
322 
323  buildHolesList( pair, doing_npth );
324 
325  // The file is created if it has holes, or if it is the non plated drill file
326  // to be sure the NPTH file is up to date in separate files mode.
327  // Also a PTH drill file is always created, to be sure at least one plated hole drill file
328  // is created (do not create any PTH drill file can be seen as not working drill generator).
329  if( getHolesCount() > 0 || doing_npth || pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
330  {
331  fn = getDrillFileName( pair, doing_npth, m_merge_PTH_NPTH );
332  fn.SetPath( aPlotDirectory );
333 
334  fn.SetExt( wxEmptyString ); // Will be added by GenDrillMap
335  wxString fullfilename = fn.GetFullPath() + wxT( "-drl_map" );
336  fullfilename << wxT(".") << GetDefaultPlotExtension( m_mapFileFmt );
337 
338  bool success = genDrillMapFile( fullfilename, m_mapFileFmt );
339 
340  if( ! success )
341  {
342  if( aReporter )
343  {
344  msg.Printf( _( "Failed to create file '%s'." ), fullfilename );
345  aReporter->Report( msg, RPT_SEVERITY_ERROR );
346  }
347 
348  return;
349  }
350  else
351  {
352  if( aReporter )
353  {
354  msg.Printf( _( "Created file '%s'." ), fullfilename );
355  aReporter->Report( msg, RPT_SEVERITY_ACTION );
356  }
357  }
358  }
359  }
360 }
virtual const wxString getDrillFileName(DRILL_LAYER_PAIR aPair, bool aNPTH, bool aMerge_PTH_NPTH) const
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Returns the default plot extension for a format.
std::vector< DRILL_LAYER_PAIR > getUniqueLayerPairs() const
Get unique layer pairs by examining the micro and blind_buried vias.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
#define _(s)
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
void buildHolesList(DRILL_LAYER_PAIR aLayerPair, bool aGenerateNPTH_list)
Create the list of holes and tools for a given board.
Definition: layer_ids.h:71
bool genDrillMapFile(const wxString &aFullFileName, PLOT_FORMAT aFormat)
Plot a map of drill marks for holes.

References _, B_Cu, GENDRILL_WRITER_BASE::buildHolesList(), F_Cu, GENDRILL_WRITER_BASE::genDrillMapFile(), GetDefaultPlotExtension(), GENDRILL_WRITER_BASE::getDrillFileName(), GENDRILL_WRITER_BASE::getHolesCount(), GENDRILL_WRITER_BASE::getUniqueLayerPairs(), GENDRILL_WRITER_BASE::m_mapFileFmt, GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, REPORTER::Report(), RPT_SEVERITY_ACTION, and RPT_SEVERITY_ERROR.

Referenced by GERBER_WRITER::CreateDrillandMapFilesSet(), and CreateDrillandMapFilesSet().

◆ genDrillMapFile()

bool GENDRILL_WRITER_BASE::genDrillMapFile ( const wxString &  aFullFileName,
PLOT_FORMAT  aFormat 
)
protectedinherited

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.

Parameters
aFullFileNameis the full filename of the map file to create.
aFormatis one of the supported plot formats (see enum PlotFormat ).

Definition at line 70 of file gen_drill_report_files.cpp.

71 {
72  // Remark:
73  // Hole list must be created before calling this function, by buildHolesList(),
74  // for the right holes set (PTH, NPTH, buried/blind vias ...)
75 
76  double scale = 1.0;
77  wxPoint offset = GetOffset();
78  PLOTTER* plotter = nullptr;
79  PAGE_INFO dummy( PAGE_INFO::A4, false );
80  int bottom_limit = 0; // Y coord limit of page. 0 mean do not use
81 
82  PCB_PLOT_PARAMS plot_opts; // starts plotting with default options
83 
84  LOCALE_IO toggle; // use standard C notation for float numbers
85 
86  const PAGE_INFO& page_info = m_pageInfo ? *m_pageInfo : dummy;
87 
88  // Calculate dimensions and center of PCB. The Edge_Cuts layer must be visible
89  // to calculate the board edges bounding box
90  LSET visibleLayers = m_pcb->GetVisibleLayers();
91  m_pcb->SetVisibleLayers( visibleLayers | LSET( Edge_Cuts ) );
93  m_pcb->SetVisibleLayers( visibleLayers );
94 
95  // Some formats cannot be used to generate a document like the map files
96  // Currently HPGL (old format not very used)
97 
98  if( aFormat == PLOT_FORMAT::HPGL )
99  aFormat = PLOT_FORMAT::PDF;
100 
101  // Calculate the scale for the format type, scale 1 in HPGL, drawing on
102  // an A4 sheet in PS, + text description of symbols
103  switch( aFormat )
104  {
105  case PLOT_FORMAT::GERBER:
106  plotter = new GERBER_PLOTTER();
107  plotter->SetViewport( offset, IU_PER_MILS / 10, scale, false );
108  plotter->SetGerberCoordinatesFormat( 5 ); // format x.5 unit = mm
109  break;
110 
111  default:
112  wxASSERT( false );
114 
115  case PLOT_FORMAT::PDF:
116  case PLOT_FORMAT::POST:
117  case PLOT_FORMAT::SVG:
118  {
119  PAGE_INFO pageA4( wxT( "A4" ) );
120  wxSize pageSizeIU = pageA4.GetSizeIU();
121 
122  // Reserve a 10 mm margin around the page.
123  int margin = Millimeter2iu( 10 );
124 
125  // Calculate a scaling factor to print the board on the sheet
126  double Xscale = double( pageSizeIU.x - ( 2 * margin ) ) / bbbox.GetWidth();
127 
128  // We should print the list of drill sizes, so reserve room for it
129  // 60% height for board 40% height for list
130  int ypagesize_for_board = KiROUND( pageSizeIU.y * 0.6 );
131  double Yscale = double( ypagesize_for_board - margin ) / bbbox.GetHeight();
132 
133  scale = std::min( Xscale, Yscale );
134 
135  // Experience shows the scale should not to large, because texts
136  // create problem (can be to big or too small).
137  // So the scale is clipped at 3.0;
138  scale = std::min( scale, 3.0 );
139 
140  offset.x = KiROUND( double( bbbox.Centre().x ) - ( pageSizeIU.x / 2.0 ) / scale );
141  offset.y = KiROUND( double( bbbox.Centre().y ) - ( ypagesize_for_board / 2.0 ) / scale );
142 
143  // bottom_limit is used to plot the legend (drill diameters)
144  // texts are scaled differently for scale > 1.0 and <= 1.0
145  // so the limit is scaled differently.
146  bottom_limit = ( pageSizeIU.y - margin ) / std::min( scale, 1.0 );
147 
148  if( aFormat == PLOT_FORMAT::SVG )
149  plotter = new SVG_PLOTTER;
150  else if( aFormat == PLOT_FORMAT::PDF )
151  plotter = new PDF_PLOTTER;
152  else
153  plotter = new PS_PLOTTER;
154 
155  plotter->SetPageSettings( pageA4 );
156  plotter->SetViewport( offset, IU_PER_MILS / 10, scale, false );
157  break;
158  }
159 
160  case PLOT_FORMAT::DXF:
161  {
162  DXF_PLOTTER* dxf_plotter = new DXF_PLOTTER;
163 
164  if( m_unitsMetric )
165  dxf_plotter->SetUnits( DXF_UNITS::MILLIMETERS );
166  else
167  dxf_plotter->SetUnits( DXF_UNITS::INCHES );
168 
169  plotter = dxf_plotter;
170  plotter->SetPageSettings( page_info );
171  plotter->SetViewport( offset, IU_PER_MILS / 10, scale, false );
172  break;
173  }
174  }
175 
176  plotter->SetCreator( wxT( "PCBNEW" ) );
177  plotter->SetColorMode( false );
178 
179  KIGFX::PCB_RENDER_SETTINGS renderSettings;
180  renderSettings.SetDefaultPenWidth( Millimeter2iu( 0.2 ) );
181 
182  plotter->SetRenderSettings( &renderSettings );
183 
184  if( !plotter->OpenFile( aFullFileName ) )
185  {
186  delete plotter;
187  return false;
188  }
189 
190  plotter->ClearHeaderLinesList();
191 
192  // For the Gerber X2 format we need to set the "FileFunction" to Drillmap
193  // and set a few other options.
194  if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
195  {
196  GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
197  gbrplotter->DisableApertMacros( false );
198  gbrplotter->UseX2format( true ); // Mandatory
199  gbrplotter->UseX2NetAttributes( false ); // net attributes hace no meaning here
200 
201  // Attributes are added using X2 format
202  AddGerberX2Header( gbrplotter, m_pcb, false );
203 
204  wxString text;
205 
206  // Add the TF.FileFunction
207  text = "%TF.FileFunction,Drillmap*%";
208  gbrplotter->AddLineToHeader( text );
209 
210  // Add the TF.FilePolarity
211  text = wxT( "%TF.FilePolarity,Positive*%" );
212  gbrplotter->AddLineToHeader( text );
213  }
214 
215  plotter->StartPlot();
216 
217  // Draw items on edge layer.
218  // Not all, only items useful for drill map, i.e. board outlines.
219  BRDITEMS_PLOTTER itemplotter( plotter, m_pcb, plot_opts );
220 
221  // Use attributes of a drawing layer (we are not really draw the Edge.Cuts layer)
222  itemplotter.SetLayerSet( Dwgs_User );
223 
224  for( BOARD_ITEM* item : m_pcb->Drawings() )
225  {
226  if( item->GetLayer() != Edge_Cuts )
227  continue;
228 
229  switch( item->Type() )
230  {
231  case PCB_SHAPE_T:
232  {
233  PCB_SHAPE dummy_shape( *static_cast<PCB_SHAPE*>( item ) );
234  dummy_shape.SetLayer( Dwgs_User );
235  itemplotter.PlotPcbShape( &dummy_shape );
236  }
237  break;
238 
239  default:
240  break;
241  }
242  }
243 
244  int plotX, plotY, TextWidth;
245  int intervalle = 0;
246  char line[1024];
247  wxString msg;
248  int textmarginaftersymbol = Millimeter2iu( 2 );
249 
250  // Set Drill Symbols width
251  plotter->SetCurrentLineWidth( -1 );
252 
253  // Plot board outlines and drill map
254  plotDrillMarks( plotter );
255 
256  // Print a list of symbols used.
257  int charSize = Millimeter2iu( 2 ); // text size in IUs
258 
259  // real char scale will be 1/scale, because the global plot scale is scale
260  // for scale < 1.0 ( plot bigger actual size)
261  // Therefore charScale = 1.0 / scale keep the initial charSize
262  // (for scale < 1 we use the global scaling factor: the board must be plotted
263  // smaller than the actual size)
264  double charScale = std::min( 1.0, 1.0 / scale );
265 
266  TextWidth = KiROUND( ( charSize * charScale ) / 10.0 ); // Set text width (thickness)
267  intervalle = KiROUND( charSize * charScale ) + TextWidth;
268 
269  // Trace information.
270  plotX = KiROUND( bbbox.GetX() + textmarginaftersymbol * charScale );
271  plotY = bbbox.GetBottom() + intervalle;
272 
273  // Plot title "Info"
274  wxString Text = wxT( "Drill Map:" );
275  plotter->Text( wxPoint( plotX, plotY ), COLOR4D::UNSPECIFIED, Text, 0,
276  wxSize( KiROUND( charSize * charScale ), KiROUND( charSize * charScale ) ),
277  GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, TextWidth, false, false );
278 
279  // For some formats (PS, PDF SVG) we plot the drill size list on more than one column
280  // because the list must be contained inside the printed page
281  // (others formats do not have a defined page size)
282  int max_line_len = 0; // The max line len in iu of the currently plotted column
283 
284  for( unsigned ii = 0; ii < m_toolListBuffer.size(); ii++ )
285  {
286  DRILL_TOOL& tool = m_toolListBuffer[ii];
287 
288  if( tool.m_TotalCount == 0 )
289  continue;
290 
291  plotY += intervalle;
292 
293  // Ensure there are room to plot the line
294  if( bottom_limit && ( plotY+intervalle > bottom_limit ) )
295  {
296  plotY = bbbox.GetBottom() + intervalle;
297  plotX += max_line_len + Millimeter2iu( 10 );//column_width;
298  max_line_len = 0;
299  }
300 
301  int plot_diam = KiROUND( tool.m_Diameter );
302 
303  // For markers plotted with the comment, keep marker size <= text height
304  plot_diam = std::min( plot_diam, KiROUND( charSize * charScale ) );
305  int x = KiROUND( plotX - textmarginaftersymbol * charScale - plot_diam / 2.0 );
306  int y = KiROUND( plotY + charSize * charScale );
307 
308  plotter->SetCurrentLineWidth( getMarkerBestPenSize( plot_diam ) );
309  plotter->Marker( wxPoint( x, y ), plot_diam, ii );
310  plotter->SetCurrentLineWidth( -1 );
311 
312  // List the diameter of each drill in mm and inches.
313  sprintf( line, "%3.3fmm / %2.4f\" ", diameter_in_mm( tool.m_Diameter ),
314  diameter_in_inches( tool.m_Diameter ) );
315 
316  msg = FROM_UTF8( line );
317 
318  // Now list how many holes and ovals are associated with each drill.
319  if( ( tool.m_TotalCount == 1 ) && ( tool.m_OvalCount == 0 ) )
320  sprintf( line, "(1 hole)" );
321  else if( tool.m_TotalCount == 1 ) // && ( toolm_OvalCount == 1 )
322  sprintf( line, "(1 slot)" );
323  else if( tool.m_OvalCount == 0 )
324  sprintf( line, "(%d holes)", tool.m_TotalCount );
325  else if( tool.m_OvalCount == 1 )
326  sprintf( line, "(%d holes + 1 slot)", tool.m_TotalCount - 1 );
327  else // if ( toolm_OvalCount > 1 )
328  sprintf( line, "(%d holes + %d slots)", tool.m_TotalCount - tool.m_OvalCount,
329  tool.m_OvalCount );
330 
331  msg += FROM_UTF8( line );
332 
333  if( tool.m_Hole_NotPlated )
334  msg += wxT( " (not plated)" );
335 
336  plotter->Text( wxPoint( plotX, y ), COLOR4D::UNSPECIFIED, msg, 0,
337  wxSize( KiROUND( charSize * charScale ), KiROUND( charSize * charScale ) ),
338  GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, TextWidth, false, false );
339 
340  intervalle = KiROUND( ( ( charSize * charScale ) + TextWidth ) * 1.2 );
341 
342  if( intervalle < ( plot_diam + ( 1 * IU_PER_MM / scale ) + TextWidth ) )
343  intervalle = plot_diam + ( 1 * IU_PER_MM / scale ) + TextWidth;
344 
345  // Evaluate the text horizontal size, to know the maximal column size
346  // This is a rough value, but ok to create a new column to plot next texts
347  int text_len = msg.Len() * ( ( charSize * charScale ) + TextWidth );
348  max_line_len = std::max( max_line_len, text_len + plot_diam );
349  }
350 
351  plotter->EndPlot();
352  delete plotter;
353 
354  return true;
355 }
double diameter_in_inches(double ius)
double diameter_in_mm(double ius)
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:174
void UseX2NetAttributes(bool aEnable)
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
virtual bool StartPlot()=0
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
int GetX() const
Definition: eda_rect.h:107
static constexpr double IU_PER_MM
Mock up a conversion function.
const EDA_RECT GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition: board.h:738
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:76
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition: plotter.h:152
int getMarkerBestPenSize(int aMarkerDiameter)
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition: plotter.h:155
int GetWidth() const
Definition: eda_rect.h:118
void AddGerberX2Header(PLOTTER *aPlotter, const BOARD *aBoard, bool aUseX1CompatibilityMode)
Calculate some X2 attributes as defined in the Gerber file format specification J4 (chapter 5) and ad...
Definition: pcbplot.cpp:282
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:481
void UseX2format(bool aEnable)
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
void AddLineToHeader(const wxString &aExtraString)
Add a line to the list of free lines to print at the beginning of the file.
Definition: plotter.h:183
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false)
Definition: plotter.h:470
int GetBottom() const
Definition: eda_rect.h:123
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
PCB specific render settings.
Definition: pcb_painter.h:64
std::vector< DRILL_TOOL > m_toolListBuffer
virtual bool EndPlot()=0
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition: board.cpp:499
virtual PLOT_FORMAT GetPlotterType() const =0
Returns the effective plot engine in use.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:53
static const wxChar A4[]
Definition: page_info.h:63
wxPoint GetOffset()
Return the plot offset (usually the position of the drill/place origin).
Parameters and options when plotting/printing a board.
int GetHeight() const
Definition: eda_rect.h:119
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror)=0
Set the plot offset and scaling for the current plot.
void Marker(const wxPoint &position, int diametre, unsigned aShapeId)
Draw a pattern shape number aShapeId, to coord position.
Definition: plotter.cpp:332
void DisableApertMacros(bool aDisable)
Disable Aperture Macro (AM) command, only for broken Gerber Readers.
Base plotter engine class.
Definition: plotter.h:121
const int scale
Handle the component boundary box.
Definition: eda_rect.h:42
#define IU_PER_MILS
Definition: plotter.cpp:130
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
wxPoint Centre() const
Definition: eda_rect.h:64
void ClearHeaderLinesList()
Remove all lines from the list of free lines to print at the beginning of the file.
Definition: plotter.h:191
bool plotDrillMarks(PLOTTER *aPlotter)
Write the drill marks in HPGL, POSTSCRIPT or other supported formats/.
virtual void Text(const wxPoint &aPos, const COLOR4D &aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=nullptr)
Draw text with the plotter.
Definition: gr_text.cpp:219
void SetDefaultPenWidth(int aWidth)
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
static constexpr int Millimeter2iu(double mm)
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
DRAWINGS & Drawings()
Definition: board.h:237
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: plotter.h:158

References PAGE_INFO::A4, AddGerberX2Header(), PLOTTER::AddLineToHeader(), EDA_RECT::Centre(), PLOTTER::ClearHeaderLinesList(), diameter_in_inches(), diameter_in_mm(), GERBER_PLOTTER::DisableApertMacros(), BOARD::Drawings(), dummy(), Dwgs_User, DXF, Edge_Cuts, PLOTTER::EndPlot(), FROM_UTF8(), GERBER, BOARD::GetBoardEdgesBoundingBox(), EDA_RECT::GetBottom(), EDA_RECT::GetHeight(), getMarkerBestPenSize(), GENDRILL_WRITER_BASE::GetOffset(), PLOTTER::GetPlotterType(), BOARD::GetVisibleLayers(), EDA_RECT::GetWidth(), EDA_RECT::GetX(), GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, HPGL, INCHES, IU_PER_MILS, IU_PER_MM, KI_FALLTHROUGH, KiROUND(), DRILL_TOOL::m_Diameter, DRILL_TOOL::m_Hole_NotPlated, DRILL_TOOL::m_OvalCount, GENDRILL_WRITER_BASE::m_pageInfo, GENDRILL_WRITER_BASE::m_pcb, GENDRILL_WRITER_BASE::m_toolListBuffer, DRILL_TOOL::m_TotalCount, GENDRILL_WRITER_BASE::m_unitsMetric, PLOTTER::Marker(), Millimeter2iu(), MILLIMETERS, PLOTTER::OpenFile(), PCB_SHAPE_T, PDF, GENDRILL_WRITER_BASE::plotDrillMarks(), BRDITEMS_PLOTTER::PlotPcbShape(), POST, scale, PLOTTER::SetColorMode(), PLOTTER::SetCreator(), PLOTTER::SetCurrentLineWidth(), KIGFX::RENDER_SETTINGS::SetDefaultPenWidth(), PLOTTER::SetGerberCoordinatesFormat(), BOARD_ITEM::SetLayer(), BRDITEMS_PLOTTER::SetLayerSet(), PLOTTER::SetPageSettings(), PLOTTER::SetRenderSettings(), DXF_PLOTTER::SetUnits(), PLOTTER::SetViewport(), BOARD::SetVisibleLayers(), PLOTTER::StartPlot(), SVG, PLOTTER::Text(), text, GERBER_PLOTTER::UseX2format(), and GERBER_PLOTTER::UseX2NetAttributes().

Referenced by GENDRILL_WRITER_BASE::CreateMapFilesSet().

◆ GenDrillReportFile()

bool GENDRILL_WRITER_BASE::GenDrillReportFile ( const wxString &  aFullFileName)
inherited

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

Parameters
aFullFileNameis the name of the file to create.
Returns
true if the file is created.

Definition at line 358 of file gen_drill_report_files.cpp.

359 {
360  FILE_OUTPUTFORMATTER out( aFullFileName );
361 
362  static const char separator[] =
363  " =============================================================\n";
364 
365  wxASSERT( m_pcb );
366 
367  unsigned totalHoleCount;
368  wxFileName brdFilename( m_pcb->GetFileName() );
369 
370  std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();
371 
372  out.Print( 0, "Drill report for %s\n", TO_UTF8( brdFilename.GetFullName() ) );
373  out.Print( 0, "Created on %s\n\n", TO_UTF8( DateAndTime() ) );
374 
375  // Output the cu layer stackup, so layer name references make sense.
376  out.Print( 0, "Copper Layer Stackup:\n" );
377  out.Print( 0, separator );
378 
380 
381  int conventional_layer_num = 1;
382 
383  for( LSEQ seq = cu.Seq(); seq; ++seq, ++conventional_layer_num )
384  {
385  out.Print( 0, " L%-2d: %-25s %s\n",
386  conventional_layer_num,
387  TO_UTF8( m_pcb->GetLayerName( *seq ) ),
388  layerName( *seq ).c_str() ); // generic layer name
389  }
390 
391  out.Print( 0, "\n\n" );
392 
393  /* output hole lists:
394  * 1 - through holes
395  * 2 - for partial holes only: by layer starting and ending pair
396  * 3 - Non Plated through holes
397  */
398 
399  bool buildNPTHlist = false; // First pass: build PTH list only
400 
401  // in this loop are plated only:
402  for( unsigned pair_ndx = 0; pair_ndx < hole_sets.size(); ++pair_ndx )
403  {
404  DRILL_LAYER_PAIR pair = hole_sets[pair_ndx];
405 
406  buildHolesList( pair, buildNPTHlist );
407 
408  if( pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
409  {
410  out.Print( 0, "Drill file '%s' contains\n",
411  TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) );
412 
413  out.Print( 0, " plated through holes:\n" );
414  out.Print( 0, separator );
415  totalHoleCount = printToolSummary( out, false );
416  out.Print( 0, " Total plated holes count %u\n", totalHoleCount );
417  }
418  else // blind/buried
419  {
420  out.Print( 0, "Drill file '%s' contains\n",
421  TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) );
422 
423  out.Print( 0, " holes connecting layer pair: '%s and %s' (%s vias):\n",
424  TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.first ) ) ),
425  TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.second ) ) ),
426  pair.first == F_Cu || pair.second == B_Cu ? "blind" : "buried" );
427 
428  out.Print( 0, separator );
429  totalHoleCount = printToolSummary( out, false );
430  out.Print( 0, " Total plated holes count %u\n", totalHoleCount );
431  }
432 
433  out.Print( 0, "\n\n" );
434  }
435 
436  // NPTHoles. Generate the full list (pads+vias) if PTH and NPTH are merged,
437  // or only the NPTH list (which never has vias)
438  if( !m_merge_PTH_NPTH )
439  buildNPTHlist = true;
440 
441  buildHolesList( DRILL_LAYER_PAIR( F_Cu, B_Cu ), buildNPTHlist );
442 
443  // nothing wrong with an empty NPTH file in report.
444  if( m_merge_PTH_NPTH )
445  out.Print( 0, "Not plated through holes are merged with plated holes\n" );
446  else
447  out.Print( 0, "Drill file '%s' contains\n",
449  true, m_merge_PTH_NPTH ) ) );
450 
451  out.Print( 0, " unplated through holes:\n" );
452  out.Print( 0, separator );
453  totalHoleCount = printToolSummary( out, true );
454  out.Print( 0, " Total unplated holes count %u\n", totalHoleCount );
455 
456  return true;
457 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:759
unsigned printToolSummary(OUTPUTFORMATTER &aOut, bool aSummaryNPTH) const
Print m_toolListBuffer[] tools to aOut and returns total hole count.
virtual const wxString getDrillFileName(DRILL_LAYER_PAIR aPair, bool aNPTH, bool aMerge_PTH_NPTH) const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:362
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:467
std::vector< DRILL_LAYER_PAIR > getUniqueLayerPairs() const
Get unique layer pairs by examining the micro and blind_buried vias.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
const wxString & GetFileName() const
Definition: board.h:229
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:477
void buildHolesList(DRILL_LAYER_PAIR aLayerPair, bool aGenerateNPTH_list)
Create the list of holes and tools for a given board.
const std::string layerName(PCB_LAYER_ID aLayer) const
Definition: layer_ids.h:71
Used for text file output.
Definition: richio.h:456
wxString DateAndTime()
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914

References LSET::AllCuMask(), B_Cu, GENDRILL_WRITER_BASE::buildHolesList(), DateAndTime(), F_Cu, GENDRILL_WRITER_BASE::getDrillFileName(), BOARD::GetEnabledLayers(), BOARD::GetFileName(), BOARD::GetLayerName(), GENDRILL_WRITER_BASE::getUniqueLayerPairs(), GENDRILL_WRITER_BASE::layerName(), GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, GENDRILL_WRITER_BASE::m_pcb, OUTPUTFORMATTER::Print(), GENDRILL_WRITER_BASE::printToolSummary(), LSET::Seq(), TO_UTF8, and ToLAYER_ID().

Referenced by DIALOG_GENDRILL::OnGenReportFile().

◆ getDrillFileName()

const wxString GENDRILL_WRITER_BASE::getDrillFileName ( DRILL_LAYER_PAIR  aPair,
bool  aNPTH,
bool  aMerge_PTH_NPTH 
) const
protectedvirtualinherited
Parameters
aPairis the layer pair.
aNPTHuse true to generate the filename of NPTH holes.
aMerge_PTH_NPTHuse true to generate the filename of a file which containd both NPH and NPTH holes.
Returns
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

Reimplemented in GERBER_WRITER.

Definition at line 273 of file gendrill_file_writer_base.cpp.

275 {
276  wxASSERT( m_pcb );
277 
278  wxString extend;
279 
280  if( aNPTH )
281  extend = wxT( "-NPTH" );
282  else if( aPair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
283  {
284  if( !aMerge_PTH_NPTH )
285  extend = wxT( "-PTH" );
286  // if merged, extend with nothing
287  }
288  else
289  {
290  extend += '-';
291  extend += layerPairName( aPair );
292  }
293 
294  wxFileName fn = m_pcb->GetFileName();
295 
296  fn.SetName( fn.GetName() + extend );
297  fn.SetExt( m_drillFileExtension );
298 
299  wxString ret = fn.GetFullName();
300 
301  return ret;
302 }
const wxString & GetFileName() const
Definition: board.h:229
const std::string layerPairName(DRILL_LAYER_PAIR aPair) const
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
Definition: layer_ids.h:71

References B_Cu, F_Cu, BOARD::GetFileName(), GENDRILL_WRITER_BASE::layerPairName(), GENDRILL_WRITER_BASE::m_drillFileExtension, and GENDRILL_WRITER_BASE::m_pcb.

Referenced by CreateDrillandMapFilesSet(), GENDRILL_WRITER_BASE::CreateMapFilesSet(), GENDRILL_WRITER_BASE::GenDrillReportFile(), and GERBER_WRITER::getDrillFileName().

◆ getHolesCount()

int GENDRILL_WRITER_BASE::getHolesCount ( ) const
inlineprotectedinherited

◆ GetOffset()

wxPoint EXCELLON_WRITER::GetOffset ( )
inline

Return the plot offset (usually the position of the auxiliary axis.

Definition at line 56 of file gendrill_Excellon_writer.h.

56 { return m_offset; }

References GENDRILL_WRITER_BASE::m_offset.

◆ getUniqueLayerPairs()

std::vector< DRILL_LAYER_PAIR > GENDRILL_WRITER_BASE::getUniqueLayerPairs ( ) const
protectedinherited

Get unique layer pairs by examining the micro and blind_buried vias.

Definition at line 206 of file gendrill_file_writer_base.cpp.

207 {
208  wxASSERT( m_pcb );
209 
210  static const KICAD_T interesting_stuff_to_collect[] = {
211  PCB_VIA_T,
212  EOT
213  };
214 
215  PCB_TYPE_COLLECTOR vias;
216 
217  vias.Collect( m_pcb, interesting_stuff_to_collect );
218 
219  std::set< DRILL_LAYER_PAIR > unique;
220 
221  DRILL_LAYER_PAIR layer_pair;
222 
223  for( int i = 0; i < vias.GetCount(); ++i )
224  {
225  PCB_VIA* v = static_cast<PCB_VIA*>( vias[i] );
226 
227  v->LayerPair( &layer_pair.first, &layer_pair.second );
228 
229  // only make note of blind buried.
230  // thru hole is placed unconditionally as first in fetched list.
231  if( layer_pair != DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
232  {
233  unique.insert( layer_pair );
234  }
235  }
236 
237  std::vector<DRILL_LAYER_PAIR> ret;
238 
239  ret.emplace_back( F_Cu, B_Cu ); // always first in returned list
240 
241  for( std::set<DRILL_LAYER_PAIR>::const_iterator it = unique.begin(); it != unique.end(); ++it )
242  ret.push_back( *it );
243 
244  return ret;
245 }
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
Definition: pcb_track.cpp:434
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
void Collect(BOARD_ITEM *aBoard, const KICAD_T aScanList[])
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
Definition: collectors.cpp:609
Definition: layer_ids.h:71
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition: collectors.h:614

References B_Cu, PCB_TYPE_COLLECTOR::Collect(), EOT, F_Cu, COLLECTOR::GetCount(), PCB_VIA::LayerPair(), GENDRILL_WRITER_BASE::m_pcb, and PCB_VIA_T.

Referenced by GERBER_WRITER::CreateDrillandMapFilesSet(), CreateDrillandMapFilesSet(), GENDRILL_WRITER_BASE::CreateMapFilesSet(), and GENDRILL_WRITER_BASE::GenDrillReportFile().

◆ layerName()

const std::string GENDRILL_WRITER_BASE::layerName ( PCB_LAYER_ID  aLayer) const
protectedinherited
Returns
a string from aLayer to identify the layer. string are "front" "back" or "in<aLayer>"

Definition at line 248 of file gendrill_file_writer_base.cpp.

249 {
250  // Generic names here.
251  switch( aLayer )
252  {
253  case F_Cu:
254  return "front";
255  case B_Cu:
256  return "back";
257  default:
258  return StrPrintf( "in%d", aLayer );
259  }
260 }
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
Definition: richio.cpp:79
Definition: layer_ids.h:71

References B_Cu, F_Cu, and StrPrintf().

Referenced by GENDRILL_WRITER_BASE::GenDrillReportFile(), and GENDRILL_WRITER_BASE::layerPairName().

◆ layerPairName()

const std::string GENDRILL_WRITER_BASE::layerPairName ( DRILL_LAYER_PAIR  aPair) const
protectedinherited
Returns
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

Definition at line 263 of file gendrill_file_writer_base.cpp.

264 {
265  std::string ret = layerName( aPair.first );
266  ret += '-';
267  ret += layerName( aPair.second );
268 
269  return ret;
270 }
const std::string layerName(PCB_LAYER_ID aLayer) const

References GENDRILL_WRITER_BASE::layerName().

Referenced by GENDRILL_WRITER_BASE::getDrillFileName().

◆ plotDrillMarks()

bool GENDRILL_WRITER_BASE::plotDrillMarks ( PLOTTER aPlotter)
protectedinherited

Write 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.

Parameters
aPlotteris a PLOTTER instance (HPGL, POSTSCRIPT ... plotter).

Definition at line 460 of file gen_drill_report_files.cpp.

461 {
462  // Plot the drill map:
463  wxPoint pos;
464 
465  for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
466  {
467  const HOLE_INFO& hole = m_holeListBuffer[ii];
468  pos = hole.m_Hole_Pos;
469 
470  // Gives a good line thickness to have a good marker shape:
472 
473  // Always plot the drill symbol (for slots identifies the needed cutter!
474  aPlotter->Marker( pos, hole.m_Hole_Diameter, hole.m_Tool_Reference - 1 );
475 
476  if( hole.m_Hole_Shape != 0 )
477  {
478  wxSize oblong_size = hole.m_Hole_Size;
479  aPlotter->FlashPadOval( pos, oblong_size, hole.m_Hole_Orient, SKETCH, nullptr );
480  }
481  }
482 
483  aPlotter->SetCurrentLineWidth( -1 );
484 
485  return true;
486 }
int getMarkerBestPenSize(int aMarkerDiameter)
virtual void FlashPadOval(const wxPoint &aPadPos, const wxSize &aSize, double aPadOrient, OUTLINE_MODE aTraceMode, void *aData)=0
Handle hole which must be drilled (diameter, position and layers).
void Marker(const wxPoint &position, int diametre, unsigned aShapeId)
Draw a pattern shape number aShapeId, to coord position.
Definition: plotter.cpp:332
std::vector< HOLE_INFO > m_holeListBuffer
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.

References PLOTTER::FlashPadOval(), getMarkerBestPenSize(), HOLE_INFO::m_Hole_Diameter, HOLE_INFO::m_Hole_Orient, HOLE_INFO::m_Hole_Pos, HOLE_INFO::m_Hole_Shape, HOLE_INFO::m_Hole_Size, GENDRILL_WRITER_BASE::m_holeListBuffer, HOLE_INFO::m_Tool_Reference, PLOTTER::Marker(), PLOTTER::SetCurrentLineWidth(), and SKETCH.

Referenced by GENDRILL_WRITER_BASE::genDrillMapFile().

◆ printToolSummary()

unsigned GENDRILL_WRITER_BASE::printToolSummary ( OUTPUTFORMATTER aOut,
bool  aSummaryNPTH 
) const
protectedinherited

Print m_toolListBuffer[] tools to aOut and returns total hole count.

Parameters
aOutis the current OUTPUTFORMATTER to print summary.
aSummaryNPTHis true to print summary for NPTH, false for PTH.

Definition at line 489 of file gen_drill_report_files.cpp.

490 {
491  unsigned totalHoleCount = 0;
492 
493  for( unsigned ii = 0; ii < m_toolListBuffer.size(); ii++ )
494  {
495  const DRILL_TOOL& tool = m_toolListBuffer[ii];
496 
497  if( aSummaryNPTH && !tool.m_Hole_NotPlated )
498  continue;
499 
500  if( !aSummaryNPTH && tool.m_Hole_NotPlated )
501  continue;
502 
503  // List the tool number assigned to each drill in mm then in inches.
504  int tool_number = ii+1;
505  out.Print( 0, " T%d %2.3fmm %2.4f\" ", tool_number,
506  diameter_in_mm( tool.m_Diameter ),
507  diameter_in_inches( tool.m_Diameter ) );
508 
509  // Now list how many holes and ovals are associated with each drill.
510  if( ( tool.m_TotalCount == 1 ) && ( tool.m_OvalCount == 0 ) )
511  out.Print( 0, "(1 hole)\n" );
512  else if( tool.m_TotalCount == 1 )
513  out.Print( 0, "(1 hole) (with 1 slot)\n" );
514  else if( tool.m_OvalCount == 0 )
515  out.Print( 0, "(%d holes)\n", tool.m_TotalCount );
516  else if( tool.m_OvalCount == 1 )
517  out.Print( 0, "(%d holes) (with 1 slot)\n", tool.m_TotalCount );
518  else // tool.m_OvalCount > 1
519  out.Print( 0, "(%d holes) (with %d slots)\n", tool.m_TotalCount, tool.m_OvalCount );
520 
521  totalHoleCount += tool.m_TotalCount;
522  }
523 
524  out.Print( 0, "\n" );
525 
526  return totalHoleCount;
527 }
double diameter_in_inches(double ius)
double diameter_in_mm(double ius)
std::vector< DRILL_TOOL > m_toolListBuffer

References diameter_in_inches(), diameter_in_mm(), DRILL_TOOL::m_Diameter, DRILL_TOOL::m_Hole_NotPlated, DRILL_TOOL::m_OvalCount, GENDRILL_WRITER_BASE::m_toolListBuffer, DRILL_TOOL::m_TotalCount, and OUTPUTFORMATTER::Print().

Referenced by GENDRILL_WRITER_BASE::GenDrillReportFile().

◆ SetFormat()

void EXCELLON_WRITER::SetFormat ( bool  aMetric,
ZEROS_FMT  aZerosFmt = DECIMAL_FORMAT,
int  aLeftDigits = 0,
int  aRightDigits = 0 
)

Initialize internal parameters to match the given format.

Parameters
aMetricset to true for metric coordinates, false for imperial units.
aZerosFmtis the zero format DECIMAL_FORMAT, SUPPRESS_LEADING, SUPPRESS_TRAILING, or KEEP_ZEROS.
aLeftDigitsis the number of digits for integer part of coordinates if <= 0 (default), a suitable value will be used, depending on units.
aRightDigitsis number of digits for mantissa part of coordinates if <= 0 (default), a suitable value will be used, depending on units.

Definition at line 354 of file gendrill_Excellon_writer.cpp.

356 {
357  m_unitsMetric = aMetric;
358  m_zeroFormat = aZerosFmt;
359 
360  /* Set conversion scale depending on drill file units */
361  if( m_unitsMetric )
362  m_conversionUnits = 1.0 / IU_PER_MM; // EXCELLON units = mm
363  else
364  m_conversionUnits = 0.001 / IU_PER_MILS; // EXCELLON units = INCHES
365 
366  // Set the zero counts. if aZerosFmt == DECIMAL_FORMAT, these values
367  // will be set, but not used.
368  if( aLeftDigits <= 0 )
369  aLeftDigits = m_unitsMetric ? 3 : 2;
370 
371  if( aRightDigits <= 0 )
372  aRightDigits = m_unitsMetric ? 3 : 4;
373 
374  m_precision.m_Lhs = aLeftDigits;
375  m_precision.m_Rhs = aRightDigits;
376 }
static constexpr double IU_PER_MM
Mock up a conversion function.
#define IU_PER_MILS
Definition: plotter.cpp:130

References IU_PER_MILS, IU_PER_MM, GENDRILL_WRITER_BASE::m_conversionUnits, DRILL_PRECISION::m_Lhs, GENDRILL_WRITER_BASE::m_precision, DRILL_PRECISION::m_Rhs, GENDRILL_WRITER_BASE::m_unitsMetric, and GENDRILL_WRITER_BASE::m_zeroFormat.

Referenced by DIALOG_GENDRILL::GenDrillAndMapFiles().

◆ SetMapFileFormat()

void GENDRILL_WRITER_BASE::SetMapFileFormat ( PLOT_FORMAT  aMapFmt)
inlineinherited

Initialize the format for the drill map file.

Parameters
aMapFmta 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.

Definition at line 201 of file gendrill_file_writer_base.h.

202  {
203  m_mapFileFmt = aMapFmt;
204  }

References GENDRILL_WRITER_BASE::m_mapFileFmt.

Referenced by DIALOG_GENDRILL::GenDrillAndMapFiles().

◆ SetMergeOption()

void GENDRILL_WRITER_BASE::SetMergeOption ( bool  aMerge)
inlineinherited

Set the option to make separate drill files for PTH and NPTH.

Parameters
aMergeset to true to make only one file containing PTH and NPTH or false to create 2 separate files.

Definition at line 178 of file gendrill_file_writer_base.h.

References GENDRILL_WRITER_BASE::m_merge_PTH_NPTH.

Referenced by DIALOG_GENDRILL::OnGenReportFile().

◆ SetOptions()

void EXCELLON_WRITER::SetOptions ( bool  aMirror,
bool  aMinimalHeader,
const wxPoint &  aOffset,
bool  aMerge_PTH_NPTH 
)
inline

Initialize internal parameters to match drill options.

Parameters
aMirrorset to true to create mirrored coordinates (Y coordinates negated).
aMinimalHeaderset to true to use a minimal header (no comments, no info).
aOffsetis the drill coordinates offset.
aMerge_PTH_NPTHset to true to create only one file containing PTH and NPTH false to create 2 separate files : one for PTH and one for NPTH.

Definition at line 89 of file gendrill_Excellon_writer.h.

91  {
92  m_mirror = aMirror;
93  m_offset = aOffset;
94  m_minimalHeader = aMinimalHeader;
95  m_merge_PTH_NPTH = aMerge_PTH_NPTH;
96  }

References GENDRILL_WRITER_BASE::m_merge_PTH_NPTH, m_minimalHeader, m_mirror, and GENDRILL_WRITER_BASE::m_offset.

Referenced by DIALOG_GENDRILL::GenDrillAndMapFiles().

◆ SetPageInfo()

void GENDRILL_WRITER_BASE::SetPageInfo ( const PAGE_INFO aPageInfo)
inlineinherited

Set the page info used to plot drill maps.

If NULL, a A4 page format will be used.

Parameters
aPageInfois a reference to the page info, usually used to plot/display the board.

Definition at line 192 of file gendrill_file_writer_base.h.

192 { m_pageInfo = aPageInfo; }

References GENDRILL_WRITER_BASE::m_pageInfo.

◆ SetRouteModeForOvalHoles()

void EXCELLON_WRITER::SetRouteModeForOvalHoles ( bool  aUseRouteModeForOvalHoles)
inline

Definition at line 61 of file gendrill_Excellon_writer.h.

62  {
63  m_useRouteModeForOval = aUseRouteModeForOvalHoles;
64  }

References m_useRouteModeForOval.

Referenced by DIALOG_GENDRILL::GenDrillAndMapFiles().

◆ writeCoordinates()

void EXCELLON_WRITER::writeCoordinates ( char *  aLine,
double  aCoordX,
double  aCoordY 
)
private

Create a line like according to the selected format.

Definition at line 379 of file gendrill_Excellon_writer.cpp.

380 {
381  wxString xs, ys;
382  int xpad = m_precision.m_Lhs + m_precision.m_Rhs;
383  int ypad = xpad;
384 
385  switch( m_zeroFormat )
386  {
387  default:
388  case DECIMAL_FORMAT:
389  /* In Excellon files, resolution is 1/1000 mm or 1/10000 inch (0.1 mil)
390  * Although in decimal format, Excellon specifications do not specify
391  * clearly the resolution. However it seems to be 1/1000mm or 0.1 mil
392  * like in non decimal formats, so we trunk coordinates to 3 or 4 digits in mantissa
393  * Decimal format just prohibit useless leading 0:
394  * 0.45 or .45 is right, but 00.54 is incorrect.
395  */
396  if( m_unitsMetric )
397  {
398  // resolution is 1/1000 mm
399  xs.Printf( wxT( "%.3f" ), aCoordX );
400  ys.Printf( wxT( "%.3f" ), aCoordY );
401  }
402  else
403  {
404  // resolution is 1/10000 inch
405  xs.Printf( wxT( "%.4f" ), aCoordX );
406  ys.Printf( wxT( "%.4f" ), aCoordY );
407  }
408 
409  //Remove useless trailing 0
410  while( xs.Last() == '0' )
411  xs.RemoveLast();
412 
413  if( xs.Last() == '.' ) // however keep a trailing 0 after the floating point separator
414  xs << '0';
415 
416  while( ys.Last() == '0' )
417  ys.RemoveLast();
418 
419  if( ys.Last() == '.' )
420  ys << '0';
421 
422  sprintf( aLine, "X%sY%s\n", TO_UTF8( xs ), TO_UTF8( ys ) );
423  break;
424 
425  case SUPPRESS_LEADING:
426  for( int i = 0; i< m_precision.m_Rhs; i++ )
427  {
428  aCoordX *= 10; aCoordY *= 10;
429  }
430 
431  sprintf( aLine, "X%dY%d\n", KiROUND( aCoordX ), KiROUND( aCoordY ) );
432  break;
433 
434  case SUPPRESS_TRAILING:
435  {
436  for( int i = 0; i < m_precision.m_Rhs; i++ )
437  {
438  aCoordX *= 10;
439  aCoordY *= 10;
440  }
441 
442  if( aCoordX < 0 )
443  xpad++;
444 
445  if( aCoordY < 0 )
446  ypad++;
447 
448  xs.Printf( wxT( "%0*d" ), xpad, KiROUND( aCoordX ) );
449  ys.Printf( wxT( "%0*d" ), ypad, KiROUND( aCoordY ) );
450 
451  size_t j = xs.Len() - 1;
452 
453  while( xs[j] == '0' && j )
454  xs.Truncate( j-- );
455 
456  j = ys.Len() - 1;
457 
458  while( ys[j] == '0' && j )
459  ys.Truncate( j-- );
460 
461  sprintf( aLine, "X%sY%s\n", TO_UTF8( xs ), TO_UTF8( ys ) );
462  break;
463  }
464 
465  case KEEP_ZEROS:
466  for( int i = 0; i< m_precision.m_Rhs; i++ )
467  {
468  aCoordX *= 10; aCoordY *= 10;
469  }
470 
471  if( aCoordX < 0 )
472  xpad++;
473 
474  if( aCoordY < 0 )
475  ypad++;
476 
477  xs.Printf( wxT( "%0*d" ), xpad, KiROUND( aCoordX ) );
478  ys.Printf( wxT( "%0*d" ), ypad, KiROUND( aCoordY ) );
479  sprintf( aLine, "X%sY%s\n", TO_UTF8( xs ), TO_UTF8( ys ) );
480  break;
481  }
482 }
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73

References GENDRILL_WRITER_BASE::DECIMAL_FORMAT, GENDRILL_WRITER_BASE::KEEP_ZEROS, KiROUND(), DRILL_PRECISION::m_Lhs, GENDRILL_WRITER_BASE::m_precision, DRILL_PRECISION::m_Rhs, GENDRILL_WRITER_BASE::m_unitsMetric, GENDRILL_WRITER_BASE::m_zeroFormat, GENDRILL_WRITER_BASE::SUPPRESS_LEADING, GENDRILL_WRITER_BASE::SUPPRESS_TRAILING, and TO_UTF8.

Referenced by createDrillFile().

◆ writeEXCELLONEndOfFile()

void EXCELLON_WRITER::writeEXCELLONEndOfFile ( )
private

Definition at line 571 of file gendrill_Excellon_writer.cpp.

572 {
573  // add if minimal here
574  fputs( "T0\nM30\n", m_file );
575  fclose( m_file );
576 }

References m_file.

Referenced by createDrillFile().

◆ writeEXCELLONHeader()

void EXCELLON_WRITER::writeEXCELLONHeader ( DRILL_LAYER_PAIR  aLayerPair,
TYPE_FILE  aHolesType 
)
private

Print the DRILL file header.

The full header is something like: M48 ;DRILL file {PCBNEW (2007-11-29-b)} date 17/1/2008-21:02:35 ;FORMAT={ <precision> / absolute / <units> / <numbers format>="">} ; #@! TF.FileFunction,Plated,1,4,PTH ; #@! TF.CreationDate,2018-11-23T15:59:51+01:00 ; #@! TF.GenerationSoftware,Kicad,Pcbnew,2017.04 FMAT,2 INCH,TZ

Parameters
aLayerPairis the layer pair for the current holes.
aHolesTypeis the holes type in file (PTH, NPTH, mixed).

Definition at line 485 of file gendrill_Excellon_writer.cpp.

486 {
487  fputs( "M48\n", m_file ); // The beginning of a header
488 
489  if( !m_minimalHeader )
490  {
491  // The next lines in EXCELLON files are comments:
492  wxString msg;
493  msg << wxT( "KiCad " ) << GetBuildVersion();
494 
495  fprintf( m_file, "; DRILL file {%s} date %s\n", TO_UTF8( msg ), TO_UTF8( DateAndTime() ) );
496  msg = wxT( "; FORMAT={" );
497 
498  // Print precision:
499  // Note in decimal format the precision is not used.
500  // the floating point notation has higher priority than the precision.
503  else
504  msg << wxT( "-:-" ); // in decimal format the precision is irrelevant
505 
506  msg << wxT( "/ absolute / " );
507  msg << ( m_unitsMetric ? wxT( "metric" ) : wxT( "inch" ) );
508 
509  /* Adding numbers notation format.
510  * this is same as m_Choice_Zeros_Format strings, but NOT translated
511  * because some EXCELLON parsers do not like non ASCII values
512  * so we use ONLY English (ASCII) strings.
513  * if new options are added in m_Choice_Zeros_Format, they must also
514  * be added here
515  */
516  msg << wxT( " / " );
517 
518  const wxString zero_fmt[4] =
519  {
520  wxT( "decimal" ),
521  wxT( "suppress leading zeros" ),
522  wxT( "suppress trailing zeros" ),
523  wxT( "keep zeros" )
524  };
525 
526  msg << zero_fmt[m_zeroFormat] << wxT( "}\n" );
527  fputs( TO_UTF8( msg ), m_file );
528 
529  // add the structured comment TF.CreationDate:
530  // The attribute value must conform to the full version of the ISO 8601
532  fputs( TO_UTF8( msg ), m_file );
533 
534  // Add the application name that created the drill file
535  msg = wxT( "; #@! TF.GenerationSoftware,Kicad,Pcbnew," );
536  msg << GetBuildVersion() << wxT( "\n" );
537  fputs( TO_UTF8( msg ), m_file );
538 
539  // Add the standard X2 FileFunction for drill files
540  // TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH]
541  msg = BuildFileFunctionAttributeString( aLayerPair, aHolesType , true ) + wxT( "\n" );
542  fputs( TO_UTF8( msg ), m_file );
543 
544  fputs( "FMAT,2\n", m_file ); // Use Format 2 commands (version used since 1979)
545  }
546 
547  fputs( m_unitsMetric ? "METRIC" : "INCH", m_file );
548 
549  switch( m_zeroFormat )
550  {
551  case DECIMAL_FORMAT:
552  fputs( "\n", m_file );
553  break;
554 
555  case SUPPRESS_LEADING:
556  fputs( ",TZ\n", m_file );
557  break;
558 
559  case SUPPRESS_TRAILING:
560  fputs( ",LZ\n", m_file );
561  break;
562 
563  case KEEP_ZEROS:
564  // write nothing, but TZ is acceptable when all zeros are kept
565  fputs( "\n", m_file );
566  break;
567  }
568 }
wxString GbrMakeCreationDateAttributeString(GBR_NC_STRING_FORMAT aFormat)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
wxString GetBuildVersion()
Get the full KiCad version string.
const wxString BuildFileFunctionAttributeString(DRILL_LAYER_PAIR aLayerPair, TYPE_FILE aHoleType, bool aCompatNCdrill=false) const
wxString DateAndTime()

References GENDRILL_WRITER_BASE::BuildFileFunctionAttributeString(), DateAndTime(), GENDRILL_WRITER_BASE::DECIMAL_FORMAT, GBR_NC_STRING_FORMAT_NCDRILL, GbrMakeCreationDateAttributeString(), GetBuildVersion(), DRILL_PRECISION::GetPrecisionString(), GENDRILL_WRITER_BASE::KEEP_ZEROS, m_file, m_minimalHeader, GENDRILL_WRITER_BASE::m_precision, GENDRILL_WRITER_BASE::m_unitsMetric, GENDRILL_WRITER_BASE::m_zeroFormat, GENDRILL_WRITER_BASE::SUPPRESS_LEADING, GENDRILL_WRITER_BASE::SUPPRESS_TRAILING, and TO_UTF8.

Referenced by createDrillFile().

◆ writeHoleAttribute()

void EXCELLON_WRITER::writeHoleAttribute ( HOLE_ATTRIBUTE  aAttribute)
private

Write a comment string giving the hole attribute.

Parameters
aAttributeis the hole attribute.

Definition at line 157 of file gendrill_Excellon_writer.cpp.

158 {
159  // Hole attributes are comments (lines starting by ';') in the drill files
160  // For tools (file header), they are similar to X2 apertures attributes.
161  // for attributes added in coordinate list, they are just comments.
162  if( !m_minimalHeader )
163  {
164  switch( aAttribute )
165  {
167  fprintf( m_file, "; #@! TA.AperFunction,Plated,PTH,ViaDrill\n" );
168  break;
169 
171  fprintf( m_file, "; #@! TA.AperFunction,Plated,Buried,ViaDrill\n" );
172  break;
173 
175  fprintf( m_file, "; #@! TA.AperFunction,Plated,PTH,ComponentDrill\n" );
176  break;
177 
179  fprintf( m_file, "; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill\n" );
180  break;
181 
183  fprintf( m_file, "; #@! TD\n" );
184  break;
185  }
186  }
187 }

References HOLE_MECHANICAL, HOLE_PAD, HOLE_UNKNOWN, HOLE_VIA_BURIED, HOLE_VIA_THROUGH, m_file, and m_minimalHeader.

Referenced by createDrillFile().

Member Data Documentation

◆ m_conversionUnits

double GENDRILL_WRITER_BASE::m_conversionUnits
protectedinherited

◆ m_drillFileExtension

wxString GENDRILL_WRITER_BASE::m_drillFileExtension
protectedinherited

◆ m_file

FILE* EXCELLON_WRITER::m_file
private

◆ m_holeListBuffer

◆ m_mapFileFmt

◆ m_merge_PTH_NPTH

◆ m_minimalHeader

bool EXCELLON_WRITER::m_minimalHeader
private

◆ m_mirror

bool EXCELLON_WRITER::m_mirror
private

Definition at line 157 of file gendrill_Excellon_writer.h.

Referenced by createDrillFile(), EXCELLON_WRITER(), and SetOptions().

◆ m_offset

wxPoint GENDRILL_WRITER_BASE::m_offset
protectedinherited

◆ m_pageInfo

const PAGE_INFO* GENDRILL_WRITER_BASE::m_pageInfo
protectedinherited

◆ m_pcb

◆ m_precision

DRILL_PRECISION GENDRILL_WRITER_BASE::m_precision
protectedinherited

◆ m_toolListBuffer

std::vector<DRILL_TOOL> GENDRILL_WRITER_BASE::m_toolListBuffer
protectedinherited

◆ m_unitsMetric

◆ m_useRouteModeForOval

bool EXCELLON_WRITER::m_useRouteModeForOval
private

◆ m_zeroFormat


The documentation for this class was generated from the following files: