/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020-2024 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 #include #include #include #include #include #include #include // A list of all basic (ie: non-compound) board geometry items std::vector DRC_TEST_PROVIDER::s_allBasicItems; std::vector DRC_TEST_PROVIDER::s_allBasicItemsButZones; DRC_TEST_PROVIDER_REGISTRY::~DRC_TEST_PROVIDER_REGISTRY() { for( DRC_TEST_PROVIDER* provider : m_providers ) delete provider; } DRC_TEST_PROVIDER::DRC_TEST_PROVIDER() : UNITS_PROVIDER( pcbIUScale, EDA_UNITS::MILLIMETRES ), m_drcEngine( nullptr ) { } void DRC_TEST_PROVIDER::Init() { if( s_allBasicItems.size() == 0 ) { for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) { if( i != PCB_FOOTPRINT_T && i != PCB_GROUP_T ) { s_allBasicItems.push_back( (KICAD_T) i ); if( i != PCB_ZONE_T ) s_allBasicItemsButZones.push_back( (KICAD_T) i ); } } } } const wxString DRC_TEST_PROVIDER::GetName() const { return wxT( "" ); } const wxString DRC_TEST_PROVIDER::GetDescription() const { return wxEmptyString; } void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr& item, const VECTOR2I& aMarkerPos, int aMarkerLayer ) { std::lock_guard lock( m_statsMutex ); if( item->GetViolatingRule() ) accountCheck( item->GetViolatingRule() ); item->SetViolatingTest( this ); m_drcEngine->ReportViolation( item, aMarkerPos, aMarkerLayer ); } bool DRC_TEST_PROVIDER::reportProgress( size_t aCount, size_t aSize, size_t aDelta ) { if( ( aCount % aDelta ) == 0 || aCount == aSize - 1 ) { if( !m_drcEngine->ReportProgress( static_cast( aCount ) / aSize ) ) return false; } return true; } bool DRC_TEST_PROVIDER::reportPhase( const wxString& aMessage ) { reportAux( aMessage ); return m_drcEngine->ReportPhase( aMessage ); } void DRC_TEST_PROVIDER::reportAux( const wxChar* fmt, ... ) { va_list vargs; va_start( vargs, fmt ); wxString str; str.PrintfV( fmt, vargs ); va_end( vargs ); m_drcEngine->ReportAux( str ); } void DRC_TEST_PROVIDER::accountCheck( const DRC_RULE* ruleToTest ) { auto it = m_stats.find( ruleToTest ); if( it == m_stats.end() ) m_stats[ ruleToTest ] = 1; else m_stats[ ruleToTest ] += 1; } void DRC_TEST_PROVIDER::accountCheck( const DRC_CONSTRAINT& constraintToTest ) { accountCheck( constraintToTest.GetParentRule() ); } void DRC_TEST_PROVIDER::reportRuleStatistics() { if( !m_isRuleDriven ) return; m_drcEngine->ReportAux( wxT( "Rule hit statistics: " ) ); for( const std::pair& stat : m_stats ) { if( stat.first ) { m_drcEngine->ReportAux( wxString::Format( wxT( " - rule '%s': %d hits " ), stat.first->m_Name, stat.second ) ); } } } int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector& aTypes, LSET aLayers, const std::function& aFunc ) { BOARD *brd = m_drcEngine->GetBoard(); std::bitset typeMask; int n = 0; if( aTypes.size() == 0 ) { for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) typeMask[ i ] = true; } else { for( KICAD_T aType : aTypes ) typeMask[ aType ] = true; } for( PCB_TRACK* item : brd->Tracks() ) { if( (item->GetLayerSet() & aLayers).any() ) { if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T ) { aFunc( item ); n++; } else if( typeMask[ PCB_VIA_T ] && item->Type() == PCB_VIA_T ) { aFunc( item ); n++; } else if( typeMask[ PCB_ARC_T ] && item->Type() == PCB_ARC_T ) { aFunc( item ); n++; } } } for( BOARD_ITEM* item : brd->Drawings() ) { if( (item->GetLayerSet() & aLayers).any() ) { if( typeMask[ PCB_DIMENSION_T ] && BaseType( item->Type() ) == PCB_DIMENSION_T ) { if( !aFunc( item ) ) return n; n++; } else if( typeMask[ PCB_SHAPE_T ] && item->Type() == PCB_SHAPE_T ) { if( !aFunc( item ) ) return n; n++; } else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T ) { if( !aFunc( item ) ) return n; n++; } else if( typeMask[ PCB_TEXTBOX_T ] && item->Type() == PCB_TEXTBOX_T ) { if( !aFunc( item ) ) return n; n++; } else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T ) { if( !aFunc( item ) ) return n; n++; } } } if( typeMask[ PCB_ZONE_T ] ) { for( ZONE* item : brd->Zones() ) { if( ( item->GetLayerSet() & aLayers ).any() ) { if( !aFunc( item ) ) return n; n++; } } } for( FOOTPRINT* footprint : brd->Footprints() ) { if( typeMask[ PCB_FIELD_T ] ) { for( PCB_FIELD* field : footprint->GetFields() ) { if( ( field->GetLayerSet() & aLayers ).any() ) { if( !aFunc( field ) ) return n; n++; } } } if( typeMask[ PCB_PAD_T ] ) { for( PAD* pad : footprint->Pads() ) { // Careful: if a pad has a hole then it pierces all layers if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() ) { if( !aFunc( pad ) ) return n; n++; } } } for( BOARD_ITEM* dwg : footprint->GraphicalItems() ) { if( (dwg->GetLayerSet() & aLayers).any() ) { if( typeMask[ PCB_DIMENSION_T ] && BaseType( dwg->Type() ) == PCB_DIMENSION_T ) { if( !aFunc( dwg ) ) return n; n++; } else if( typeMask[ PCB_TEXT_T ] && dwg->Type() == PCB_TEXT_T ) { if( !aFunc( dwg ) ) return n; n++; } else if( typeMask[ PCB_TEXTBOX_T ] && dwg->Type() == PCB_TEXTBOX_T ) { if( !aFunc( dwg ) ) return n; n++; } else if( typeMask[ PCB_SHAPE_T ] && dwg->Type() == PCB_SHAPE_T ) { if( !aFunc( dwg ) ) return n; n++; } } } if( typeMask[ PCB_ZONE_T ] ) { for( ZONE* zone : footprint->Zones() ) { if( (zone->GetLayerSet() & aLayers).any() ) { if( !aFunc( zone ) ) return n; n++; } } } if( typeMask[ PCB_FOOTPRINT_T ] ) { if( !aFunc( footprint ) ) return n; n++; } } return n; } bool DRC_TEST_PROVIDER::isInvisibleText( const BOARD_ITEM* aItem ) const { if( const PCB_TEXT* text = dynamic_cast( aItem ) ) { if( !text->IsVisible() ) return true; } return false; } wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource, double aConstraint, double aActual ) { wxString constraint_str = MessageTextFromValue( aConstraint ); wxString actual_str = MessageTextFromValue( aActual ); if( constraint_str == actual_str ) { // Use more precise formatting if the message-text strings were equal. constraint_str = StringFromValue( aConstraint, true ); actual_str = StringFromValue( aActual, true ); } return wxString::Format( aFormatString, aSource, constraint_str, actual_str ); }