Move connection width testing to rule system.
Also copies connection width progress reporting architecture over to the sliver checker.
This commit is contained in:
parent
927bc8141b
commit
0304ad4494
|
@ -4,6 +4,7 @@ board_edge
|
|||
buried_via
|
||||
clearance
|
||||
condition
|
||||
connection_width
|
||||
constraint
|
||||
courtyard_clearance
|
||||
diff_pair_gap
|
||||
|
|
|
@ -186,7 +186,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
|
|||
m_DRCSeverities[ DRCE_LIB_FOOTPRINT_ISSUES ] = RPT_SEVERITY_WARNING;
|
||||
m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = RPT_SEVERITY_WARNING;
|
||||
|
||||
m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = RPT_SEVERITY_WARNING;
|
||||
// TODO: Change to warning after testing
|
||||
m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = RPT_SEVERITY_IGNORE;
|
||||
|
||||
m_MaxError = ARC_HIGH_DEF;
|
||||
m_ZoneKeepExternalFillets = false;
|
||||
|
|
|
@ -577,7 +577,8 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
|| rcItem->GetErrorCode() == DRCE_VIA_DIAMETER
|
||||
|| rcItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
|
||||
|| rcItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
|
||||
|| rcItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE )
|
||||
|| rcItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
|
||||
|| rcItem->GetErrorCode() == DRCE_CONNECTION_WIDTH )
|
||||
{
|
||||
menu.Append( 3, _( "Run constraints resolution tool..." ) );
|
||||
}
|
||||
|
|
|
@ -368,6 +368,7 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
|
|||
tokens = wxT( "annular_width|"
|
||||
"assertion|"
|
||||
"clearance|"
|
||||
"connection_width|"
|
||||
"courtyard_clearance|"
|
||||
"diff_pair_gap|"
|
||||
"diff_pair_uncoupled|"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
* annular\_width
|
||||
* clearance
|
||||
* connection\_width
|
||||
* courtyard_clearance
|
||||
* diff\_pair\_gap
|
||||
* diff\_pair\_uncoupled
|
||||
|
@ -272,3 +273,10 @@ For the latter use a `(layer "layer_name")` clause in the rule.
|
|||
(layer "F.Courtyard")
|
||||
(constraint physical_clearance (min 3mm))
|
||||
(condition "B.Layer == 'Edge.Cuts'"))
|
||||
|
||||
|
||||
# Check current-carrying capacity
|
||||
(rule high-current
|
||||
(constraint track_width (min 1.0mm))
|
||||
(constraint connection_width (min 0.8mm))
|
||||
(condition "A.NetClass == 'Power'"))
|
|
@ -25,6 +25,7 @@ _HKI( "### Top-level Clauses\n"
|
|||
"\n"
|
||||
" * annular\\_width\n"
|
||||
" * clearance\n"
|
||||
" * connection\\_width\n"
|
||||
" * courtyard_clearance\n"
|
||||
" * diff\\_pair\\_gap\n"
|
||||
" * diff\\_pair\\_uncoupled\n"
|
||||
|
@ -273,4 +274,10 @@ _HKI( "### Top-level Clauses\n"
|
|||
" (layer \"F.Courtyard\")\n"
|
||||
" (constraint physical_clearance (min 3mm))\n"
|
||||
" (condition \"B.Layer == 'Edge.Cuts'\"))\n"
|
||||
"" );
|
||||
"\n"
|
||||
"\n"
|
||||
" # Check current-carrying capacity\n"
|
||||
" (rule high-current\n"
|
||||
" (constraint track_width (min 1.0mm))\n"
|
||||
" (constraint connection_width (min 0.8mm))\n"
|
||||
" (condition \"A.NetClass == 'Power'\"))" );
|
||||
|
|
|
@ -152,6 +152,10 @@ void DRC_ENGINE::loadImplicitRules()
|
|||
widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
|
||||
rule->AddConstraint( widthConstraint );
|
||||
|
||||
DRC_CONSTRAINT connectionConstraint( CONNECTION_WIDTH_CONSTRAINT );
|
||||
connectionConstraint.Value().SetMin( bds.m_MinConn );
|
||||
rule->AddConstraint( connectionConstraint );
|
||||
|
||||
DRC_CONSTRAINT drillConstraint( HOLE_SIZE_CONSTRAINT );
|
||||
drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
|
||||
rule->AddConstraint( drillConstraint );
|
||||
|
@ -890,6 +894,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
case TEXT_THICKNESS_CONSTRAINT:
|
||||
case DIFF_PAIR_GAP_CONSTRAINT:
|
||||
case LENGTH_CONSTRAINT:
|
||||
case CONNECTION_WIDTH_CONSTRAINT:
|
||||
{
|
||||
if( aReporter )
|
||||
{
|
||||
|
@ -958,12 +963,8 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
break;
|
||||
|
||||
case TEXT_HEIGHT_CONSTRAINT:
|
||||
REPORT( wxString::Format( _( "Checking %s: min %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
min ) )
|
||||
break;
|
||||
|
||||
case TEXT_THICKNESS_CONSTRAINT:
|
||||
case CONNECTION_WIDTH_CONSTRAINT:
|
||||
REPORT( wxString::Format( _( "Checking %s: min %s." ),
|
||||
EscapeHTML( c->constraint.GetName() ),
|
||||
min ) )
|
||||
|
@ -1487,10 +1488,15 @@ bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
|
|||
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
|
||||
PCB_LAYER_ID aMarkerLayer )
|
||||
{
|
||||
static std::mutex globalLock;
|
||||
|
||||
m_errorLimits[ aItem->GetErrorCode() ] -= 1;
|
||||
|
||||
if( m_violationHandler )
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( globalLock );
|
||||
m_violationHandler( aItem, aPos, aMarkerLayer );
|
||||
}
|
||||
|
||||
if( m_reporter )
|
||||
{
|
||||
|
@ -1605,6 +1611,20 @@ bool DRC_ENGINE::QueryWorstConstraint( DRC_CONSTRAINT_T aConstraintId, DRC_CONST
|
|||
}
|
||||
|
||||
|
||||
std::set<int> DRC_ENGINE::QueryDistinctConstraints( DRC_CONSTRAINT_T aConstraintId )
|
||||
{
|
||||
std::set<int> distinctMinimums;
|
||||
|
||||
if( m_constraintMap.count( aConstraintId ) )
|
||||
{
|
||||
for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
|
||||
distinctMinimums.emplace( c->constraint.GetValue().Min() );
|
||||
}
|
||||
|
||||
return distinctMinimums;
|
||||
}
|
||||
|
||||
|
||||
// fixme: move two functions below to pcbcommon?
|
||||
int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
|
||||
wxString& aBaseDpName )
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 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
|
||||
|
@ -176,6 +176,7 @@ public:
|
|||
bool IsCancelled() const;
|
||||
|
||||
bool QueryWorstConstraint( DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT& aConstraint );
|
||||
std::set<int> QueryDistinctConstraints( DRC_CONSTRAINT_T aConstraintId );
|
||||
|
||||
std::vector<DRC_TEST_PROVIDER*> GetTestProviders() const { return m_testProviders; };
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@ enum DRC_CONSTRAINT_T
|
|||
VIA_COUNT_CONSTRAINT,
|
||||
PHYSICAL_CLEARANCE_CONSTRAINT,
|
||||
PHYSICAL_HOLE_CLEARANCE_CONSTRAINT,
|
||||
ASSERTION_CONSTRAINT
|
||||
ASSERTION_CONSTRAINT,
|
||||
CONNECTION_WIDTH_CONSTRAINT
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -313,6 +313,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
|||
case T_text_height: c.m_Type = TEXT_HEIGHT_CONSTRAINT; break;
|
||||
case T_text_thickness: c.m_Type = TEXT_THICKNESS_CONSTRAINT; break;
|
||||
case T_track_width: c.m_Type = TRACK_WIDTH_CONSTRAINT; break;
|
||||
case T_connection_width: c.m_Type = CONNECTION_WIDTH_CONSTRAINT; break;
|
||||
case T_annular_width: c.m_Type = ANNULAR_WIDTH_CONSTRAINT; break;
|
||||
case T_via_diameter: c.m_Type = VIA_DIAMETER_CONSTRAINT; break;
|
||||
case T_zone_connection: c.m_Type = ZONE_CONNECTION_CONSTRAINT; break;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <drc/drc_rtree.h>
|
||||
#include <drc/drc_rule_condition.h>
|
||||
#include <footprint.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
|
@ -569,19 +570,24 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
|||
if( !reportPhase( _( "Checking nets for minimum connection width..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
LSET copperLayerSet = m_drcEngine->GetBoard()->GetEnabledLayers() & LSET::AllCuMask();
|
||||
LSEQ copperLayers = copperLayerSet.Seq();
|
||||
|
||||
BOARD* board = m_drcEngine->GetBoard();
|
||||
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
|
||||
LSET copperLayerSet = m_drcEngine->GetBoard()->GetEnabledLayers() & LSET::AllCuMask();
|
||||
LSEQ copperLayers = copperLayerSet.Seq();
|
||||
BOARD* board = m_drcEngine->GetBoard();
|
||||
DRC_RTREE* tree = board->m_CopperItemRTreeCache.get();
|
||||
std::set<int> distinctMinWidths
|
||||
= m_drcEngine->QueryDistinctConstraints( CONNECTION_WIDTH_CONSTRAINT );
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return false; // DRC cancelled
|
||||
|
||||
std::map<PCB_LAYER_ID, std::map<int, std::set<BOARD_ITEM*>>> net_items;
|
||||
std::atomic<size_t> done( 1 );
|
||||
struct ITEMS_POLY
|
||||
{
|
||||
std::set<BOARD_ITEM*> items;
|
||||
SHAPE_POLY_SET poly;
|
||||
};
|
||||
|
||||
DRC_RTREE* tree = board->m_CopperItemRTreeCache.get();
|
||||
std::map< std::pair<int, PCB_LAYER_ID>, ITEMS_POLY > dataset;
|
||||
std::atomic<size_t> done( 1 );
|
||||
|
||||
auto calc_effort =
|
||||
[&]( const std::set<BOARD_ITEM*>& items, PCB_LAYER_ID aLayer ) -> size_t
|
||||
|
@ -604,28 +610,38 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
|||
return effort;
|
||||
};
|
||||
|
||||
auto min_checker =
|
||||
[&](const std::set<BOARD_ITEM*>& aItems, PCB_LAYER_ID aLayer ) -> size_t
|
||||
auto build_netlayer_polys =
|
||||
[&]( int aNetcode, const PCB_LAYER_ID aLayer ) -> size_t
|
||||
{
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
SHAPE_POLY_SET poly;
|
||||
ITEMS_POLY& data = dataset[ { aNetcode, aLayer } ];
|
||||
|
||||
for( BOARD_ITEM* item : aItems )
|
||||
for( BOARD_ITEM* item : data.items )
|
||||
{
|
||||
item->TransformShapeWithClearanceToPolygon( poly, aLayer, 0, ARC_HIGH_DEF,
|
||||
ERROR_OUTSIDE );
|
||||
item->TransformShapeWithClearanceToPolygon( data.poly, aLayer, 0,
|
||||
ARC_HIGH_DEF, ERROR_OUTSIDE );
|
||||
}
|
||||
|
||||
poly.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
data.poly.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
int minimum_width = bds.m_MinConn;
|
||||
POLYGON_TEST test( minimum_width );
|
||||
done.fetch_add( calc_effort( data.items, aLayer ) );
|
||||
|
||||
for( int ii = 0; ii < poly.OutlineCount(); ++ii )
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto min_checker =
|
||||
[&]( const ITEMS_POLY& aDataset, const PCB_LAYER_ID aLayer, int aMinWidth ) -> size_t
|
||||
{
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
POLYGON_TEST test( aMinWidth );
|
||||
|
||||
for( int ii = 0; ii < aDataset.poly.OutlineCount(); ++ii )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& chain = poly.COutline( ii );
|
||||
const SHAPE_LINE_CHAIN& chain = aDataset.poly.COutline( ii );
|
||||
|
||||
test.FindPairs( chain );
|
||||
auto& ret = test.GetVertices();
|
||||
|
@ -635,42 +651,57 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
|||
SEG span( chain.CPoint( pt.first ), chain.CPoint( pt.second ) );
|
||||
VECTOR2I location = ( span.A + span.B ) / 2;
|
||||
int dist = ( span.A - span.B ).EuclideanNorm();
|
||||
std::set<BOARD_ITEM*> items = tree->GetObjectsAt( location, aLayer,
|
||||
minimum_width );
|
||||
std::set<BOARD_ITEM*> nearbyItems = tree->GetObjectsAt( location, aLayer,
|
||||
aMinWidth );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CONNECTION_WIDTH );
|
||||
wxString msg;
|
||||
std::vector<BOARD_ITEM*> items;
|
||||
|
||||
msg.Printf( _( "Minimum connection width %s; actual %s" ),
|
||||
MessageTextFromValue( userUnits(), minimum_width ),
|
||||
MessageTextFromValue( userUnits(), dist ) );
|
||||
|
||||
drce->SetErrorMessage( msg + wxS( " " ) + layerDesc( aLayer ) );
|
||||
|
||||
for( BOARD_ITEM* item : items )
|
||||
for( BOARD_ITEM* item : nearbyItems )
|
||||
{
|
||||
if( item->HitTest( location, minimum_width ) )
|
||||
drce->AddItem( item );
|
||||
if( item->HitTest( location, aMinWidth ) )
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
if( !drce->GetIDs().empty() )
|
||||
reportViolation( drce, location, aLayer );
|
||||
if( !items.empty() )
|
||||
{
|
||||
DRC_CONSTRAINT c = m_drcEngine->EvalRules( CONNECTION_WIDTH_CONSTRAINT,
|
||||
items[0],
|
||||
items.size() > 1 ? items[1]
|
||||
: nullptr,
|
||||
aLayer );
|
||||
|
||||
if( c.Value().Min() == aMinWidth )
|
||||
{
|
||||
auto drce = DRC_ITEM::Create( DRCE_CONNECTION_WIDTH );
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( _( "Minimum connection width %s; actual %s" ),
|
||||
MessageTextFromValue( userUnits(), aMinWidth ),
|
||||
MessageTextFromValue( userUnits(), dist ) );
|
||||
|
||||
drce->SetErrorMessage( msg + wxS( " " ) + layerDesc( aLayer ) );
|
||||
drce->SetViolatingRule( c.GetParentRule() );
|
||||
|
||||
for( BOARD_ITEM* item : items )
|
||||
drce->AddItem( item );
|
||||
|
||||
reportViolation( drce, location, aLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done.fetch_add( calc_effort( aItems, aLayer ) );
|
||||
done.fetch_add( calc_effort( aDataset.items, aLayer ) );
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
for( PCB_LAYER_ID layer : copperLayers )
|
||||
{
|
||||
auto& layer_items = net_items[layer];
|
||||
|
||||
for( ZONE* zone : board->m_DRCCopperZones )
|
||||
{
|
||||
if( !zone->GetIsRuleArea() && zone->IsOnLayer( layer ) )
|
||||
layer_items[zone->GetNetCode()].emplace( zone );
|
||||
dataset[ { zone->GetNetCode(), layer } ].items.emplace( zone );
|
||||
}
|
||||
|
||||
for( PCB_TRACK* track : board->Tracks() )
|
||||
|
@ -678,11 +709,11 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
|||
if( PCB_VIA* via = dynamic_cast<PCB_VIA*>( track ) )
|
||||
{
|
||||
if( via->FlashLayer( static_cast<int>( layer ) ) )
|
||||
layer_items[via->GetNetCode()].emplace( via );
|
||||
dataset[ { via->GetNetCode(), layer } ].items.emplace( via );
|
||||
}
|
||||
else if( track->IsOnLayer( layer ) )
|
||||
{
|
||||
layer_items[track->GetNetCode()].emplace( track );
|
||||
dataset[ { track->GetNetCode(), layer } ].items.emplace( track );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -691,29 +722,50 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
|||
for( PAD* pad : fp->Pads() )
|
||||
{
|
||||
if( pad->FlashLayer( static_cast<int>( layer ) ) )
|
||||
layer_items[pad->GetNetCode()].emplace( pad );
|
||||
dataset[ { pad->GetNetCode(), layer } ].items.emplace( pad );
|
||||
}
|
||||
|
||||
// Footprint zones are also in the m_DRCCopperZones cache
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
std::vector<std::future<size_t>> returns;
|
||||
size_t return_count = 0;
|
||||
size_t total_effort = 0;
|
||||
size_t total_effort = 0;
|
||||
|
||||
for( auto& layer_items : net_items )
|
||||
return_count += layer_items.second.size();
|
||||
for( const std::pair<const std::pair<int, PCB_LAYER_ID>, ITEMS_POLY>& netLayer : dataset )
|
||||
total_effort += calc_effort( netLayer.second.items, netLayer.first.second );
|
||||
|
||||
returns.reserve( return_count );
|
||||
total_effort += total_effort * distinctMinWidths.size();
|
||||
|
||||
for( auto& layer_items : net_items )
|
||||
returns.reserve( dataset.size() );
|
||||
|
||||
for( const std::pair<const std::pair<int, PCB_LAYER_ID>, ITEMS_POLY>& netLayer : dataset )
|
||||
{
|
||||
for( const auto& items : layer_items.second )
|
||||
returns.emplace_back( tp.submit( build_netlayer_polys, netLayer.first.first,
|
||||
netLayer.first.second ) );
|
||||
}
|
||||
|
||||
for( std::future<size_t>& retval : returns )
|
||||
{
|
||||
std::future_status status;
|
||||
|
||||
do
|
||||
{
|
||||
returns.emplace_back( tp.submit( min_checker, items.second, layer_items.first ) );
|
||||
total_effort += calc_effort( items.second, layer_items.first );
|
||||
m_drcEngine->ReportProgress( static_cast<double>( done ) / total_effort );
|
||||
status = retval.wait_for( std::chrono::milliseconds( 100 ) );
|
||||
} while( status != std::future_status::ready );
|
||||
}
|
||||
|
||||
returns.clear();
|
||||
returns.reserve( dataset.size() * distinctMinWidths.size() );
|
||||
|
||||
for( const std::pair<const std::pair<int, PCB_LAYER_ID>, ITEMS_POLY>& netLayer : dataset )
|
||||
{
|
||||
for( int minWidth : distinctMinWidths )
|
||||
{
|
||||
returns.emplace_back( tp.submit( min_checker, netLayer.second, netLayer.first.second,
|
||||
minWidth ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,91 +89,186 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
|
|||
int testLength = widthTolerance / ( 2 * sin( DEG2RAD( angleTolerance / 2 ) ) );
|
||||
LSET copperLayerSet = m_drcEngine->GetBoard()->GetEnabledLayers() & LSET::AllCuMask();
|
||||
LSEQ copperLayers = copperLayerSet.Seq();
|
||||
int layerCount = copperLayers.size();
|
||||
size_t layerCount = copperLayers.size();
|
||||
|
||||
// Report progress on board zones only. Everything else is in the noise.
|
||||
int zoneLayerCount = 0;
|
||||
std::atomic<size_t> done( 1 );
|
||||
|
||||
for( PCB_LAYER_ID layer : copperLayers )
|
||||
{
|
||||
for( ZONE* zone : m_drcEngine->GetBoard()->Zones() )
|
||||
{
|
||||
if( !zone->GetIsRuleArea() && zone->IsOnLayer( layer ) )
|
||||
zoneLayerCount++;
|
||||
}
|
||||
}
|
||||
|
||||
PROGRESS_REPORTER* reporter = m_drcEngine->GetProgressReporter();
|
||||
|
||||
if( reporter && reporter->IsCancelled() )
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return false; // DRC cancelled
|
||||
|
||||
std::vector<SHAPE_POLY_SET> layerPolys( layerCount );
|
||||
std::vector<size_t> layerEfforts( layerCount );
|
||||
size_t total_effort = 0;
|
||||
std::atomic<size_t> done( 1 );
|
||||
|
||||
auto calc_effort =
|
||||
[&]( BOARD_ITEM* item, PCB_LAYER_ID aLayer ) -> size_t
|
||||
{
|
||||
if( item->Type() == PCB_ZONE_T )
|
||||
{
|
||||
ZONE* zone = static_cast<ZONE*>( item );
|
||||
return zone->GetFilledPolysList( aLayer )->FullPointCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
|
||||
auto poly_builder =
|
||||
[&]( size_t ii ) -> size_t
|
||||
{
|
||||
PCB_LAYER_ID layer = copperLayers[ii];
|
||||
SHAPE_POLY_SET& poly = layerPolys[ii];
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
SHAPE_POLY_SET fill;
|
||||
|
||||
forEachGeometryItem( s_allBasicItems, LSET().set( layer ),
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
if( dynamic_cast<ZONE*>( item) )
|
||||
{
|
||||
ZONE* zone = static_cast<ZONE*>( item );
|
||||
|
||||
if( !zone->GetIsRuleArea() )
|
||||
{
|
||||
fill = zone->GetFill( layer )->CloneDropTriangulation();
|
||||
fill.Unfracture( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
for( int jj = 0; jj < fill.OutlineCount(); ++jj )
|
||||
poly.AddOutline( fill.Outline( jj ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->TransformShapeWithClearanceToPolygon( poly, layer, 0,
|
||||
ARC_LOW_DEF,
|
||||
ERROR_OUTSIDE );
|
||||
}
|
||||
|
||||
done.fetch_add( calc_effort( item, layer ) );
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
} );
|
||||
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
poly.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// Sharpen corners
|
||||
poly.Deflate( widthTolerance / 2, ARC_LOW_DEF,
|
||||
SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto sliver_checker =
|
||||
[&]( int aItem ) -> size_t
|
||||
[&]( size_t ii ) -> size_t
|
||||
{
|
||||
PCB_LAYER_ID layer = copperLayers[ii];
|
||||
SHAPE_POLY_SET& poly = layerPolys[ii];
|
||||
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_COPPER_SLIVER ) )
|
||||
return 0;
|
||||
|
||||
// Frequently, in filled areas, some points of the polygons are very near (dist is
|
||||
// only a few internal units, like 2 or 3 units).
|
||||
// We skip very small vertices: one cannot really compute a valid orientation of
|
||||
// such a vertex
|
||||
// So skip points near than min_len (in internal units).
|
||||
const int min_len = 3;
|
||||
|
||||
for( int jj = 0; jj < poly.OutlineCount(); ++jj )
|
||||
{
|
||||
PCB_LAYER_ID layer = copperLayers[aItem];
|
||||
SHAPE_POLY_SET& poly = layerPolys[aItem];
|
||||
const std::vector<VECTOR2I>& pts = poly.Outline( jj ).CPoints();
|
||||
int ptCount = pts.size();
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
for( int kk = 0; kk < ptCount; ++kk )
|
||||
{
|
||||
VECTOR2I pt = pts[ kk ];
|
||||
VECTOR2I ptPrior = pts[ ( ptCount + kk - 1 ) % ptCount ];
|
||||
VECTOR2I vPrior = ( ptPrior - pt );
|
||||
|
||||
SHAPE_POLY_SET fill;
|
||||
if( std::abs( vPrior.x ) < min_len && std::abs( vPrior.y ) < min_len && ptCount > 5)
|
||||
{
|
||||
ptPrior = pts[ ( ptCount + kk - 2 ) % ptCount ];
|
||||
vPrior = ( ptPrior - pt );
|
||||
}
|
||||
|
||||
forEachGeometryItem( s_allBasicItems, LSET().set( layer ),
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
if( dynamic_cast<ZONE*>( item) )
|
||||
{
|
||||
ZONE* zone = static_cast<ZONE*>( item );
|
||||
VECTOR2I ptAfter = pts[ ( kk + 1 ) % ptCount ];
|
||||
VECTOR2I vAfter = ( ptAfter - pt );
|
||||
|
||||
if( !zone->GetIsRuleArea() )
|
||||
{
|
||||
fill = zone->GetFill( layer )->CloneDropTriangulation();
|
||||
fill.Unfracture( SHAPE_POLY_SET::PM_FAST );
|
||||
if( std::abs( vAfter.x ) < min_len && std::abs( vAfter.y ) < min_len && ptCount > 5 )
|
||||
{
|
||||
ptAfter = pts[ ( kk + 2 ) % ptCount ];
|
||||
vAfter = ( ptAfter - pt );
|
||||
}
|
||||
|
||||
for( int jj = 0; jj < fill.OutlineCount(); ++jj )
|
||||
poly.AddOutline( fill.Outline( jj ) );
|
||||
VECTOR2I vIncluded = vPrior.Resize( testLength ) - vAfter.Resize( testLength );
|
||||
|
||||
// Report progress on board zones only. Everything
|
||||
// else is in the noise.
|
||||
done.fetch_add( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->TransformShapeWithClearanceToPolygon( poly, layer, 0,
|
||||
ARC_LOW_DEF,
|
||||
ERROR_OUTSIDE );
|
||||
}
|
||||
if( vIncluded.SquaredEuclideanNorm() < SEG::Square( widthTolerance ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_COPPER_SLIVER );
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + layerDesc( layer ) );
|
||||
reportViolation( drce, pt, layer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return false;
|
||||
done.fetch_add( layerEfforts[ layer ] );
|
||||
|
||||
return true;
|
||||
} );
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return 0;
|
||||
for( size_t ii = 0; ii < layerCount; ++ii )
|
||||
{
|
||||
PCB_LAYER_ID layer = copperLayers[ii];
|
||||
|
||||
poly.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
forEachGeometryItem( s_allBasicItems, LSET().set( layer ),
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
layerEfforts[ layer ] += calc_effort( item, layer );
|
||||
return true;
|
||||
} );
|
||||
|
||||
// Sharpen corners
|
||||
poly.Deflate( widthTolerance / 2, ARC_LOW_DEF,
|
||||
SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
|
||||
total_effort += layerEfforts[ layer ];
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
total_effort *= 2; // Once for building polys; once for checking slivers
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
std::vector<std::future<size_t>> returns;
|
||||
|
||||
returns.reserve( copperLayers.size() );
|
||||
returns.reserve( layerCount );
|
||||
|
||||
for( size_t ii = 0; ii < copperLayers.size(); ++ii )
|
||||
for( size_t ii = 0; ii < layerCount; ++ii )
|
||||
returns.emplace_back( tp.submit( poly_builder, ii ) );
|
||||
|
||||
for( auto& retval : returns )
|
||||
{
|
||||
std::future_status status;
|
||||
|
||||
do
|
||||
{
|
||||
m_drcEngine->ReportProgress( static_cast<double>( done ) / total_effort );
|
||||
|
||||
status = retval.wait_for( std::chrono::milliseconds( 100 ) );
|
||||
} while( status != std::future_status::ready );
|
||||
}
|
||||
|
||||
returns.clear();
|
||||
returns.reserve( layerCount );
|
||||
|
||||
for( size_t ii = 0; ii < layerCount; ++ii )
|
||||
returns.emplace_back( tp.submit( sliver_checker, ii ) );
|
||||
|
||||
for( auto& retval : returns )
|
||||
|
@ -182,66 +277,12 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
|
|||
|
||||
do
|
||||
{
|
||||
m_drcEngine->ReportProgress( static_cast<double>( zoneLayerCount ) / done );
|
||||
m_drcEngine->ReportProgress( static_cast<double>( done ) / total_effort );
|
||||
|
||||
status = retval.wait_for( std::chrono::milliseconds( 100 ) );
|
||||
} while( status != std::future_status::ready );
|
||||
}
|
||||
|
||||
|
||||
for( int ii = 0; ii < layerCount; ++ii )
|
||||
{
|
||||
PCB_LAYER_ID layer = copperLayers[ii];
|
||||
SHAPE_POLY_SET& poly = layerPolys[ii];
|
||||
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_COPPER_SLIVER ) )
|
||||
continue;
|
||||
|
||||
// Frequently, in filled areas, some points of the polygons are very near (dist is only
|
||||
// a few internal units, like 2 or 3 units.
|
||||
// We skip very small vertices: one cannot really compute a valid orientation of
|
||||
// such a vertex
|
||||
// So skip points near than min_len (in internal units).
|
||||
const int min_len = 3;
|
||||
|
||||
for( int jj = 0; jj < poly.OutlineCount(); ++jj )
|
||||
{
|
||||
const std::vector<VECTOR2I>& pts = poly.Outline( jj ).CPoints();
|
||||
int ptCount = pts.size();
|
||||
|
||||
for( int kk = 0; kk < ptCount; ++kk )
|
||||
{
|
||||
VECTOR2I pt = pts[ kk ];
|
||||
VECTOR2I ptPrior = pts[ ( ptCount + kk - 1 ) % ptCount ];
|
||||
VECTOR2I vPrior = ( ptPrior - pt );
|
||||
|
||||
if( std::abs( vPrior.x ) < min_len && std::abs( vPrior.y ) < min_len && ptCount > 5)
|
||||
{
|
||||
ptPrior = pts[ ( ptCount + kk - 2 ) % ptCount ];
|
||||
vPrior = ( ptPrior - pt );
|
||||
}
|
||||
|
||||
VECTOR2I ptAfter = pts[ ( kk + 1 ) % ptCount ];
|
||||
VECTOR2I vAfter = ( ptAfter - pt );
|
||||
|
||||
if( std::abs( vAfter.x ) < min_len && std::abs( vAfter.y ) < min_len && ptCount > 5 )
|
||||
{
|
||||
ptAfter = pts[ ( kk + 2 ) % ptCount ];
|
||||
vAfter = ( ptAfter - pt );
|
||||
}
|
||||
|
||||
VECTOR2I vIncluded = vPrior.Resize( testLength ) - vAfter.Resize( testLength );
|
||||
|
||||
if( vIncluded.SquaredEuclideanNorm() < SEG::Square( widthTolerance ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_COPPER_SLIVER );
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + layerDesc( layer ) );
|
||||
reportViolation( drce, pt, layer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -317,6 +317,20 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
|
|||
reportMax( r->GetUnits(), constraint ) ) );
|
||||
break;
|
||||
|
||||
case DRCE_CONNECTION_WIDTH:
|
||||
r = m_inspectClearanceDialog->AddPage( _( "Connection Width" ) );
|
||||
reportHeader( _( "Connection width resolution for:" ), a, b, r );
|
||||
|
||||
if( compileError )
|
||||
reportCompileError( r );
|
||||
|
||||
constraint = drcEngine.EvalRules( CONNECTION_WIDTH_CONSTRAINT, a, b, layer, r );
|
||||
|
||||
r->Report( "" );
|
||||
r->Report( wxString::Format( _( "Resolved min connection width constraint: %s." ),
|
||||
reportMin( r->GetUnits(), constraint ) ) );
|
||||
break;
|
||||
|
||||
case DRCE_VIA_DIAMETER:
|
||||
r = m_inspectClearanceDialog->AddPage( _( "Via Diameter" ) );
|
||||
reportHeader( _( "Via diameter resolution for:" ), a, r );
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
(version 1)
|
||||
(rule high_current_netclass
|
||||
(constraint connection_width (min 0.16mm))
|
||||
(condition "A.NetClass == 'High_current'"))
|
||||
(rule high_current_area
|
||||
(constraint connection_width (min 0.16mm))
|
||||
(condition "A.insideArea('high_current')"))
|
|
@ -0,0 +1,141 @@
|
|||
(kicad_pcb (version 20220621) (generator pcbnew)
|
||||
|
||||
(general
|
||||
(thickness 1.6)
|
||||
)
|
||||
|
||||
(paper "A4")
|
||||
(layers
|
||||
(0 "F.Cu" signal)
|
||||
(31 "B.Cu" signal)
|
||||
(32 "B.Adhes" user "B.Adhesive")
|
||||
(33 "F.Adhes" user "F.Adhesive")
|
||||
(34 "B.Paste" user)
|
||||
(35 "F.Paste" user)
|
||||
(36 "B.SilkS" user "B.Silkscreen")
|
||||
(37 "F.SilkS" user "F.Silkscreen")
|
||||
(38 "B.Mask" user)
|
||||
(39 "F.Mask" user)
|
||||
(40 "Dwgs.User" user "User.Drawings")
|
||||
(41 "Cmts.User" user "User.Comments")
|
||||
(42 "Eco1.User" user "User.Eco1")
|
||||
(43 "Eco2.User" user "User.Eco2")
|
||||
(44 "Edge.Cuts" user)
|
||||
(45 "Margin" user)
|
||||
(46 "B.CrtYd" user "B.Courtyard")
|
||||
(47 "F.CrtYd" user "F.Courtyard")
|
||||
(48 "B.Fab" user)
|
||||
(49 "F.Fab" user)
|
||||
(50 "User.1" user)
|
||||
(51 "User.2" user)
|
||||
(52 "User.3" user)
|
||||
(53 "User.4" user)
|
||||
(54 "User.5" user)
|
||||
(55 "User.6" user)
|
||||
(56 "User.7" user)
|
||||
(57 "User.8" user)
|
||||
(58 "User.9" user)
|
||||
)
|
||||
|
||||
(setup
|
||||
(stackup
|
||||
(layer "F.SilkS" (type "Top Silk Screen"))
|
||||
(layer "F.Paste" (type "Top Solder Paste"))
|
||||
(layer "F.Mask" (type "Top Solder Mask") (thickness 0.01))
|
||||
(layer "F.Cu" (type "copper") (thickness 0.035))
|
||||
(layer "dielectric 1" (type "core") (thickness 1.51) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02))
|
||||
(layer "B.Cu" (type "copper") (thickness 0.035))
|
||||
(layer "B.Mask" (type "Bottom Solder Mask") (thickness 0.01))
|
||||
(layer "B.Paste" (type "Bottom Solder Paste"))
|
||||
(layer "B.SilkS" (type "Bottom Silk Screen"))
|
||||
(copper_finish "None")
|
||||
(dielectric_constraints no)
|
||||
)
|
||||
(pad_to_mask_clearance 0)
|
||||
(pcbplotparams
|
||||
(layerselection 0x00010fc_ffffffff)
|
||||
(plot_on_all_layers_selection 0x0000000_00000000)
|
||||
(disableapertmacros false)
|
||||
(usegerberextensions false)
|
||||
(usegerberattributes true)
|
||||
(usegerberadvancedattributes true)
|
||||
(creategerberjobfile true)
|
||||
(dashed_line_dash_ratio 12.000000)
|
||||
(dashed_line_gap_ratio 3.000000)
|
||||
(svgprecision 4)
|
||||
(plotframeref false)
|
||||
(viasonmask false)
|
||||
(mode 1)
|
||||
(useauxorigin false)
|
||||
(hpglpennumber 1)
|
||||
(hpglpenspeed 20)
|
||||
(hpglpendiameter 15.000000)
|
||||
(dxfpolygonmode true)
|
||||
(dxfimperialunits true)
|
||||
(dxfusepcbnewfont true)
|
||||
(psnegative false)
|
||||
(psa4output false)
|
||||
(plotreference true)
|
||||
(plotvalue true)
|
||||
(plotinvisibletext false)
|
||||
(sketchpadsonfab false)
|
||||
(subtractmaskfromsilk false)
|
||||
(outputformat 1)
|
||||
(mirror false)
|
||||
(drillshape 1)
|
||||
(scaleselection 1)
|
||||
(outputdirectory "")
|
||||
)
|
||||
)
|
||||
|
||||
(net 0 "")
|
||||
(net 1 "net_1")
|
||||
(net 2 "net_HC")
|
||||
(net 3 "net_2")
|
||||
(net 4 "net_3")
|
||||
|
||||
(gr_rect (start 103.8606 72.2884) (end 121.1326 81.661)
|
||||
(stroke (width 0.1) (type default)) (fill none) (layer "Edge.Cuts") (tstamp 0fed72c1-482a-43d6-acdf-98ed8c42a640))
|
||||
(gr_text "<<- no error" (at 117.2972 78.6892) (layer "F.Cu") (tstamp 1cdd5a64-dfb1-4eda-890c-555989cf19dc)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
(gr_text "<<- error" (at 117.2972 74.3458) (layer "F.Cu") (tstamp 24703be7-31d2-4cc0-807d-d1af2764829c)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
(gr_text "<<- error" (at 117.348 77.6732) (layer "F.Cu") (tstamp 48240202-f51e-42b8-906f-77194bafa596)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
(gr_text "High_current rule area:" (at 105.5116 76.327) (layer "F.Cu") (tstamp 5a232032-2a77-4c5c-a932-e0dd3c3db8c9)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
(gr_text "High_current netclass:" (at 106.1466 73.9394) (layer "F.Cu") (tstamp dd7b0757-fb61-40bd-84e1-598677c91625)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
(gr_text "<<- error" (at 117.094 79.4766) (layer "F.Cu") (tstamp e8c4ea88-467d-4e67-8480-f5f76e9ac3cf)
|
||||
(effects (font (size 0.2 0.2) (thickness 0.04) bold) (justify left bottom))
|
||||
)
|
||||
|
||||
(segment (start 112.5474 77.5716) (end 106.1212 77.5716) (width 0.25) (layer "F.Cu") (net 1) (tstamp 07a05dc9-fd0c-4bac-8cfe-73f661e50f58))
|
||||
(segment (start 112.7506 77.5716) (end 116.7384 77.5716) (width 0.25) (layer "F.Cu") (net 1) (tstamp b9c8bd88-3577-41fd-b8a3-f84c3ec54539))
|
||||
(segment (start 112.8014 74.2442) (end 116.7892 74.2442) (width 0.25) (layer "F.Cu") (net 2) (tstamp 5fd40a5e-8558-46fc-9321-fcda035db40b))
|
||||
(segment (start 112.5982 74.2442) (end 106.172 74.2442) (width 0.25) (layer "F.Cu") (net 2) (tstamp 7014ab67-9149-4546-9f6e-d99764e15f97))
|
||||
(segment (start 112.7252 78.5622) (end 116.713 78.5622) (width 0.25) (layer "F.Cu") (net 3) (tstamp 7c6d2fd8-65cf-4c16-ba39-e8c3cd86d13d))
|
||||
(segment (start 112.522 78.5622) (end 106.0958 78.5622) (width 0.25) (layer "F.Cu") (net 3) (tstamp a38443b8-d7a2-41c0-b6b5-5218a5114002))
|
||||
(segment (start 108.3818 79.3496) (end 112.5474 79.3496) (width 0.25) (layer "F.Cu") (net 4) (tstamp db40c24a-6762-409a-acaf-cbcefb8e7d40))
|
||||
(segment (start 112.776 79.3496) (end 116.4082 79.3496) (width 0.25) (layer "F.Cu") (net 4) (tstamp e8d7189c-1bf1-4f6c-abd7-bbbd5fd5f896))
|
||||
|
||||
(zone (net 0) (net_name "") (layer "F.Cu") (tstamp b0befc79-e815-4fdd-bd77-757b21ce75e2) (name "high_current") (hatch edge 0.508)
|
||||
(connect_pads (clearance 0))
|
||||
(min_thickness 0.254) (filled_areas_thickness no)
|
||||
(keepout (tracks allowed) (vias allowed) (pads allowed) (copperpour allowed) (footprints allowed))
|
||||
(fill (thermal_gap 0.508) (thermal_bridge_width 0.508) (island_removal_mode 2) (island_area_min 10))
|
||||
(polygon
|
||||
(pts
|
||||
(xy 118.5418 77.9526)
|
||||
(xy 105.4354 77.9526)
|
||||
(xy 105.4354 76.454)
|
||||
(xy 118.5418 76.454)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
|
@ -0,0 +1,262 @@
|
|||
{
|
||||
"board": {
|
||||
"3dviewports": [],
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"board_outline_line_width": 0.09999999999999999,
|
||||
"copper_line_width": 0.19999999999999998,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": false,
|
||||
"courtyard_line_width": 0.049999999999999996,
|
||||
"dimension_precision": 4,
|
||||
"dimension_units": 3,
|
||||
"dimensions": {
|
||||
"arrow_length": 1270000,
|
||||
"extension_offset": 500000,
|
||||
"keep_text_aligned": true,
|
||||
"suppress_zeroes": false,
|
||||
"text_position": 0,
|
||||
"units_format": 1
|
||||
},
|
||||
"fab_line_width": 0.09999999999999999,
|
||||
"fab_text_italic": false,
|
||||
"fab_text_size_h": 1.0,
|
||||
"fab_text_size_v": 1.0,
|
||||
"fab_text_thickness": 0.15,
|
||||
"fab_text_upright": false,
|
||||
"other_line_width": 0.15,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 0.762,
|
||||
"height": 1.524,
|
||||
"width": 1.524
|
||||
},
|
||||
"silk_line_width": 0.15,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.15,
|
||||
"silk_text_upright": false,
|
||||
"zones": {
|
||||
"min_clearance": 0.508
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [
|
||||
{
|
||||
"gap": 0.0,
|
||||
"via_gap": 0.0,
|
||||
"width": 0.0
|
||||
}
|
||||
],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"clearance": "error",
|
||||
"connection_width": "error",
|
||||
"copper_edge_clearance": "error",
|
||||
"copper_sliver": "warning",
|
||||
"courtyards_overlap": "error",
|
||||
"diff_pair_gap_out_of_range": "error",
|
||||
"diff_pair_uncoupled_length_too_long": "error",
|
||||
"drill_out_of_range": "error",
|
||||
"duplicate_footprints": "warning",
|
||||
"extra_footprint": "warning",
|
||||
"footprint_type_mismatch": "warning",
|
||||
"hole_clearance": "error",
|
||||
"hole_near_hole": "error",
|
||||
"invalid_outline": "error",
|
||||
"isolated_copper": "warning",
|
||||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "warning",
|
||||
"lib_footprint_mismatch": "warning",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
"missing_footprint": "warning",
|
||||
"net_conflict": "warning",
|
||||
"npth_inside_courtyard": "ignore",
|
||||
"overlapping_pads": "warning",
|
||||
"padstack": "warning",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_edge_clearance": "warning",
|
||||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"solder_mask_bridge": "error",
|
||||
"starved_thermal": "error",
|
||||
"text_height": "warning",
|
||||
"text_thickness": "warning",
|
||||
"through_hole_pad_without_hole": "error",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "ignore",
|
||||
"track_width": "error",
|
||||
"tracks_crossing": "error",
|
||||
"unconnected_items": "error",
|
||||
"unresolved_variable": "error",
|
||||
"via_dangling": "warning",
|
||||
"zones_intersect": "error"
|
||||
},
|
||||
"rules": {
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_connection": 0.12,
|
||||
"min_copper_edge_clearance": 0.0,
|
||||
"min_hole_clearance": 0.25,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.19999999999999998,
|
||||
"min_microvia_drill": 0.09999999999999999,
|
||||
"min_resolved_spokes": 2,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_text_height": 0.7999999999999999,
|
||||
"min_text_thickness": 0.12,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.19999999999999998,
|
||||
"min_via_annular_width": 0.049999999999999996,
|
||||
"min_via_diameter": 0.39999999999999997,
|
||||
"solder_mask_clearance": 0.0,
|
||||
"solder_mask_min_width": 0.0,
|
||||
"solder_mask_to_copper_clearance": 0.0,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"teardrop_options": [
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 5,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_onpadsmd": true,
|
||||
"td_onroundshapesonly": false,
|
||||
"td_ontrackend": false,
|
||||
"td_onviapad": true
|
||||
}
|
||||
],
|
||||
"teardrop_parameters": [
|
||||
{
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_target_name": "td_round_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_target_name": "td_rect_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_target_name": "td_track_end",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
}
|
||||
],
|
||||
"track_widths": [
|
||||
0.0
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false
|
||||
},
|
||||
"layer_presets": [],
|
||||
"viewports": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "connection_width.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.1,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.1,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.4,
|
||||
"wire_width": 6.0
|
||||
},
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.1,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "High_current",
|
||||
"nets": [
|
||||
"net_HC"
|
||||
],
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.25,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.4,
|
||||
"wire_width": 6.0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"net_colors": null
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": []
|
||||
},
|
||||
"sheets": [],
|
||||
"text_variables": {}
|
||||
}
|
|
@ -48,14 +48,15 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperConn, DRC_REGRESSION_TEST_FIXTURE )
|
|||
{
|
||||
// Check for minimum copper connection errors
|
||||
|
||||
std::vector<wxString> tests =
|
||||
std::vector<std::pair<wxString, int>> tests =
|
||||
{
|
||||
"issue9870"
|
||||
{ "issue9870", 12 },
|
||||
{ "connection_width_rules", 3 }
|
||||
};
|
||||
|
||||
for( const wxString& relPath : tests )
|
||||
for( const std::pair<wxString, int>& test : tests )
|
||||
{
|
||||
KI_TEST::LoadBoard( m_settingsManager, relPath, m_board );
|
||||
KI_TEST::LoadBoard( m_settingsManager, test.first, m_board );
|
||||
KI_TEST::FillZones( m_board.get() );
|
||||
|
||||
std::vector<DRC_ITEM> violations;
|
||||
|
@ -82,10 +83,10 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperConn, DRC_REGRESSION_TEST_FIXTURE )
|
|||
|
||||
bds.m_DRCEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
|
||||
|
||||
if( violations.size() == 12 )
|
||||
if( violations.size() == test.second )
|
||||
{
|
||||
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
|
||||
BOOST_TEST_MESSAGE( wxString::Format( "DRC connection width: %s, passed", relPath ) );
|
||||
BOOST_TEST_MESSAGE( wxString::Format( "DRC connection width: %s, passed", test.first ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -98,7 +99,7 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperConn, DRC_REGRESSION_TEST_FIXTURE )
|
|||
itemMap ) );
|
||||
}
|
||||
|
||||
BOOST_ERROR( wxString::Format( "DRC connection width: %s, failed", relPath ) );
|
||||
BOOST_ERROR( wxString::Format( "DRC connection width: %s, failed", test.first ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue