Add DRC testing for copper graphic to zone fill collisions.

This commit is contained in:
Jeff Young 2023-06-30 11:56:36 +01:00
parent 8b26f50003
commit 60696a895c
8 changed files with 1223 additions and 19 deletions

View File

@ -785,6 +785,21 @@ inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance,
static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, static bool collideSingleShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual,
VECTOR2I* aLocation, VECTOR2I* aMTV ) VECTOR2I* aLocation, VECTOR2I* aMTV )
{ {
if( aA->Type() == SH_POLY_SET )
{
const SHAPE_POLY_SET* polySetA = static_cast<const SHAPE_POLY_SET*>( aA );
wxASSERT( !aMTV );
return polySetA->Collide( aB, aClearance, aActual, aLocation );
}
else if( aB->Type() == SH_POLY_SET )
{
const SHAPE_POLY_SET* polySetB = static_cast<const SHAPE_POLY_SET*>( aB );
wxASSERT( !aMTV );
return polySetB->Collide( aA, aClearance, aActual, aLocation );
}
switch( aA->Type() ) switch( aA->Type() )
{ {
case SH_NULL: case SH_NULL:
@ -1086,20 +1101,6 @@ static bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int
} }
} }
} }
else if( aA->Type() == SH_POLY_SET )
{
const SHAPE_POLY_SET* polySetA = static_cast<const SHAPE_POLY_SET*>( aA );
wxASSERT( !aMTV );
return polySetA->Collide( aB, aClearance, aActual, aLocation );
}
else if( aB->Type() == SH_POLY_SET )
{
const SHAPE_POLY_SET* polySetB = static_cast<const SHAPE_POLY_SET*>( aB );
wxASSERT( !aMTV );
return polySetB->Collide( aA, aClearance, aActual, aLocation );
}
else else
{ {
return collideSingleShapes( aA, aB, aClearance, aActual, aLocation, aMTV ); return collideSingleShapes( aA, aB, aClearance, aActual, aLocation, aMTV );

View File

@ -96,10 +96,14 @@ private:
void testPadClearances(); void testPadClearances();
void testGraphicClearances();
void testZonesToZones(); void testZonesToZones();
void testItemAgainstZone( BOARD_ITEM* aItem, ZONE* aZone, PCB_LAYER_ID aLayer ); void testItemAgainstZone( BOARD_ITEM* aItem, ZONE* aZone, PCB_LAYER_ID aLayer );
void testKnockoutTextAgainstZone( BOARD_ITEM* aText, NETINFO_ITEM** aInheritedNet, ZONE* aZone );
typedef struct checked typedef struct checked
{ {
checked() checked()
@ -160,6 +164,14 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
testPadClearances(); testPadClearances();
} }
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) )
{
if( !reportPhase( _( "Checking copper graphic clearances..." ) ) )
return false; // DRC cancelled
testGraphicClearances();
}
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) ) if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) )
{ {
if( !reportPhase( _( "Checking copper zone clearances..." ) ) ) if( !reportPhase( _( "Checking copper zone clearances..." ) ) )
@ -431,6 +443,89 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
} }
/*
* We have to special-case knockout text as it's most often knocked-out of a zone, so it's
* presumed to collide with one. However, if it collides with more than one, and they have
* different nets, then we have a short.
*/
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testKnockoutTextAgainstZone( BOARD_ITEM* aText,
NETINFO_ITEM** aInheritedNet,
ZONE* aZone )
{
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
bool testShorts = !m_drcEngine->IsErrorLimitExceeded( DRCE_SHORTING_ITEMS );
if( !testClearance && !testShorts )
return;
PCB_LAYER_ID layer = aText->GetLayer();
if( !aZone->GetLayerSet().test( layer ) )
return;
BOX2I itemBBox = aText->GetBoundingBox();
BOX2I worstCaseBBox = itemBBox;
worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
if( !worstCaseBBox.Intersects( aZone->GetBoundingBox() ) )
return;
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ aZone ].get();
if( !zoneTree )
return;
std::shared_ptr<SHAPE> itemShape = aText->GetEffectiveShape( layer, FLASHING::DEFAULT );
if( *aInheritedNet == nullptr )
{
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), layer ) )
*aInheritedNet = aZone->GetNet();
}
if( *aInheritedNet == aZone->GetNet() )
return;
DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aText, aZone, layer );
int clearance = constraint.GetValue().Min();
int actual;
VECTOR2I pos;
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance >= 0 )
{
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), layer,
std::max( 0, clearance - m_drcEpsilon ), &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce;
wxString msg;
if( testShorts && actual == 0 && *aInheritedNet )
{
drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
msg.Printf( _( "(nets %s and %s)" ),
( *aInheritedNet )->GetNetname(),
aZone->GetNetname() );
}
else
{
drce = DRC_ITEM::Create( DRCE_CLEARANCE );
msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
clearance,
actual );
}
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( aText, aZone );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, layer );
}
}
}
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
{ {
// This is the number of tests between 2 calls to the progress bar // This is the number of tests between 2 calls to the progress bar
@ -815,7 +910,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
} }
} }
if( !reportProgress( ii++, count, progressDelta ) ) if( !reportProgress( ii++, (int) count, progressDelta ) )
return; return;
} }
@ -825,6 +920,72 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
{
const int progressDelta = 100;
size_t count = m_board->Drawings().size();
int ii = 0;
for( FOOTPRINT* footprint : m_board->Footprints() )
count += footprint->GraphicalItems().size();
reportAux( wxT( "Testing %d graphics..." ), count );
auto isKnockoutText =
[]( BOARD_ITEM* item )
{
if( item->Type() == PCB_TEXT_T )
return static_cast<PCB_TEXT*>( item )->IsKnockout();
else if( item->Type() == PCB_FP_TEXT_T )
return static_cast<FP_TEXT*>( item )->IsKnockout();
else
return false;
};
auto testGraphicAgainstZone =
[&]( BOARD_ITEM* item )
{
if( !IsCopperLayer( item->GetLayer() ) )
return;
// Knockout text is most often knocked-out of a zone, so it's presumed to
// collide with one. However, if it collides with more than one, and they
// have different nets, then we have a short.
NETINFO_ITEM* inheritedNet = nullptr;
for( ZONE* zone : m_board->m_DRCCopperZones )
{
if( isKnockoutText( item ) )
testKnockoutTextAgainstZone( item, &inheritedNet, zone );
else
testItemAgainstZone( item, zone, item->GetLayer() );
if( m_drcEngine->IsCancelled() )
return;
}
};
for( BOARD_ITEM* item : m_board->Drawings() )
{
testGraphicAgainstZone( item );
if( !reportProgress( ii++, (int) count, progressDelta ) )
return;
}
for( FOOTPRINT* footprint : m_board->Footprints() )
{
for( BOARD_ITEM* item : footprint->GraphicalItems() )
{
testGraphicAgainstZone( item );
if( !reportProgress( ii++, (int) count, progressDelta ) )
return;
}
}
}
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
{ {
const int progressDelta = 50; const int progressDelta = 50;

View File

@ -365,7 +365,7 @@ void PCB_TEXT::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aL
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, ERROR_INSIDE ); TransformTextToPolySet( poly, 0, GetBoard()->GetDesignSettings().m_MaxError, aErrorLoc );
buildBoundingHull( &aBuffer, poly, aClearance ); buildBoundingHull( &aBuffer, poly, aClearance );
} }

View File

@ -0,0 +1,410 @@
(kicad_pcb (version 20221018) (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
(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 "Test1")
(net 2 "Test2")
(net 3 "Test3")
(footprint "Connector_Wire:SolderWirePad_1x01_SMD_1x2mm" (layer "B.Cu")
(tstamp ca5993ae-dd71-48b4-90b5-80f8f75da987)
(at 153.75 83.55 180)
(descr "Wire Pad, Square, SMD Pad, 5mm x 10mm,")
(tags "MesurementPoint Square SMDPad 5mmx10mm ")
(attr exclude_from_pos_files exclude_from_bom)
(fp_text reference "REF**" (at 0 2.54) (layer "B.SilkS")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 6399a8cf-5382-4bce-ba64-4dfde3ade47a)
)
(fp_text value "SolderWirePad_1x01_SMD_1x2mm" (at 0 -2.54) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 430c8d54-ab51-43c0-92b3-5d6fbb078310)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp a917afff-2f63-452d-b185-91ecbe43eead)
)
(fp_line (start -0.63 -1.27) (end 0.63 -1.27)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp 6ca357af-ad11-43da-b598-c0750bdfde27))
(fp_line (start -0.63 1.27) (end -0.63 -1.27)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp 310f9ca4-b0af-47f2-a88a-b7ef1cf6fb3a))
(fp_line (start 0.63 -1.27) (end 0.63 1.27)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp d66c1cf8-e4ab-4443-a7d8-edb1da6d4316))
(fp_line (start 0.63 1.27) (end -0.63 1.27)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp ee1db011-af60-43d7-8b53-6f3509e93f29))
(fp_line (start -0.63 -1.27) (end -0.63 1.27)
(stroke (width 0.1) (type solid)) (layer "B.Fab") (tstamp ff006fc0-ed05-4222-8abb-c96ac6671151))
(fp_line (start -0.63 1.27) (end 0.63 1.27)
(stroke (width 0.1) (type solid)) (layer "B.Fab") (tstamp c7131b36-fc5f-41c4-aa20-7fd3da3905b2))
(fp_line (start 0.63 -1.27) (end -0.63 -1.27)
(stroke (width 0.1) (type solid)) (layer "B.Fab") (tstamp b2b534d0-5721-4e67-bcf2-5e13a3b4a76b))
(fp_line (start 0.63 1.27) (end 0.63 -1.27)
(stroke (width 0.1) (type solid)) (layer "B.Fab") (tstamp 5e2f4003-df05-4479-b514-2002705ba3c5))
(pad "1" smd roundrect (at 0 0 180) (size 1 2) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.25)
(net 3 "Test3") (tstamp 5b7a22ae-aba8-4d28-b413-f13f01e1b3b7))
)
(footprint "NetTie:NetTie-2_SMD_Pad0.5mm" (layer "B.Cu")
(tstamp e79c5996-ed5b-4e02-88ac-11f9036c04c1)
(at 155.35 85.75 -90)
(descr "Net tie, 2 pin, 0.5mm square SMD pads")
(tags "net tie")
(property "Sheetfile" "UAVNav_Core.kicad_sch")
(property "Sheetname" "UAVNav_Core")
(property "exclude_from_bom" "")
(property "ki_description" "Net tie, 2 pins")
(property "ki_keywords" "net tie short")
(attr exclude_from_pos_files exclude_from_bom)
(net_tie_pad_groups "1, 2")
(fp_text reference "NT2" (at 0 1.2 90) (layer "B.SilkS") hide
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 146ccf02-58cd-48fa-91d5-369ef2b2fc43)
)
(fp_text value "Net-Tie_2" (at 0 -1.2 90) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 8ecd81aa-f7ad-48a3-ad05-c7ce3d88a782)
)
(fp_poly
(pts
(xy -0.5 0.25)
(xy 0.5 0.25)
(xy 0.5 -0.25)
(xy -0.5 -0.25)
)
(stroke (width 0) (type solid)) (fill solid) (layer "B.Cu") (tstamp 4e729321-142d-4160-a36b-2f04a38006f8))
(pad "1" smd circle (at -0.5 0 270) (size 0.5 0.5) (layers "B.Cu")
(net 1 "Test1") (pinfunction "1") (pintype "passive") (tstamp 1032c1e0-1464-4daf-9a92-755e91fe89e6))
(pad "2" smd circle (at 0.5 0 270) (size 0.5 0.5) (layers "B.Cu")
(net 2 "Test2") (pinfunction "2") (pintype "passive") (tstamp f61d1578-8818-4727-8655-15416c8bd70b))
)
(gr_rect (start 139.573 79.375) (end 163.957 93.091)
(stroke (width 0.05) (type default)) (fill none) (layer "Edge.Cuts") (tstamp 2146930a-368d-424c-864c-4d2ba41cbcae))
(gr_text "Otherwise" (at 155.194 89.281) (layer "B.Cu" knockout) (tstamp 6c4f9b12-5489-4923-9fc0-4f8130f1cb8b)
(effects (font (size 1.5 1.5) (thickness 0.3) bold) (justify left bottom mirror))
)
(gr_text "What" (at 156.845 84.455) (layer "B.Cu") (tstamp 7cdcf930-f446-408b-862f-6846f278bce8)
(effects (font (size 1 1) (thickness 0.15)) (justify left bottom))
)
(zone (net 2) (net_name "Test2") (layer "B.Cu") (tstamp a78787ef-dd0d-4073-9547-f9e19d46d566) (hatch edge 0.5)
(priority 2)
(connect_pads (clearance 0.5))
(min_thickness 0.25) (filled_areas_thickness no)
(fill yes (thermal_gap 0.5) (thermal_bridge_width 0.5) (island_removal_mode 1) (island_area_min 10))
(polygon
(pts
(xy 143.637 84.582)
(xy 147.955 84.582)
(xy 147.955 91.694)
(xy 143.637 91.694)
)
)
(filled_polygon
(layer "B.Cu")
(pts
(xy 147.898039 84.601685)
(xy 147.943794 84.654489)
(xy 147.955 84.706)
(xy 147.955 87.098251)
(xy 147.935315 87.16529)
(xy 147.882511 87.211045)
(xy 147.831 87.222251)
(xy 144.137333 87.222251)
(xy 144.137333 89.441405)
(xy 147.831 89.441405)
(xy 147.898039 89.46109)
(xy 147.943794 89.513894)
(xy 147.955 89.565405)
(xy 147.955 91.57)
(xy 147.935315 91.637039)
(xy 147.882511 91.682794)
(xy 147.831 91.694)
(xy 143.761 91.694)
(xy 143.693961 91.674315)
(xy 143.648206 91.621511)
(xy 143.637 91.57)
(xy 143.637 84.706)
(xy 143.656685 84.638961)
(xy 143.709489 84.593206)
(xy 143.761 84.582)
(xy 147.831 84.582)
)
)
)
(zone (net 3) (net_name "Test3") (layer "B.Cu") (tstamp d8faf083-2cf6-4659-b189-791fef968e17) (hatch edge 0.5)
(connect_pads (clearance 0.127))
(min_thickness 0.2) (filled_areas_thickness no)
(fill yes (thermal_gap 0.5) (thermal_bridge_width 0.5))
(polygon
(pts
(xy 157.4 82.05)
(xy 157.4 88.1)
(xy 152.7 88.1)
(xy 152.7 82.05)
)
)
(filled_polygon
(layer "B.Cu")
(pts
(xy 157.359191 82.068907)
(xy 157.395155 82.118407)
(xy 157.4 82.149)
(xy 157.4 88.001)
(xy 157.381093 88.059191)
(xy 157.331593 88.095155)
(xy 157.301 88.1)
(xy 155.164513 88.1)
(xy 155.106322 88.081093)
(xy 155.070358 88.031593)
(xy 155.065513 88.001)
(xy 155.065513 87.222252)
(xy 155.065513 87.222251)
(xy 152.799 87.222251)
(xy 152.740809 87.203344)
(xy 152.704845 87.153844)
(xy 152.7 87.123251)
(xy 152.7 86.25)
(xy 154.967794 86.25)
(xy 154.9865 86.368107)
(xy 154.986501 86.368111)
(xy 155.040787 86.474652)
(xy 155.040789 86.474655)
(xy 155.125345 86.559211)
(xy 155.125347 86.559212)
(xy 155.125346 86.559212)
(xy 155.231888 86.613498)
(xy 155.231892 86.6135)
(xy 155.33385 86.629648)
(xy 155.349999 86.632206)
(xy 155.35 86.632206)
(xy 155.350001 86.632206)
(xy 155.364206 86.629955)
(xy 155.468108 86.6135)
(xy 155.574655 86.559211)
(xy 155.659211 86.474655)
(xy 155.7135 86.368108)
(xy 155.732206 86.25)
(xy 155.7135 86.131892)
(xy 155.659211 86.025345)
(xy 155.574655 85.940789)
(xy 155.574652 85.940787)
(xy 155.574653 85.940787)
(xy 155.468111 85.886501)
(xy 155.468108 85.8865)
(xy 155.409054 85.877147)
(xy 155.350001 85.867794)
(xy 155.349999 85.867794)
(xy 155.231892 85.8865)
(xy 155.231888 85.886501)
(xy 155.125347 85.940787)
(xy 155.040787 86.025347)
(xy 154.986501 86.131888)
(xy 154.9865 86.131892)
(xy 154.967794 86.249999)
(xy 154.967794 86.25)
(xy 152.7 86.25)
(xy 152.7 85.25)
(xy 154.967794 85.25)
(xy 154.9865 85.368107)
(xy 154.986501 85.368111)
(xy 155.040787 85.474652)
(xy 155.040789 85.474655)
(xy 155.125345 85.559211)
(xy 155.125347 85.559212)
(xy 155.125346 85.559212)
(xy 155.231888 85.613498)
(xy 155.231892 85.6135)
(xy 155.33385 85.629648)
(xy 155.349999 85.632206)
(xy 155.35 85.632206)
(xy 155.350001 85.632206)
(xy 155.364206 85.629955)
(xy 155.468108 85.6135)
(xy 155.574655 85.559211)
(xy 155.659211 85.474655)
(xy 155.7135 85.368108)
(xy 155.732206 85.25)
(xy 155.7135 85.131892)
(xy 155.659211 85.025345)
(xy 155.574655 84.940789)
(xy 155.574652 84.940787)
(xy 155.574653 84.940787)
(xy 155.468111 84.886501)
(xy 155.468108 84.8865)
(xy 155.409054 84.877147)
(xy 155.350001 84.867794)
(xy 155.349999 84.867794)
(xy 155.231892 84.8865)
(xy 155.231888 84.886501)
(xy 155.125347 84.940787)
(xy 155.040787 85.025347)
(xy 154.986501 85.131888)
(xy 154.9865 85.131892)
(xy 154.967794 85.249999)
(xy 154.967794 85.25)
(xy 152.7 85.25)
(xy 152.7 84.780722)
(xy 152.718907 84.722531)
(xy 152.768407 84.686567)
(xy 152.829593 84.686567)
(xy 152.879093 84.722531)
(xy 152.883261 84.72875)
(xy 152.90768 84.76834)
(xy 153.031659 84.892319)
(xy 153.180875 84.984356)
(xy 153.347306 85.039506)
(xy 153.450013 85.049999)
(xy 153.5 85.049998)
(xy 154 85.049998)
(xy 154.000001 85.049999)
(xy 154.049986 85.049999)
(xy 154.152687 85.039507)
(xy 154.152699 85.039504)
(xy 154.319124 84.984356)
(xy 154.46834 84.892319)
(xy 154.592319 84.76834)
(xy 154.684356 84.619124)
(xy 154.739506 84.452693)
(xy 154.75 84.349987)
(xy 154.75 83.8)
(xy 154.000001 83.8)
(xy 154 83.800001)
(xy 154 85.049998)
(xy 153.5 85.049998)
(xy 153.5 83.399)
(xy 153.518907 83.340809)
(xy 153.568407 83.304845)
(xy 153.599 83.3)
(xy 154.749998 83.3)
(xy 154.749999 83.299999)
(xy 154.749999 82.750013)
(xy 154.739507 82.647312)
(xy 154.739504 82.6473)
(xy 154.684356 82.480875)
(xy 154.592319 82.331659)
(xy 154.479664 82.219004)
(xy 154.451887 82.164487)
(xy 154.461458 82.104055)
(xy 154.504723 82.06079)
(xy 154.549668 82.05)
(xy 157.301 82.05)
)
)
)
(zone (net 3) (net_name "Test3") (layer "B.Cu") (tstamp e7fb42af-8060-4e89-b56c-5293c80f1b68) (hatch edge 0.5)
(priority 1)
(connect_pads (clearance 0.5))
(min_thickness 0.25) (filled_areas_thickness no)
(fill yes (thermal_gap 0.5) (thermal_bridge_width 0.5) (island_removal_mode 1) (island_area_min 10))
(polygon
(pts
(xy 159.385 89.154)
(xy 150.241 89.154)
(xy 150.241 91.313)
(xy 159.385 91.313)
)
)
(filled_polygon
(layer "B.Cu")
(pts
(xy 159.328039 89.173685)
(xy 159.373794 89.226489)
(xy 159.385 89.278)
(xy 159.385 91.189)
(xy 159.365315 91.256039)
(xy 159.312511 91.301794)
(xy 159.261 91.313)
(xy 150.365 91.313)
(xy 150.297961 91.293315)
(xy 150.252206 91.240511)
(xy 150.241 91.189)
(xy 150.241 89.565405)
(xy 150.260685 89.498366)
(xy 150.313489 89.452611)
(xy 150.365 89.441405)
(xy 155.065513 89.441405)
(xy 155.065513 89.278)
(xy 155.085198 89.210961)
(xy 155.138002 89.165206)
(xy 155.189513 89.154)
(xy 159.261 89.154)
)
)
)
)

View File

@ -0,0 +1,533 @@
{
"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.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"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": "error",
"footprint_type_mismatch": "ignore",
"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",
"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": "warning",
"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.0,
"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.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.09999999999999999,
"min_via_diameter": 0.5,
"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": [],
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "test_copper_graphics.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.127,
"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.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "Quantity",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Reference"
},
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"fa34e893-36fd-4808-a15f-a0155a635056",
""
]
],
"text_variables": {}
}

View File

@ -47,6 +47,7 @@ set( QA_PCBNEW_SRCS
drc/test_drc_courtyard_overlap.cpp drc/test_drc_courtyard_overlap.cpp
drc/test_drc_regressions.cpp drc/test_drc_regressions.cpp
drc/test_drc_copper_conn.cpp drc/test_drc_copper_conn.cpp
drc/test_drc_copper_graphics.cpp
drc/test_drc_copper_sliver.cpp drc/test_drc_copper_sliver.cpp
drc/test_solder_mask_bridging.cpp drc/test_solder_mask_bridging.cpp

View File

@ -0,0 +1,98 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <pcbnew_utils/board_test_utils.h>
#include <board.h>
#include <board_design_settings.h>
#include <pcb_marker.h>
#include <drc/drc_item.h>
#include <settings/settings_manager.h>
struct DRC_COPPER_GRAPHICS_TEST_FIXTURE
{
DRC_COPPER_GRAPHICS_TEST_FIXTURE() :
m_settingsManager( true /* headless */ )
{ }
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<BOARD> m_board;
};
BOOST_FIXTURE_TEST_CASE( DRCCopperGraphicsTest, DRC_COPPER_GRAPHICS_TEST_FIXTURE )
{
wxString brd_name( wxT( "test_copper_graphics" ) );
KI_TEST::LoadBoard( m_settingsManager, brd_name, m_board );
// Do NOT refill zones; this will prevent some of the items from being tested.
// KI_TEST::FillZones( m_board.get() );
std::vector<DRC_ITEM> violations;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// Disable some DRC tests not useful in this testcase (and time consuming)
bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_ISSUES ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCSeverities[ DRCE_COPPER_SLIVER ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCSeverities[ DRCE_STARVED_THERMAL ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCSeverities[ DRCE_ISOLATED_COPPER ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer )
{
PCB_MARKER temp( aItem, aPos );
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
violations.push_back( *aItem );
} );
bds.m_DRCEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
const int expected_err_cnt = 4; // "What" copper text shorting zone
// Copper knockout text shorting two zones twice (but not
// three times as the two vertical zones are the same net)
// Net-tie rectangle shorting zone
if( violations.size() == expected_err_cnt )
{
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
BOOST_TEST_MESSAGE( "DRC copper graphics test passed" );
}
else
{
BOOST_CHECK_EQUAL( violations.size(), expected_err_cnt );
UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::INCHES );
std::map<KIID, EDA_ITEM*> itemMap;
m_board->FillItemMap( itemMap );
for( const DRC_ITEM& item : violations )
BOOST_TEST_MESSAGE( item.ShowReport( &unitsProvider, RPT_SEVERITY_ERROR, itemMap ) );
BOOST_ERROR( wxString::Format( "DRC copper graphics test failed board <%s>", brd_name ) );
}
}

View File

@ -30,9 +30,9 @@
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
struct DRC_REGRESSION_TEST_FIXTURE struct DRC_SOLDER_MASK_BRIDGING_TEST_FIXTURE
{ {
DRC_REGRESSION_TEST_FIXTURE() : DRC_SOLDER_MASK_BRIDGING_TEST_FIXTURE() :
m_settingsManager( true /* headless */ ) m_settingsManager( true /* headless */ )
{ } { }
@ -41,7 +41,7 @@ struct DRC_REGRESSION_TEST_FIXTURE
}; };
BOOST_FIXTURE_TEST_CASE( DRCSolderMaskBridgingTest, DRC_REGRESSION_TEST_FIXTURE ) BOOST_FIXTURE_TEST_CASE( DRCSolderMaskBridgingTest, DRC_SOLDER_MASK_BRIDGING_TEST_FIXTURE )
{ {
wxString brd_name( wxT( "solder_mask_bridge_test" ) ); wxString brd_name( wxT( "solder_mask_bridge_test" ) );
KI_TEST::LoadBoard( m_settingsManager, brd_name, m_board ); KI_TEST::LoadBoard( m_settingsManager, brd_name, m_board );