diff --git a/pcbnew/drc/drc_test_provider_edge_clearance.cpp b/pcbnew/drc/drc_test_provider_edge_clearance.cpp index 7e2d2dd05f..15bc40c96d 100644 --- a/pcbnew/drc/drc_test_provider_edge_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_edge_clearance.cpp @@ -38,6 +38,7 @@ TODO: - separate holes to edge check - tester only looks for edge crossings. it doesn't check if items are inside/outside the board area. + - pad test missing! */ class DRC_TEST_PROVIDER_EDGE_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE diff --git a/pcbnew/drc/drc_test_provider_silk_to_pad.cpp b/pcbnew/drc/drc_test_provider_silk_to_pad.cpp index e60f1c08cf..c07f207a36 100644 --- a/pcbnew/drc/drc_test_provider_silk_to_pad.cpp +++ b/pcbnew/drc/drc_test_provider_silk_to_pad.cpp @@ -44,9 +44,6 @@ Silk to pads clearance test. Check all pads against silkscreen (mask opening in the pad vs silkscreen) Errors generated: - DRCE_SILK_ON_PADS - - TODO: - - tester only looks for edge crossings. it doesn't check if items are inside/outside the board area. */ namespace test { @@ -106,18 +103,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run() reportAux( "Worst clearance : %d nm", m_largestClearance ); reportPhase(( "Pad to silkscreen clearances..." )); - struct SHAPE_ON_LAYER - { - SHAPE_ON_LAYER( std::shared_ptr aShape, PCB_LAYER_ID aLayer ) - : shape ( aShape ), - layer ( aLayer ) - { - } - std::shared_ptr shape; - PCB_LAYER_ID layer; - }; - - DRC_RTREE padTree; + DRC_RTREE padTree, silkTree; auto addPadToTree = [&padTree]( BOARD_ITEM *item ) -> bool @@ -126,106 +112,64 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run() return true; }; - - auto checkClearance = - [&] ( BOARD_ITEM* refItem ) -> bool + auto addSilkToTree = + [&silkTree]( BOARD_ITEM *item ) -> bool { - const PCB_LAYER_ID padOuterLayers[] = { F_Cu, B_Cu }; - const PCB_LAYER_ID padSilkLayers[] = { F_SilkS, B_SilkS }; - - - for( int i = 0; i < 2; i++ ) - { - padTree.QueryColliding( - refItem, - padSilkLayers[i], - padOuterLayers[i], - [&] ( BOARD_ITEM *chkItem ) -> bool - { - return true; - }, - [&] ( BOARD_ITEM *collItem, int distance ) -> bool - { - auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_PAD, - refItem, collItem ); - - int minClearance = constraint.GetValue().Min(); - - if( !distance || distance < minClearance ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SILK_OVER_PAD ); - wxString msg; - - msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - constraint.GetParentRule()->m_Name, - MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), distance, true ) ); - - drcItem->SetErrorMessage( msg ); - drcItem->SetItems( refItem, collItem ); - drcItem->SetViolatingRule( constraint.GetParentRule() ); - - reportViolation( drcItem, refItem->GetPosition() ); - } - return true; - }, - m_largestClearance - ); - } - + silkTree.insert( item ); return true; }; - int numPads = forEachGeometryItem( { PCB_PAD_T }, LSET::AllTechMask() | LSET::AllCuMask(), addPadToTree ); + auto checkClearance = [&]( const DRC_RTREE::LAYER_PAIR& aLayers, + DRC_RTREE::ITEM_WITH_SHAPE* aRefItem, + DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool { + auto constraint = m_drcEngine->EvalRulesForItems( + DRC_CONSTRAINT_TYPE_SILK_TO_PAD, aRefItem->parent, aTestItem->parent ); - int numSilk = forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T }, - LSET( 2, F_SilkS, B_SilkS ), - checkClearance - ); + int minClearance = constraint.GetValue().Min(); - - reportAux( "Tested %d pads against %d silkscreen features.", numPads, numSilk ); + accountCheck( constraint ); - - -#if 0 + int actual; + + if( ! aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual ) ) + return true; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SILK_OVER_PAD ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + constraint.GetParentRule()->m_Name, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( aRefItem->parent, aTestItem->parent ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + reportViolation( drcItem, aRefItem->parent->GetPosition() ); - for( auto& silkShape : boardOutline ) + return !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_OVER_PAD ); + }; + + int numPads = forEachGeometryItem( + { PCB_PAD_T }, LSET::AllTechMask() | LSET::AllCuMask(), addPadToTree ); + + int numSilk = + forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T }, + LSET( 2, F_SilkS, B_SilkS ), addSilkToTree ); + + reportAux( _("Testing %d pads against %d silkscreen features."), numPads, numSilk ); + + const std::vector layerPairs = { - for( auto& padShape : boardItems ) - { -// printf("BoardT %d\n", boardItem->Type() ); - - auto shape = boardItem->GetEffectiveShape(); + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Cu ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Cu ) + }; - auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, - outlineItem, boardItem ); - int minClearance = constraint.GetValue().Min(); - int actual; + padTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance ); - if( refShape->Collide( shape.get(), minClearance, &actual ) ) - { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); - wxString msg; - - msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - rule->GetName(), - MessageTextFromValue( userUnits(), minClearance, true ), - MessageTextFromValue( userUnits(), actual, true ) ); - - drcItem->SetErrorMessage( msg ); - drcItem->SetItems( outlineItem, boardItem ); - drcItem->SetViolatingRule( rule ); - - reportViolation( drcItem, refShape->Centre()); - } - } - } - - return true; - -#endif + reportRuleStatistics(); return true; } diff --git a/pcbnew/drc/drc_test_provider_silk_to_silk.cpp b/pcbnew/drc/drc_test_provider_silk_to_silk.cpp new file mode 100644 index 0000000000..287523188a --- /dev/null +++ b/pcbnew/drc/drc_test_provider_silk_to_silk.cpp @@ -0,0 +1,213 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + Silk to silk clearance test. Check all silkscreen features against each other. + Errors generated: + - DRCE_SILK_CLEARANCE + +*/ + +namespace test { + +class DRC_TEST_PROVIDER_SILK_TO_SILK : public ::DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_SILK_TO_SILK () + { + } + + virtual ~DRC_TEST_PROVIDER_SILK_TO_SILK() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "silk_to_silk"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests for overlapping silkscreen features."; + } + + virtual int GetNumPhases() const override + { + return 1; + } + + virtual std::set GetConstraintTypes() const override; + +private: + + BOARD* m_board; + int m_largestClearance; +}; + +}; + + +bool test::DRC_TEST_PROVIDER_SILK_TO_SILK::Run() +{ + m_board = m_drcEngine->GetBoard(); + + DRC_CONSTRAINT worstClearanceConstraint; + m_largestClearance = 0; + + if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_SILK, + worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) + { + m_largestClearance = worstClearanceConstraint.m_Value.Min(); + } + + reportAux( "Worst clearance : %d nm", m_largestClearance ); + reportPhase(( "Silkscreen clearances..." )); + + DRC_RTREE silkTree; + + auto addToTree = + [&silkTree]( BOARD_ITEM *item ) -> bool + { + silkTree.insert( item ); + return true; + }; + + auto checkClearance = [&]( const DRC_RTREE::LAYER_PAIR& aLayers, + DRC_RTREE::ITEM_WITH_SHAPE* aRefItem, + DRC_RTREE::ITEM_WITH_SHAPE* aTestItem ) -> bool { + auto constraint = m_drcEngine->EvalRulesForItems( + DRC_CONSTRAINT_TYPE_SILK_TO_SILK, aRefItem->parent, aTestItem->parent ); + + int minClearance = constraint.GetValue().Min(); + + accountCheck( constraint ); + + int actual; + + // only check for silkscreen collisions belonging to different modules or overlapping texts + + + KICAD_T typeRef = aRefItem->parent->Type(); + KICAD_T typeTest = aTestItem->parent->Type(); + + MODULE *parentModRef = nullptr; + MODULE *parentModTest = nullptr; + + if( typeRef == PCB_MODULE_EDGE_T || typeRef == PCB_MODULE_TEXT_T ) + { + parentModRef = static_cast ( aRefItem->parent->GetParent() ); + } + + if( typeTest == PCB_MODULE_EDGE_T || typeTest == PCB_MODULE_TEXT_T ) + { + parentModTest = static_cast ( aTestItem->parent->GetParent() ); + } + + + // silkscreen drawings within the same module (or globally on the board) + // don't report clearance errors. Everything else does. + + if( parentModRef && parentModRef == parentModTest ) + { + if( typeRef == PCB_MODULE_EDGE_T && typeTest == PCB_MODULE_EDGE_T ) + return true; + } + + if( !parentModRef && !parentModTest ) + { + if( typeRef == PCB_LINE_T && typeTest == PCB_LINE_T ) + return true; + } + + if( ! aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual ) ) + return true; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SILK_CLEARANCE ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + constraint.GetParentRule()->m_Name, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( aRefItem->parent, aTestItem->parent ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + reportViolation( drcItem, aRefItem->parent->GetPosition() ); + + + return !m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_CLEARANCE ); + }; + + int numSilk = + forEachGeometryItem( { PCB_LINE_T, PCB_MODULE_EDGE_T, PCB_TEXT_T, PCB_MODULE_TEXT_T }, + LSET( 2, F_SilkS, B_SilkS ), addToTree ); + + reportAux( _("Testing %d silkscreen features."), numSilk ); + + const std::vector layerPairs = + { + DRC_RTREE::LAYER_PAIR( F_SilkS, F_SilkS ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_SilkS ) + }; + + silkTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance ); + + reportRuleStatistics(); + + return true; +} + + +std::set test::DRC_TEST_PROVIDER_SILK_TO_SILK::GetConstraintTypes() const +{ + return { DRC_CONSTRAINT_TYPE_SILK_TO_SILK }; +} + + +namespace detail +{ + static DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file