From 6d5b6c8b81dfc21ee06476754f6aefb376c09411 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 29 May 2020 21:23:08 +0100 Subject: [PATCH] A bit more refactoring to get code out of the DRC tool. --- pcbnew/CMakeLists.txt | 1 + pcbnew/dialogs/dialog_drc.cpp | 8 +- pcbnew/dialogs/dialog_netlist.cpp | 3 +- pcbnew/drc/drc.cpp | 425 ++++++++++++------------------ pcbnew/drc/drc.h | 31 +-- pcbnew/drc/footprint_tester.cpp | 90 +++++++ pcbnew/drc/footprint_tester.h | 34 +++ 7 files changed, 310 insertions(+), 282 deletions(-) create mode 100644 pcbnew/drc/footprint_tester.cpp create mode 100644 pcbnew/drc/footprint_tester.h diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 1c4aaab5f8..1cf0e53791 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -238,6 +238,7 @@ set( PCBNEW_DRC_SRCS drc/drc.cpp drc/drc_clearance_test_functions.cpp drc/drc_rule_parser.cpp + drc/footprint_tester.cpp ) set( PCBNEW_NETLIST_SRCS diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 7e4488504f..b4196212bd 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -182,10 +182,10 @@ void DIALOG_DRC::syncCheckboxes() void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent ) { setDRCParameters(); - m_tester->m_doZonesTest = m_cbReportTracksToZonesErrors->GetValue(); - m_tester->m_refillZones = m_cbRefillZones->GetValue(); - m_tester->m_reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue(); - m_tester->m_testFootprints = m_cbTestFootprints->GetValue(); + m_tester->m_testTracksAgainstZones = m_cbReportTracksToZonesErrors->GetValue(); + m_tester->m_refillZones = m_cbRefillZones->GetValue(); + m_tester->m_reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue(); + m_tester->m_testFootprints = m_cbTestFootprints->GetValue(); m_brdEditor->RecordDRCExclusions(); deleteAllMarkers(); diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index 14651efc47..e618106177 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -190,7 +191,7 @@ void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event ) HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) ); std::vector drcItems; - DRC::TestFootprints( netlist, m_parent->GetBoard(), GetUserUnits(), drcItems ); + TestFootprints( netlist, m_parent->GetBoard(), drcItems ); for( DRC_ITEM* item : drcItems ) dlg.AddHTML_Text( item->ShowHtml( m_parent ) ); diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index d0ff27c0e1..7730d083e0 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -58,8 +58,8 @@ #include #include #include +#include #include -#include DRC::DRC() : PCB_TOOL_BASE( "pcbnew.DRCTool" ), @@ -71,7 +71,7 @@ DRC::DRC() : { // establish initial values for everything: m_doUnconnectedTest = true; // enable unconnected tests - m_doZonesTest = false; // disable zone to items clearance tests + m_testTracksAgainstZones = false; // disable zone to items clearance tests m_doKeepoutTest = true; // enable keepout areas to items clearance tests m_refillZones = false; // Only fill zones if requested by user. m_reportAllTrackErrors = false; @@ -179,180 +179,6 @@ void DRC::DestroyDRCDialog( int aReason ) } -int DRC::testZoneToZoneOutlines( BOARD_COMMIT& aCommit ) -{ - BOARD* board = m_editFrame->GetBoard(); - int nerrors = 0; - - std::vector smoothed_polys; - smoothed_polys.resize( board->GetAreaCount() ); - - for( int ia = 0; ia < board->GetAreaCount(); ia++ ) - { - ZONE_CONTAINER* zoneRef = board->GetArea( ia ); - std::set colinearCorners; - zoneRef->GetColinearCorners( board, colinearCorners ); - - zoneRef->BuildSmoothedPoly( smoothed_polys[ia], &colinearCorners ); - } - - // iterate through all areas - for( int ia = 0; ia < board->GetAreaCount(); ia++ ) - { - ZONE_CONTAINER* zoneRef = board->GetArea( ia ); - - if( !zoneRef->IsOnCopperLayer() ) - continue; - - // If we are testing a single zone, then iterate through all other zones - // Otherwise, we have already tested the zone combination - for( int ia2 = ia + 1; ia2 < board->GetAreaCount(); ia2++ ) - { - ZONE_CONTAINER* zoneToTest = board->GetArea( ia2 ); - - if( zoneRef == zoneToTest ) - continue; - - // test for same layer - if( zoneRef->GetLayer() != zoneToTest->GetLayer() ) - continue; - - // Test for same net - if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 ) - continue; - - // test for different priorities - if( zoneRef->GetPriority() != zoneToTest->GetPriority() ) - continue; - - // test for different types - if( zoneRef->GetIsKeepout() != zoneToTest->GetIsKeepout() ) - continue; - - // Examine a candidate zone: compare zoneToTest to zoneRef - - // Get clearance used in zone to zone test. The policy used to - // obtain that value is now part of the zone object itself by way of - // ZONE_CONTAINER::GetClearance(). - int zone2zoneClearance = zoneRef->GetClearance( zoneToTest, &m_clearanceSource ); - - // Keepout areas have no clearance, so set zone2zoneClearance to 1 - // ( zone2zoneClearance = 0 can create problems in test functions) - if( zoneRef->GetIsKeepout() ) - zone2zoneClearance = 1; - - // test for some corners of zoneRef inside zoneToTest - for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ ) - { - VECTOR2I currentVertex = *iterator; - wxPoint pt( currentVertex.x, currentVertex.y ); - - if( smoothed_polys[ia2].Contains( currentVertex ) ) - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); - drcItem->SetItems( zoneRef, zoneToTest ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); - addMarkerToPcb( aCommit, marker ); - nerrors++; - } - } - - // test for some corners of zoneToTest inside zoneRef - for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ ) - { - VECTOR2I currentVertex = *iterator; - wxPoint pt( currentVertex.x, currentVertex.y ); - - if( smoothed_polys[ia].Contains( currentVertex ) ) - { - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); - drcItem->SetItems( zoneToTest, zoneRef ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); - addMarkerToPcb( aCommit, marker ); - nerrors++; - } - } - - // Iterate through all the segments of refSmoothedPoly - std::map conflictPoints; - - for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ ) - { - // Build ref segment - SEG refSegment = *refIt; - - // Iterate through all the segments in smoothed_polys[ia2] - for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ ) - { - // Build test segment - SEG testSegment = *testIt; - wxPoint pt; - - int ax1, ay1, ax2, ay2; - ax1 = refSegment.A.x; - ay1 = refSegment.A.y; - ax2 = refSegment.B.x; - ay2 = refSegment.B.y; - - int bx1, by1, bx2, by2; - bx1 = testSegment.A.x; - by1 = testSegment.A.y; - bx2 = testSegment.B.x; - by2 = testSegment.B.y; - - int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, - 0, - ax1, ay1, ax2, ay2, - 0, - zone2zoneClearance, - &pt.x, &pt.y ); - - if( d < zone2zoneClearance ) - { - if( conflictPoints.count( pt ) ) - conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d ); - else - conflictPoints[ pt ] = d; - } - } - } - - for( const std::pair& conflict : conflictPoints ) - { - int actual = conflict.second; - DRC_ITEM* drcItem; - - if( actual <= 0 ) - { - drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); - } - else - { - drcItem = new DRC_ITEM( DRCE_ZONES_TOO_CLOSE ); - - m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), - m_clearanceSource, - MessageTextFromValue( userUnits(), zone2zoneClearance, true ), - MessageTextFromValue( userUnits(), conflict.second, true ) ); - - drcItem->SetErrorMessage( m_msg ); - } - - drcItem->SetItems( zoneRef, zoneToTest ); - - MARKER_PCB* marker = new MARKER_PCB( drcItem, conflict.first ); - addMarkerToPcb( aCommit, marker ); - nerrors++; - } - } - } - - return nerrors; -} - - bool DRC::LoadRules() { wxString rulesFilepath = m_editFrame->Prj().AbsolutePath( "drc-rules" ); @@ -606,7 +432,7 @@ void DRC::RunTests( wxTextCtrl* aMessages ) if( m_drcDialog ) m_drcDialog->Raise(); - TestFootprints( netlist, m_pcb, m_drcDialog->GetUserUnits(), m_footprints ); + TestFootprints( netlist, m_pcb, m_footprints ); m_footprintsTested = true; } @@ -802,7 +628,7 @@ void DRC::testTracks( BOARD_COMMIT& aCommit, wxWindow *aActiveWindow, bool aShow } // Test new segment against tracks and pads, optionally against copper zones - doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_doZonesTest ); + doTrackDrc( aCommit, *seg_it, seg_it + 1, m_pcb->Tracks().end(), m_testTracksAgainstZones ); // Test for dangling items int code = (*seg_it)->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; @@ -850,6 +676,9 @@ void DRC::testUnconnected() void DRC::testZones( BOARD_COMMIT& aCommit ) { + BOARD* board = m_editFrame->GetBoard(); + BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); + // Test copper areas for valid netcodes // if a netcode is < 0 the netname was not found when reading a netlist // if a netcode is == 0 the netname is void, and the zone is not connected. @@ -858,17 +687,18 @@ void DRC::testZones( BOARD_COMMIT& aCommit ) // In recent Pcbnew versions, the netcode is always >= 0, but an internal net name // is stored, and initialized from the file or the zone properties editor. // if it differs from the net name from net code, there is a DRC issue - if( !m_pcb->GetDesignSettings().Ignore( DRCE_ZONE_HAS_EMPTY_NET ) ) + + std::vector smoothed_polys; + smoothed_polys.resize( board->GetAreaCount() ); + + for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) { - for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) + ZONE_CONTAINER* zone = m_pcb->GetArea( ii ); + + if( !bds.Ignore( DRCE_ZONE_HAS_EMPTY_NET ) && zone->IsOnCopperLayer() ) { - ZONE_CONTAINER* zone = m_pcb->GetArea( ii ); - - if( !zone->IsOnCopperLayer() ) - continue; - int netcode = zone->GetNetCode(); - // a netcode < 0 or > 0 and no pad in net is a error or strange + // a netcode < 0 or > 0 and no pad in net is a error or strange // perhaps a "dead" net, which happens when all pads in this net were removed // Remark: a netcode < 0 should not happen (this is more a bug somewhere) int pads_in_net = ( netcode > 0 ) ? m_pcb->GetConnectivity()->GetPadCount( netcode ) : 1; @@ -882,10 +712,163 @@ void DRC::testZones( BOARD_COMMIT& aCommit ) addMarkerToPcb( aCommit, marker ); } } + + ZONE_CONTAINER* zoneRef = board->GetArea( ii ); + std::set colinearCorners; + zoneRef->GetColinearCorners( board, colinearCorners ); + + zoneRef->BuildSmoothedPoly( smoothed_polys[ii], &colinearCorners ); } - // Test copper areas outlines, and create markers when needed - testZoneToZoneOutlines( aCommit ); + // iterate through all areas + for( int ia = 0; ia < board->GetAreaCount(); ia++ ) + { + ZONE_CONTAINER* zoneRef = board->GetArea( ia ); + + if( !zoneRef->IsOnCopperLayer() ) + continue; + + // If we are testing a single zone, then iterate through all other zones + // Otherwise, we have already tested the zone combination + for( int ia2 = ia + 1; ia2 < board->GetAreaCount(); ia2++ ) + { + ZONE_CONTAINER* zoneToTest = board->GetArea( ia2 ); + + if( zoneRef == zoneToTest ) + continue; + + // test for same layer + if( zoneRef->GetLayer() != zoneToTest->GetLayer() ) + continue; + + // Test for same net + if( zoneRef->GetNetCode() == zoneToTest->GetNetCode() && zoneRef->GetNetCode() >= 0 ) + continue; + + // test for different priorities + if( zoneRef->GetPriority() != zoneToTest->GetPriority() ) + continue; + + // test for different types + if( zoneRef->GetIsKeepout() != zoneToTest->GetIsKeepout() ) + continue; + + // Examine a candidate zone: compare zoneToTest to zoneRef + + // Get clearance used in zone to zone test. The policy used to + // obtain that value is now part of the zone object itself by way of + // ZONE_CONTAINER::GetClearance(). + int zone2zoneClearance = zoneRef->GetClearance( zoneToTest, &m_clearanceSource ); + + // Keepout areas have no clearance, so set zone2zoneClearance to 1 + // ( zone2zoneClearance = 0 can create problems in test functions) + if( zoneRef->GetIsKeepout() ) + zone2zoneClearance = 1; + + // test for some corners of zoneRef inside zoneToTest + for( auto iterator = smoothed_polys[ia].IterateWithHoles(); iterator; iterator++ ) + { + VECTOR2I currentVertex = *iterator; + wxPoint pt( currentVertex.x, currentVertex.y ); + + if( smoothed_polys[ia2].Contains( currentVertex ) ) + { + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); + drcItem->SetItems( zoneRef, zoneToTest ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); + addMarkerToPcb( aCommit, marker ); + } + } + + // test for some corners of zoneToTest inside zoneRef + for( auto iterator = smoothed_polys[ia2].IterateWithHoles(); iterator; iterator++ ) + { + VECTOR2I currentVertex = *iterator; + wxPoint pt( currentVertex.x, currentVertex.y ); + + if( smoothed_polys[ia].Contains( currentVertex ) ) + { + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); + drcItem->SetItems( zoneToTest, zoneRef ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, pt ); + addMarkerToPcb( aCommit, marker ); + } + } + + // Iterate through all the segments of refSmoothedPoly + std::map conflictPoints; + + for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ ) + { + // Build ref segment + SEG refSegment = *refIt; + + // Iterate through all the segments in smoothed_polys[ia2] + for( auto testIt = smoothed_polys[ia2].IterateSegmentsWithHoles(); testIt; testIt++ ) + { + // Build test segment + SEG testSegment = *testIt; + wxPoint pt; + + int ax1, ay1, ax2, ay2; + ax1 = refSegment.A.x; + ay1 = refSegment.A.y; + ax2 = refSegment.B.x; + ay2 = refSegment.B.y; + + int bx1, by1, bx2, by2; + bx1 = testSegment.A.x; + by1 = testSegment.A.y; + bx2 = testSegment.B.x; + by2 = testSegment.B.y; + + int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, + 0, + ax1, ay1, ax2, ay2, + 0, + zone2zoneClearance, + &pt.x, &pt.y ); + + if( d < zone2zoneClearance ) + { + if( conflictPoints.count( pt ) ) + conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d ); + else + conflictPoints[ pt ] = d; + } + } + } + + for( const std::pair& conflict : conflictPoints ) + { + int actual = conflict.second; + DRC_ITEM* drcItem; + + if( actual <= 0 ) + { + drcItem = new DRC_ITEM( DRCE_ZONES_INTERSECT ); + } + else + { + drcItem = new DRC_ITEM( DRCE_ZONES_TOO_CLOSE ); + + m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + m_clearanceSource, + MessageTextFromValue( userUnits(), zone2zoneClearance, true ), + MessageTextFromValue( userUnits(), conflict.second, true ) ); + + drcItem->SetErrorMessage( m_msg ); + } + + drcItem->SetItems( zoneRef, zoneToTest ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, conflict.first ); + addMarkerToPcb( aCommit, marker ); + } + } + } } @@ -1394,72 +1377,6 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart, } -void DRC::TestFootprints( NETLIST& aNetlist, BOARD* aPCB, EDA_UNITS aUnits, - std::vector& aDRCList ) -{ - wxString msg; - - auto comp = []( const MODULE* x, const MODULE* y ) - { - return x->GetReference().CmpNoCase( y->GetReference() ) < 0; - }; - auto mods = std::set( comp ); - - if( !aPCB->GetDesignSettings().Ignore( DRCE_DUPLICATE_FOOTPRINT ) ) - { - // Search for duplicate footprints on the board - for( MODULE* mod : aPCB->Modules() ) - { - auto ins = mods.insert( mod ); - - if( !ins.second ) - { - DRC_ITEM* item = new DRC_ITEM( DRCE_DUPLICATE_FOOTPRINT ); - item->SetItems( mod, *ins.first ); - aDRCList.push_back( item ); - } - } - } - - if( !aPCB->GetDesignSettings().Ignore( DRCE_MISSING_FOOTPRINT ) ) - { - // Search for component footprints in the netlist but not on the board. - for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) - { - COMPONENT* component = aNetlist.GetComponent( ii ); - MODULE* module = aPCB->FindModuleByReference( component->GetReference() ); - - if( module == NULL ) - { - msg.Printf( _( "Missing footprint %s (%s)" ), - component->GetReference(), - component->GetValue() ); - - DRC_ITEM* item = new DRC_ITEM( DRCE_MISSING_FOOTPRINT ); - item->SetErrorMessage( msg ); - aDRCList.push_back( item ); - } - } - } - - if( !aPCB->GetDesignSettings().Ignore( DRCE_EXTRA_FOOTPRINT ) ) - { - // Search for component footprints found on board but not in netlist. - for( auto module : mods ) - { - COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() ); - - if( component == NULL ) - { - DRC_ITEM* item = new DRC_ITEM( DRCE_EXTRA_FOOTPRINT ); - item->SetItems( module ); - aDRCList.push_back( item ); - } - } - } -} - - void DRC::setTransitions() { Go( &DRC::ShowDRCDialog, PCB_ACTIONS::runDRC.MakeEvent() ); diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 9d2fc92b0f..3b3f07524b 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -158,11 +158,8 @@ public: void Reset( RESET_REASON aReason ) override; private: - - // protected or private functions() are lowercase first character. - bool m_doPad2PadTest; // enable pad to pad clearance tests bool m_doUnconnectedTest; // enable unconnected tests - bool m_doZonesTest; // enable zone to items clearance tests + bool m_testTracksAgainstZones; // enable zone to items clearance tests bool m_doKeepoutTest; // enable keepout areas to items clearance tests bool m_refillZones; // refill zones if requested (by user). bool m_reportAllTrackErrors; // Report all tracks errors (or only 4 first errors) @@ -182,13 +179,15 @@ private: std::vector m_ruleSelectors; std::vector m_rules; + // Temp variables for performance during a single DRC run + // // wxString's c'tor is surprisingly expensive, and in the world of DRC everything matters - wxString m_msg; - wxString m_clearanceSource; - - // Used during a single DRC run - int m_largestClearance; + // + wxString m_msg; + wxString m_clearanceSource; + int m_largestClearance; +private: ///> Sets up handlers for various events. void setTransitions() override; @@ -206,13 +205,6 @@ private: //---------------------------------------------- - /** - * Tests whether distance between zones complies with the DRC rules. - * - * @return Errors count - */ - int testZoneToZoneOutlines( BOARD_COMMIT& aCommit ); - /** * Perform the DRC on all tracks. * @@ -307,13 +299,6 @@ public: */ bool LoadRules(); - /** - * Test the board footprints against a netlist. Will report DRCE_MISSING_FOOTPRINT, - * DRCE_DUPLICATE_FOOTPRINT and DRCE_EXTRA_FOOTPRINT errors in aDRCList. - */ - static void TestFootprints( NETLIST& aNetlist, BOARD* aPCB, EDA_UNITS aUnits, - std::vector& aDRCList ); - /** * Fetches a reasonable point for marking a violoation between two non-point objects. */ diff --git a/pcbnew/drc/footprint_tester.cpp b/pcbnew/drc/footprint_tester.cpp new file mode 100644 index 0000000000..14a2f70193 --- /dev/null +++ b/pcbnew/drc/footprint_tester.cpp @@ -0,0 +1,90 @@ +/* + * 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 + */ + +#include +#include +#include + +void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector& aDRCList ) +{ + wxString msg; + + auto comp = []( const MODULE* x, const MODULE* y ) + { + return x->GetReference().CmpNoCase( y->GetReference() ) < 0; + }; + auto mods = std::set( comp ); + + if( !aBoard->GetDesignSettings().Ignore( DRCE_DUPLICATE_FOOTPRINT ) ) + { + // Search for duplicate footprints on the board + for( MODULE* mod : aBoard->Modules() ) + { + auto ins = mods.insert( mod ); + + if( !ins.second ) + { + DRC_ITEM* item = new DRC_ITEM( DRCE_DUPLICATE_FOOTPRINT ); + item->SetItems( mod, *ins.first ); + aDRCList.push_back( item ); + } + } + } + + if( !aBoard->GetDesignSettings().Ignore( DRCE_MISSING_FOOTPRINT ) ) + { + // Search for component footprints in the netlist but not on the board. + for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) + { + COMPONENT* component = aNetlist.GetComponent( ii ); + MODULE* module = aBoard->FindModuleByReference( component->GetReference() ); + + if( module == NULL ) + { + msg.Printf( _( "Missing footprint %s (%s)" ), + component->GetReference(), + component->GetValue() ); + + DRC_ITEM* item = new DRC_ITEM( DRCE_MISSING_FOOTPRINT ); + item->SetErrorMessage( msg ); + aDRCList.push_back( item ); + } + } + } + + if( !aBoard->GetDesignSettings().Ignore( DRCE_EXTRA_FOOTPRINT ) ) + { + // Search for component footprints found on board but not in netlist. + for( auto module : mods ) + { + COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() ); + + if( component == NULL ) + { + DRC_ITEM* item = new DRC_ITEM( DRCE_EXTRA_FOOTPRINT ); + item->SetItems( module ); + aDRCList.push_back( item ); + } + } + } +} diff --git a/pcbnew/drc/footprint_tester.h b/pcbnew/drc/footprint_tester.h new file mode 100644 index 0000000000..bff20988a2 --- /dev/null +++ b/pcbnew/drc/footprint_tester.h @@ -0,0 +1,34 @@ +/* + * 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 FOOTPRINT_TESTER_H +#define FOOTPRINT_TESTER_H + +#include + +class BOARD; + + +void TestFootprints( NETLIST& aNetlist, BOARD* aBoard, std::vector& aDRCList ); + +#endif // FOOTPRINT_TESTER_H