Added check for custom thermal spoke count

When using custom thermal spoke templates, the user can create templates with fewer, or more, thermal spokes than 4.
This commit is contained in:
Daniel Treffenstädt 2025-02-27 22:40:40 +00:00 committed by Seth Hillbrand
parent e81956f292
commit 5e467a969d
5 changed files with 1136 additions and 4 deletions

View File

@ -155,19 +155,35 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
zoneFill->Outline( jj ).Intersect( padOutline, intersections, true, &padBBox );
std::vector<SHAPE_LINE_CHAIN::INTERSECTION> unique_intersections;
for( const auto& i : intersections )
{
const auto found = std::find_if(
std::begin( unique_intersections ), std::end( unique_intersections ),
[&]( const SHAPE_LINE_CHAIN::INTERSECTION& j ) -> bool
{
return ( j.p == i.p );
} );
if( found == std::end( unique_intersections ) )
unique_intersections.emplace_back( i );
}
// If we connect to an island that only connects to a single item then we *are*
// that item. Thermal spokes to this (otherwise isolated) island don't provide
// electrical connectivity to anything, so we don't count them.
if( intersections.size() >= 2 )
if( unique_intersections.size() >= 2 )
{
if( alg::contains( isolatedIslands.m_SingleConnectionOutlines, jj ) )
{
ignoredSpokes += (int) intersections.size() / 2;
ignoredSpokePos = ( intersections[0].p + intersections[1].p ) / 2;
ignoredSpokes += (int) unique_intersections.size() / 2;
ignoredSpokePos =
( unique_intersections[0].p + unique_intersections[1].p ) / 2;
}
else
{
spokes += (int) intersections.size() / 2;
spokes += (int) unique_intersections.size() / 2;
}
}
}
@ -175,6 +191,51 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
if( spokes == 0 && ignoredSpokes == 0 ) // Not connected at all
continue;
int customSpokes = 0;
if( pad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
{
for( const std::shared_ptr<PCB_SHAPE>& primitive : pad->GetPrimitives( aLayer ) )
{
if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::SEGMENT )
{
customSpokes++;
}
}
}
if( customSpokes > 0 )
{
if( spokes < customSpokes )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_STARVED_THERMAL );
VECTOR2I pos;
if( ignoredSpokes )
{
msg = wxString::Format(
_( "(layer %s; %d spokes connected to isolated island)" ),
board->GetLayerName( aLayer ), ignoredSpokes );
pos = ignoredSpokePos;
}
else
{
msg = wxString::Format(
_( "(layer %s; %s custom spoke count %d; actual %d)" ),
board->GetLayerName( aLayer ), constraint.GetName(), customSpokes,
spokes );
pos = pad->GetPosition();
}
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( aZone, pad );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, aLayer );
}
continue;
}
if( spokes >= minCount ) // We already have enough
continue;

View File

@ -0,0 +1,683 @@
(kicad_pcb
(version 20240108)
(generator "pcbnew")
(generator_version "8.0")
(general
(thickness 1.6)
(legacy_teardrops no)
)
(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)
(allow_soldermask_bridges_in_footprints no)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(plot_on_all_layers_selection 0x0000000_00000000)
(disableapertmacros no)
(usegerberextensions no)
(usegerberattributes yes)
(usegerberadvancedattributes yes)
(creategerberjobfile yes)
(dashed_line_dash_ratio 12.000000)
(dashed_line_gap_ratio 3.000000)
(svgprecision 4)
(plotframeref no)
(viasonmask no)
(mode 1)
(useauxorigin no)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(pdf_front_fp_property_popups yes)
(pdf_back_fp_property_popups yes)
(dxfpolygonmode yes)
(dxfimperialunits yes)
(dxfusepcbnewfont yes)
(psnegative no)
(psa4output no)
(plotreference yes)
(plotvalue yes)
(plotfptext yes)
(plotinvisibletext no)
(sketchpadsonfab no)
(subtractmaskfromsilk no)
(outputformat 1)
(mirror no)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
(net 1 "a")
(footprint "test_thermal_spoke_count:C_0805_2012Metric_custom_spokes"
(layer "F.Cu")
(uuid "0244deae-bf20-4b88-9777-64b2d7691357")
(at 115 110)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(property "Reference" "REF**"
(at 0 -1.68 0)
(layer "F.SilkS")
(uuid "bc682ff4-2b11-46e3-b1c2-3b6d25fcf846")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Value" "C_0805_2012Metric_custom_spokes"
(at 0 1.68 0)
(layer "F.Fab")
(uuid "072679ec-ac3a-4d1d-a5f7-3744f9ddb4fb")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Footprint" "test_thermal_spoke_count:C_0805_2012Metric_custom_spokes"
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "d41501df-c1bb-4186-b903-cbd2995bbbfd")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Datasheet" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "c00d6c15-5585-4547-92fe-189864da301a")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Description" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "ba30ed52-4e2e-4eb6-9902-9fba4d856030")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(attr smd)
(fp_line
(start -0.261252 -0.735)
(end 0.261252 -0.735)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "de72caec-2256-4d78-bcc7-d40112bd0d81")
)
(fp_line
(start -0.261252 0.735)
(end 0.261252 0.735)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "4822adf0-3104-4d27-bb76-9d994ee9701c")
)
(fp_line
(start -1.7 -0.98)
(end 1.7 -0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "3ea6d36a-0032-48d1-8378-1f1d69d864f6")
)
(fp_line
(start -1.7 0.98)
(end -1.7 -0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "2bc289a7-bd66-4c0d-a4ad-57ea85a1dcb6")
)
(fp_line
(start 1.7 -0.98)
(end 1.7 0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "ec60335f-d34e-498f-a34d-ee6158b03f4e")
)
(fp_line
(start 1.7 0.98)
(end -1.7 0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "3486fd80-33a9-41c3-97a9-fce5b670b16f")
)
(fp_line
(start -1 -0.625)
(end 1 -0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "b43c6a88-e2d7-4dbb-919b-dd2f205f049a")
)
(fp_line
(start -1 0.625)
(end -1 -0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "1e6222e4-17f4-48f4-9cf9-2659b6360c8a")
)
(fp_line
(start 1 -0.625)
(end 1 0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "6132f1e9-c2e7-4dab-86ef-0c2a1d07ead5")
)
(fp_line
(start 1 0.625)
(end -1 0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "c558181e-bdde-4a46-8372-85fce1a0cb17")
)
(fp_text user "${REFERENCE}"
(at 0 0 0)
(layer "F.Fab")
(uuid "2d56eea7-05eb-4805-9a07-fb60a362127e")
(effects
(font
(size 0.5 0.5)
(thickness 0.08)
)
)
)
(pad "1" smd custom
(at -0.95 0)
(size 1 1)
(layers "F.Cu" "F.Paste" "F.Mask")
(net 1 "a")
(thermal_bridge_angle 90)
(options
(clearance outline)
(anchor circle)
)
(primitives
(gr_poly
(pts
(xy -0.5 -0.475) (xy -0.48097 -0.570671) (xy -0.426777 -0.651777) (xy -0.345671 -0.70597) (xy -0.25 -0.725)
(xy 0.25 -0.725) (xy 0.345671 -0.70597) (xy 0.426777 -0.651777) (xy 0.48097 -0.570671) (xy 0.5 -0.475)
(xy 0.5 0.475) (xy 0.48097 0.570671) (xy 0.426777 0.651777) (xy 0.345671 0.70597) (xy 0.25 0.725)
(xy -0.25 0.725) (xy -0.345671 0.70597) (xy -0.426777 0.651777) (xy -0.48097 0.570671) (xy -0.5 0.475)
)
(width 0)
(fill yes)
)
(gr_vector
(start 0 0)
(end 0 1.5)
)
(gr_vector
(start 0 0)
(end -1.55 0)
)
(gr_vector
(start 0 0)
(end 0 -1.5)
)
)
(uuid "57856e2d-8127-4a1b-a518-b91d9a7d047b")
)
(pad "2" smd custom
(at 0.95 0)
(size 1 1)
(layers "F.Cu" "F.Paste" "F.Mask")
(net 1 "a")
(thermal_bridge_angle 90)
(options
(clearance outline)
(anchor circle)
)
(primitives
(gr_poly
(pts
(xy -0.5 -0.475) (xy -0.48097 -0.570671) (xy -0.426777 -0.651777) (xy -0.345671 -0.70597) (xy -0.25 -0.725)
(xy 0.25 -0.725) (xy 0.345671 -0.70597) (xy 0.426777 -0.651777) (xy 0.48097 -0.570671) (xy 0.5 -0.475)
(xy 0.5 0.475) (xy 0.48097 0.570671) (xy 0.426777 0.651777) (xy 0.345671 0.70597) (xy 0.25 0.725)
(xy -0.25 0.725) (xy -0.345671 0.70597) (xy -0.426777 0.651777) (xy -0.48097 0.570671) (xy -0.5 0.475)
)
(width 0)
(fill yes)
)
(gr_vector
(start 0.05 0)
(end 1.55 0)
)
)
(uuid "79e6da3c-a69f-45fb-993e-66f3776e8fb6")
)
(model "${KICAD8_3DMODEL_DIR}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl"
(offset
(xyz 0 0 0)
)
(scale
(xyz 1 1 1)
)
(rotate
(xyz 0 0 0)
)
)
)
(footprint "test_thermal_spoke_count:C_0805_2012Metric"
(layer "F.Cu")
(uuid "7f0321db-d18d-4db3-814e-d3cbe9174170")
(at 115 115)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(property "Reference" "REF**"
(at 0 -1.68 0)
(layer "F.SilkS")
(uuid "7620a590-f89d-4338-b569-b31a139cf2c6")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Value" "C_0805_2012Metric"
(at 0 1.68 0)
(layer "F.Fab")
(uuid "98b0617c-b5d6-4d36-a22a-c269f6e7ab8a")
(effects
(font
(size 1 1)
(thickness 0.15)
)
)
)
(property "Footprint" "Capacitor_SMD:C_0805_2012Metric"
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "4e244502-c332-4674-a9f9-127ed7e2c613")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Datasheet" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "3a99221b-4466-4711-a20f-943b695fae94")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(property "Description" ""
(at 0 0 0)
(unlocked yes)
(layer "F.Fab")
(hide yes)
(uuid "0ff62164-ea53-42e9-82fc-fbd2d12a6c22")
(effects
(font
(size 1.27 1.27)
(thickness 0.15)
)
)
)
(attr smd)
(fp_line
(start -0.261252 -0.735)
(end 0.261252 -0.735)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "e96917d9-4815-46d8-a69b-210484683373")
)
(fp_line
(start -0.261252 0.735)
(end 0.261252 0.735)
(stroke
(width 0.12)
(type solid)
)
(layer "F.SilkS")
(uuid "0bfdab70-dbf6-4782-a9e2-149880329c1b")
)
(fp_line
(start -1.7 -0.98)
(end 1.7 -0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "b141feac-ac7f-44c1-b0b9-333393f5d977")
)
(fp_line
(start -1.7 0.98)
(end -1.7 -0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "67ad3e16-d526-41a4-8481-5c7227eefda6")
)
(fp_line
(start 1.7 -0.98)
(end 1.7 0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "d6dbbd74-3b67-47c1-8692-78970209fe2d")
)
(fp_line
(start 1.7 0.98)
(end -1.7 0.98)
(stroke
(width 0.05)
(type solid)
)
(layer "F.CrtYd")
(uuid "fb55b0d1-516b-454d-b643-f0997bb6c2db")
)
(fp_line
(start -1 -0.625)
(end 1 -0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "07045590-ab12-48d6-a987-618e487ea022")
)
(fp_line
(start -1 0.625)
(end -1 -0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "f48448bf-bf44-463d-8e03-9ee9b592249f")
)
(fp_line
(start 1 -0.625)
(end 1 0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "350fcc90-360d-4ed2-a8b9-07d8a2068ca3")
)
(fp_line
(start 1 0.625)
(end -1 0.625)
(stroke
(width 0.1)
(type solid)
)
(layer "F.Fab")
(uuid "15bfbddb-9283-4485-b44c-b323dce8bd05")
)
(fp_text user "${REFERENCE}"
(at 0 0 0)
(layer "F.Fab")
(uuid "b8220eaf-1387-419f-ab7b-c4d751ed6ead")
(effects
(font
(size 0.5 0.5)
(thickness 0.08)
)
)
)
(pad "1" smd roundrect
(at -0.95 0)
(size 1 1.45)
(layers "F.Cu" "F.Paste" "F.Mask")
(roundrect_rratio 0.25)
(net 1 "a")
(uuid "88a94303-0d98-40f5-9430-aa0040cc0e14")
)
(pad "2" smd roundrect
(at 0.95 0)
(size 1 1.45)
(layers "F.Cu" "F.Paste" "F.Mask")
(roundrect_rratio 0.25)
(net 1 "a")
(uuid "32dc8534-4659-4a08-bc1c-d65ac79b10c2")
)
(model "${KICAD8_3DMODEL_DIR}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl"
(offset
(xyz 0 0 0)
)
(scale
(xyz 1 1 1)
)
(rotate
(xyz 0 0 0)
)
)
)
(gr_line
(start 105 120)
(end 105 105)
(stroke
(width 0.05)
(type default)
)
(layer "Edge.Cuts")
(uuid "2d491e9d-9826-4802-9d04-148f1a1d0082")
)
(gr_line
(start 105 105)
(end 125 105)
(stroke
(width 0.05)
(type default)
)
(layer "Edge.Cuts")
(uuid "4f1fbf4a-901e-47ab-bcc0-f6b79bd079e0")
)
(gr_line
(start 125 105)
(end 125 120)
(stroke
(width 0.05)
(type default)
)
(layer "Edge.Cuts")
(uuid "5b3a6e6a-a5a4-4fa7-9aa3-61c213eaf61a")
)
(gr_line
(start 125 120)
(end 105 120)
(stroke
(width 0.05)
(type default)
)
(layer "Edge.Cuts")
(uuid "8dec62ec-2e2a-4ba3-b755-50add5a4189d")
)
(zone
(net 1)
(net_name "a")
(layer "F.Cu")
(uuid "681a4c00-defd-41da-8504-1bb039b834fa")
(hatch edge 0.5)
(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 105 109) (xy 115 109) (xy 115 105) (xy 125 105) (xy 125 116) (xy 115 116) (xy 115 120) (xy 105 120)
)
)
(filled_polygon
(layer "F.Cu")
(pts
(xy 124.442539 105.520185) (xy 124.488294 105.572989) (xy 124.4995 105.6245) (xy 124.4995 115.876)
(xy 124.479815 115.943039) (xy 124.427011 115.988794) (xy 124.3755 116) (xy 116.979546 116) (xy 116.912507 115.980315)
(xy 116.866752 115.927511) (xy 116.856808 115.858353) (xy 116.874007 115.810904) (xy 116.884354 115.794128)
(xy 116.884358 115.794119) (xy 116.939505 115.627697) (xy 116.939506 115.62769) (xy 116.949999 115.524986)
(xy 116.95 115.524973) (xy 116.95 115.25) (xy 114.3 115.25) (xy 114.3 116.224999) (xy 114.349972 116.224999)
(xy 114.349986 116.224998) (xy 114.452697 116.214505) (xy 114.619119 116.159358) (xy 114.619124 116.159356)
(xy 114.768345 116.067315) (xy 114.788319 116.047342) (xy 114.849642 116.013857) (xy 114.919334 116.018841)
(xy 114.975267 116.060713) (xy 114.999684 116.126177) (xy 115 116.135023) (xy 115 119.3755) (xy 114.980315 119.442539)
(xy 114.927511 119.488294) (xy 114.876 119.4995) (xy 105.6245 119.4995) (xy 105.557461 119.479815)
(xy 105.511706 119.427011) (xy 105.5005 119.3755) (xy 105.5005 115.524986) (xy 113.050001 115.524986)
(xy 113.060494 115.627697) (xy 113.115641 115.794119) (xy 113.115643 115.794124) (xy 113.207684 115.943345)
(xy 113.331654 116.067315) (xy 113.480875 116.159356) (xy 113.48088 116.159358) (xy 113.647302 116.214505)
(xy 113.647309 116.214506) (xy 113.750019 116.224999) (xy 113.799999 116.224998) (xy 113.8 116.224998)
(xy 113.8 115.25) (xy 113.050001 115.25) (xy 113.050001 115.524986) (xy 105.5005 115.524986) (xy 105.5005 114.475013)
(xy 113.05 114.475013) (xy 113.05 114.75) (xy 113.8 114.75) (xy 113.8 113.775) (xy 114.3 113.775)
(xy 114.3 114.75) (xy 115.7 114.75) (xy 116.2 114.75) (xy 116.949999 114.75) (xy 116.949999 114.475028)
(xy 116.949998 114.475013) (xy 116.939505 114.372302) (xy 116.884358 114.20588) (xy 116.884356 114.205875)
(xy 116.792315 114.056654) (xy 116.668345 113.932684) (xy 116.519124 113.840643) (xy 116.519119 113.840641)
(xy 116.352697 113.785494) (xy 116.35269 113.785493) (xy 116.249986 113.775) (xy 116.2 113.775)
(xy 116.2 114.75) (xy 115.7 114.75) (xy 115.7 113.775) (xy 115.699999 113.774999) (xy 115.650029 113.775)
(xy 115.650011 113.775001) (xy 115.547302 113.785494) (xy 115.38088 113.840641) (xy 115.380875 113.840643)
(xy 115.231654 113.932684) (xy 115.107683 114.056655) (xy 115.107681 114.056658) (xy 115.105536 114.060136)
(xy 115.103442 114.062018) (xy 115.103202 114.062323) (xy 115.10315 114.062281) (xy 115.053587 114.106858)
(xy 114.984624 114.118078) (xy 114.920543 114.090232) (xy 114.894464 114.060136) (xy 114.892318 114.056658)
(xy 114.892316 114.056655) (xy 114.768345 113.932684) (xy 114.619124 113.840643) (xy 114.619119 113.840641)
(xy 114.452697 113.785494) (xy 114.45269 113.785493) (xy 114.349986 113.775) (xy 114.3 113.775)
(xy 113.8 113.775) (xy 113.799999 113.774999) (xy 113.750029 113.775) (xy 113.750011 113.775001)
(xy 113.647302 113.785494) (xy 113.48088 113.840641) (xy 113.480875 113.840643) (xy 113.331654 113.932684)
(xy 113.207684 114.056654) (xy 113.115643 114.205875) (xy 113.115641 114.20588) (xy 113.060494 114.372302)
(xy 113.060493 114.372309) (xy 113.05 114.475013) (xy 105.5005 114.475013) (xy 105.5005 110.474996)
(xy 113.045 110.474996) (xy 113.054701 110.573507) (xy 113.054701 110.57351) (xy 113.073732 110.66919)
(xy 113.073735 110.669202) (xy 113.0871 110.721565) (xy 113.087103 110.721573) (xy 113.149135 110.851231)
(xy 113.14914 110.851238) (xy 113.20331 110.93231) (xy 113.203335 110.932345) (xy 113.235725 110.975616)
(xy 113.342664 111.071672) (xy 113.342671 111.071677) (xy 113.423745 111.125849) (xy 113.423771 111.125866)
(xy 113.470256 111.153445) (xy 113.470254 111.153445) (xy 113.60581 111.201267) (xy 113.701474 111.220295)
(xy 113.701492 111.220298) (xy 113.799999 111.229999) (xy 113.8 111.229999) (xy 113.8 110.25) (xy 113.045 110.25)
(xy 113.045 110.474996) (xy 105.5005 110.474996) (xy 105.5005 109.124) (xy 105.520185 109.056961)
(xy 105.572989 109.011206) (xy 105.6245 109) (xy 113.019649 109) (xy 113.086688 109.019685) (xy 113.132443 109.072489)
(xy 113.142387 109.141647) (xy 113.126292 109.187271) (xy 113.121554 109.195256) (xy 113.073732 109.33081)
(xy 113.073732 109.330811) (xy 113.054704 109.426474) (xy 113.054701 109.426492) (xy 113.045 109.525003)
(xy 113.045 109.75) (xy 113.926 109.75) (xy 113.993039 109.769685) (xy 114.038794 109.822489) (xy 114.05 109.874)
(xy 114.05 110) (xy 114.176 110) (xy 114.243039 110.019685) (xy 114.288794 110.072489) (xy 114.3 110.124)
(xy 114.3 111.229999) (xy 114.398507 111.220298) (xy 114.39851 111.220298) (xy 114.49419 111.201267)
(xy 114.494202 111.201264) (xy 114.546565 111.187899) (xy 114.546573 111.187896) (xy 114.676231 111.125864)
(xy 114.676238 111.125859) (xy 114.75731 111.071689) (xy 114.757345 111.071664) (xy 114.800616 111.039274)
(xy 114.896671 110.932336) (xy 114.896889 110.932011) (xy 114.89699 110.931926) (xy 114.899393 110.928834)
(xy 114.900064 110.929356) (xy 114.950495 110.887199) (xy 115.019819 110.878482) (xy 115.082851 110.908629)
(xy 115.10227 110.931042) (xy 115.102365 110.930975) (xy 115.103048 110.93194) (xy 115.103119 110.932022)
(xy 115.103335 110.932346) (xy 115.135725 110.975616) (xy 115.242664 111.071672) (xy 115.242671 111.071677)
(xy 115.323745 111.125849) (xy 115.323771 111.125866) (xy 115.370256 111.153445) (xy 115.370254 111.153445)
(xy 115.50581 111.201267) (xy 115.601474 111.220295) (xy 115.601492 111.220298) (xy 115.700003 111.23)
(xy 116.199997 111.23) (xy 116.298507 111.220298) (xy 116.29851 111.220298) (xy 116.39419 111.201267)
(xy 116.394202 111.201264) (xy 116.446565 111.187899) (xy 116.446573 111.187896) (xy 116.576231 111.125864)
(xy 116.576238 111.125859) (xy 116.65731 111.071689) (xy 116.657345 111.071664) (xy 116.700616 111.039274)
(xy 116.796672 110.932335) (xy 116.796677 110.932328) (xy 116.850849 110.851254) (xy 116.850866 110.851228)
(xy 116.878445 110.804744) (xy 116.926267 110.669189) (xy 116.926267 110.669188) (xy 116.945295 110.573525)
(xy 116.945298 110.573507) (xy 116.955 110.474996) (xy 116.955 110.25) (xy 116.124 110.25) (xy 116.056961 110.230315)
(xy 116.011206 110.177511) (xy 116 110.126) (xy 116 109.874) (xy 116.019685 109.806961) (xy 116.072489 109.761206)
(xy 116.124 109.75) (xy 116.955 109.75) (xy 116.955 109.525003) (xy 116.945298 109.426492) (xy 116.945298 109.426489)
(xy 116.926267 109.330809) (xy 116.926264 109.330797) (xy 116.912899 109.278434) (xy 116.912896 109.278426)
(xy 116.850864 109.148768) (xy 116.850859 109.148761) (xy 116.796689 109.067689) (xy 116.796664 109.067654)
(xy 116.764274 109.024383) (xy 116.657335 108.928327) (xy 116.657328 108.928322) (xy 116.576254 108.87415)
(xy 116.576228 108.874133) (xy 116.529743 108.846554) (xy 116.529745 108.846554) (xy 116.394189 108.798732)
(xy 116.298525 108.779704) (xy 116.298507 108.779701) (xy 116.199997 108.77) (xy 115.700003 108.77)
(xy 115.601492 108.779701) (xy 115.601489 108.779701) (xy 115.505809 108.798732) (xy 115.505797 108.798735)
(xy 115.453434 108.8121) (xy 115.453426 108.812103) (xy 115.323768 108.874135) (xy 115.323761 108.87414)
(xy 115.242689 108.92831) (xy 115.24266 108.928331) (xy 115.198308 108.961531) (xy 115.132843 108.985946)
(xy 115.064571 108.971093) (xy 115.015166 108.921686) (xy 115 108.862262) (xy 115 105.6245) (xy 115.019685 105.557461)
(xy 115.072489 105.511706) (xy 115.124 105.5005) (xy 124.3755 105.5005)
)
)
)
)

View File

@ -0,0 +1,286 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"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.05,
"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.1,
"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.1,
"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.0,
"height": 1.45,
"width": 1.0
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"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": "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_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"lib_footprint_mismatch": "ignore",
"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.5,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 4,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "test_thermal_spoke_count.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"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.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"legacy_lib_dir": "",
"legacy_lib_list": []
},
"sheets": [],
"text_variables": {}
}

View File

@ -65,6 +65,7 @@ set( QA_PCBNEW_SRCS
drc/test_drc_skew.cpp
drc/test_drc_component_classes.cpp
drc/test_drc_incorrect_text_mirror.cpp
drc/test_drc_starved_thermal.cpp
pcb_io/altium/test_altium_rule_transformer.cpp
pcb_io/altium/test_altium_pcblib_import.cpp

View File

@ -0,0 +1,101 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <pad.h>
#include <pcb_track.h>
#include <pcb_marker.h>
#include <footprint.h>
#include <drc/drc_item.h>
#include <settings/settings_manager.h>
struct DRC_REGRESSION_TEST_FIXTURE
{
// clang-format off : suggestions look worse.
DRC_REGRESSION_TEST_FIXTURE() : m_settingsManager( true /* headless */ ) {}
// clang-format on
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<BOARD> m_board;
};
BOOST_FIXTURE_TEST_CASE( DRCStarvedThermal, DRC_REGRESSION_TEST_FIXTURE )
{
// Check for starved thermal connection
// clang-format off : suggestions look worse.
std::vector<std::pair<wxString, int>> tests = {
{ "test_starved_thermal", 2 },
};
// clang-format on
for( const std::pair<wxString, int>& test : tests )
{
KI_TEST::LoadBoard( m_settingsManager, test.first, m_board );
KI_TEST::FillZones( m_board.get() );
std::vector<DRC_ITEM> violations;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// Ensure that our desired error is fired
bds.m_DRCSeverities[DRCE_STARVED_THERMAL] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );
} );
bds.m_DRCEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
if( violations.size() == test.second )
{
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
BOOST_TEST_MESSAGE( wxString::Format( "DRC starved thermal: %s, passed", test.first ) );
}
else
{
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 starved thermal: %s, failed (violations found %d expected %d)", test.first,
(int) violations.size(), test.second ) );
}
}
}