Add overlapping pad test and share some tests between board & fp editor DRC.
Fixes https://gitlab.com/kicad/code/kicad/issues/10086
This commit is contained in:
parent
b497647873
commit
5aa561abe1
|
@ -183,6 +183,10 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
|
||||||
m_DRCSeverities[ DRCE_TEXT_HEIGHT ] = RPT_SEVERITY_WARNING;
|
m_DRCSeverities[ DRCE_TEXT_HEIGHT ] = RPT_SEVERITY_WARNING;
|
||||||
m_DRCSeverities[ DRCE_TEXT_THICKNESS ] = RPT_SEVERITY_WARNING;
|
m_DRCSeverities[ DRCE_TEXT_THICKNESS ] = RPT_SEVERITY_WARNING;
|
||||||
|
|
||||||
|
m_DRCSeverities[ DRCE_FOOTPRINT_TYPE_MISMATCH ] = RPT_SEVERITY_WARNING;
|
||||||
|
m_DRCSeverities[ DRCE_LIB_FOOTPRINT_ISSUES ] = RPT_SEVERITY_WARNING;
|
||||||
|
m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = RPT_SEVERITY_WARNING;
|
||||||
|
|
||||||
m_MaxError = ARC_HIGH_DEF;
|
m_MaxError = ARC_HIGH_DEF;
|
||||||
m_ZoneKeepExternalFillets = false;
|
m_ZoneKeepExternalFillets = false;
|
||||||
m_UseHeightForLengthCalcs = true;
|
m_UseHeightForLengthCalcs = true;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <footprint.h>
|
#include <footprint.h>
|
||||||
|
#include <pad.h>
|
||||||
#include <pcb_marker.h>
|
#include <pcb_marker.h>
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <footprint_edit_frame.h>
|
#include <footprint_edit_frame.h>
|
||||||
|
@ -101,12 +102,15 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTLINE_ERROR_HANDLER errorHandler =
|
auto errorHandler =
|
||||||
[&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt )
|
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, int aErrorCode,
|
||||||
|
const wxString& aMsg, const VECTOR2I& aPt )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( aErrorCode );
|
||||||
|
|
||||||
|
if( !aMsg.IsEmpty() )
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
|
|
||||||
drcItem->SetItems( aItemA, aItemB );
|
drcItem->SetItems( aItemA, aItemB );
|
||||||
|
|
||||||
PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
|
PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
|
||||||
|
@ -114,37 +118,32 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
|
||||||
m_frame->GetCanvas()->GetView()->Add( marker );
|
m_frame->GetCanvas()->GetView()->Add( marker );
|
||||||
};
|
};
|
||||||
|
|
||||||
footprint->BuildPolyCourtyards( &errorHandler );
|
OUTLINE_ERROR_HANDLER outlineErrorHandler =
|
||||||
|
[&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt )
|
||||||
|
|
||||||
const std::function<void( const wxString& msg )> typeWarning =
|
|
||||||
[&]( const wxString& aMsg )
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_FOOTPRINT_TYPE_MISMATCH );
|
errorHandler( aItemA, aItemB, DRCE_MALFORMED_COURTYARD, aMsg, aPt );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
|
|
||||||
drcItem->SetItems( footprint );
|
|
||||||
|
|
||||||
PCB_MARKER* marker = new PCB_MARKER( drcItem, wxPoint( 0, 0 ) );
|
|
||||||
board->Add( marker );
|
|
||||||
m_frame->GetCanvas()->GetView()->Add( marker );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::function<void( const wxString& msg, const VECTOR2I& position )> tstHoleInTHPad =
|
footprint->BuildPolyCourtyards( &outlineErrorHandler );
|
||||||
[&]( const wxString& aMsg, const VECTOR2I& aPosition )
|
|
||||||
|
footprint->CheckFootprintAttributes(
|
||||||
|
[&]( const wxString& msg )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PAD_TH_WITH_NO_HOLE );
|
errorHandler( footprint, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH, msg, { 0, 0 } );
|
||||||
|
} );
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
|
footprint->CheckPads(
|
||||||
drcItem->SetItems( footprint );
|
[&]( const PAD* aPad, int aErrorCode, const wxString& aMsg )
|
||||||
|
{
|
||||||
|
errorHandler( aPad, nullptr, aErrorCode, aMsg, aPad->GetPosition() );
|
||||||
|
} );
|
||||||
|
|
||||||
PCB_MARKER* marker = new PCB_MARKER( drcItem, aPosition );
|
footprint->CheckOverlappingPads(
|
||||||
board->Add( marker );
|
[&]( const PAD* aPadA, const PAD* aPadB, const VECTOR2I& aPosition )
|
||||||
m_frame->GetCanvas()->GetView()->Add( marker );
|
{
|
||||||
};
|
errorHandler( aPadA, aPadB, DRCE_OVERLAPPING_PADS, wxEmptyString, aPosition );
|
||||||
|
} );
|
||||||
|
|
||||||
footprint->CheckFootprintAttributes( &typeWarning );
|
|
||||||
footprint->CheckFootprintTHPadNoHoles( &tstHoleInTHPad );
|
|
||||||
m_checksRun = true;
|
m_checksRun = true;
|
||||||
|
|
||||||
SetMarkersProvider( new DRC_ITEMS_PROVIDER( board, MARKER_BASE::MARKER_DRC ) );
|
SetMarkersProvider( new DRC_ITEMS_PROVIDER( board, MARKER_BASE::MARKER_DRC ) );
|
||||||
|
@ -178,7 +177,7 @@ void DIALOG_FOOTPRINT_CHECKER::OnSelectItem( wxDataViewEvent& aEvent )
|
||||||
|
|
||||||
if( node && item )
|
if( node && item )
|
||||||
{
|
{
|
||||||
PCB_LAYER_ID principalLayer = item->GetLayer();
|
PCB_LAYER_ID principalLayer = item->GetLayerSet().Seq()[0];
|
||||||
LSET violationLayers;
|
LSET violationLayers;
|
||||||
std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
|
std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,10 @@ DRC_ITEM DRC_ITEM::footprintTHPadhasNoHole( DRCE_PAD_TH_WITH_NO_HOLE,
|
||||||
_( "Through hole pad has no hole" ),
|
_( "Through hole pad has no hole" ),
|
||||||
wxT( "through_hole_pad_without_hole" ) );
|
wxT( "through_hole_pad_without_hole" ) );
|
||||||
|
|
||||||
|
DRC_ITEM DRC_ITEM::footprintOverlappingPads( DRCE_OVERLAPPING_PADS,
|
||||||
|
_( "Pads with different numbers overlap" ),
|
||||||
|
wxT( "overlapping_pads" ) );
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
|
std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
|
||||||
DRC_ITEM::heading_electrical,
|
DRC_ITEM::heading_electrical,
|
||||||
|
@ -307,7 +311,8 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
|
||||||
DRC_ITEM::footprintTypeMismatch,
|
DRC_ITEM::footprintTypeMismatch,
|
||||||
DRC_ITEM::libFootprintIssues,
|
DRC_ITEM::libFootprintIssues,
|
||||||
DRC_ITEM::libFootprintMismatch,
|
DRC_ITEM::libFootprintMismatch,
|
||||||
DRC_ITEM::footprintTHPadhasNoHole
|
DRC_ITEM::footprintTHPadhasNoHole,
|
||||||
|
DRC_ITEM::footprintOverlappingPads
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
@ -364,7 +369,8 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
|
||||||
case DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE: return std::make_shared<DRC_ITEM>( diffPairGapOutOfRange );
|
case DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE: return std::make_shared<DRC_ITEM>( diffPairGapOutOfRange );
|
||||||
case DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG: return std::make_shared<DRC_ITEM>( diffPairUncoupledLengthTooLong );
|
case DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG: return std::make_shared<DRC_ITEM>( diffPairUncoupledLengthTooLong );
|
||||||
case DRCE_FOOTPRINT_TYPE_MISMATCH: return std::make_shared<DRC_ITEM>( footprintTypeMismatch );
|
case DRCE_FOOTPRINT_TYPE_MISMATCH: return std::make_shared<DRC_ITEM>( footprintTypeMismatch );
|
||||||
case DRCE_PAD_TH_WITH_NO_HOLE: return std::make_shared<DRC_ITEM>( footprintTHPadhasNoHole );
|
case DRCE_PAD_TH_WITH_NO_HOLE: return std::make_shared<DRC_ITEM>( footprintTHPadhasNoHole );
|
||||||
|
case DRCE_OVERLAPPING_PADS: return std::make_shared<DRC_ITEM>( footprintOverlappingPads );
|
||||||
default:
|
default:
|
||||||
wxFAIL_MSG( wxT( "Unknown DRC error code" ) );
|
wxFAIL_MSG( wxT( "Unknown DRC error code" ) );
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -75,6 +75,7 @@ enum PCB_DRC_CODE {
|
||||||
DRCE_LIB_FOOTPRINT_ISSUES, // footprint not found in active libraries
|
DRCE_LIB_FOOTPRINT_ISSUES, // footprint not found in active libraries
|
||||||
DRCE_LIB_FOOTPRINT_MISMATCH, // footprint does not match the current library
|
DRCE_LIB_FOOTPRINT_MISMATCH, // footprint does not match the current library
|
||||||
DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole
|
DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole
|
||||||
|
DRCE_OVERLAPPING_PADS, // footprint with overlapping pads
|
||||||
|
|
||||||
DRCE_UNRESOLVED_VARIABLE,
|
DRCE_UNRESOLVED_VARIABLE,
|
||||||
DRCE_ASSERTION_FAILURE, // user-defined (custom rule) assertion
|
DRCE_ASSERTION_FAILURE, // user-defined (custom rule) assertion
|
||||||
|
@ -199,6 +200,7 @@ private:
|
||||||
static DRC_ITEM diffPairUncoupledLengthTooLong;
|
static DRC_ITEM diffPairUncoupledLengthTooLong;
|
||||||
static DRC_ITEM footprintTypeMismatch;
|
static DRC_ITEM footprintTypeMismatch;
|
||||||
static DRC_ITEM footprintTHPadhasNoHole;
|
static DRC_ITEM footprintTHPadhasNoHole;
|
||||||
|
static DRC_ITEM footprintOverlappingPads;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DRC_RULE* m_violatingRule = nullptr;
|
DRC_RULE* m_violatingRule = nullptr;
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include <drc/drc_item.h>
|
#include <drc/drc_item.h>
|
||||||
#include <drc/drc_rule.h>
|
#include <drc/drc_rule.h>
|
||||||
#include <drc/drc_test_provider_clearance_base.h>
|
#include <drc/drc_test_provider_clearance_base.h>
|
||||||
#include "convert_basic_shapes_to_polygon.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drilled hole size test. scans vias/through-hole pads and checks for min drill sizes
|
Drilled hole size test. scans vias/through-hole pads and checks for min drill sizes
|
||||||
|
@ -66,7 +65,6 @@ public:
|
||||||
private:
|
private:
|
||||||
void checkViaHole( PCB_VIA* via, bool aExceedMicro, bool aExceedStd );
|
void checkViaHole( PCB_VIA* via, bool aExceedMicro, bool aExceedStd );
|
||||||
void checkPadHole( PAD* aPad );
|
void checkPadHole( PAD* aPad );
|
||||||
void checkPadStack( PAD* aPad );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,23 +77,32 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
|
||||||
|
|
||||||
for( FOOTPRINT* footprint : m_drcEngine->GetBoard()->Footprints() )
|
for( FOOTPRINT* footprint : m_drcEngine->GetBoard()->Footprints() )
|
||||||
{
|
{
|
||||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE )
|
|
||||||
&& m_drcEngine->IsErrorLimitExceeded( DRCE_PADSTACK ) )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( PAD* pad : footprint->Pads() )
|
for( PAD* pad : footprint->Pads() )
|
||||||
{
|
{
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) )
|
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) )
|
||||||
checkPadHole( pad );
|
checkPadHole( pad );
|
||||||
|
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_PADSTACK ) )
|
|
||||||
checkPadStack( pad );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( FOOTPRINT* footprint : m_drcEngine->GetBoard()->Footprints() )
|
||||||
|
{
|
||||||
|
footprint->CheckPads(
|
||||||
|
[&]( const PAD* pad, int errorCode, const wxString& msg )
|
||||||
|
{
|
||||||
|
if( m_drcEngine->IsErrorLimitExceeded( errorCode ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( errorCode );
|
||||||
|
|
||||||
|
if( !msg.IsEmpty() )
|
||||||
|
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
|
||||||
|
|
||||||
|
drcItem->SetItems( pad );
|
||||||
|
reportViolation( drcItem, pad->GetPosition(), UNDEFINED_LAYER );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_MICROVIA_DRILL_OUT_OF_RANGE )
|
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_MICROVIA_DRILL_OUT_OF_RANGE )
|
||||||
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) )
|
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) )
|
||||||
{
|
{
|
||||||
|
@ -130,53 +137,6 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run()
|
||||||
return !m_drcEngine->IsCancelled();
|
return !m_drcEngine->IsCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_HOLE_SIZE::checkPadStack( PAD* aPad )
|
|
||||||
{
|
|
||||||
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
|
|
||||||
{
|
|
||||||
if( !aPad->IsOnCopperLayer() )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
|
||||||
m_msg.Printf( _( " (PTH pad has no copper layers)" ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
|
||||||
drcItem->SetItems( aPad );
|
|
||||||
|
|
||||||
reportViolation( drcItem, aPad->GetPosition(), UNDEFINED_LAYER );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LSET lset = aPad->GetLayerSet() & LSET::AllCuMask();
|
|
||||||
PCB_LAYER_ID layer = lset.Seq().at( 0 );
|
|
||||||
int maxError = m_drcEngine->GetBoard()->GetDesignSettings().m_MaxError;
|
|
||||||
SHAPE_POLY_SET padOutline;
|
|
||||||
|
|
||||||
aPad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, maxError,
|
|
||||||
ERROR_LOC::ERROR_INSIDE );
|
|
||||||
|
|
||||||
const SHAPE_SEGMENT* drillShape = aPad->GetEffectiveHoleShape();
|
|
||||||
const SEG drillSeg = drillShape->GetSeg();
|
|
||||||
SHAPE_POLY_SET drillOutline;
|
|
||||||
|
|
||||||
TransformOvalToPolygon( drillOutline, drillSeg.A, drillSeg.B,
|
|
||||||
drillShape->GetWidth(), maxError, ERROR_LOC::ERROR_INSIDE );
|
|
||||||
|
|
||||||
padOutline.BooleanSubtract( drillOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
|
||||||
|
|
||||||
if( padOutline.IsEmpty() )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PADSTACK );
|
|
||||||
m_msg.Printf( _( " (PTH pad's hole leaves no copper)" ) );
|
|
||||||
|
|
||||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
|
|
||||||
drcItem->SetItems( aPad );
|
|
||||||
|
|
||||||
reportViolation( drcItem, aPad->GetPosition(), UNDEFINED_LAYER );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_HOLE_SIZE::checkPadHole( PAD* aPad )
|
void DRC_TEST_PROVIDER_HOLE_SIZE::checkPadHole( PAD* aPad )
|
||||||
{
|
{
|
||||||
int holeMinor = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
int holeMinor = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
||||||
|
|
|
@ -45,9 +45,12 @@
|
||||||
#include <view/view.h>
|
#include <view/view.h>
|
||||||
#include <geometry/shape_null.h>
|
#include <geometry/shape_null.h>
|
||||||
#include <i18n_utility.h>
|
#include <i18n_utility.h>
|
||||||
|
#include <drc/drc_item.h>
|
||||||
|
#include <geometry/shape_segment.h>
|
||||||
#include <convert_shape_list_to_polygon.h>
|
#include <convert_shape_list_to_polygon.h>
|
||||||
#include <geometry/convex_hull.h>
|
#include <geometry/convex_hull.h>
|
||||||
#include "fp_textbox.h"
|
#include "fp_textbox.h"
|
||||||
|
#include "convert_basic_shapes_to_polygon.h"
|
||||||
|
|
||||||
FOOTPRINT::FOOTPRINT( BOARD* parent ) :
|
FOOTPRINT::FOOTPRINT( BOARD* parent ) :
|
||||||
BOARD_ITEM_CONTAINER((BOARD_ITEM*) parent, PCB_FOOTPRINT_T ),
|
BOARD_ITEM_CONTAINER((BOARD_ITEM*) parent, PCB_FOOTPRINT_T ),
|
||||||
|
@ -2179,11 +2182,10 @@ void FOOTPRINT::BuildPolyCourtyards( OUTLINE_ERROR_HANDLER* aErrorHandler )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& msg )>* aErrorHandler )
|
void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler )
|
||||||
{
|
{
|
||||||
|
int likelyAttr = GetLikelyAttribute();
|
||||||
int likelyAttr = GetLikelyAttribute();
|
int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
|
||||||
int setAttr = ( GetAttributes() & ( FP_SMD | FP_THROUGH_HOLE ) );
|
|
||||||
|
|
||||||
// This is only valid if the footprint doesn't have FP_SMD and FP_THROUGH_HOLE set
|
// This is only valid if the footprint doesn't have FP_SMD and FP_THROUGH_HOLE set
|
||||||
// Which is, unfortunately, possible in theory but not in the UI (I think)
|
// Which is, unfortunately, possible in theory but not in the UI (I think)
|
||||||
|
@ -2206,29 +2208,94 @@ void FOOTPRINT::CheckFootprintAttributes( const std::function<void( const wxStri
|
||||||
|
|
||||||
msg = wxT( "(" ) + msg + wxT( ")" );
|
msg = wxT( "(" ) + msg + wxT( ")" );
|
||||||
|
|
||||||
(*aErrorHandler)( msg );
|
(aErrorHandler)( msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FOOTPRINT::CheckFootprintTHPadNoHoles(
|
|
||||||
const std::function<void( const wxString& msg, const VECTOR2I& position )>* aErrorHandler )
|
void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
|
||||||
|
const wxString& )>& aErrorHandler )
|
||||||
{
|
{
|
||||||
if( aErrorHandler == nullptr )
|
if( aErrorHandler == nullptr )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for( const PAD* pad: Pads() )
|
for( PAD* pad: Pads() )
|
||||||
{
|
{
|
||||||
|
if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
|
||||||
if( pad->GetAttribute() != PAD_ATTRIB::PTH
|
|
||||||
&& pad->GetAttribute() != PAD_ATTRIB::NPTH )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( pad->GetDrillSizeX() < 1 || pad->GetDrillSizeY() < 1 )
|
|
||||||
{
|
{
|
||||||
wxString msg;
|
if( pad->GetDrillSizeX() < 1 || pad->GetDrillSizeY() < 1 )
|
||||||
msg.Printf( _( "(pad \"%s\")" ), pad->GetNumber() );
|
(aErrorHandler)( pad, DRCE_PAD_TH_WITH_NO_HOLE, wxEmptyString );
|
||||||
|
}
|
||||||
|
|
||||||
(*aErrorHandler)( msg, pad->GetPosition() );
|
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||||
|
{
|
||||||
|
if( !pad->IsOnCopperLayer() )
|
||||||
|
{
|
||||||
|
(aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad has no copper layers)" ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LSET lset = pad->GetLayerSet() & LSET::AllCuMask();
|
||||||
|
PCB_LAYER_ID layer = lset.Seq().at( 0 );
|
||||||
|
SHAPE_POLY_SET padOutline;
|
||||||
|
|
||||||
|
pad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, ARC_HIGH_DEF,
|
||||||
|
ERROR_LOC::ERROR_INSIDE );
|
||||||
|
|
||||||
|
const SHAPE_SEGMENT* drillShape = pad->GetEffectiveHoleShape();
|
||||||
|
const SEG drillSeg = drillShape->GetSeg();
|
||||||
|
SHAPE_POLY_SET drillOutline;
|
||||||
|
|
||||||
|
TransformOvalToPolygon( drillOutline, drillSeg.A, drillSeg.B,
|
||||||
|
drillShape->GetWidth(), ARC_HIGH_DEF,
|
||||||
|
ERROR_LOC::ERROR_INSIDE );
|
||||||
|
|
||||||
|
padOutline.BooleanSubtract( drillOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||||
|
|
||||||
|
if( padOutline.IsEmpty() )
|
||||||
|
{
|
||||||
|
(aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FOOTPRINT::CheckOverlappingPads( const std::function<void( const PAD*, const PAD*,
|
||||||
|
const VECTOR2I& )>& aErrorHandler )
|
||||||
|
{
|
||||||
|
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
|
||||||
|
|
||||||
|
for( PAD* pad : Pads() )
|
||||||
|
{
|
||||||
|
for( PAD* other : Pads() )
|
||||||
|
{
|
||||||
|
if( other == pad || pad->SameLogicalPadAs( other ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// store canonical order so we don't collide in both directions
|
||||||
|
// (a:b and b:a)
|
||||||
|
if( static_cast<void*>( pad ) > static_cast<void*>( other ) )
|
||||||
|
std::swap( pad, other );
|
||||||
|
|
||||||
|
if( checkedPairs.count( { pad, other } ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checkedPairs[ { pad, other } ] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VECTOR2I pos;
|
||||||
|
SHAPE* padShape = pad->GetEffectiveShape().get();
|
||||||
|
SHAPE* otherShape = other->GetEffectiveShape().get();
|
||||||
|
|
||||||
|
if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
|
||||||
|
{
|
||||||
|
(aErrorHandler)( pad, other, pos );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,27 +339,24 @@ public:
|
||||||
/**
|
/**
|
||||||
* Test if footprint attributes for type (SMD/Through hole/Other) match the expected
|
* Test if footprint attributes for type (SMD/Through hole/Other) match the expected
|
||||||
* type based on the pads in the footprint.
|
* type based on the pads in the footprint.
|
||||||
* Footprints with plated through-hole pads should usually be marked through hole even if they also
|
* Footprints with plated through-hole pads should usually be marked through hole even if they
|
||||||
* have SMD because they might not be auto-placed. Exceptions to this might be shielded connectors
|
* also have SMD because they might not be auto-placed. Exceptions to this might be shielded
|
||||||
* Otherwise, footprints with SMD pads should be marked SMD
|
* connectors. Otherwise, footprints with SMD pads should be marked SMD.
|
||||||
* Footprints with no connecting pads should be marked "Other"
|
* Footprints with no connecting pads should be marked "Other"
|
||||||
*
|
*
|
||||||
* @param aErrorHandler callback to handle the error messages generated
|
* @param aErrorHandler callback to handle the error messages generated
|
||||||
*/
|
*/
|
||||||
void CheckFootprintAttributes( const std::function<void( const wxString& msg )>* aErrorHandler );
|
void CheckFootprintAttributes( const std::function<void( const wxString& )>& aErrorHandler );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if footprint attributes for type (SMD/Through hole/Other) match the expected
|
* Run DRC checks on footprint's pads.
|
||||||
* type based on the pads in the footprint.
|
|
||||||
* Footprints with plated through-hole pads should usually be marked through hole even if they also
|
|
||||||
* have SMD because they might not be auto-placed. Exceptions to this might be shielded connectors
|
|
||||||
* Otherwise, footprints with SMD pads should be marked SMD
|
|
||||||
* Footprints with no connecting pads should be marked "Other"
|
|
||||||
*
|
*
|
||||||
* @param aErrorHandler callback to handle the error messages generated
|
* @param aErrorHandler callback to handle the error messages generated
|
||||||
*/
|
*/
|
||||||
void CheckFootprintTHPadNoHoles( const std::function<void( const wxString& msg, const VECTOR2I& position )>*
|
void CheckPads( const std::function<void( const PAD*, int, const wxString& )>& aErrorHandler );
|
||||||
aErrorHandler );
|
|
||||||
|
void CheckOverlappingPads( const std::function<void( const PAD*, const PAD*,
|
||||||
|
const VECTOR2I& )>& aErrorHandler );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate pads shapes on layer \a aLayer as polygons and adds these polygons to
|
* Generate pads shapes on layer \a aLayer as polygons and adds these polygons to
|
||||||
|
|
|
@ -335,7 +335,7 @@ void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
|
||||||
SHAPE_POLY_SET itemPoly, clippedPoly;
|
SHAPE_POLY_SET itemPoly, clippedPoly;
|
||||||
|
|
||||||
if( aLayer == UNDEFINED_LAYER )
|
if( aLayer == UNDEFINED_LAYER )
|
||||||
aLayer = aItem->GetLayer();
|
aLayer = aItem->GetLayerSet().Seq()[0];
|
||||||
|
|
||||||
switch( aItem->Type() )
|
switch( aItem->Type() )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue