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 ); } } } } }
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; }
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( auto& pad : module->Pads() ) { 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++; } }
bool GENDRILL_WRITER_BASE::GenDrillReportFile( const wxString& aFullFileName ) { FILE_OUTPUTFORMATTER out( aFullFileName ); static const char separator[] = " =============================================================\n"; wxASSERT( m_pcb ); unsigned totalHoleCount; wxString brdFilename = m_pcb->GetFileName(); std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs(); out.Print( 0, "Drill report for %s\n", TO_UTF8( brdFilename ) ); out.Print( 0, "Created on %s\n\n", TO_UTF8( DateAndTime() ) ); // Output the cu layer stackup, so layer name references make sense. out.Print( 0, "Copper Layer Stackup:\n" ); out.Print( 0, separator ); LSET cu = m_pcb->GetEnabledLayers() & LSET::AllCuMask(); int conventional_layer_num = 1; for( LSEQ seq = cu.Seq(); seq; ++seq, ++conventional_layer_num ) { out.Print( 0, " L%-2d: %-25s %s\n", conventional_layer_num, TO_UTF8( m_pcb->GetLayerName( *seq ) ), layerName( *seq ).c_str() // generic layer name ); } out.Print( 0, "\n\n" ); /* output hole lists: * 1 - through holes * 2 - for partial holes only: by layer starting and ending pair * 3 - Non Plated through holes */ bool buildNPTHlist = false; // First pass: build PTH list only // in this loop are plated only: for( unsigned pair_ndx = 0; pair_ndx < hole_sets.size(); ++pair_ndx ) { DRILL_LAYER_PAIR pair = hole_sets[pair_ndx]; buildHolesList( pair, buildNPTHlist ); if( pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) ) { out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) ); out.Print( 0, " plated through holes:\n" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, false ); out.Print( 0, " Total plated holes count %u\n", totalHoleCount ); } else // blind/buried { out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) ); out.Print( 0, " holes connecting layer pair: '%s and %s' (%s vias):\n", TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.first ) ) ), TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.second ) ) ), pair.first == F_Cu || pair.second == B_Cu ? "blind" : "buried" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, false ); out.Print( 0, " Total plated holes count %u\n", totalHoleCount ); } out.Print( 0, "\n\n" ); } // NPTHoles. Generate the full list (pads+vias) if PTH and NPTH are merged, // or only the NPTH list (which never has vias) if( !m_merge_PTH_NPTH ) buildNPTHlist = true; buildHolesList( DRILL_LAYER_PAIR( F_Cu, B_Cu ), buildNPTHlist ); // nothing wrong with an empty NPTH file in report. if( m_merge_PTH_NPTH ) out.Print( 0, "Not plated through holes are merged with plated holes\n" ); else out.Print( 0, "Drill file '%s' contains\n", TO_UTF8( getDrillFileName( DRILL_LAYER_PAIR( F_Cu, B_Cu ), true, m_merge_PTH_NPTH ) ) ); out.Print( 0, " unplated through holes:\n" ); out.Print( 0, separator ); totalHoleCount = printToolSummary( out, true ); out.Print( 0, " Total unplated holes count %u\n", totalHoleCount ); return true; }
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 ); }