drc_proto: all tests now supported in drc_proto. Not tested yet!

This commit is contained in:
Tomasz Wlostowski 2020-08-25 19:42:52 +02:00
parent 147540b3bb
commit adbd94553d
21 changed files with 1752 additions and 223 deletions

View File

@ -44,6 +44,14 @@ add_executable( drc_proto
drc_test_provider_hole_clearance.cpp
drc_test_provider_edge_clearance.cpp
drc_test_provider_hole_size.cpp
drc_test_provider_disallow.cpp
drc_test_provider_track_width.cpp
drc_test_provider_annulus.cpp
drc_test_provider_connectivity.cpp
drc_test_provider_courtyard_clearance.cpp
drc_test_provider_via_diameter.cpp
drc_test_provider_lvs.cpp
drc_test_provider_misc.cpp
drc_engine.cpp
drc_item.cpp
../qa_utils/mocks.cpp

View File

@ -43,6 +43,10 @@ void drcPrintDebugMessage( int level, wxString msg, const char *function, int li
if( wxGetEnv( "DRC_DEBUG", &valueStr ) )
{
int setLevel = wxAtoi( valueStr );
if( level <= setLevel )
{
printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
}
}
}
@ -50,6 +54,8 @@ void drcPrintDebugMessage( int level, wxString msg, const char *function, int li
test::DRC_ENGINE::DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS *aSettings ) :
m_board( aBoard ),
m_designSettings ( aSettings ),
m_worksheet( nullptr ),
m_schematicNetlist( nullptr ),
m_reporter( nullptr ),
m_progressReporter( nullptr )
{
@ -64,11 +70,6 @@ test::DRC_ENGINE::~DRC_ENGINE()
test::DRC_REPORT::~DRC_REPORT()
{
for( auto item : m_entries )
{
if ( item.m_marker )
delete item.m_marker;
}
}
@ -139,11 +140,11 @@ bool test::DRC_ENGINE::CompileRules()
for( auto provider : m_testProviders )
{
ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
drc_dbg(11, "do prov %s", provider->GetName() );
drc_dbg(7, "do prov %s", provider->GetName() );
for ( auto id : provider->GetMatchingConstraintIds() )
{
drc_dbg(11, "do id %d", id);
drc_dbg(7, "do id %d", id);
if( m_constraintMap.find(id) == m_constraintMap.end() )
m_constraintMap[id] = new CONSTRAINT_SET;
@ -151,14 +152,14 @@ bool test::DRC_ENGINE::CompileRules()
for( auto rule : m_rules )
{
drc_dbg(11, "Scan provider %s, rule %s", provider->GetName(), rule->GetName() );
drc_dbg(7, "Scan provider %s, rule %s", provider->GetName(), rule->GetName() );
if( ! rule->IsEnabled() )
continue;
for( auto& constraint : rule->Constraints() )
{
drc_dbg(11, "scan constraint id %d\n", constraint.GetType() );
drc_dbg(7, "scan constraint id %d\n", constraint.GetType() );
if( constraint.GetType() != id )
continue;
@ -191,8 +192,6 @@ bool test::DRC_ENGINE::CompileRules()
void test::DRC_ENGINE::RunTests( )
{
//m_largestClearance = m_designSettings->GetBiggestClearanceValue();
m_drcReport.reset( new test::DRC_REPORT );
m_testProviders = DRC_TEST_PROVIDER_REGISTRY::Instance().GetTestProviders();
@ -209,8 +208,11 @@ void test::DRC_ENGINE::RunTests( )
for( auto provider : m_testProviders )
{
bool skipProvider = false;
auto matchingConstraints = provider->GetMatchingConstraintIds();
for( auto ruleID : provider->GetMatchingConstraintIds() )
if( matchingConstraints.size() )
{
for( auto ruleID : matchingConstraints )
{
if( !HasCorrectRulesForId( ruleID ) )
{
@ -219,6 +221,7 @@ void test::DRC_ENGINE::RunTests( )
break;
}
}
}
if( skipProvider )
continue;
@ -271,11 +274,17 @@ void test::DRC_ENGINE::Report( std::shared_ptr<DRC_ITEM> aItem, ::MARKER_PCB *aM
if( m_reporter )
{
m_reporter->Report ( wxString::Format( "Test '%s': violation of rule '%s' : %s (code %d)",
wxString msg = wxString::Format( "Test '%s': %s (code %d)",
aItem->GetViolatingTest()->GetName(),
aItem->GetViolatingRule()->GetName(),
aItem->GetErrorMessage(),
aItem->GetErrorCode() ), RPT_SEVERITY_ERROR /* fixme */ );
aItem->GetErrorCode() );
auto rule = aItem->GetViolatingRule();
if( rule )
msg += wxString::Format( ", violating rule: '%s'", rule->GetName() );
m_reporter->Report ( msg, RPT_SEVERITY_ERROR /* fixme */ );
wxString violatingItemsStr = "Violating items: ";

View File

@ -53,12 +53,20 @@ class NETLIST;
class PROGRESS_REPORTER;
class REPORTER;
namespace KIGFX
{
class WS_PROXY_VIEW_ITEM;
};
void drcPrintDebugMessage( int level, wxString msg, const char *function, int line );
#define drc_dbg(level, fmt, ...) \
drcPrintDebugMessage(level, wxString::Format( fmt, __VA_ARGS__ ), __FUNCTION__, __LINE__ );
//#define drc_dbg(level, fmt, ...) \
// wxLogTrace("DUPA", fmt, __VA_ARGS__);
namespace test
{
@ -91,7 +99,7 @@ enum PCB_DRC_CODE
DRCE_HOLE_CLEARANCE, ///< overlapping drilled holes break drill bits
DRCE_TRACK_WIDTH, ///< Track width is too small or too large
DRCE_TOO_SMALL_VIA, ///< Too small via size
DRCE_VIA_ANNULUS, ///< Via size and drill leave annulus too small or too large
DRCE_ANNULUS, ///< Via size and drill leave annulus too small or too large
DRCE_TOO_SMALL_DRILL, ///< Too small via or pad drill
DRCE_VIA_HOLE_BIGGER, ///< via's hole is bigger than its diameter
DRCE_PADSTACK, ///< something is wrong with a pad or via stackup
@ -111,6 +119,7 @@ enum PCB_DRC_CODE
DRCE_EXTRA_FOOTPRINT, ///< netlist item not found for footprint
DRCE_UNRESOLVED_VARIABLE,
DRCE_VIA_DIAMETER, ///< Via diameter checks (min/max)
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
};
@ -158,6 +167,26 @@ public:
DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings );
~DRC_ENGINE();
void SetSchematicNetlist( NETLIST* aNetlist )
{
m_schematicNetlist = aNetlist;
}
NETLIST* GetSchematicNetlist() const
{
return m_schematicNetlist;
}
void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet )
{
m_worksheet = aWorksheet;
}
KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const
{
return m_worksheet;
}
void SetProgressReporter( PROGRESS_REPORTER* aProgRep )
{
m_progressReporter = aProgRep;
@ -183,6 +212,8 @@ public:
return m_board;
}
const DRC_CONSTRAINT& EvalRulesForItems(
DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a, BOARD_ITEM* b = nullptr, PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
@ -233,6 +264,8 @@ private:
BOARD_DESIGN_SETTINGS* m_designSettings;
BOARD* m_board;
KIGFX::WS_PROXY_VIEW_ITEM* m_worksheet;
NETLIST* m_schematicNetlist;
std::shared_ptr<DRC_REPORT> m_drcReport;

View File

@ -88,9 +88,9 @@ test::DRC_ITEM test::DRC_ITEM::viaTooSmall( DRCE_TOO_SMALL_VIA,
_( "Via size too small" ),
wxT( "via_too_small" ) );
test::DRC_ITEM test::DRC_ITEM::viaAnnulus( DRCE_VIA_ANNULUS,
_( "Via annulus" ),
wxT( "via_annulus" ) );
test::DRC_ITEM test::DRC_ITEM::annulus( DRCE_ANNULUS,
_( "annulus" ),
wxT( "annulus" ) );
test::DRC_ITEM test::DRC_ITEM::drillTooSmall( DRCE_TOO_SMALL_DRILL,
_( "Drill too small" ),
@ -175,7 +175,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> test::DRC_ITEM::allItemTypes( {
DRC_ITEM::holeClearance,
DRC_ITEM::trackWidth,
DRC_ITEM::viaTooSmall,
DRC_ITEM::viaAnnulus,
DRC_ITEM::annulus,
DRC_ITEM::drillTooSmall,
DRC_ITEM::viaHoleLargerThanPad,
DRC_ITEM::padstack,
@ -215,7 +215,7 @@ std::shared_ptr<test::DRC_ITEM> test::DRC_ITEM::Create( int aErrorCode )
case DRCE_HOLE_CLEARANCE: item = new DRC_ITEM( holeClearance ); break;
case DRCE_TRACK_WIDTH: item = new DRC_ITEM( trackWidth ); break;
case DRCE_TOO_SMALL_VIA: item = new DRC_ITEM( viaTooSmall ); break;
case DRCE_VIA_ANNULUS: item = new DRC_ITEM( viaAnnulus ); break;
case DRCE_ANNULUS: item = new DRC_ITEM( annulus ); break;
case DRCE_TOO_SMALL_DRILL: item = new DRC_ITEM( drillTooSmall ); break;
case DRCE_VIA_HOLE_BIGGER: item = new DRC_ITEM( viaHoleLargerThanPad ); break;
case DRCE_PADSTACK: item = new DRC_ITEM( padstack ); break;

View File

@ -98,7 +98,7 @@ private:
static DRC_ITEM holeClearance;
static DRC_ITEM trackWidth;
static DRC_ITEM viaTooSmall;
static DRC_ITEM viaAnnulus;
static DRC_ITEM annulus;
static DRC_ITEM drillTooSmall;
static DRC_ITEM viaHoleLargerThanPad;
static DRC_ITEM padstack;

View File

@ -36,6 +36,9 @@
int main( int argc, char *argv[] )
{
wxLogTrace("DUPA", "Debug Test!\n");
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
propMgr.Rebuild();

View File

@ -26,7 +26,7 @@
#define DRC_RTREE_H_
#include <eda_rect.h>
#include <board_connected_item.h>
#include <class_board_item.h>
#include <set>
#include <vector>
@ -46,7 +46,7 @@ private:
public:
DRC_RTREE()
{
for( int layer : LSET::AllCuMask().Seq() )
for( int layer : LSET::AllLayersMask().Seq() )
m_tree[layer] = new drc_rtree();
m_count = 0;

View File

@ -57,7 +57,8 @@ enum DRC_CONSTRAINT_TYPE_T
DRC_CONSTRAINT_TYPE_SILK_TO_SILK,
DRC_CONSTRAINT_TYPE_TRACK_WIDTH,
DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH,
DRC_CONSTRAINT_TYPE_DISALLOW
DRC_CONSTRAINT_TYPE_DISALLOW,
DRC_CONSTRAINT_TYPE_VIA_DIAMETER
};
enum DRC_DISALLOW_T
@ -127,6 +128,8 @@ class DRC_CONSTRAINT
DRC_CONSTRAINT_TYPE_T GetType() const { return m_Type; }
const LSET& GetAllowedLayers() const { return m_LayerCondition; }
public:
DRC_CONSTRAINT_TYPE_T m_Type;
int m_DisallowFlags;

View File

@ -99,7 +99,7 @@ void test::DRC_TEST_PROVIDER::reportRuleStatistics()
}
}
int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T> aTypes, const LSET aLayers, std::function<int(BOARD_ITEM*)> aFunc )
int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T> aTypes, const LSET aLayers, std::function<bool(BOARD_ITEM*)> aFunc )
{
BOARD *brd = m_drcEngine->GetBoard();
std::bitset<MAX_STRUCT_TYPE_ID> typeMask;
@ -124,6 +124,8 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T> aTy
case PCB_VIA_T:
case PCB_ARC_T:*/
for ( auto item : brd->Tracks() )
{
if( (item->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T )
{
@ -141,6 +143,7 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T> aTy
n++;
}
}
}
/* case PCB_DIMENSION_T:
case PCB_LINE_T:
@ -148,80 +151,124 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T> aTy
case PCB_TARGET_T:
*/
for( auto item : brd->Drawings() )
{
if( (item->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_DIMENSION_T ] && item->Type() == PCB_DIMENSION_T )
{
aFunc( item );
if( !aFunc( item ) )
return n;
n++;
}
else if( typeMask[ PCB_LINE_T ] && item->Type() == PCB_LINE_T )
{
aFunc( item );
if( !aFunc( item ) )
return n;
n++;
}
else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T )
{
aFunc( item );
if( !aFunc( item ) )
return n;
n++;
}
else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T )
{
aFunc( item );
if( !aFunc( item ) )
return n;
n++;
}
}
}
for( auto item : brd->Zones() )
{
if( (item->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_ZONE_AREA_T ] && item->Type() == PCB_ZONE_AREA_T )
{
aFunc( item );
if( !aFunc( item ) )
return n;
n++;
}
}
}
for( auto mod : brd->Modules() )
{
if( typeMask[ PCB_MODULE_TEXT_T ] )
{
aFunc( &mod->Reference() );
if( (mod->Reference().GetLayerSet() & aLayers).any() )
{
if( !aFunc( &mod->Reference() ) )
return n;
n++;
aFunc( &mod->Value() );
}
if( (mod->Value().GetLayerSet() & aLayers).any() )
{
if( !aFunc( &mod->Value() ) )
return n;
n++;
}
}
for( auto pad : mod->Pads() )
{
if( (pad->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_PAD_T ] && pad->Type() == PCB_PAD_T )
{
aFunc( pad );
if( !aFunc( pad ) )
return n;
n++;
}
}
}
for( auto dwg : mod->GraphicalItems() )
{
if( (dwg->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_MODULE_TEXT_T ] && dwg->Type() == PCB_MODULE_TEXT_T )
{
aFunc( dwg );
if( !aFunc( dwg ) )
return n;
n++;
}
else if( typeMask[ PCB_MODULE_EDGE_T ] && dwg->Type() == PCB_MODULE_EDGE_T )
{
aFunc( dwg );
if( !aFunc( dwg ) )
return n;
n++;
}
}
}
for( auto zone : mod->Zones() )
{
if( (zone->GetLayerSet() & aLayers).any() )
{
if( typeMask[ PCB_MODULE_ZONE_AREA_T ] && zone->Type() == PCB_MODULE_ZONE_AREA_T )
{
aFunc( zone );
if( ! aFunc( zone ) )
return n;
n++;
}
}
}
}
return n;
}

View File

@ -106,9 +106,14 @@ public:
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const = 0;
virtual bool IsRuleDriven() const
{
return m_isRuleDriven;
}
protected:
int forEachGeometryItem( const std::vector<KICAD_T> aTypes, const LSET aLayers, std::function<int(BOARD_ITEM*)> aFunc );
int forEachGeometryItem( const std::vector<KICAD_T> aTypes, const LSET aLayers, std::function<bool(BOARD_ITEM*)> aFunc );
virtual void reportRuleStatistics();
virtual void accountCheck( const test::DRC_RULE* ruleToTest );
@ -119,6 +124,7 @@ protected:
DRC_ENGINE *m_drcEngine;
std::unordered_map<const test::DRC_RULE*, int> m_stats;
bool m_enable;
bool m_isRuleDriven = true;
};

View File

@ -0,0 +1,160 @@
/*
* 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 <class_board.h>
#include <class_track.h>
#include <class_via.h>
#include <class_pad.h>
#include <common.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
/*
Via/pad annular ring width test. Checks if there's sufficient copper ring around PTH/NPTH holes (vias/pads)
Errors generated:
- DRCE_ANNULUS
Todo:
- check pad holes too.
- pad stack support (different IAR/OAR values depending on layer)
*/
namespace test
{
class DRC_TEST_PROVIDER_ANNULUS : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_ANNULUS()
{
}
virtual ~DRC_TEST_PROVIDER_ANNULUS()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "annulus";
};
virtual const wxString GetDescription() const override
{
return "Tests pad/via annular rings";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
};
}; // namespace test
bool test::DRC_TEST_PROVIDER_ANNULUS::Run()
{
if( !m_drcEngine->HasCorrectRulesForId(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) )
{
ReportAux( "No annulus constraints found. Skipping check." );
return false;
}
ReportStage( ( "Testing via annular rings" ), 0, 2 );
auto checkAnnulus = [&]( BOARD_ITEM* item ) -> bool
{
bool fail_min = false, fail_max = false;
int v_min, v_max;
auto via = dyn_cast<VIA*>( item );
// fixme: check minimum IAR/OAR ring for THT pads too
if( !via )
return true;
test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH, via );
int annulus = ( via->GetWidth() - via->GetDrillValue() ) / 2;
if( constraint.Value().HasMin() )
{
v_min = constraint.Value().Min();
fail_min = annulus < v_min;
}
if( constraint.Value().HasMax() )
{
v_max = constraint.Value().Max();
fail_max = annulus > v_max;
}
if( fail_min || fail_max )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULUS );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s; actual annulus %s, constraint %s %s)" ),
constraint.GetParentRule()->GetName(),
MessageTextFromValue( userUnits(), annulus, true ),
fail_min ? _( "minimum" ) : _( "maximum" ),
MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, via->GetPosition() );
if( isErrorLimitExceeded( DRCE_ANNULUS ) )
return false;
}
return true;
};
forEachGeometryItem( { PCB_VIA_T }, LSET::AllCuMask(), checkAnnulus );
reportRuleStatistics();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T>
test::DRC_TEST_PROVIDER_ANNULUS::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_ANNULUS> dummy;
}

View File

@ -0,0 +1,177 @@
/*
* 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 <class_board.h>
#include <common.h>
#include <connectivity/connectivity_data.h>
#include <connectivity/connectivity_algo.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
/*
Connectivity test provider. Not rule-driven.
Errors generated:
- DRCE_DANGLING_TRACK
- DRCE_DANGLING_VIA
- DRCE_ZONE_HAS_EMPTY_NET
*/
namespace test
{
class DRC_TEST_PROVIDER_CONNECTIVITY : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_CONNECTIVITY()
{
}
virtual ~DRC_TEST_PROVIDER_CONNECTIVITY()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "connectivity";
};
virtual const wxString GetDescription() const override
{
return "Tests board connectivity";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
};
}; // namespace test
bool test::DRC_TEST_PROVIDER_CONNECTIVITY::Run()
{
ReportStage( ( "Testing dangling pads/vias" ), 0, 2 );
BOARD* board = m_drcEngine->GetBoard();
std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
connectivity->Clear();
connectivity->Build( board ); // just in case. This really needs to be reliable.
for( auto track : board->Tracks() )
{
bool exceedT = isErrorLimitExceeded( DRCE_DANGLING_TRACK );
bool exceedV = isErrorLimitExceeded( DRCE_DANGLING_VIA );
// Test for dangling items
int code = track->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
wxPoint pos;
if( track->Type() == PCB_VIA_T && exceedV )
continue;
else if( track->Type() == PCB_TRACE_T && exceedT )
continue;
if( connectivity->TestTrackEndpointDangling( track, &pos ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
wxString msg;
msg.Printf( drcItem->GetErrorText() );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( track );
ReportWithMarker( drcItem, pos );
}
if( exceedV && exceedT )
break;
}
ReportStage( ( "Testing starved zones" ), 0, 2 );
/* test starved zones */
for( auto zone : board->Zones() )
{
if( !zone->IsOnCopperLayer() )
continue;
int netcode = zone->GetNetCode();
// 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 ) ? connectivity->GetPadCount( netcode ) : 1;
if( ( netcode < 0 ) || pads_in_net == 0 )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET );
wxString msg;
msg.Printf( drcItem->GetErrorText() );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( zone );
ReportWithMarker( drcItem, zone->GetPosition() );
if( isErrorLimitExceeded( DRCE_ZONE_HAS_EMPTY_NET ) )
break;
}
}
ReportStage( ( "Testing unconnected ratlines" ), 0, 2 );
connectivity->RecalculateRatsnest();
std::vector<CN_EDGE> edges;
connectivity->GetUnconnectedEdges( edges );
for( const CN_EDGE& edge : edges )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
ReportWithMarker( drcItem, edge.GetSourceNode()->Pos() );
if( isErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) )
break;
}
reportRuleStatistics();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T>
test::DRC_TEST_PROVIDER_CONNECTIVITY::GetMatchingConstraintIds() const
{
return {};
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_CONNECTIVITY> dummy;
}

View File

@ -46,6 +46,7 @@
- DRCE_CLEARANCE
- DRCE_TRACKS_CROSSING
- DRCE_ZONES_INTERSECT
- DRCE_SHORTING_ITEMS
TODO: improve zone clearance check (super slow)
*/
@ -121,6 +122,8 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
ReportStage( ("Testing copper zone clearances"), 1, 2 );
testZones();
reportRuleStatistics();
return true;
}

View File

@ -0,0 +1,229 @@
/*
* 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 <common.h>
#include <class_board.h>
#include <class_drawsegment.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h>
/*
Couartyard clearance. Tests for malformed component courtyards and overlapping footprints.
Generated errors:
- DRCE_OVERLAPPING_FOOTPRINTS
- DRCE_MISSING_COURTYARD
- DRCE_MALFORMED_COURTYARD
TODO: do an actual clearance check instead of polygon intersection. Treat closed outlines
as filled and allow open curves in the courtyard.
*/
namespace test {
class DRC_TEST_PROVIDER_COURTYARD_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE
{
public:
DRC_TEST_PROVIDER_COURTYARD_CLEARANCE ()
{
m_isRuleDriven = false;
}
virtual ~DRC_TEST_PROVIDER_COURTYARD_CLEARANCE ()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "courtyard_clearance";
};
virtual const wxString GetDescription() const override
{
return "Tests components' courtyard clearance";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
void testFootprintCourtyardDefinitions();
void testOverlappingComponentCourtyards();
};
};
void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
{
ReportStage( _("Testing component courtyard definitions"), 0, 2 );
for( MODULE* footprint : m_board->Modules() )
{
if( footprint->BuildPolyCourtyard() )
{
if( footprint->GetPolyCourtyardFront().OutlineCount() == 0
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
{
if( isErrorLimitExceeded( DRCE_MISSING_COURTYARD ) )
continue;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
wxString msg;
msg.Printf( drcItem->GetErrorText( ));
drcItem->SetItems( footprint );
ReportWithMarker( drcItem, footprint->GetPosition() );
}
else
{
footprint->GetPolyCourtyardFront().BuildBBoxCaches();
footprint->GetPolyCourtyardBack().BuildBBoxCaches();
}
}
else
{
if( !isErrorLimitExceeded( DRCE_MALFORMED_COURTYARD) )
{
wxString msg;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
ReportWithMarker( drcItem, footprint->GetPosition() );
}
}
}
}
void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
{
ReportStage( _("Testing component courtyard overlap"), 0, 2 );
for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ )
{
MODULE* footprint = *it1;
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
continue; // No courtyards defined
for( auto it2 = it1 + 1; it2 != m_board->Modules().end(); it2++ )
{
MODULE* test = *it2;
SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront();
SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack();
SHAPE_POLY_SET intersection;
bool overlap = false;
wxPoint pos;
if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0
&& footprintFront.BBoxFromCaches().Intersects( testFront.BBoxFromCaches() ) )
{
intersection.RemoveAllContours();
intersection.Append( footprintFront );
// Build the common area between footprint and the test:
intersection.BooleanIntersection( testFront, SHAPE_POLY_SET::PM_FAST );
// If the intersection exists then they overlap
if( intersection.OutlineCount() > 0 )
{
overlap = true;
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
}
}
if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0
&& footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) )
{
intersection.RemoveAllContours();
intersection.Append( footprintBack );
intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST );
if( intersection.OutlineCount() > 0 )
{
overlap = true;
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
}
}
if( overlap )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS );
drcItem->SetItems( footprint, test );
ReportWithMarker ( drcItem, pos );
if( isErrorLimitExceeded( DRCE_OVERLAPPING_FOOTPRINTS ) )
return;
}
}
}
}
bool test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
{
m_board = m_drcEngine->GetBoard();
// fixme: don't use polygon intersection but distance for clearance tests
//m_largestClearance = 0;
//ReportAux( "Worst courtyard clearance : %d nm", m_largestClearance );
testFootprintCourtyardDefinitions();
testOverlappingComponentCourtyards();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE> dummy;
}

View File

@ -0,0 +1,130 @@
/*
* 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 <class_board.h>
#include <common.h>
#include <geometry/shape.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
/*
"Disallow" test. Goes through all items, matching types/conditions drop errors.
Errors generated:
- DRCE_ALLOWED_ITEMS
*/
namespace test
{
class DRC_TEST_PROVIDER_DISALLOW : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_DISALLOW()
{
}
virtual ~DRC_TEST_PROVIDER_DISALLOW()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "disallow";
};
virtual const wxString GetDescription() const override
{
return "Tests for disallowed items (e.g. keepouts)";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
};
}; // namespace test
bool test::DRC_TEST_PROVIDER_DISALLOW::Run()
{
if( !m_drcEngine->HasCorrectRulesForId( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW ) )
{
ReportAux( "No disallow constraints found. Skipping check." );
return false;
}
ReportStage( ("Testing for disallow constraints"), 0, 2 );
auto checkItem = [&] ( BOARD_ITEM *item ) -> bool
{
test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW, item );
if( constraint.Allowed() )
return true;
if( ( constraint.GetAllowedLayers() & item->GetLayerSet() ).any() )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS );
wxString msg;
msg.Printf(
drcItem->GetErrorText() + _( " (%s)" ), constraint.GetParentRule()->GetName() );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, item->GetPosition() );
if( isErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) )
return false;
}
return true;
};
forEachGeometryItem( {}, LSET::AllLayersMask(), checkItem );
reportRuleStatistics();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T>
test::DRC_TEST_PROVIDER_DISALLOW::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_DISALLOW> dummy;
}

View File

@ -104,34 +104,36 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
std::vector<DRAWSEGMENT*> boardOutline;
std::vector<BOARD_ITEM*> boardItems;
auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> int
auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> bool
{
boardOutline.push_back( dyn_cast<DRAWSEGMENT*>( item ) );
return 0;
return true;
};
auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> int
auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> bool
{
boardItems.push_back( item );
return 0;
return true;
};
forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems );
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
wxString val;
wxGetEnv( "WXTRACE", &val);
drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
bool stop = false;
for( auto outlineItem : boardOutline )
{
drc_dbg(12, "RefT %d %p\n", outlineItem->Type(), outlineItem );
auto refShape = outlineItem->GetEffectiveShape();
for( auto boardItem : boardItems )
{
drc_dbg(12, "BoardT %d %p\n", boardItem->Type(), boardItem );
drc_dbg(10, "RefT %d %p %s %d\n", outlineItem->Type(), outlineItem, outlineItem->GetClass(), outlineItem->GetLayer() );
drc_dbg(10, "BoardT %d %p %s %d\n", boardItem->Type(), boardItem, boardItem->GetClass(), boardItem->GetLayer() );
auto shape = boardItem->GetEffectiveShape();
@ -154,10 +156,21 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, refShape->Centre() );
if( isErrorLimitExceeded( DRCE_COPPER_EDGE_CLEARANCE ) )
{
stop = true;
break;
}
}
}
if( stop )
break;
}
reportRuleStatistics();
return true;
}

View File

@ -0,0 +1,214 @@
/*
* 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 <class_board.h>
#include <class_track.h>
#include <common.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
#include <kiway.h>
#include <netlist_reader/pcb_netlist.h>
/*
Layout-versus-schematic (LVS) test.
Errors generated:
- DRCE_MISSING_FOOTPRINT
- DRCE_DUPLICATE_FOOTPRINT
- DRCE_EXTRA_FOOTPRINT
TODO:
- cross-check PCB netlist against SCH netlist
- cross-check PCB fields against SCH fields
*/
namespace test
{
class DRC_TEST_PROVIDER_LVS : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_LVS()
{
m_isRuleDriven = false;
}
virtual ~DRC_TEST_PROVIDER_LVS()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "LVS";
};
virtual const wxString GetDescription() const override
{
return "Performs layout-vs-schematics integity check";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
bool fetchNetlistFromSchematic( NETLIST& aNetlist );
void testFootprints( NETLIST& aNetlist );
};
}; // namespace test
void test::DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
{
wxString msg;
BOARD* board = m_drcEngine->GetBoard();
auto comp = []( const MODULE* x, const MODULE* y ) {
return x->GetReference().CmpNoCase( y->GetReference() ) < 0;
};
auto mods = std::set<MODULE*, decltype( comp )>( comp );
for( MODULE* mod : board->Modules() )
{
auto ins = mods.insert( mod );
if( !ins.second )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
drcItem->SetItems( mod, *ins.first );
ReportWithMarker( drcItem, mod->GetPosition() );
if( isErrorLimitExceeded( DRCE_DUPLICATE_FOOTPRINT ) )
break;
}
}
// 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 = board->FindModuleByReference( component->GetReference() );
if( module == nullptr )
{
msg.Printf( _( "Missing footprint %s (%s)" ), component->GetReference(),
component->GetValue() );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
drcItem->SetErrorMessage( msg );
Report( drcItem );
if( isErrorLimitExceeded( DRCE_MISSING_FOOTPRINT ) )
break;
}
}
for( auto module : mods )
{
COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() );
if( component == NULL )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
drcItem->SetItems( module );
ReportWithMarker( drcItem, module->GetPosition() );
if( isErrorLimitExceeded( DRCE_EXTRA_FOOTPRINT ) )
break;
}
}
}
bool test::DRC_TEST_PROVIDER_LVS::fetchNetlistFromSchematic( NETLIST& aNetlist )
{
// fixme: make it work without dependency on EDIT_FRAME/kiway
#if 0
std::string payload;
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, payload, nullptr );
try
{
auto lineReader = new STRING_LINE_READER( payload, _( "Eeschema netlist" ) );
KICAD_NETLIST_READER netlistReader( lineReader, &aNetlist );
netlistReader.LoadNetlist();
}
catch( const IO_ERROR& )
{
assert( false ); // should never happen
return false;
}
#endif
return false;
}
bool test::DRC_TEST_PROVIDER_LVS::Run()
{
ReportStage( _( "Layout-vs-Schematic checks..." ), 0, 2 );
#if 0
if ( !Kiface().IsSingle() )
{
NETLIST netlist; // fixme: fetch from schematic without referring directly to the FRAME
if( ! fetchNetlistFromSchematic( netlist ) )
{
ReportAux( _( "Unable to fetch the schematic netlist. Skipping LVS checks. ") );
return true;
}
testFootprints( netlist );
}
#endif
reportRuleStatistics();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_LVS::GetMatchingConstraintIds() const
{
return {};
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_LVS> dummy;
}

View File

@ -0,0 +1,216 @@
/*
* 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 <class_board.h>
#include <class_track.h>
#include <common.h>
#include <class_module.h>
#include <class_pcb_text.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
#include <ws_draw_item.h>
#include <ws_proxy_view_item.h>
/*
Miscellaneous tests:
- DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
- DRCE_INVALID_OUTLINE, ///< invalid board outline
- DRCE_UNRESOLVED_VARIABLE,
TODO:
- if grows too big, split into separate providers
*/
namespace test
{
class DRC_TEST_PROVIDER_MISC : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_MISC()
{
m_isRuleDriven = false;
}
virtual ~DRC_TEST_PROVIDER_MISC()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "miscellanous";
};
virtual const wxString GetDescription() const override
{
return "Misc checks (board outline, missing textvars)";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
void testOutline();
void testDisabledLayers();
void testTextVars();
BOARD* m_board;
};
}; // namespace test
void test::DRC_TEST_PROVIDER_MISC::testOutline()
{
wxPoint error_loc( m_board->GetBoardEdgesBoundingBox().GetPosition() );
SHAPE_POLY_SET boardOutlines;
if( m_board->GetBoardPolygonOutlines( boardOutlines, nullptr, &error_loc ) )
return;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( m_board );
ReportWithMarker( drcItem, error_loc );
}
void test::DRC_TEST_PROVIDER_MISC::testDisabledLayers()
{
LSET disabledLayers = m_board->GetEnabledLayers().flip();
// Perform the test only for copper layers
disabledLayers &= LSET::AllCuMask();
auto checkDisabledLayers = [&]( BOARD_ITEM* item ) -> bool {
if( ( disabledLayers & item->GetLayerSet() ).any() )
{
wxString msg;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM );
msg.Printf( drcItem->GetErrorText() + _( " (layer %s)" ), item->GetLayerName() );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( item );
ReportWithMarker( drcItem, item->GetPosition() );
}
return true;
};
// fixme: what about graphical items?
forEachGeometryItem( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_PAD_T },
LSET::AllLayersMask(), checkDisabledLayers );
}
void test::DRC_TEST_PROVIDER_MISC::testTextVars()
{
auto checkUnresolvedTextVar = [&]( EDA_ITEM* item ) -> bool {
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
assert( text );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
if( isErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) )
return false;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( item );
ReportWithMarker( drcItem, item->GetPosition() );
}
return true;
};
forEachGeometryItem(
{ PCB_MODULE_TEXT_T, PCB_TEXT_T }, LSET::AllLayersMask(), checkUnresolvedTextVar );
WS_DRAW_ITEM_LIST wsItems;
auto worksheet = m_drcEngine->GetWorksheet();
if( !worksheet )
return;
wsItems.SetMilsToIUfactor( IU_PER_MILS );
wsItems.BuildWorkSheetGraphicList( worksheet->GetPageInfo(), worksheet->GetTitleBlock() );
for( WS_DRAW_ITEM_BASE* item = wsItems.GetFirst(); item; item = wsItems.GetNext() )
{
if( WS_DRAW_ITEM_TEXT* text = dynamic_cast<WS_DRAW_ITEM_TEXT*>( item ) )
{
if( isErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) )
return;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( text );
ReportWithMarker( drcItem, text->GetPosition() );
}
}
}
bool test::DRC_TEST_PROVIDER_MISC::Run()
{
m_board = m_drcEngine->GetBoard();
ReportStage( _( "Test board outline" ), 0, 3 );
testOutline();
ReportStage( _( "Test disabled layers" ), 1, 3 );
testDisabledLayers();
ReportStage( _( "Test text variables" ), 2, 3 );
testTextVars();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_MISC::GetMatchingConstraintIds() const
{
return {};
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_MISC> dummy;
}

View File

@ -0,0 +1,168 @@
/*
* 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 <common.h>
#include <class_board.h>
#include <class_drawsegment.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h>
/*
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 {
class DRC_TEST_PROVIDER_SILK_TO_PAD : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_SILK_TO_PAD ()
{
}
virtual ~DRC_TEST_PROVIDER_SILK_TO_PAD()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "silk_to_pad";
};
virtual const wxString GetDescription() const override
{
return "Tests for silkscreen covering components pads";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
};
};
bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
{
m_board = m_drcEngine->GetBoard();
DRC_CONSTRAINT worstClearanceConstraint;
m_largestClearance = 0;
if( m_drcEngine->QueryWorstConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_SILK_TO_PAD, worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{
m_largestClearance = worstClearanceConstraint.m_Value.Min();
}
ReportAux( "Worst clearance : %d nm", m_largestClearance );
ReportStage( ("Testing pads vs silkscreen clearance"), 0, 2 );
std::vector<DRAWSEGMENT*> boardOutline;
std::vector<BOARD_ITEM*> boardItems;
auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> int
{
boardOutline.push_back( dyn_cast<DRAWSEGMENT*>( item ) );
};
auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> int
{
boardItems.push_back( item );
};
forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems );
forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems );
drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() );
for( auto outlineItem : boardOutline )
{
//printf("RefT %d\n", outlineItem->Type() );
auto refShape = outlineItem->GetEffectiveShape();
for( auto boardItem : boardItems )
{
// printf("BoardT %d\n", boardItem->Type() );
auto shape = boardItem->GetEffectiveShape();
test::DRC_RULE* rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem );
int minClearance = rule->GetConstraint().GetValue().Min();
int actual;
if( refShape->Collide( shape.get(), minClearance, &actual ) )
{
DRC_ITEM* 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 );
ReportWithMarker( drcItem, refShape->Centre() );
}
}
}
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_EDGE_CLEARANCE> dummy;
}

View File

@ -22,44 +22,32 @@
*/
#include <class_board.h>
#include <class_drawsegment.h>
#include <class_pad.h>
#include <class_track.h>
#include <common.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h>
#include <drc_proto/drc_test_provider.h>
/*
Drilled hole size test. scans vias/through-hole pads and checks for min drill sizes
Track width test. As the name says, checks width of the tracks (including segments and arcs)
Errors generated:
- DRCE_TOO_SMALL_DRILL
- DRCE_TOO_SMALL_MICROVIA_DRILL
TODO: max drill size check
- DRCE_TRACK_WIDTH
*/
namespace test
{
class DRC_TEST_PROVIDER_HOLE_SIZE : public DRC_TEST_PROVIDER
class DRC_TEST_PROVIDER_TRACK_WIDTH : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_HOLE_SIZE()
DRC_TEST_PROVIDER_TRACK_WIDTH()
{
}
virtual ~DRC_TEST_PROVIDER_HOLE_SIZE()
virtual ~DRC_TEST_PROVIDER_TRACK_WIDTH()
{
}
@ -67,137 +55,105 @@ public:
virtual const wxString GetName() const override
{
return "hole_size";
return "width";
};
virtual const wxString GetDescription() const override
{
return "Tests sizes of drilled holes (via/pad drills)";
return "Tests track widths";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
bool checkVia( VIA* via );
bool checkPad( D_PAD* aPad );
BOARD* m_board;
};
}; // namespace test
bool test::DRC_TEST_PROVIDER_HOLE_SIZE::Run()
bool test::DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
{
ReportStage( ( "Testing pad holes" ), 0, 2 );
for( auto module : m_board->Modules() )
if( !m_drcEngine->HasCorrectRulesForId(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) )
{
for( auto pad : module->Pads() )
{
if( checkPad( pad ) )
break;
}
ReportAux( "No track width constraints found. Skipping check." );
return false;
}
ReportStage( ( "Testing via/microvia holes" ), 0, 2 );
ReportStage( ( "Testing track widths" ), 0, 2 );
std::vector<VIA*> vias;
auto checkTrackWidth = [&]( BOARD_ITEM* item ) -> bool {
int width;
VECTOR2I p0;
for( auto track : m_board->Tracks() )
if( auto arc = dyn_cast<ARC*>( item ) )
{
if( track->Type() == PCB_VIA_T )
{
vias.push_back( static_cast<VIA*>( track ) );
width = arc->GetWidth();
p0 = arc->GetStart();
}
else if( auto trk = dyn_cast<TRACK*>( item ) )
{
width = trk->GetWidth();
p0 = ( trk->GetStart() + trk->GetEnd() ) / 2;
}
test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH, item );
for( auto via : vias )
bool fail_min = false, fail_max = false;
int constraintWidth;
if( constraint.Value().HasMin() && width < constraint.Value().Min() )
{
if( checkVia( via ) )
break;
fail_min = true;
constraintWidth = constraint.Value().Min();
}
if( constraint.Value().HasMax() && width > constraint.Value().Max() )
{
fail_max = true;
constraintWidth = constraint.Value().Max();
}
if( fail_min || fail_max )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACK_WIDTH );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s; width %s, constraint %s %s)" ),
constraint.GetParentRule()->GetName(),
MessageTextFromValue( userUnits(), width, true ),
fail_min ? _( "minimum" ) : _( "maximum" ),
MessageTextFromValue( userUnits(), constraintWidth, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, p0 );
if( isErrorLimitExceeded( DRCE_TRACK_WIDTH ) )
return false;
}
return true;
};
forEachGeometryItem( { PCB_TRACE_T, PCB_ARC_T }, LSET::AllCuMask(), checkTrackWidth );
reportRuleStatistics();
return true;
}
bool test::DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( D_PAD* aPad )
std::set<test::DRC_CONSTRAINT_TYPE_T>
test::DRC_TEST_PROVIDER_TRACK_WIDTH::GetMatchingConstraintIds() const
{
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( holeSize == 0 )
return true;
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE, aPad );
auto minHole = rule->GetConstraint().GetValue().Min();
accountCheck( rule );
if( holeSize < minHole )
{
wxString msg;
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
msg.Printf( drcItem->GetErrorText() + _( " (%s; actual %s)" ),
MessageTextFromValue( userUnits(), minHole, true ),
MessageTextFromValue( userUnits(), holeSize, true ) );
drcItem->SetViolatingRule( rule );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( aPad );
ReportWithMarker( drcItem, aPad->GetPosition() );
return isErrorLimitExceeded( DRCE_TOO_SMALL_DRILL );
}
return false;
}
bool test::DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( VIA* via )
{
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE, via );
auto minHole = rule->GetConstraint().GetValue().Min();
accountCheck( rule );
if( via->GetDrillValue() < minHole )
{
wxString msg;
int errorCode = via->GetViaType() == VIATYPE::MICROVIA ? DRCE_TOO_SMALL_MICROVIA_DRILL :
DRCE_TOO_SMALL_DRILL;
DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
msg.Printf( drcItem->GetErrorText() + _( " (%s; actual %s)" ),
MessageTextFromValue( userUnits(), minHole, true ),
MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) );
drcItem->SetViolatingRule( rule );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( via );
ReportWithMarker( drcItem, via->GetPosition() );
return isErrorLimitExceeded( errorCode );
}
return false;
}
std::set<test::DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_HOLE_SIZE::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE };
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_HOLE_SIZE> dummy;
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_TRACK_WIDTH> dummy;
}

View File

@ -0,0 +1,154 @@
/*
* 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 <class_board.h>
#include <class_track.h>
#include <common.h>
#include <drc_proto/drc_engine.h>
#include <drc_proto/drc_item.h>
#include <drc_proto/drc_rule.h>
#include <drc_proto/drc_test_provider.h>
/*
Via diameter test.
Errors generated:
- DRCE_TOO_SMALL_VIA
- DRCE_TOO_SMALL_MICROVIA
*/
namespace test
{
class DRC_TEST_PROVIDER_VIA_DIAMETER : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_VIA_DIAMETER()
{
}
virtual ~DRC_TEST_PROVIDER_VIA_DIAMETER()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "diameter";
};
virtual const wxString GetDescription() const override
{
return "Tests via diameters";
}
virtual std::set<test::DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
};
}; // namespace test
bool test::DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
{
if( !m_drcEngine->HasCorrectRulesForId(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) )
{
ReportAux( "No diameter constraints found. Skipping check." );
return false;
}
ReportStage( ( "Testing via diameters" ), 0, 2 );
auto checkViaDiameter = [&]( BOARD_ITEM* item ) -> bool {
auto via = dyn_cast<VIA*>( item );
// fixme: move to pad stack check?
if( !via )
return true;
test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems(
test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER, item );
bool fail_min = false, fail_max = false;
int constraintDiameter;
int diameter = via->GetWidth();
if( constraint.Value().HasMin() && diameter < constraint.Value().Min() )
{
fail_min = true;
constraintDiameter = constraint.Value().Min();
}
if( constraint.Value().HasMax() && diameter > constraint.Value().Max() )
{
fail_max = true;
constraintDiameter = constraint.Value().Max();
}
if( fail_min || fail_max )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_VIA_DIAMETER );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s; diameter %s, constraint %s %s)" ),
constraint.GetParentRule()->GetName(),
MessageTextFromValue( userUnits(), diameter, true ),
fail_min ? _( "minimum" ) : _( "maximum" ),
MessageTextFromValue( userUnits(), constraintDiameter, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, via->GetPosition() );
if( isErrorLimitExceeded( DRCE_VIA_DIAMETER ) )
return false;
}
return true;
};
forEachGeometryItem( { PCB_VIA_T }, LSET::AllCuMask(), checkViaDiameter );
reportRuleStatistics();
return true;
}
std::set<test::DRC_CONSTRAINT_TYPE_T>
test::DRC_TEST_PROVIDER_VIA_DIAMETER::GetMatchingConstraintIds() const
{
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER };
}
namespace detail
{
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_VIA_DIAMETER> dummy;
}