Move hole testing to DRC client and improve performance.
This commit is contained in:
parent
0658d297e5
commit
75b139c7b4
|
@ -233,6 +233,7 @@ set( PCBNEW_MICROWAVE_SRCS
|
|||
|
||||
set( PCBNEW_DRC_SRCS
|
||||
drc/drc_courtyard_tester.cpp
|
||||
drc/drc_drilled_hole_tester.cpp
|
||||
drc/drc.cpp
|
||||
drc/drc_clearance_test_functions.cpp
|
||||
drc/drc_rule_parser.cpp
|
||||
|
|
|
@ -24,7 +24,13 @@
|
|||
|
||||
/**
|
||||
* @file class_track.h
|
||||
* @brief Definitions for tracks, vias and zones.
|
||||
* @brief A single base class (TRACK) represents both tracks and vias, with subclasses
|
||||
* for curved tracks (ARC) and vias (VIA). All told there are three KICAD_Ts:
|
||||
* PCB_TRACK_T, PCB_ARC_T, and PCB_VIA_T.
|
||||
*
|
||||
* For vias there is a further VIATYPE which indicates THROUGH, BLIND_BURIED, or
|
||||
* MICROVIA, which are supported by the synthetic KICAD_Ts PCB_LOCATE_STDVIA_T,
|
||||
* PCB_LOCATE_BBVIA_T, and PCB_LOCATE_UVIA_T.
|
||||
*/
|
||||
|
||||
#ifndef CLASS_TRACK_H
|
||||
|
@ -367,6 +373,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
VIATYPE GetViaType() const { return m_ViaType; }
|
||||
void SetViaType( VIATYPE aViaType ) { m_ViaType = aViaType; }
|
||||
|
||||
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
|
||||
|
||||
virtual LSET GetLayerSet() const override;
|
||||
|
@ -429,16 +438,6 @@ public:
|
|||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
||||
VIATYPE GetViaType() const
|
||||
{
|
||||
return m_ViaType;
|
||||
}
|
||||
|
||||
void SetViaType( VIATYPE aViaType )
|
||||
{
|
||||
m_ViaType = aViaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetDrill
|
||||
* sets the drill value for vias.
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <tool/tool_manager.h>
|
||||
#include <tools/pcb_actions.h>
|
||||
#include <tools/pcb_tool_base.h>
|
||||
#include <tools/zone_filler_tool.h>
|
||||
#include <kiface_i.h>
|
||||
#include <pcbnew.h>
|
||||
#include <drc/drc.h>
|
||||
|
@ -53,7 +54,7 @@
|
|||
#include <geometry/shape_arc.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_courtyard_tester.h>
|
||||
#include <tools/zone_filler_tool.h>
|
||||
#include <drc/drc_drilled_hole_tester.h>
|
||||
#include <confirm.h>
|
||||
#include "drc_rule_parser.h"
|
||||
|
||||
|
@ -776,192 +777,9 @@ void DRC::testPad2Pad()
|
|||
|
||||
void DRC::testDrilledHoles()
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
DRC_DRILLED_HOLE_TESTER tester( [&]( MARKER_PCB* aMarker ) { addMarkerToPcb( aMarker ); } );
|
||||
|
||||
// Test drilled holes to minimize drill bit breakage.
|
||||
//
|
||||
// Check pad & std. via circular holes for hole-to-hole-min (non-circular holes are milled)
|
||||
// Check pad & std. via holes for via-min-drill (minimum hole classification)
|
||||
// Check uvia holes for uvia-min-drill (laser drill classification)
|
||||
|
||||
struct DRILLED_HOLE
|
||||
{
|
||||
wxPoint m_location;
|
||||
int m_drillRadius = 0;
|
||||
BOARD_ITEM* m_owner = nullptr;
|
||||
};
|
||||
|
||||
std::vector<DRILLED_HOLE> holes;
|
||||
DRILLED_HOLE hole;
|
||||
wxString msg;
|
||||
|
||||
for( MODULE* mod : m_pcb->Modules() )
|
||||
{
|
||||
for( D_PAD* pad : mod->Pads( ) )
|
||||
{
|
||||
int holeSize = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
|
||||
|
||||
if( holeSize == 0 )
|
||||
continue;
|
||||
|
||||
NETCLASS* netclass = pad->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
|
||||
: pad->GetNetClass().get();
|
||||
int minHole = bds.m_MinThroughDrill;
|
||||
wxString minHoleSource = _( "board" );
|
||||
|
||||
std::vector<DRC_SELECTOR*> matched;
|
||||
|
||||
MatchSelectors( bds.m_DRCRuleSelectors, pad, netclass, nullptr, nullptr, &matched );
|
||||
|
||||
for( DRC_SELECTOR* selector : matched )
|
||||
{
|
||||
if( selector->m_Rule->m_Hole > minHole )
|
||||
{
|
||||
minHole = selector->m_Rule->m_Hole;
|
||||
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
|
||||
}
|
||||
}
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) && holeSize < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_PAD_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( userUnits(), minHole, true ),
|
||||
MessageTextFromValue( userUnits(), holeSize, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( pad );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() );
|
||||
addMarkerToPcb( marker );
|
||||
}
|
||||
|
||||
if( 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 )
|
||||
continue;
|
||||
|
||||
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
|
||||
: via->GetNetClass().get();
|
||||
int minHole = 0;
|
||||
wxString minHoleSource;
|
||||
|
||||
std::vector<DRC_SELECTOR*> matched;
|
||||
|
||||
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
|
||||
|
||||
for( DRC_SELECTOR* selector : matched )
|
||||
{
|
||||
if( selector->m_Rule->m_Hole > minHole )
|
||||
{
|
||||
minHole = selector->m_Rule->m_Hole;
|
||||
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
|
||||
}
|
||||
}
|
||||
|
||||
if( via->GetViaType() == VIATYPE::MICROVIA )
|
||||
{
|
||||
if( bds.m_MicroViasMinDrill > minHole )
|
||||
{
|
||||
minHole = bds.m_MicroViasMinDrill;
|
||||
minHoleSource = _( "board" );
|
||||
}
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) && via->GetDrillValue() < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( userUnits(), minHole, true ),
|
||||
MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( via );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, via->GetPosition() );
|
||||
addMarkerToPcb( marker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( bds.m_MinThroughDrill > minHole )
|
||||
{
|
||||
minHole = bds.m_MinThroughDrill;
|
||||
minHoleSource = _( "board" );
|
||||
}
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) && via->GetDrillValue() < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( userUnits(), minHole, true ),
|
||||
MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( via );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, via->GetPosition() );
|
||||
addMarkerToPcb( marker );
|
||||
}
|
||||
|
||||
hole.m_location = via->GetPosition();
|
||||
hole.m_drillRadius = via->GetDrillValue() / 2;
|
||||
hole.m_owner = via;
|
||||
holes.push_back( hole );
|
||||
}
|
||||
}
|
||||
|
||||
if( bds.m_HoleToHoleMin == 0 || bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) )
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) );
|
||||
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
|
||||
|
||||
if( actual < bds.m_HoleToHoleMin )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( userUnits(), bds.m_HoleToHoleMin, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
|
||||
|
||||
MARKER_PCB* marker = new MARKER_PCB( drcItem, refHole.m_location );
|
||||
addMarkerToPcb( marker );
|
||||
}
|
||||
}
|
||||
}
|
||||
tester.RunDRC( userUnits(), *m_pcb );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1890,9 +1708,9 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li
|
|||
|
||||
void DRC::doCourtyardsDrc()
|
||||
{
|
||||
DRC_COURTYARD_TESTER drc_overlap( [&]( MARKER_PCB* aMarker ) { addMarkerToPcb( aMarker ); } );
|
||||
DRC_COURTYARD_TESTER tester( [&]( MARKER_PCB* aMarker ) { addMarkerToPcb( aMarker ); } );
|
||||
|
||||
drc_overlap.RunDRC( *m_pcb );
|
||||
tester.RunDRC( userUnits(), *m_pcb );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,26 +33,15 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Flag to enable courtyard DRC debug tracing.
|
||||
*
|
||||
* Use "KICAD_DRC_COURTYARD" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
static const wxChar* DRC_COURTYARD_TRACE = wxT( "KICAD_DRC_COURTYARD" );
|
||||
|
||||
|
||||
DRC_COURTYARD_TESTER::DRC_COURTYARD_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
||||
DRC_TEST_PROVIDER( aMarkerHandler )
|
||||
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const
|
||||
bool DRC_COURTYARD_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
||||
{
|
||||
wxLogTrace( DRC_COURTYARD_TRACE, "Running DRC: Courtyard" );
|
||||
|
||||
// Detects missing (or malformed) footprint courtyards and courtyard incursions (for those
|
||||
// with a courtyard).
|
||||
wxString msg;
|
||||
|
@ -96,8 +85,6 @@ bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const
|
|||
|
||||
if( !aBoard.GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) )
|
||||
{
|
||||
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for courtyard overlap" );
|
||||
|
||||
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ )
|
||||
{
|
||||
MODULE* footprint = *it1;
|
||||
|
@ -162,8 +149,6 @@ bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const
|
|||
if( !aBoard.GetDesignSettings().Ignore( DRCE_PTH_IN_COURTYARD )
|
||||
|| !aBoard.GetDesignSettings().Ignore( DRCE_NPTH_IN_COURTYARD ) )
|
||||
{
|
||||
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for through-holes in courtyards" );
|
||||
|
||||
for( MODULE* footprint : aBoard.Modules() )
|
||||
{
|
||||
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
|
||||
|
|
|
@ -25,13 +25,11 @@
|
|||
#ifndef DRC_COURTYARD_OVERLAP__H
|
||||
#define DRC_COURTYARD_OVERLAP__H
|
||||
|
||||
#include <class_board.h>
|
||||
|
||||
#include <drc/drc_provider.h>
|
||||
|
||||
/**
|
||||
* A class that provides the courtyard-based DRC checks.
|
||||
*/
|
||||
|
||||
class BOARD;
|
||||
|
||||
class DRC_COURTYARD_TESTER : public DRC_TEST_PROVIDER
|
||||
{
|
||||
public:
|
||||
|
@ -39,7 +37,7 @@ public:
|
|||
|
||||
virtual ~DRC_COURTYARD_TESTER() {};
|
||||
|
||||
bool RunDRC( BOARD& aBoard ) const override;
|
||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
||||
};
|
||||
|
||||
#endif // DRC_COURTYARD_OVERLAP__H
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <drc/drc_drilled_hole_tester.h>
|
||||
|
||||
#include <class_module.h>
|
||||
#include <drc/drc.h>
|
||||
|
||||
#include <widgets/ui_common.h>
|
||||
|
||||
|
||||
DRC_DRILLED_HOLE_TESTER::DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler ) :
|
||||
DRC_TEST_PROVIDER( std::move( aMarkerHandler ) ),
|
||||
m_units( EDA_UNITS::MILLIMETRES ),
|
||||
m_board( nullptr ),
|
||||
m_largestRadius( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool DRC_DRILLED_HOLE_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
// Test drilled holes to minimize drill bit breakage.
|
||||
//
|
||||
// Check pad & std. via circular holes for hole-to-hole-min (non-circular holes are milled)
|
||||
// Check pad & std. via holes for via-min-drill (minimum hole classification)
|
||||
// Check uvia holes for uvia-min-drill (laser drill classification)
|
||||
|
||||
m_units = aUnits;
|
||||
m_board = &aBoard;
|
||||
m_holes.clear();
|
||||
m_largestRadius = 0;
|
||||
|
||||
for( MODULE* mod : aBoard.Modules() )
|
||||
{
|
||||
for( D_PAD* pad : mod->Pads( ) )
|
||||
success |= checkPad( pad );
|
||||
}
|
||||
|
||||
for( TRACK* track : aBoard.Tracks() )
|
||||
{
|
||||
VIA* via = dynamic_cast<VIA*>( track );
|
||||
|
||||
if( via )
|
||||
{
|
||||
if( via->GetViaType() == VIATYPE::MICROVIA )
|
||||
success |= checkMicroVia( via );
|
||||
else
|
||||
success |= checkVia( via );
|
||||
}
|
||||
}
|
||||
|
||||
success |= checkHoles();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
|
||||
{
|
||||
wxString msg;
|
||||
bool success = true;
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
||||
|
||||
if( holeSize == 0 )
|
||||
return true;
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) )
|
||||
{
|
||||
NETCLASS* netclass = aPad->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
|
||||
: aPad->GetNetClass().get();
|
||||
int minHole = bds.m_MinThroughDrill;
|
||||
wxString minHoleSource = _( "board" );
|
||||
|
||||
std::vector<DRC_SELECTOR*> matched;
|
||||
MatchSelectors( bds.m_DRCRuleSelectors, aPad, netclass, nullptr, nullptr, &matched );
|
||||
|
||||
for( DRC_SELECTOR* selector : matched )
|
||||
{
|
||||
if( selector->m_Rule->m_Hole > minHole )
|
||||
{
|
||||
minHole = selector->m_Rule->m_Hole;
|
||||
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
|
||||
}
|
||||
}
|
||||
|
||||
if( holeSize < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_PAD_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( m_units, minHole, true ),
|
||||
MessageTextFromValue( m_units, holeSize, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( aPad );
|
||||
|
||||
HandleMarker( new MARKER_PCB( drcItem, aPad->GetPosition() ) );
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
|
||||
{
|
||||
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
|
||||
addHole( aPad->GetPosition(), aPad->GetDrillSize().x / 2, aPad );
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
|
||||
{
|
||||
wxString msg;
|
||||
bool success = true;
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) )
|
||||
{
|
||||
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
|
||||
: via->GetNetClass().get();
|
||||
int minHole = bds.m_MinThroughDrill;
|
||||
wxString minHoleSource = _( "board" );
|
||||
|
||||
std::vector<DRC_SELECTOR*> matched;
|
||||
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
|
||||
|
||||
for( DRC_SELECTOR* selector : matched )
|
||||
{
|
||||
if( selector->m_Rule->m_Hole > minHole )
|
||||
{
|
||||
minHole = selector->m_Rule->m_Hole;
|
||||
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
|
||||
}
|
||||
}
|
||||
|
||||
if( via->GetDrillValue() < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_VIA_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s min hole %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( m_units, minHole, true ),
|
||||
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( via );
|
||||
|
||||
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( !bds.Ignore( DRCE_DRILLED_HOLES_TOO_CLOSE ) && bds.m_HoleToHoleMin != 0 )
|
||||
{
|
||||
addHole( via->GetPosition(), via->GetDrillValue() / 2, via );
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
|
||||
{
|
||||
wxString msg;
|
||||
bool success = true;
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
|
||||
{
|
||||
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault().get()
|
||||
: via->GetNetClass().get();
|
||||
int minHole = bds.m_MicroViasMinDrill;
|
||||
wxString minHoleSource = _( "board" );
|
||||
|
||||
std::vector<DRC_SELECTOR*> matched;
|
||||
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
|
||||
|
||||
for( DRC_SELECTOR* selector : matched )
|
||||
{
|
||||
if( selector->m_Rule->m_Hole > minHole )
|
||||
{
|
||||
minHole = selector->m_Rule->m_Hole;
|
||||
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
|
||||
}
|
||||
}
|
||||
|
||||
if( via->GetDrillValue() < minHole )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_MICROVIA_DRILL );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s minimum %s; actual %s)" ),
|
||||
minHoleSource,
|
||||
MessageTextFromValue( m_units, minHole, true ),
|
||||
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( via );
|
||||
|
||||
HandleMarker( new MARKER_PCB( drcItem, via->GetPosition() ) );
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void DRC_DRILLED_HOLE_TESTER::addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner )
|
||||
{
|
||||
DRILLED_HOLE hole;
|
||||
|
||||
hole.m_location = aLocation;
|
||||
hole.m_drillRadius = aRadius;
|
||||
hole.m_owner = aOwner;
|
||||
|
||||
m_largestRadius = std::max( m_largestRadius, aRadius );
|
||||
|
||||
m_holes.push_back( hole );
|
||||
}
|
||||
|
||||
|
||||
bool DRC_DRILLED_HOLE_TESTER::checkHoles()
|
||||
{
|
||||
wxString msg;
|
||||
bool success = true;
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
// No need to check if we're ignoring DRCE_DRILLED_HOLES_TOO_CLOSE; if we are then we
|
||||
// won't have collected any holes to test.
|
||||
|
||||
// Sort holes by X for performance. In the nested iteration we then need to look at
|
||||
// following holes only while they are within the refHole's neighborhood as defined by
|
||||
// the refHole radius + the minimum hole-to-hole clearance + the largest radius any of
|
||||
// the following holes can have.
|
||||
std::sort( m_holes.begin(), m_holes.end(),
|
||||
[]( const DRILLED_HOLE& a, const DRILLED_HOLE& b )
|
||||
{
|
||||
if( a.m_location.x == b.m_location.x )
|
||||
return a.m_location.y < b.m_location.y;
|
||||
else
|
||||
return a.m_location.x < b.m_location.x;
|
||||
} );
|
||||
|
||||
for( size_t ii = 0; ii < m_holes.size(); ++ii )
|
||||
{
|
||||
const DRILLED_HOLE& refHole = m_holes[ ii ];
|
||||
int neighborhood = refHole.m_drillRadius + bds.m_HoleToHoleMin + m_largestRadius;
|
||||
|
||||
for( size_t jj = ii + 1; jj < m_holes.size(); ++jj )
|
||||
{
|
||||
const DRILLED_HOLE& checkHole = m_holes[ jj ];
|
||||
|
||||
if( refHole.m_location.x + neighborhood < checkHole.m_location.x )
|
||||
break;
|
||||
|
||||
// Holes with identical locations are allowable
|
||||
if( checkHole.m_location == refHole.m_location )
|
||||
continue;
|
||||
|
||||
int actual = KiROUND( GetLineLength( checkHole.m_location, refHole.m_location ) );
|
||||
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
|
||||
|
||||
if( actual < bds.m_HoleToHoleMin )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_DRILLED_HOLES_TOO_CLOSE );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
|
||||
MessageTextFromValue( m_units, bds.m_HoleToHoleMin, true ),
|
||||
MessageTextFromValue( m_units, actual, true ) );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
|
||||
|
||||
HandleMarker( new MARKER_PCB( drcItem, refHole.m_location ) );
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DRC_DRILLED_HOLE_TESTER__H
|
||||
#define DRC_DRILLED_HOLE_TESTER__H
|
||||
|
||||
#include <drc/drc_provider.h>
|
||||
|
||||
|
||||
class BOARD;
|
||||
class BOARD_ITEM;
|
||||
|
||||
|
||||
class DRC_DRILLED_HOLE_TESTER : public DRC_TEST_PROVIDER
|
||||
{
|
||||
public:
|
||||
DRC_DRILLED_HOLE_TESTER( MARKER_HANDLER aMarkerHandler );
|
||||
|
||||
virtual ~DRC_DRILLED_HOLE_TESTER() {};
|
||||
|
||||
bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) override;
|
||||
|
||||
private:
|
||||
bool checkPad( D_PAD* aPad );
|
||||
bool checkVia( VIA* aVia );
|
||||
bool checkMicroVia( VIA* aVia );
|
||||
|
||||
void addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner );
|
||||
bool checkHoles();
|
||||
|
||||
private:
|
||||
struct DRILLED_HOLE
|
||||
{
|
||||
wxPoint m_location;
|
||||
int m_drillRadius = 0;
|
||||
BOARD_ITEM* m_owner = nullptr;
|
||||
};
|
||||
|
||||
EDA_UNITS m_units;
|
||||
BOARD* m_board;
|
||||
std::vector<DRILLED_HOLE> m_holes;
|
||||
int m_largestRadius;
|
||||
};
|
||||
|
||||
#endif // DRC_DRILLED_HOLE_TESTER__H
|
|
@ -50,7 +50,7 @@ public:
|
|||
* Note: Board is non-const, as some DRC functions modify the board (e.g. zone fill
|
||||
* or polygon coalescing)
|
||||
*/
|
||||
virtual bool RunDRC( BOARD& aBoard ) const = 0;
|
||||
virtual bool RunDRC( EDA_UNITS aUnits, BOARD& aBoard ) = 0;
|
||||
|
||||
virtual ~DRC_TEST_PROVIDER() {}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include <widgets/ui_common.h>
|
||||
|
||||
#include "../board_test_utils.h"
|
||||
#include "drc_test_utils.h"
|
||||
|
||||
|
||||
struct COURTYARD_TEST_FIXTURE
|
||||
|
@ -281,9 +280,9 @@ static bool InvalidMatchesExpected( BOARD& aBoard, const MARKER_PCB& aMarker,
|
|||
* @param aMarkers list of markers produced by the DRC
|
||||
* @param aCollisions list of expected collisions
|
||||
*/
|
||||
static void CheckInvalidsMatchExpected( BOARD& aBoard,
|
||||
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers,
|
||||
const std::vector<COURTYARD_INVALID_INFO>& aExpInvalids )
|
||||
static void CheckInvalidsMatchExpected( BOARD& aBoard,
|
||||
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers,
|
||||
const std::vector<COURTYARD_INVALID_INFO>& aExpInvalids )
|
||||
{
|
||||
KI_TEST::CheckUnorderedMatches( aExpInvalids, aMarkers,
|
||||
[&]( const COURTYARD_INVALID_INFO& aInvalid,
|
||||
|
@ -294,8 +293,8 @@ static void CheckInvalidsMatchExpected( BOARD& aBoard,
|
|||
}
|
||||
|
||||
|
||||
void DoCourtyardInvalidTest(
|
||||
const COURTYARD_INVALID_CASE& aCase, const KI_TEST::BOARD_DUMPER& aDumper )
|
||||
void DoCourtyardInvalidTest( const COURTYARD_INVALID_CASE& aCase,
|
||||
const KI_TEST::BOARD_DUMPER& aDumper )
|
||||
{
|
||||
auto board = MakeBoard( aCase.m_mods );
|
||||
|
||||
|
@ -313,7 +312,7 @@ void DoCourtyardInvalidTest(
|
|||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
||||
} );
|
||||
|
||||
drc_overlap.RunDRC( *board );
|
||||
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board );
|
||||
|
||||
CheckInvalidsMatchExpected( *board, markers, aCase.m_exp_errors );
|
||||
}
|
||||
|
|
|
@ -423,9 +423,9 @@ static bool CollisionMatchesExpected( BOARD& aBoard, const MARKER_PCB& aMarker,
|
|||
* @param aMarkers list of markers produced by the DRC
|
||||
* @param aCollisions list of expected collisions
|
||||
*/
|
||||
static void CheckCollisionsMatchExpected( BOARD& aBoard,
|
||||
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers,
|
||||
const std::vector<COURTYARD_COLLISION>& aExpCollisions )
|
||||
static void CheckCollisionsMatchExpected( BOARD& aBoard,
|
||||
const std::vector<std::unique_ptr<MARKER_PCB>>& aMarkers,
|
||||
const std::vector<COURTYARD_COLLISION>& aExpCollisions )
|
||||
{
|
||||
for( const auto& marker : aMarkers )
|
||||
{
|
||||
|
@ -460,8 +460,8 @@ static BOARD_DESIGN_SETTINGS GetOverlapCheckDesignSettings()
|
|||
* Run a single courtyard overlap testcase
|
||||
* @param aCase The testcase to run.
|
||||
*/
|
||||
static void DoCourtyardOverlapTest(
|
||||
const COURTYARD_OVERLAP_TEST_CASE& aCase, const KI_TEST::BOARD_DUMPER& aDumper )
|
||||
static void DoCourtyardOverlapTest( const COURTYARD_OVERLAP_TEST_CASE& aCase,
|
||||
const KI_TEST::BOARD_DUMPER& aDumper )
|
||||
{
|
||||
auto board = MakeBoard( aCase.m_mods );
|
||||
|
||||
|
@ -479,7 +479,7 @@ static void DoCourtyardOverlapTest(
|
|||
markers.push_back( std::unique_ptr<MARKER_PCB>( aMarker ) );
|
||||
} );
|
||||
|
||||
drc_overlap.RunDRC( *board );
|
||||
drc_overlap.RunDRC( EDA_UNITS::MILLIMETRES, *board );
|
||||
|
||||
CheckCollisionsMatchExpected( *board, markers, aCase.m_collisions );
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
DRC_DURATION duration;
|
||||
{
|
||||
SCOPED_PROF_COUNTER<DRC_DURATION> timer( duration );
|
||||
drc_prov->RunDRC( aBoard );
|
||||
drc_prov->RunDRC( EDA_UNITS::MILLIMETRES, aBoard );
|
||||
}
|
||||
|
||||
// report results
|
||||
|
|
Loading…
Reference in New Issue