diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index cc807ee189..44647378f2 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -170,6 +170,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std: m_DRCSeverities[ DRCE_COPPER_SLIVER ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_ISOLATED_COPPER ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_PADSTACK ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_MISSING_FOOTPRINT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_DUPLICATE_FOOTPRINT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_EXTRA_FOOTPRINT ] = RPT_SEVERITY_WARNING; diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 4fadf81ca2..e4a507cbf8 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -1249,8 +1249,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() warning_msgs.Add( _( "Warning: Pad size is less than zero." ) ); } - // Test hole size against pad size - if( m_dummyPad->IsOnCopperLayer() ) + // Test hole against pad shape + if( m_dummyPad->IsOnCopperLayer() && m_dummyPad->GetDrillSize().x > 0 ) { LSET lset = m_dummyPad->GetLayerSet() & LSET::AllCuMask(); PCB_LAYER_ID layer = lset.Seq().at( 0 ); @@ -1260,19 +1260,23 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() m_dummyPad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, maxError, ERROR_LOC::ERROR_INSIDE ); - const SHAPE_SEGMENT* drillShape = m_dummyPad->GetEffectiveHoleShape(); - const SEG drillSeg = drillShape->GetSeg(); - SHAPE_POLY_SET drillOutline; - - TransformOvalToPolygon( drillOutline, drillSeg.A, drillSeg.B, - drillShape->GetWidth(), maxError, ERROR_LOC::ERROR_INSIDE ); - - drillOutline.BooleanSubtract( padOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST ); - - if( drillOutline.BBox().GetWidth() > 0 || drillOutline.BBox().GetHeight() > 0 ) + if( !padOutline.Collide( m_dummyPad->GetPosition() ) ) { - warning_msgs.Add( _( "Warning: Pad drill will leave no copper or drill shape and " - "pad shape do not overlap." ) ); + warning_msgs.Add( _( "Warning: Pad hole not inside pad shape." ) ); + } + else if( m_dummyPad->GetAttribute() == PAD_ATTRIB::PTH ) + { + const SHAPE_SEGMENT* drillShape = m_dummyPad->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() ) + warning_msgs.Add( _( "Warning: Pad hole will leave no copper." ) ); } } diff --git a/pcbnew/drc/drc_test_provider_hole_size.cpp b/pcbnew/drc/drc_test_provider_hole_size.cpp index 9a8d17a58c..faad8518d7 100644 --- a/pcbnew/drc/drc_test_provider_hole_size.cpp +++ b/pcbnew/drc/drc_test_provider_hole_size.cpp @@ -21,20 +21,23 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include #include +#include #include #include #include #include - +#include "convert_basic_shapes_to_polygon.h" /* Drilled hole size test. scans vias/through-hole pads and checks for min drill sizes Errors generated: - DRCE_DRILL_OUT_OF_RANGE - DRCE_MICROVIA_DRILL_OUT_OF_RANGE + - DRCE_PADSTACK */ class DRC_TEST_PROVIDER_HOLE_SIZE : public DRC_TEST_PROVIDER @@ -61,8 +64,9 @@ public: } private: - void checkVia( PCB_VIA* via, bool aExceedMicro, bool aExceedStd ); - void checkPad( PAD* aPad ); + void checkViaHole( PCB_VIA* via, bool aExceedMicro, bool aExceedStd ); + void checkPadHole( PAD* aPad ); + void checkPadStack( PAD* aPad ); }; @@ -75,15 +79,19 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run() for( FOOTPRINT* footprint : m_drcEngine->GetBoard()->Footprints() ) { - if( m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) ) + if( m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) + && m_drcEngine->IsErrorLimitExceeded( DRCE_PADSTACK ) ) + { break; + } for( PAD* pad : footprint->Pads() ) { - if( m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) ) - break; + if( !m_drcEngine->IsErrorLimitExceeded( DRCE_DRILL_OUT_OF_RANGE ) ) + checkPadHole( pad ); - checkPad( pad ); + if( !m_drcEngine->IsErrorLimitExceeded( DRCE_PADSTACK ) ) + checkPadStack( pad ); } } } @@ -112,7 +120,7 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run() if( exceedMicro && exceedStd ) break; - checkVia( static_cast( track ), exceedMicro, exceedStd ); + checkViaHole( static_cast( track ), exceedMicro, exceedStd ); } } } @@ -122,8 +130,54 @@ bool DRC_TEST_PROVIDER_HOLE_SIZE::Run() 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 drcItem = DRC_ITEM::Create( DRCE_PADSTACK ); + m_msg.Printf( _( " (PTH pad has no copper layers)" ) ); -void DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( PAD* aPad ) + 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 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 ) { int holeMinor = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y ); int holeMajor = std::max( aPad->GetDrillSize().x, aPad->GetDrillSize().y ); @@ -180,7 +234,7 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( PAD* aPad ) } -void DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( PCB_VIA* via, bool aExceedMicro, bool aExceedStd ) +void DRC_TEST_PROVIDER_HOLE_SIZE::checkViaHole( PCB_VIA* via, bool aExceedMicro, bool aExceedStd ) { int errorCode;