Add hole-to-hole clearance testing to DRC.

Also move courtyard testing flags to BoardSettings API.  Both are
still stored in the config until we decide where they go in order
to prevent prematurely disturbing the board file format.

Fixes: lp:684067
* https://bugs.launchpad.net/kicad/+bug/684067

(cherry picked from commit 5399f60)
This commit is contained in:
Jeff Young 2018-04-14 15:58:01 +01:00
parent eacaa39aa2
commit bbc25cd694
6 changed files with 205 additions and 26 deletions

View File

@ -52,6 +52,7 @@
#define DEFAULT_VIASMINDRILL 0.3 // vias (not micro vias) min drill diameter
#define DEFAULT_MICROVIASMINSIZE 0.2 // micro vias (not vias) min diameter
#define DEFAULT_MICROVIASMINDRILL 0.1 // micro vias (not vias) min drill diameter
#define DEFAULT_HOLETOHOLEMIN 0.25 // separation between drilled hole edges
/**
* Struct VIA_DIMENSION
@ -413,6 +414,44 @@ public:
return m_useCustomTrackVia;
}
/**
* Function GetMinHoleSeparation
* @return The minimum distance between the edges of two holes or 0, which indicates that
* hole-to-hole separation should not be checked.
*/
int GetMinHoleSeparation() const;
/**
* Function SetMinHoleSeparation
* @param aValue The minimum distance between the edges of two holes or 0 to disable
* hole-to-hole separation checking.
*/
void SetMinHoleSeparation( int aDistance );
/**
* Function RequireCourtyardDefinitions
* @return True if footprints without courtyard definitions are considered DRC violations.
*/
bool RequireCourtyardDefinitions() const;
/**
* Function SetRequireCourtyardDefinitions
* @param aRequire Set to true to generate DRC violations from missing courtyards.
*/
void SetRequireCourtyardDefinitions( bool aRequire );
/**
* Function ProhibitOverlappingCourtyards
* @return True if overlapping courtyards are considered DRC violations.
*/
bool ProhibitOverlappingCourtyards() const;
/**
* Function SetProhibitOverlappingCourtyards
* @param aRequire Set to true to generate DRC violations from overlapping courtyards.
*/
void SetProhibitOverlappingCourtyards( bool aRequire );
/**
* Function GetVisibleLayers
* returns a bit-mask of all the layers that are visible

View File

@ -35,6 +35,11 @@
#include <class_track.h>
#include <convert_to_biu.h>
#include <kiface_i.h>
#define TestMissingCourtyardKey wxT( "TestMissingCourtyard" )
#define TestFootprintCourtyardKey wxT( "TestFootprintCourtyard" )
#define MinHoleSeparationKey wxT( "MinHoleSeparation" )
BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
@ -58,12 +63,12 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
m_UseConnectedTrackWidth = false;
m_BlindBuriedViaAllowed = false; // true to allow blind/buried vias
m_MicroViasAllowed = false; // true to allow micro vias
m_MicroViasAllowed = false; // true to allow micro vias
m_DrawSegmentWidth = Millimeter2iu( DEFAULT_GRAPHIC_THICKNESS ); // current graphic line width (not EDGE layer)
m_DrawSegmentWidth = Millimeter2iu( DEFAULT_GRAPHIC_THICKNESS ); // current graphic line width (not EDGE layer)
m_EdgeSegmentWidth = Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ); // current graphic line width (EDGE layer only)
m_PcbTextWidth = Millimeter2iu( DEFAULT_TEXT_PCB_THICKNESS ); // current Pcb (not module) Text width
m_EdgeSegmentWidth = Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ); // current graphic line width (EDGE layer only)
m_PcbTextWidth = Millimeter2iu( DEFAULT_TEXT_PCB_THICKNESS ); // current Pcb (not module) Text width
m_PcbTextSize = wxSize( Millimeter2iu( DEFAULT_TEXT_PCB_SIZE ),
Millimeter2iu( DEFAULT_TEXT_PCB_SIZE ) ); // current Pcb (not module) Text size
@ -315,6 +320,70 @@ void BOARD_DESIGN_SETTINGS::SetTrackWidthIndex( unsigned aIndex )
}
int BOARD_DESIGN_SETTINGS::GetMinHoleSeparation() const
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
int value;
config->Read( MinHoleSeparationKey, &value, Millimeter2iu( DEFAULT_HOLETOHOLEMIN ) );
return value;
}
void BOARD_DESIGN_SETTINGS::SetMinHoleSeparation( int aDistance )
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
config->Write( MinHoleSeparationKey, aDistance );
}
bool BOARD_DESIGN_SETTINGS::RequireCourtyardDefinitions() const
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
bool value;
config->Read( TestMissingCourtyardKey, &value, false );
return value;
}
void BOARD_DESIGN_SETTINGS::SetRequireCourtyardDefinitions( bool aRequire )
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
config->Write( TestMissingCourtyardKey, aRequire );
}
bool BOARD_DESIGN_SETTINGS::ProhibitOverlappingCourtyards() const
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
bool value;
config->Read( TestFootprintCourtyardKey, &value, false );
return value;
}
void BOARD_DESIGN_SETTINGS::SetProhibitOverlappingCourtyards( bool aRequire )
{
// 6.0 TODO: we need to decide where these go, but until then don't disturb the
// file format unnecessarily.
wxConfigBase* config = Kiface().KifaceSettings();
config->Write( TestFootprintCourtyardKey, aRequire );
}
void BOARD_DESIGN_SETTINGS::SetVisibleAlls()
{
SetVisibleLayers( LSET().set() );

View File

@ -251,8 +251,6 @@ void DIALOG_DRC_CONTROL::OnStartdrcClick( wxCommandEvent& event )
true, // DRC test for zones enabled
true, // DRC test for keepout areas enabled
m_cbRefillZones->GetValue(),
m_cbCourtyardOverlap->GetValue(),
m_cbCourtyardMissing->GetValue(),
m_cbReportAllTrackErrors->GetValue(),
reportName, make_report );
@ -325,8 +323,6 @@ void DIALOG_DRC_CONTROL::OnListUnconnectedClick( wxCommandEvent& event )
true, // DRC test for zones enabled
true, // DRC test for keepout areas enabled
m_cbRefillZones->GetValue(),
m_cbCourtyardOverlap->GetValue(),
m_cbCourtyardMissing->GetValue(),
m_cbReportAllTrackErrors->GetValue(),
reportName, make_report );

View File

@ -138,10 +138,6 @@ DRC::DRC( PCB_EDIT_FRAME* aPcbWindow )
m_doUnconnectedTest = true; // enable unconnected tests
m_doZonesTest = true; // enable zone to items clearance tests
m_doKeepoutTest = true; // enable keepout areas to items clearance tests
m_doFootprintOverlapping = true; // enable courtyards areas overlap tests
m_doNoCourtyardDefined = true; // enable missing courtyard in footprint warning
m_abortDRC = false;
m_drcInProgress = false;
m_refillZones = false; // Only fill zones if requested by user.
m_reportAllTrackErrors = false;
m_doCreateRptFile = false;
@ -423,6 +419,15 @@ void DRC::RunTests( wxTextCtrl* aMessages )
testPad2Pad();
}
// test clearances between drilled holes
if( aMessages )
{
aMessages->AppendText( _( "Drill clearances...\n" ) );
wxSafeYield();
}
testDrilledHoles();
// test track and via clearances to other tracks, pads, and vias
if( aMessages )
{
@ -493,7 +498,8 @@ void DRC::RunTests( wxTextCtrl* aMessages )
testTexts();
// find overlapping courtyard ares.
if( m_doFootprintOverlapping || m_doNoCourtyardDefined )
if( m_pcb->GetDesignSettings().ProhibitOverlappingCourtyards()
|| m_pcb->GetDesignSettings().RequireCourtyardDefinitions() )
{
if( aMessages )
{
@ -708,6 +714,78 @@ void DRC::testPad2Pad()
}
void DRC::testDrilledHoles()
{
int holeToHoleMin = m_pcb->GetDesignSettings().GetMinHoleSeparation();
if( holeToHoleMin == 0 ) // No min setting turns testing off.
return;
// Test drilled hole clearances to minimize drill bit breakage.
//
// Notes: slots are milled, so we're only concerned with circular holes
// microvias are laser-drilled, so we're only concerned with standard vias
struct DRILLED_HOLE
{
wxPoint m_location;
int m_drillRadius;
BOARD_ITEM* m_owner;
};
std::vector<DRILLED_HOLE> holes;
DRILLED_HOLE hole;
for( MODULE* mod : m_pcb->Modules() )
{
for( D_PAD* pad : mod->Pads( ) )
{
if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
hole.m_location = pad->GetPosition();
hole.m_drillRadius = pad->GetDrillSize().x / 2;
hole.m_owner = pad;
holes.push_back( hole );
}
}
}
for( TRACK* track : m_pcb->Tracks() )
{
VIA* via = dynamic_cast<VIA*>( track );
if( via && via->GetViaType() == VIA_THROUGH )
{
hole.m_location = via->GetPosition();
hole.m_drillRadius = via->GetDrillValue() / 2;
hole.m_owner = via;
holes.push_back( hole );
}
}
for( size_t ii = 0; ii < holes.size(); ++ii )
{
const DRILLED_HOLE& refHole = holes[ ii ];
for( size_t jj = ii + 1; jj < holes.size(); ++jj )
{
const DRILLED_HOLE& checkHole = holes[ jj ];
// Holes with identical locations are allowable
if( checkHole.m_location == refHole.m_location )
continue;
if( KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) )
< checkHole.m_drillRadius + refHole.m_drillRadius + holeToHoleMin )
{
addMarkerToPcb( new MARKER_PCB( DRCE_DRILLED_HOLES_TOO_CLOSE, refHole.m_location,
refHole.m_owner, refHole.m_location,
checkHole.m_owner, checkHole.m_location ) );
}
}
}
}
void DRC::testTracks( wxWindow *aActiveWindow, bool aShowProgressBar )
{
wxProgressDialog * progressDialog = NULL;
@ -1243,7 +1321,7 @@ bool DRC::doFootprintOverlappingDrc()
{
bool is_ok = footprint->BuildPolyCourtyard();
if( !is_ok && m_doFootprintOverlapping )
if( !is_ok && m_pcb->GetDesignSettings().ProhibitOverlappingCourtyards() )
{
m_currentMarker = fillMarker( footprint, footprint->GetPosition(),
DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT,
@ -1253,7 +1331,7 @@ bool DRC::doFootprintOverlappingDrc()
success = false;
}
if( !m_doNoCourtyardDefined )
if( !m_pcb->GetDesignSettings().RequireCourtyardDefinitions() )
continue;
if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 &&
@ -1269,7 +1347,7 @@ bool DRC::doFootprintOverlappingDrc()
}
}
if( !m_doFootprintOverlapping )
if( !m_pcb->GetDesignSettings().ProhibitOverlappingCourtyards() )
return success;
// Now test for overlapping on top layer:

View File

@ -91,6 +91,7 @@
#define DRCE_MICRO_VIA_NOT_ALLOWED 47 ///< micro vias are not allowed
#define DRCE_BURIED_VIA_NOT_ALLOWED 48 ///< buried vias are not allowed
#define DRCE_DISABLED_LAYER_ITEM 49 ///< item on a disabled layer
#define DRCE_DRILLED_HOLES_TOO_CLOSE 50 ///< overlapping drilled holes break drill bits
class EDA_DRAW_PANEL;
@ -172,8 +173,6 @@ private:
bool m_doZonesTest;
bool m_doKeepoutTest;
bool m_doCreateRptFile;
bool m_doFootprintOverlapping;
bool m_doNoCourtyardDefined;
bool m_refillZones;
bool m_reportAllTrackErrors;
@ -181,9 +180,6 @@ private:
MARKER_PCB* m_currentMarker;
bool m_abortDRC;
bool m_drcInProgress;
/**
* in legacy canvas, when creating a track, the drc test must only display the
* error message, and do not create a DRC marker.
@ -307,6 +303,8 @@ private:
void testPad2Pad();
void testDrilledHoles();
void testUnconnected();
void testZones();
@ -435,6 +433,7 @@ public:
~DRC();
/**
* Function Drc
* tests the current segment and returns the result and displays the error
* in the status panel only if one exists.
* No marker created or added to the board. Must be used only during track
@ -446,6 +445,7 @@ public:
int DrcOnCreatingTrack( TRACK* aRefSeg, TRACK* aList );
/**
* Function Drc
* tests the outline segment starting at CornerIndex and returns the result and displays
* the error in the status panel only if one exists.
* Test Edge inside other areas
@ -503,15 +503,12 @@ public:
* @param aZonesTest Tells whether to test zones.
* @param aRefillZones Refill zones before performing DRC.
* @param aKeepoutTest Tells whether to test keepout areas.
* @param aCourtyardTest Tells whether to test footprint courtyard overlap.
* @param aCourtyardMissingTest Tells whether to test missing courtyard definition in footprint.
* @param aReportAllTrackErrors Tells whether or not to stop checking track connections after the first error.
* @param aReportName A string telling the disk file report name entered.
* @param aSaveReport A boolean telling whether to generate disk file report.
*/
void SetSettings( bool aPad2PadTest, bool aUnconnectedTest,
bool aZonesTest, bool aKeepoutTest, bool aRefillZones,
bool aCourtyardTest, bool aCourtyardMissingTest,
bool aReportAllTrackErrors,
const wxString& aReportName, bool aSaveReport )
{
@ -521,8 +518,6 @@ public:
m_doKeepoutTest = aKeepoutTest;
m_rptFilename = aReportName;
m_doCreateRptFile = aSaveReport;
m_doFootprintOverlapping = aCourtyardTest;
m_doNoCourtyardDefined = aCourtyardMissingTest;
m_refillZones = aRefillZones;
m_drcInLegacyRoutingMode = false;
m_reportAllTrackErrors = aReportAllTrackErrors;

View File

@ -97,6 +97,8 @@ wxString DRC_ITEM::GetErrorText() const
return wxString( _( "Too small via drill" ) );
case DRCE_TOO_SMALL_MICROVIA_DRILL:
return wxString( _( "Too small micro via drill" ) );
case DRCE_DRILLED_HOLES_TOO_CLOSE:
return wxString( _( "Drilled holes too close together" ) );
// use &lt; since this is text ultimately embedded in HTML
case DRCE_NETCLASS_TRACKWIDTH: