ADDED: Minimum copper connection width DRC check
Checks all copper connections in each net/layer for minimum width setting. Fixes https://gitlab.com/kicad/code/kicad/issues/9870
This commit is contained in:
parent
e454595348
commit
3081023b5e
|
@ -504,6 +504,7 @@ set( BMAPS_MID
|
|||
via_sketch
|
||||
via_diameter
|
||||
via_hole_diameter
|
||||
width_conn
|
||||
width_track_via
|
||||
width_track
|
||||
zip
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 348 B |
Binary file not shown.
After Width: | Height: | Size: 392 B |
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="Слой_1"
|
||||
data-name="Слой 1"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
sodipodi:docname="width_conn.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2099"
|
||||
id="namedview30"
|
||||
showgrid="true"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="9.3450346"
|
||||
inkscape:cy="18.573014"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="37"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="Слой_1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid_kicad"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
color="#9999ff"
|
||||
opacity="0.13"
|
||||
empspacing="2" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata43">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>width_track</dc:title>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs160374">
|
||||
<style
|
||||
id="style160372">.cls-1,.cls-2{fill:none;stroke-linecap:round;stroke-linejoin:round;}.cls-1{stroke:#1a81c4;stroke-width:2px;}.cls-2{stroke:#545454;}.cls-3{fill:#545454;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title160376">width_track</title>
|
||||
<path
|
||||
id="polyline160378"
|
||||
style="fill:#42b8eb;fill-opacity:1;stroke:#42b8eb;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 19,20 h 4 V 4 h -4 l -3,8 3,8"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="8.5"
|
||||
y1="10"
|
||||
x2="14.5"
|
||||
y2="10"
|
||||
id="line160380"
|
||||
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ded3dd;stroke-opacity:1" />
|
||||
<polygon
|
||||
class="cls-5"
|
||||
points="16.038,14.028 13.984,16.082 11.178,11.222 "
|
||||
id="polygon858"
|
||||
transform="matrix(-1.5444005,-0.7071068,1.5444005,-0.7071068,11.432046,25.339192)"
|
||||
style="fill:#ded3dd;stroke:none;stroke-width:0.676648;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;fill-opacity:1" />
|
||||
<path
|
||||
id="polyline160378-3"
|
||||
style="fill:#42b8eb;fill-opacity:1;stroke:#42b8eb;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 1,4 V 20 H 4 L 7,12 4,4 H 1"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#42b8eb;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 7,12 h 9.666667"
|
||||
id="path959" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="11.5"
|
||||
y1="7"
|
||||
x2="11.5"
|
||||
y2="1"
|
||||
id="line993"
|
||||
style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ded3dd;stroke-opacity:1" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="14.5"
|
||||
y1="14"
|
||||
x2="8.5"
|
||||
y2="14"
|
||||
id="line995"
|
||||
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ded3dd;stroke-opacity:1" />
|
||||
<polygon
|
||||
class="cls-5"
|
||||
points="16.038,14.028 13.984,16.082 11.178,11.222 "
|
||||
id="polygon997"
|
||||
transform="matrix(1.5444005,0.7071068,-1.5444005,0.7071068,11.567954,-1.339192)"
|
||||
style="fill:#ded3dd;stroke:none;stroke-width:0.676648;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;fill-opacity:1" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="11.5"
|
||||
y1="17"
|
||||
x2="11.5"
|
||||
y2="23"
|
||||
id="line999"
|
||||
style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ded3dd;stroke-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="Слой_1"
|
||||
data-name="Слой 1"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
sodipodi:docname="width_conn.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<path
|
||||
id="polyline160378"
|
||||
style="fill:#1a81c4;fill-opacity:1;stroke:#1a81c4;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 19,20 h 4 V 4 h -4 l -3,8 3,8"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
id="polyline160378-3"
|
||||
style="fill:#1a81c4;fill-opacity:1;stroke:#1a81c4;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 1,4 V 20 H 4 L 7,12 4,4 H 1"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1793"
|
||||
inkscape:window-height="959"
|
||||
id="namedview30"
|
||||
showgrid="true"
|
||||
inkscape:zoom="22.627417"
|
||||
inkscape:cx="10.171091"
|
||||
inkscape:cy="14.382296"
|
||||
inkscape:window-x="4119"
|
||||
inkscape:window-y="214"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="Слой_1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid_kicad"
|
||||
spacingx="0.5"
|
||||
spacingy="0.5"
|
||||
color="#9999ff"
|
||||
opacity="0.13"
|
||||
empspacing="2" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata43">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>width_track</dc:title>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs160374">
|
||||
<style
|
||||
id="style160372">.cls-1,.cls-2{fill:none;stroke-linecap:round;stroke-linejoin:round;}.cls-1{stroke:#1a81c4;stroke-width:2px;}.cls-2{stroke:#545454;}.cls-3{fill:#545454;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title160376">width_track</title>
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="8.5"
|
||||
y1="10"
|
||||
x2="14.5"
|
||||
y2="10"
|
||||
id="line160380"
|
||||
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<polygon
|
||||
class="cls-5"
|
||||
points="16.038,14.028 13.984,16.082 11.178,11.222 "
|
||||
id="polygon858"
|
||||
transform="matrix(-1.5444005,-0.7071068,1.5444005,-0.7071068,11.432046,25.339192)"
|
||||
style="fill:#545454;stroke:none;stroke-width:0.676648;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<path
|
||||
style="fill:none;stroke:#1a81c4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 7,12 h 9.666667"
|
||||
id="path959" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="11.5"
|
||||
y1="7"
|
||||
x2="11.5"
|
||||
y2="1"
|
||||
id="line993"
|
||||
style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="14.5"
|
||||
y1="14"
|
||||
x2="8.5"
|
||||
y2="14"
|
||||
id="line995"
|
||||
style="stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<polygon
|
||||
class="cls-5"
|
||||
points="16.038,14.028 13.984,16.082 11.178,11.222 "
|
||||
id="polygon997"
|
||||
transform="matrix(1.5444005,0.7071068,-1.5444005,0.7071068,11.567954,-1.339192)"
|
||||
style="fill:#545454;stroke:none;stroke-width:0.676648;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<line
|
||||
class="cls-2"
|
||||
x1="11.5"
|
||||
y1="17"
|
||||
x2="11.5"
|
||||
y2="23"
|
||||
id="line999"
|
||||
style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</svg>
|
After Width: | Height: | Size: 4.7 KiB |
|
@ -191,8 +191,6 @@ static const wxChar AllowManualCanvasScale[] = wxT( "AllowManualCanvasScale" );
|
|||
|
||||
static const wxChar UpdateUIEventInterval[] = wxT( "UpdateUIEventInterval" );
|
||||
|
||||
static const wxChar AllowTeardrops[] = wxT( "AllowTeardrops" );
|
||||
|
||||
static const wxChar V3DRT_BevelHeight_um[] = wxT( "V3DRT_BevelHeight_um" );
|
||||
|
||||
static const wxChar V3DRT_BevelExtentFactor[] = wxT( "V3DRT_BevelExtentFactor" );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 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 as published by the
|
||||
|
@ -525,6 +525,7 @@ const std::vector<BITMAP_INFO> g_BitmapInfo = {
|
|||
{ BITMAPS::via_sketch, wxT( "via_sketch_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::via_diameter, wxT( "via_diameter_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::via_hole_diameter, wxT( "via_hole_diameter_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::width_conn, wxT( "width_conn_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::width_track_via, wxT( "width_track_via_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::width_track, wxT( "width_track_24.png" ), 24, wxT( "light" ) },
|
||||
{ BITMAPS::zip, wxT( "zip_24.png" ), 24, wxT( "light" ) },
|
||||
|
@ -900,6 +901,7 @@ const std::vector<BITMAP_INFO> g_BitmapInfo = {
|
|||
{ BITMAPS::via_sketch, wxT( "via_sketch_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::via_diameter, wxT( "via_diameter_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::via_hole_diameter, wxT( "via_hole_diameter_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::width_conn, wxT( "width_conn_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::width_track_via, wxT( "width_track_via_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::width_track, wxT( "width_track_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
{ BITMAPS::zip, wxT( "zip_dark_24.png" ), 24, wxT( "dark" ) },
|
||||
|
|
|
@ -596,6 +596,7 @@ enum class BITMAPS : unsigned int
|
|||
viewlibs_icon,
|
||||
visibility,
|
||||
visibility_off,
|
||||
width_conn,
|
||||
width_track,
|
||||
width_track_via,
|
||||
wizard_add_fplib_icon,
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#define DEFAULT_CUSTOMDPAIRVIAGAP 0.18
|
||||
|
||||
#define DEFAULT_MINCLEARANCE 0.0 // overall min clearance
|
||||
#define DEFAULT_MINCONNECTION 0.0 // overall min connection width
|
||||
#define DEFAULT_TRACKMINWIDTH 0.2 // track width min value
|
||||
#define DEFAULT_VIASMINSIZE 0.4 // vias (not micro vias) min diameter
|
||||
#define DEFAULT_MINTHROUGHDRILL 0.3 // through holes (not micro vias) min drill diameter
|
||||
|
@ -682,6 +683,7 @@ public:
|
|||
bool m_TempOverrideTrackWidth; // use selected track width temporarily even when
|
||||
// using connected track width
|
||||
int m_MinClearance; // overall min clearance
|
||||
int m_MinConn; // overall min connection width
|
||||
int m_TrackMinWidth; // overall min track width
|
||||
int m_ViasMinAnnularWidth; // overall minimum width of the via copper ring
|
||||
int m_ViasMinSize; // overall vias (not micro vias) min diameter
|
||||
|
|
|
@ -239,6 +239,7 @@ set( PCBNEW_DRC_SRCS
|
|||
drc/drc_test_provider_annular_width.cpp
|
||||
drc/drc_test_provider_disallow.cpp
|
||||
drc/drc_test_provider_connectivity.cpp
|
||||
drc/drc_test_provider_connection_width.cpp
|
||||
drc/drc_test_provider_copper_clearance.cpp
|
||||
drc/drc_test_provider_physical_clearance.cpp
|
||||
drc/drc_test_provider_courtyard_clearance.cpp
|
||||
|
|
|
@ -141,6 +141,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
|
|||
m_customDiffPair.m_ViaGap = Millimeter2iu( DEFAULT_CUSTOMDPAIRVIAGAP );
|
||||
|
||||
m_MinClearance = Millimeter2iu( DEFAULT_MINCLEARANCE );
|
||||
m_MinConn = Millimeter2iu( DEFAULT_MINCONNECTION );
|
||||
m_TrackMinWidth = Millimeter2iu( DEFAULT_TRACKMINWIDTH );
|
||||
m_ViasMinAnnularWidth = Millimeter2iu( DEFAULT_VIASMINSIZE - DEFAULT_MINTHROUGHDRILL ) / 2;
|
||||
m_ViasMinSize = Millimeter2iu( DEFAULT_VIASMINSIZE );
|
||||
|
@ -188,6 +189,9 @@ 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;
|
||||
|
||||
// TODO: Change to warning after testing
|
||||
m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = RPT_SEVERITY_IGNORE;
|
||||
|
||||
m_MaxError = ARC_HIGH_DEF;
|
||||
m_ZoneKeepExternalFillets = false;
|
||||
m_UseHeightForLengthCalcs = true;
|
||||
|
@ -231,6 +235,10 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
|
|||
&m_MinClearance, Millimeter2iu( DEFAULT_MINCLEARANCE ),
|
||||
Millimeter2iu( 0.01 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
|
||||
|
||||
m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_connection",
|
||||
&m_MinConn, Millimeter2iu( DEFAULT_MINCONNECTION ),
|
||||
Millimeter2iu( 0.00 ), Millimeter2iu( 100.0 ), MM_PER_IU ) );
|
||||
|
||||
m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_track_width",
|
||||
&m_TrackMinWidth, Millimeter2iu( DEFAULT_TRACKMINWIDTH ),
|
||||
Millimeter2iu( 0.01 ), Millimeter2iu( 25.0 ), MM_PER_IU ) );
|
||||
|
@ -818,6 +826,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
|
|||
m_CurrentViaType = aOther.m_CurrentViaType;
|
||||
m_UseConnectedTrackWidth = aOther.m_UseConnectedTrackWidth;
|
||||
m_MinClearance = aOther.m_MinClearance;
|
||||
m_MinConn = aOther.m_MinConn;
|
||||
m_TrackMinWidth = aOther.m_TrackMinWidth;
|
||||
m_ViasMinAnnularWidth = aOther.m_ViasMinAnnularWidth;
|
||||
m_ViasMinSize = aOther.m_ViasMinSize;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
PANEL_SETUP_CONSTRAINTS::PANEL_SETUP_CONSTRAINTS( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFrame ) :
|
||||
PANEL_SETUP_CONSTRAINTS_BASE( aParent->GetTreebook() ),
|
||||
m_minClearance( aFrame, m_clearanceTitle, m_clearanceCtrl, m_clearanceUnits ),
|
||||
m_minConn( aFrame, m_MinConnTitle, m_MinConnCtrl, m_MinConnUnits ),
|
||||
m_trackMinWidth( aFrame, m_TrackMinWidthTitle, m_TrackMinWidthCtrl, m_TrackMinWidthUnits ),
|
||||
m_viaMinAnnulus( aFrame, m_ViaMinAnnulusTitle, m_ViaMinAnnulusCtrl, m_ViaMinAnnulusUnits ),
|
||||
m_viaMinSize( aFrame, m_ViaMinTitle, m_SetViasMinSizeCtrl, m_ViaMinUnits ),
|
||||
|
@ -78,6 +79,7 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataToWindow()
|
|||
m_minResolvedSpokeCountCtrl->SetValue( m_BrdSettings->m_MinResolvedSpokes );
|
||||
|
||||
m_minClearance.SetValue( m_BrdSettings->m_MinClearance );
|
||||
m_minConn.SetValue( m_BrdSettings->m_MinConn );
|
||||
m_trackMinWidth.SetValue( m_BrdSettings->m_TrackMinWidth );
|
||||
m_viaMinAnnulus.SetValue( m_BrdSettings->m_ViasMinAnnularWidth );
|
||||
m_viaMinSize.SetValue(m_BrdSettings->m_ViasMinSize );
|
||||
|
@ -103,6 +105,9 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataFromWindow()
|
|||
if( !m_minClearance.Validate( 0, 10, EDA_UNITS::INCHES ) )
|
||||
return false;
|
||||
|
||||
if( !m_minConn.Validate( 0, 10, EDA_UNITS::INCHES ) )
|
||||
return false;
|
||||
|
||||
if( !m_trackMinWidth.Validate( 0, 10, EDA_UNITS::INCHES ) )
|
||||
return false;
|
||||
|
||||
|
@ -138,6 +143,7 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataFromWindow()
|
|||
m_BrdSettings->m_MinResolvedSpokes = m_minResolvedSpokeCountCtrl->GetValue();
|
||||
|
||||
m_BrdSettings->m_MinClearance = m_minClearance.GetValue();
|
||||
m_BrdSettings->m_MinConn = m_minConn.GetValue();
|
||||
m_BrdSettings->m_TrackMinWidth = m_trackMinWidth.GetValue();
|
||||
m_BrdSettings->m_ViasMinAnnularWidth = m_viaMinAnnulus.GetValue();
|
||||
m_BrdSettings->m_ViasMinSize = m_viaMinSize.GetValue();
|
||||
|
@ -171,6 +177,7 @@ bool PANEL_SETUP_CONSTRAINTS::Show( bool aShow )
|
|||
m_spokeBitmap->SetBitmap( KiBitmap( BITMAPS::thermal_spokes ) );
|
||||
m_bitmapClearance->SetBitmap( KiBitmap( BITMAPS::ps_diff_pair_gap ) );
|
||||
m_bitmapMinTrackWidth->SetBitmap( KiBitmap( BITMAPS::width_track ) );
|
||||
m_bitmapMinConn->SetBitmap( KiBitmap( BITMAPS::width_conn ) );
|
||||
m_bitmapMinViaAnnulus->SetBitmap( KiBitmap( BITMAPS::via_annulus ) );
|
||||
m_bitmapMinViaDiameter->SetBitmap( KiBitmap( BITMAPS::via_diameter ) );
|
||||
m_bitmapMinViaDrill->SetBitmap( KiBitmap( BITMAPS::via_hole_diameter ) );
|
||||
|
|
|
@ -50,6 +50,7 @@ private:
|
|||
|
||||
public:
|
||||
UNIT_BINDER m_minClearance;
|
||||
UNIT_BINDER m_minConn;
|
||||
UNIT_BINDER m_trackMinWidth;
|
||||
UNIT_BINDER m_viaMinAnnulus;
|
||||
UNIT_BINDER m_viaMinSize;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.0)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -208,6 +208,23 @@ PANEL_SETUP_CONSTRAINTS_BASE::PANEL_SETUP_CONSTRAINTS_BASE( wxWindow* parent, wx
|
|||
m_TrackMinWidthUnits->Wrap( -1 );
|
||||
fgFeatureConstraints->Add( m_TrackMinWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxLEFT, 5 );
|
||||
|
||||
m_bitmapMinConn = new wxStaticBitmap( m_scrolledWindow, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgFeatureConstraints->Add( m_bitmapMinConn, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
|
||||
|
||||
m_MinConnTitle = new wxStaticText( m_scrolledWindow, wxID_ANY, _("Minimum connection width:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
|
||||
m_MinConnTitle->Wrap( -1 );
|
||||
fgFeatureConstraints->Add( m_MinConnTitle, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT, 5 );
|
||||
|
||||
m_MinConnCtrl = new wxTextCtrl( m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_MinConnCtrl->SetToolTip( _("The minimum track width. If set, this is an absolute minimum and cannot be reduced by netclasses, custom rules, or other settings.") );
|
||||
m_MinConnCtrl->SetMinSize( wxSize( 120,-1 ) );
|
||||
|
||||
fgFeatureConstraints->Add( m_MinConnCtrl, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM|wxEXPAND|wxTOP, 5 );
|
||||
|
||||
m_MinConnUnits = new wxStaticText( m_scrolledWindow, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
|
||||
m_MinConnUnits->Wrap( -1 );
|
||||
fgFeatureConstraints->Add( m_MinConnUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxLEFT, 5 );
|
||||
|
||||
m_bitmapMinViaAnnulus = new wxStaticBitmap( m_scrolledWindow, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgFeatureConstraints->Add( m_bitmapMinViaAnnulus, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
|
@ -14,6 +14,7 @@
|
|||
<property name="file">panel_setup_constraints_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">panel_setup_constraints_base</property>
|
||||
|
@ -25,6 +26,7 @@
|
|||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">1</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
|
@ -46,6 +48,7 @@
|
|||
<property name="size">-1,-1</property>
|
||||
<property name="subclass">; forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
|
@ -2118,6 +2121,250 @@
|
|||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticBitmap" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_bitmapMinConn</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Minimum connection width:</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_MinConnTitle</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxALIGN_LEFT</property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxBOTTOM|wxEXPAND|wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">120,-1</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_MinConnCtrl</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">The minimum track width. If set, this is an absolute minimum and cannot be reduced by netclasses, custom rules, or other settings.</property>
|
||||
<property name="validator_data_type">wxString</property>
|
||||
<property name="validator_style">wxFILTER_NUMERIC</property>
|
||||
<property name="validator_type">wxTextValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">mm</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_MinConnUnits</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxALIGN_LEFT</property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.0)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -70,6 +70,10 @@ class PANEL_SETUP_CONSTRAINTS_BASE : public wxPanel
|
|||
wxStaticText* m_TrackMinWidthTitle;
|
||||
wxTextCtrl* m_TrackMinWidthCtrl;
|
||||
wxStaticText* m_TrackMinWidthUnits;
|
||||
wxStaticBitmap* m_bitmapMinConn;
|
||||
wxStaticText* m_MinConnTitle;
|
||||
wxTextCtrl* m_MinConnCtrl;
|
||||
wxStaticText* m_MinConnUnits;
|
||||
wxStaticBitmap* m_bitmapMinViaAnnulus;
|
||||
wxStaticText* m_ViaMinAnnulusTitle;
|
||||
wxTextCtrl* m_ViaMinAnnulusCtrl;
|
||||
|
@ -131,6 +135,7 @@ class PANEL_SETUP_CONSTRAINTS_BASE : public wxPanel
|
|||
wxScrolledWindow* m_scrolledWindow;
|
||||
|
||||
PANEL_SETUP_CONSTRAINTS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~PANEL_SETUP_CONSTRAINTS_BASE();
|
||||
|
||||
};
|
||||
|
|
|
@ -108,6 +108,10 @@ DRC_ITEM DRC_ITEM::holesCoLocated( DRCE_DRILLED_HOLES_COLOCATED,
|
|||
_( "Drilled holes co-located" ),
|
||||
wxT( "holes_co_located" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::connectionWidth( DRCE_CONNECTION_WIDTH,
|
||||
_( "Copper connection too narrow" ),
|
||||
wxT( "connection_width" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::trackWidth( DRCE_TRACK_WIDTH,
|
||||
_( "Track width" ),
|
||||
wxT( "track_width" ) );
|
||||
|
@ -276,6 +280,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
|
|||
DRC_ITEM::invalidOutline,
|
||||
DRC_ITEM::copperSliver,
|
||||
DRC_ITEM::solderMaskBridge,
|
||||
DRC_ITEM::connectionWidth,
|
||||
|
||||
DRC_ITEM::heading_schematic_parity,
|
||||
DRC_ITEM::duplicateFootprints,
|
||||
|
@ -335,6 +340,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
|
|||
case DRCE_DRILLED_HOLES_TOO_CLOSE: return std::make_shared<DRC_ITEM>( holeNearHole );
|
||||
case DRCE_DRILLED_HOLES_COLOCATED: return std::make_shared<DRC_ITEM>( holesCoLocated );
|
||||
case DRCE_HOLE_CLEARANCE: return std::make_shared<DRC_ITEM>( holeClearance );
|
||||
case DRCE_CONNECTION_WIDTH: return std::make_shared<DRC_ITEM>( connectionWidth );
|
||||
case DRCE_TRACK_WIDTH: return std::make_shared<DRC_ITEM>( trackWidth );
|
||||
case DRCE_ANNULAR_WIDTH: return std::make_shared<DRC_ITEM>( annularWidth );
|
||||
case DRCE_DRILL_OUT_OF_RANGE: return std::make_shared<DRC_ITEM>( drillTooSmall );
|
||||
|
|
|
@ -53,6 +53,7 @@ enum PCB_DRC_CODE {
|
|||
DRCE_HOLE_CLEARANCE, //
|
||||
DRCE_TRACK_WIDTH, // Track width is too small or too large
|
||||
DRCE_ANNULAR_WIDTH, // Via size and drill leave annular ring too small
|
||||
DRCE_CONNECTION_WIDTH, // Net connection too small
|
||||
DRCE_DRILL_OUT_OF_RANGE, // Too small via or pad drill
|
||||
DRCE_VIA_DIAMETER, // Via diameter checks (min/max)
|
||||
DRCE_PADSTACK, // something is wrong with a pad or via stackup
|
||||
|
@ -168,6 +169,7 @@ private:
|
|||
static DRC_ITEM holeNearHole;
|
||||
static DRC_ITEM holesCoLocated;
|
||||
static DRC_ITEM holeClearance;
|
||||
static DRC_ITEM connectionWidth;
|
||||
static DRC_ITEM trackWidth;
|
||||
static DRC_ITEM annularWidth;
|
||||
static DRC_ITEM drillTooSmall;
|
||||
|
|
|
@ -374,6 +374,30 @@ public:
|
|||
return collision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the BOARD_ITEMs that overlap the specified point/layer
|
||||
* @param aPt Position on the tree
|
||||
* @param aLayer Layer to search
|
||||
* @return vector of overlapping BOARD_ITEMS*
|
||||
*/
|
||||
std::set<BOARD_ITEM*> GetObjectsAt( const VECTOR2I& aPt, PCB_LAYER_ID aLayer, int aClearance = 0 )
|
||||
{
|
||||
std::set<BOARD_ITEM*> retval;
|
||||
int min[2] = { aPt.x - aClearance, aPt.y - aClearance };
|
||||
int max[2] = { aPt.x + aClearance, aPt.y + aClearance };
|
||||
|
||||
auto visitor =
|
||||
[&]( ITEM_WITH_SHAPE* aItem ) -> bool
|
||||
{
|
||||
retval.insert( aItem->parent );
|
||||
return true;
|
||||
};
|
||||
|
||||
m_tree[aLayer]->Search( min, max, visitor );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef std::pair<PCB_LAYER_ID, PCB_LAYER_ID> LAYER_PAIR;
|
||||
|
||||
struct PAIR_INFO
|
||||
|
|
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 KiCad Developers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* 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/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/debug.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <board.h>
|
||||
#include <board_connected_item.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <drc/drc_rtree.h>
|
||||
#include <footprint.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <math/box2.h>
|
||||
#include <math/vector2d.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <progress_reporter.h>
|
||||
#include <thread_pool.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pad.h>
|
||||
#include <zone.h>
|
||||
|
||||
/*
|
||||
Checks for copper connections that are less than the specified minimum width
|
||||
|
||||
Errors generated:
|
||||
- DRCE_CONNECTION_WIDTH
|
||||
*/
|
||||
|
||||
class DRC_TEST_PROVIDER_CONNECTION_WIDTH : public DRC_TEST_PROVIDER
|
||||
{
|
||||
public:
|
||||
DRC_TEST_PROVIDER_CONNECTION_WIDTH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~DRC_TEST_PROVIDER_CONNECTION_WIDTH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Run() override;
|
||||
|
||||
virtual const wxString GetName() const override
|
||||
{
|
||||
return wxT( "copper width" );
|
||||
};
|
||||
|
||||
virtual const wxString GetDescription() const override
|
||||
{
|
||||
return wxT( "Checks copper nets for connections less than a specified minimum" );
|
||||
}
|
||||
|
||||
private:
|
||||
wxString layerDesc( PCB_LAYER_ID aLayer );
|
||||
};
|
||||
|
||||
|
||||
class POLYGON_TEST
|
||||
{
|
||||
public:
|
||||
POLYGON_TEST( int aLimit ) :
|
||||
m_limit( aLimit )
|
||||
{
|
||||
};
|
||||
|
||||
bool FindPairs( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
m_hits.clear();
|
||||
m_vertices.clear();
|
||||
m_bbox = aPoly.BBox();
|
||||
|
||||
createList( aPoly );
|
||||
|
||||
m_vertices.front().updateList();
|
||||
|
||||
Vertex* p = m_vertices.front().next;
|
||||
std::set<Vertex*> all_hits;
|
||||
|
||||
while( p != &m_vertices.front() )
|
||||
{
|
||||
Vertex* match = nullptr;
|
||||
|
||||
// Only run the expensive search if we don't already have a match for the point
|
||||
if( ( all_hits.empty() || all_hits.count( p ) == 0 ) && ( match = getKink( p ) ) )
|
||||
{
|
||||
if( !all_hits.count( match ) && m_hits.emplace( p->i, match->i ).second )
|
||||
{
|
||||
all_hits.emplace( p );
|
||||
all_hits.emplace( match );
|
||||
all_hits.emplace( p->next );
|
||||
all_hits.emplace( p->prev );
|
||||
all_hits.emplace( match->next );
|
||||
all_hits.emplace( match->prev );
|
||||
}
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return !m_hits.empty();
|
||||
}
|
||||
|
||||
std::set<std::pair<int, int>>& GetVertices()
|
||||
{
|
||||
return m_hits;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
struct Vertex
|
||||
{
|
||||
Vertex( int aIndex, double aX, double aY, POLYGON_TEST* aParent ) :
|
||||
i( aIndex ),
|
||||
x( aX ),
|
||||
y( aY ),
|
||||
parent( aParent )
|
||||
{
|
||||
}
|
||||
|
||||
Vertex& operator=( const Vertex& ) = delete;
|
||||
Vertex& operator=( Vertex&& ) = delete;
|
||||
|
||||
bool operator==( const Vertex& rhs ) const
|
||||
{
|
||||
return this->x == rhs.x && this->y == rhs.y;
|
||||
}
|
||||
bool operator!=( const Vertex& rhs ) const { return !( *this == rhs ); }
|
||||
|
||||
/**
|
||||
* Remove the node from the linked list and z-ordered linked list.
|
||||
*/
|
||||
void remove()
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
|
||||
if( prevZ )
|
||||
prevZ->nextZ = nextZ;
|
||||
|
||||
if( nextZ )
|
||||
nextZ->prevZ = prevZ;
|
||||
|
||||
next = nullptr;
|
||||
prev = nullptr;
|
||||
nextZ = nullptr;
|
||||
prevZ = nullptr;
|
||||
}
|
||||
|
||||
void updateOrder()
|
||||
{
|
||||
if( !z )
|
||||
z = parent->zOrder( x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* After inserting or changing nodes, this function should be called to
|
||||
* remove duplicate vertices and ensure z-ordering is correct.
|
||||
*/
|
||||
void updateList()
|
||||
{
|
||||
Vertex* p = next;
|
||||
|
||||
while( p != this )
|
||||
{
|
||||
/**
|
||||
* Remove duplicates
|
||||
*/
|
||||
if( *p == *p->next )
|
||||
{
|
||||
p = p->prev;
|
||||
p->next->remove();
|
||||
|
||||
if( p == p->next )
|
||||
break;
|
||||
}
|
||||
|
||||
p->updateOrder();
|
||||
p = p->next;
|
||||
};
|
||||
|
||||
updateOrder();
|
||||
zSort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort all vertices in this vertex's list by their Morton code.
|
||||
*/
|
||||
void zSort()
|
||||
{
|
||||
std::deque<Vertex*> queue;
|
||||
|
||||
queue.push_back( this );
|
||||
|
||||
for( Vertex* p = next; p && p != this; p = p->next )
|
||||
queue.push_back( p );
|
||||
|
||||
std::sort( queue.begin(), queue.end(), []( const Vertex* a, const Vertex* b )
|
||||
{
|
||||
return a->z < b->z;
|
||||
} );
|
||||
|
||||
Vertex* prev_elem = nullptr;
|
||||
|
||||
for( Vertex* elem : queue )
|
||||
{
|
||||
if( prev_elem )
|
||||
prev_elem->nextZ = elem;
|
||||
|
||||
elem->prevZ = prev_elem;
|
||||
prev_elem = elem;
|
||||
}
|
||||
|
||||
prev_elem->nextZ = nullptr;
|
||||
}
|
||||
|
||||
const int i;
|
||||
const double x;
|
||||
const double y;
|
||||
POLYGON_TEST* parent;
|
||||
|
||||
// previous and next vertices nodes in a polygon ring
|
||||
Vertex* prev = nullptr;
|
||||
Vertex* next = nullptr;
|
||||
|
||||
// z-order curve value
|
||||
int32_t z = 0;
|
||||
|
||||
// previous and next nodes in z-order
|
||||
Vertex* prevZ = nullptr;
|
||||
Vertex* nextZ = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the Morton code of the Vertex
|
||||
* http://www.graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN
|
||||
*
|
||||
*/
|
||||
int32_t zOrder( const double aX, const double aY ) const
|
||||
{
|
||||
int32_t x = static_cast<int32_t>( 32767.0 * ( aX - m_bbox.GetX() ) / m_bbox.GetWidth() );
|
||||
int32_t y = static_cast<int32_t>( 32767.0 * ( aY - m_bbox.GetY() ) / m_bbox.GetHeight() );
|
||||
|
||||
x = ( x | ( x << 8 ) ) & 0x00FF00FF;
|
||||
x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
|
||||
x = ( x | ( x << 2 ) ) & 0x33333333;
|
||||
x = ( x | ( x << 1 ) ) & 0x55555555;
|
||||
|
||||
y = ( y | ( y << 8 ) ) & 0x00FF00FF;
|
||||
y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
|
||||
y = ( y | ( y << 2 ) ) & 0x33333333;
|
||||
y = ( y | ( y << 1 ) ) & 0x55555555;
|
||||
|
||||
return x | ( y << 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if there is a "substantial" protrusion in each polygon produced by the cut from
|
||||
* aA to aB. Substantial in this case means that the polygon bulges out to a wider cross-section
|
||||
* than the distance from aA to aB
|
||||
* @param aA Starting point in the polygon
|
||||
* @param aB Ending point in the polygon
|
||||
* @return True if the two polygons are both "substantial"
|
||||
*/
|
||||
bool isSubstantial( Vertex* aA, Vertex* aB ) const
|
||||
{
|
||||
// `directions` is a bitfield where
|
||||
// bit 0 = pos y
|
||||
// bit 1 = neg y
|
||||
// bit 2 = pos x
|
||||
// bit 3 = neg x
|
||||
// So, once directions = 15, we have all directions
|
||||
int directions = 0;
|
||||
|
||||
// This is a failsafe in case of invalid lists. Never check
|
||||
// more than the total number of points in m_vertices
|
||||
size_t checked = 0;
|
||||
size_t total_pts = m_vertices.size();
|
||||
|
||||
Vertex* p0 = aA;
|
||||
Vertex* p;
|
||||
Vertex* nz = p0->nextZ;
|
||||
Vertex* pz = p0->prevZ;
|
||||
|
||||
auto same_point = []( const Vertex* a, const Vertex* b ) -> bool
|
||||
{
|
||||
return a && b && a->x == b->x && a->y == b->y;
|
||||
};
|
||||
|
||||
// If we hit a fracture point, we want to continue around the
|
||||
// edge we are working on and not switch to the pair edge
|
||||
// However, this will depend on which direction the initial
|
||||
// fracture hit is. If we find that we skip directly to
|
||||
// a new fracture point, then we know that we are proceeding
|
||||
// in the wrong direction from the fracture and should
|
||||
// fall through to the next point
|
||||
if( same_point( p0, nz ) &&
|
||||
!( same_point( nz->next, nz->next->prevZ ) || same_point( nz->next, nz->next->nextZ ) ) )
|
||||
p = nz->next;
|
||||
else if( same_point( p0, pz ) &&
|
||||
!( same_point( pz->next, pz->next->prevZ ) || same_point( pz->next, pz->next->nextZ ) ) )
|
||||
p = pz->next;
|
||||
else
|
||||
p = p0->next;
|
||||
|
||||
while( p0 != aB && checked < total_pts && directions != 15 )
|
||||
{
|
||||
int bit2x = std::signbit( p->x - p0->x );
|
||||
int bit2y = std::signbit( p->y - p0->y );
|
||||
directions |= ( 1 << ( 2 + bit2x ) ) + ( 1 << bit2y );
|
||||
|
||||
p0 = p;
|
||||
if( same_point( p0, p0->nextZ ) )
|
||||
p = p->nextZ->next;
|
||||
else if( same_point( p0, p0->prevZ ) )
|
||||
p = p->prevZ->next;
|
||||
else
|
||||
p = p->next;
|
||||
|
||||
++checked;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
||||
|
||||
if( directions != 15 )
|
||||
return false;
|
||||
|
||||
p0 = aA;
|
||||
nz = p0->nextZ;
|
||||
pz = p0->prevZ;
|
||||
|
||||
if( nz && same_point( p0, nz ) &&
|
||||
!( same_point( nz->prev, nz->prev->nextZ ) || same_point( nz->prev, nz->prev->prevZ ) ) )
|
||||
p = nz->prev;
|
||||
else if( pz && same_point( p0, pz ) &&
|
||||
!( same_point( pz->prev, pz->prev->nextZ ) || same_point( pz->prev, pz->prev->prevZ ) ) )
|
||||
p = pz->prev;
|
||||
else
|
||||
p = p0->prev;
|
||||
|
||||
directions = 0;
|
||||
checked = 0;
|
||||
|
||||
while( p0 != aB && checked < total_pts && directions != 15 )
|
||||
{
|
||||
int bit2x = std::signbit( p->x - p0->x );
|
||||
int bit2y = std::signbit( p->y - p0->y );
|
||||
directions |= ( 1 << ( 2 + bit2x ) ) + ( 1 << bit2y );
|
||||
|
||||
p0 = p;
|
||||
if( same_point( p, p->nextZ ) )
|
||||
p = p->nextZ->prev;
|
||||
else if( same_point( p, p->prevZ ) )
|
||||
p = p->prevZ->prev;
|
||||
else
|
||||
p = p->prev;
|
||||
|
||||
++checked;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
||||
|
||||
return ( directions == 15 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a #SHAPE_LINE_CHAIN and links each point into a circular, doubly-linked list.
|
||||
*/
|
||||
Vertex* createList( const SHAPE_LINE_CHAIN& points )
|
||||
{
|
||||
Vertex* tail = nullptr;
|
||||
double sum = 0.0;
|
||||
|
||||
// Check for winding order
|
||||
for( int i = 0; i < points.PointCount(); i++ )
|
||||
{
|
||||
VECTOR2D p1 = points.CPoint( i );
|
||||
VECTOR2D p2 = points.CPoint( i + 1 );
|
||||
|
||||
sum += ( ( p2.x - p1.x ) * ( p2.y + p1.y ) );
|
||||
}
|
||||
|
||||
if( sum > 0.0 )
|
||||
for( int i = points.PointCount() - 1; i >= 0; i--)
|
||||
tail = insertVertex( i, points.CPoint( i ), tail );
|
||||
else
|
||||
for( int i = 0; i < points.PointCount(); i++ )
|
||||
tail = insertVertex( i, points.CPoint( i ), tail );
|
||||
|
||||
if( tail && ( *tail == *tail->next ) )
|
||||
{
|
||||
tail->next->remove();
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
Vertex* getKink( Vertex* aPt ) const
|
||||
{
|
||||
// The point needs to be at a concave surface
|
||||
if( locallyInside( aPt->prev, aPt->next ) )
|
||||
return nullptr;
|
||||
|
||||
// z-order range for the current point ± limit bounding box
|
||||
const int32_t maxZ = zOrder( aPt->x + m_limit, aPt->y + m_limit );
|
||||
const int32_t minZ = zOrder( aPt->x - m_limit, aPt->y - m_limit );
|
||||
const SEG::ecoord limit2 = SEG::Square( m_limit );
|
||||
|
||||
// first look for points in increasing z-order
|
||||
Vertex* p = aPt->nextZ;
|
||||
long min_dist = std::numeric_limits<long>::max();
|
||||
Vertex* retval = nullptr;
|
||||
|
||||
while( p && p->z <= maxZ )
|
||||
{
|
||||
int delta_i = std::abs( p->i - aPt->i );
|
||||
VECTOR2D diff( p->x - aPt->x, p->y - aPt->y );
|
||||
SEG::ecoord dist2 = diff.SquaredEuclideanNorm();
|
||||
|
||||
if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
|
||||
&& locallyInside( p, aPt ) && isSubstantial( p, aPt ) )
|
||||
{
|
||||
min_dist = dist2;
|
||||
retval = p;
|
||||
}
|
||||
|
||||
p = p->nextZ;
|
||||
}
|
||||
|
||||
p = aPt->prevZ;
|
||||
|
||||
while( p && p->z >= minZ )
|
||||
{
|
||||
int delta_i = std::abs( p->i - aPt->i );
|
||||
VECTOR2D diff( p->x - aPt->x, p->y - aPt->y );
|
||||
SEG::ecoord dist2 = diff.SquaredEuclideanNorm();
|
||||
|
||||
if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
|
||||
&& locallyInside( p, aPt ) && isSubstantial( p, aPt ) )
|
||||
{
|
||||
min_dist = dist2;
|
||||
retval = p;
|
||||
}
|
||||
|
||||
p = p->prevZ;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the twice the signed area of the triangle formed by vertices p, q, and r.
|
||||
*/
|
||||
double area( const Vertex* p, const Vertex* q, const Vertex* r ) const
|
||||
{
|
||||
return ( q->y - p->y ) * ( r->x - q->x ) - ( q->x - p->x ) * ( r->y - q->y );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the segment from vertex a -> vertex b is inside the polygon
|
||||
* around the immediate area of vertex a.
|
||||
*
|
||||
* We don't define the exact area over which the segment is inside but it is guaranteed to
|
||||
* be inside the polygon immediately adjacent to vertex a.
|
||||
*
|
||||
* @return true if the segment from a->b is inside a's polygon next to vertex a.
|
||||
*/
|
||||
bool locallyInside( const Vertex* a, const Vertex* b ) const
|
||||
{
|
||||
if( area( a->prev, a, a->next ) < 0 )
|
||||
return area( a, b, a->next ) >= 0 && area( a, a->prev, b ) >= 0;
|
||||
else
|
||||
return area( a, b, a->prev ) < 0 || area( a, a->next, b ) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an entry in the vertices lookup and optionally inserts the newly created vertex
|
||||
* into an existing linked list.
|
||||
*
|
||||
* @return a pointer to the newly created vertex.
|
||||
*/
|
||||
Vertex* insertVertex( int aIndex, const VECTOR2I& pt, Vertex* last )
|
||||
{
|
||||
m_vertices.emplace_back( aIndex, pt.x, pt.y, this );
|
||||
|
||||
Vertex* p = &m_vertices.back();
|
||||
|
||||
if( !last )
|
||||
{
|
||||
p->prev = p;
|
||||
p->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->next = last->next;
|
||||
p->prev = last;
|
||||
last->next->prev = p;
|
||||
last->next = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_limit;
|
||||
BOX2I m_bbox;
|
||||
std::deque<Vertex> m_vertices;
|
||||
std::set<std::pair<int, int>> m_hits;
|
||||
};
|
||||
|
||||
|
||||
wxString DRC_TEST_PROVIDER_CONNECTION_WIDTH::layerDesc( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return wxString::Format( wxT( "(%s)" ), m_drcEngine->GetBoard()->GetLayerName( aLayer ) );
|
||||
}
|
||||
|
||||
|
||||
bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_CONNECTION_WIDTH ) )
|
||||
return true; // Continue with other tests
|
||||
|
||||
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();
|
||||
PROGRESS_REPORTER* reporter = m_drcEngine->GetProgressReporter();
|
||||
|
||||
if( reporter && reporter->IsCancelled() )
|
||||
return false; // DRC cancelled
|
||||
|
||||
std::map<PCB_LAYER_ID, std::map<int, std::set<BOARD_CONNECTED_ITEM*>>> net_items;
|
||||
|
||||
DRC_RTREE* tree = board->m_CopperItemRTreeCache.get();
|
||||
|
||||
auto min_checker =
|
||||
[&](const std::set<BOARD_CONNECTED_ITEM*>& aItems, PCB_LAYER_ID aLayer ) -> size_t
|
||||
{
|
||||
|
||||
if( reporter && reporter->IsCancelled() )
|
||||
return 0;
|
||||
|
||||
SHAPE_POLY_SET poly;
|
||||
|
||||
for( BOARD_CONNECTED_ITEM* item : aItems )
|
||||
item->TransformShapeWithClearanceToPolygon( poly, aLayer, 0, ARC_HIGH_DEF, ERROR_OUTSIDE);
|
||||
|
||||
poly.Fracture(SHAPE_POLY_SET::PM_FAST);
|
||||
|
||||
int minimum_width = bds.m_MinConn;
|
||||
POLYGON_TEST test( minimum_width );
|
||||
|
||||
for( int ii = 0; ii < poly.OutlineCount(); ++ii )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& chain = poly.COutline( ii );
|
||||
|
||||
test.FindPairs( chain );
|
||||
auto& ret = test.GetVertices();
|
||||
|
||||
for( const std::pair<int, int>& pt : ret )
|
||||
{
|
||||
VECTOR2I location = ( chain.CPoint( pt.first ) + chain.CPoint( pt.second ) ) / 2;
|
||||
int dist = ( chain.CPoint( pt.first ) - chain.CPoint( pt.second ) ).EuclideanNorm();
|
||||
std::set<BOARD_ITEM*> items = tree->GetObjectsAt( location, aLayer, minimum_width );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CONNECTION_WIDTH );
|
||||
wxString msg;
|
||||
|
||||
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 )
|
||||
{
|
||||
if( item->HitTest( location, minimum_width ) )
|
||||
drce->AddItem( item );
|
||||
}
|
||||
|
||||
reportViolation( drce, location, aLayer );
|
||||
}
|
||||
}
|
||||
|
||||
if( reporter )
|
||||
reporter->AdvanceProgress();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
for( PCB_LAYER_ID layer : copperLayers )
|
||||
{
|
||||
auto& layer_items = net_items[layer];
|
||||
|
||||
for( ZONE* zone : board->Zones() )
|
||||
{
|
||||
if( !zone->GetIsRuleArea() && zone->IsOnLayer( layer ) )
|
||||
layer_items[zone->GetNetCode()].emplace( zone );
|
||||
}
|
||||
|
||||
for( PCB_TRACK* track : board->Tracks() )
|
||||
{
|
||||
if( PCB_VIA* via = dyn_cast<PCB_VIA*>( track ) )
|
||||
{
|
||||
if( via->FlashLayer( static_cast<int>( layer ) ) )
|
||||
layer_items[via->GetNetCode()].emplace( via );
|
||||
}
|
||||
else if( track->IsOnLayer( layer ) )
|
||||
{
|
||||
layer_items[track->GetNetCode()].emplace( track );
|
||||
}
|
||||
}
|
||||
|
||||
for( FOOTPRINT* fp : board->Footprints() )
|
||||
{
|
||||
for( PAD* pad : fp->Pads() )
|
||||
{
|
||||
if( pad->FlashLayer( static_cast<int>( layer ) ) )
|
||||
layer_items[pad->GetNetCode()].emplace( pad );
|
||||
}
|
||||
|
||||
for( FP_ZONE* zone : fp->Zones() )
|
||||
{
|
||||
if( !zone->GetIsRuleArea() && zone->IsOnLayer( layer ) )
|
||||
layer_items[zone->GetNetCode()].emplace( zone );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
std::vector<std::future<size_t>> returns;
|
||||
size_t return_count = 0;
|
||||
|
||||
for( auto& layer_items : net_items )
|
||||
return_count += layer_items.second.size();
|
||||
|
||||
returns.reserve( return_count );
|
||||
|
||||
if( reporter )
|
||||
reporter->SetMaxProgress( return_count );
|
||||
|
||||
for( auto& layer_items : net_items )
|
||||
{
|
||||
for( const auto& items : layer_items.second )
|
||||
{
|
||||
returns.emplace_back( tp.submit( min_checker, items.second, layer_items.first ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( auto& retval : returns )
|
||||
{
|
||||
std::future_status status;
|
||||
|
||||
do
|
||||
{
|
||||
status = retval.wait_for( std::chrono::milliseconds( 100 ) );
|
||||
} while( status != std::future_status::ready );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_CONNECTION_WIDTH> dummy;
|
||||
}
|
|
@ -1300,18 +1300,23 @@ void ZONE::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
if( !m_FilledPolysList.count( aLayer ) )
|
||||
return;
|
||||
|
||||
aCornerBuffer = *m_FilledPolysList.at( aLayer );
|
||||
if( !aClearance )
|
||||
{
|
||||
aCornerBuffer.Append( *m_FilledPolysList.at( aLayer ) );
|
||||
return;
|
||||
}
|
||||
|
||||
SHAPE_POLY_SET temp_buf = m_FilledPolysList.at( aLayer )->CloneDropTriangulation();
|
||||
|
||||
// Rebuild filled areas only if clearance is not 0
|
||||
if( aClearance )
|
||||
{
|
||||
int numSegs = GetArcToSegmentCount( aClearance, aError, FULL_CIRCLE );
|
||||
int numSegs = GetArcToSegmentCount( aClearance, aError, FULL_CIRCLE );
|
||||
|
||||
if( aErrorLoc == ERROR_OUTSIDE )
|
||||
aClearance += aError;
|
||||
if( aErrorLoc == ERROR_OUTSIDE )
|
||||
aClearance += aError;
|
||||
|
||||
aCornerBuffer.InflateWithLinkedHoles( aClearance, numSegs, SHAPE_POLY_SET::PM_FAST );
|
||||
}
|
||||
temp_buf.InflateWithLinkedHoles( aClearance, numSegs, SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
aCornerBuffer.Append( temp_buf );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
(kicad_pcb (version 20220609) (generator pcbnew)
|
||||
|
||||
(general
|
||||
(thickness 0)
|
||||
)
|
||||
|
||||
(paper "A4")
|
||||
(title_block
|
||||
(rev "1")
|
||||
(company "Kicad Demo")
|
||||
)
|
||||
|
||||
(layers
|
||||
(0 "F.Cu" signal "top_copper")
|
||||
(31 "B.Cu" signal "bottom_copper")
|
||||
(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)
|
||||
)
|
||||
|
||||
(setup
|
||||
(pad_to_mask_clearance 0)
|
||||
(pcbplotparams
|
||||
(layerselection 0x0001030_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 6)
|
||||
(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 0)
|
||||
(scaleselection 1)
|
||||
(outputdirectory "plots")
|
||||
)
|
||||
)
|
||||
|
||||
(net 0 "")
|
||||
(net 1 "Net-(D1-Pad2)")
|
||||
|
||||
(footprint "Diode_THT:D_A-405_P7.62mm_Horizontal" (layer "F.Cu")
|
||||
(tstamp 00000000-0000-0000-0000-00005a56d054)
|
||||
(at 134.62 72.39 180)
|
||||
(descr "D, A-405 series, Axial, Horizontal, pin pitch=7.62mm, , length*diameter=5.2*2.7mm^2, , http://www.diodes.com/_files/packages/A-405.pdf")
|
||||
(tags "D A-405 series Axial Horizontal pin pitch 7.62mm length 5.2mm diameter 2.7mm")
|
||||
(property "Sheetfile" "sonde xilinx.kicad_sch")
|
||||
(property "Sheetname" "")
|
||||
(path "/00000000-0000-0000-0000-00003ebf815e")
|
||||
(attr through_hole)
|
||||
(fp_text reference "D1" (at 3.81 -2.47 180) (layer "F.SilkS") hide
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp c8f10b4e-4d84-43c3-b9a8-d3f6adbab717)
|
||||
)
|
||||
(fp_text value "BAT46" (at 3.81 2.47 180) (layer "F.Fab") hide
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp ffcfed93-af35-4520-90de-0339323bff1b)
|
||||
)
|
||||
(fp_line (start -1.15 -1.75) (end -1.15 1.75)
|
||||
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp f7cb6518-da50-4c83-a51a-5cdc52aa486c))
|
||||
(fp_line (start -1.15 1.75) (end 8.8 1.75)
|
||||
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp dff4e628-3677-4cd4-b624-2b4ed43d10c6))
|
||||
(fp_line (start 8.8 -1.75) (end -1.15 -1.75)
|
||||
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp bb93c298-090a-46cc-8824-0ab3dbd4e704))
|
||||
(fp_line (start 8.8 1.75) (end 8.8 -1.75)
|
||||
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 707fefea-0e97-4c8d-8f18-6c94026a6ff8))
|
||||
(pad "2" thru_hole oval (at 7.62 0 180) (size 1.8 1.8) (drill 0.9) (layers *.Cu *.Mask)
|
||||
(net 1 "Net-(D1-Pad2)") (pinfunction "K") (pintype "passive") (tstamp fe2f4a9c-c9df-401c-acfb-1f0a9f7d438a))
|
||||
(model "${KICAD6_3DMODEL_DIR}/Diode_THT.3dshapes/D_A-405_P7.62mm_Horizontal.wrl"
|
||||
(offset (xyz 0 0 0))
|
||||
(scale (xyz 1 1 1))
|
||||
(rotate (xyz 0 0 0))
|
||||
)
|
||||
)
|
||||
|
||||
(gr_rect (start 119.5 69.1) (end 137.3 80.8)
|
||||
(stroke (width 0.1) (type default)) (fill none) (layer "Edge.Cuts") (tstamp 8900a23a-a318-4bb8-8db1-6b52ef189e07))
|
||||
|
||||
(via (at 126.4 78.5) (size 1.651) (drill 0.635) (layers "F.Cu" "B.Cu") (net 1) (tstamp 84387f2a-9959-4d79-a875-53244f1f4e68))
|
||||
(via (at 128.753787 79.665232) (size 0.5) (drill 0.2) (layers "F.Cu" "B.Cu") (net 1) (tstamp b06ca4b8-22df-4ec6-bf66-cf080ffc53d7))
|
||||
(segment (start 121.060406 75.523254) (end 120.717987 74.4931) (width 0.635) (layer "B.Cu") (net 1) (tstamp 0d2541aa-78dc-4d71-8d09-70964c8b4654))
|
||||
(segment (start 122.327576 73.37773) (end 122.669995 74.407884) (width 0.635) (layer "B.Cu") (net 1) (tstamp 1cd2361d-d7b8-46c4-b4c3-b2f9ca61d1df))
|
||||
(segment (start 127.531503 74.6208) (end 127.189084 73.590646) (width 0.635) (layer "B.Cu") (net 1) (tstamp 221799a2-d92f-49a1-94fe-44d3679f5dec))
|
||||
(segment (start 125.5268 73.8632) (end 126.556954 73.520781) (width 0.635) (layer "B.Cu") (net 1) (tstamp 2bf8d6b1-a5d9-4860-b639-a10275827821))
|
||||
(segment (start 125.092037 76.719181) (end 125.692037 77.619181) (width 0.635) (layer "B.Cu") (net 1) (tstamp 318fd778-f069-4bd2-88df-2d5d847e84a5))
|
||||
(segment (start 122.705989 75.036817) (end 121.675835 75.379236) (width 0.635) (layer "B.Cu") (net 1) (tstamp 6362c510-89e2-442a-9bef-a423f67b5f2a))
|
||||
(segment (start 120.684923 73.871209) (end 121.715077 73.52879) (width 0.635) (layer "B.Cu") (net 1) (tstamp 78890dfd-c95e-4f20-85c9-bb0c2e7400d3))
|
||||
(segment (start 126.617499 71.234484) (end 126.27508 70.20433) (width 0.635) (layer "B.Cu") (net 1) (tstamp c0d146af-73e9-4b0c-9981-517c8336104e))
|
||||
(segment (start 130.804351 76.175706) (end 131.834505 75.833287) (width 0.635) (layer "B.Cu") (net 1) (tstamp c3d0bba0-dc16-4de5-8b82-ebcebda9e1dd))
|
||||
(segment (start 125.299606 76.121706) (end 126.32976 75.779287) (width 0.635) (layer "B.Cu") (net 1) (tstamp f955ff3b-6368-47ac-b9bb-dcbce17cd2cd))
|
||||
|
||||
(zone (net 1) (net_name "Net-(D1-Pad2)") (layer "B.Cu") (tstamp 14c4dfe2-825b-4c9b-962f-b07daede2793) (hatch edge 0.508)
|
||||
(connect_pads (clearance 0.508))
|
||||
(min_thickness 0.254) (filled_areas_thickness no)
|
||||
(fill yes (thermal_gap 0.508) (thermal_bridge_width 0.508) (island_removal_mode 1) (island_area_min 10))
|
||||
(polygon
|
||||
(pts
|
||||
(xy 131.5 77.3)
|
||||
(xy 132.8 77)
|
||||
(xy 132.9 77.8)
|
||||
(xy 134.2 77.7)
|
||||
(xy 134.6 77.2)
|
||||
(xy 133.1 79.9)
|
||||
(xy 128.6 79.4)
|
||||
(xy 130.8 76.4)
|
||||
)
|
||||
)
|
||||
(polygon
|
||||
(pts
|
||||
(xy 131.962958 77.241665)
|
||||
(xy 132.01481 77.562503)
|
||||
(xy 132.754165 77.357194)
|
||||
(xy 132.622685 77.072469)
|
||||
)
|
||||
)
|
||||
(filled_polygon
|
||||
(layer "B.Cu")
|
||||
(island)
|
||||
(pts
|
||||
(xy 130.891171 76.519065)
|
||||
(xy 130.902415 76.531677)
|
||||
(xy 131.323031 77.072469)
|
||||
(xy 131.5 77.3)
|
||||
(xy 131.521234 77.2951)
|
||||
(xy 131.624843 77.27119)
|
||||
(xy 131.824172 77.225191)
|
||||
(xy 131.895044 77.229363)
|
||||
(xy 131.952412 77.27119)
|
||||
(xy 131.976888 77.327861)
|
||||
(xy 132.01481 77.562503)
|
||||
(xy 132.700979 77.371963)
|
||||
(xy 132.771967 77.373009)
|
||||
(xy 132.831121 77.412269)
|
||||
(xy 132.859717 77.47774)
|
||||
(xy 132.9 77.8)
|
||||
(xy 134.094101 77.708146)
|
||||
(xy 134.163554 77.722865)
|
||||
(xy 134.214026 77.772796)
|
||||
(xy 134.229489 77.842088)
|
||||
(xy 134.213908 77.894966)
|
||||
(xy 133.140721 79.826702)
|
||||
(xy 133.090154 79.876536)
|
||||
(xy 133.016663 79.89074)
|
||||
(xy 131.216605 79.690734)
|
||||
(xy 128.816526 79.424058)
|
||||
(xy 128.751031 79.396657)
|
||||
(xy 128.710748 79.338195)
|
||||
(xy 128.708467 79.267235)
|
||||
(xy 128.728834 79.224318)
|
||||
(xy 129.960613 77.544619)
|
||||
(xy 130.701351 76.534521)
|
||||
(xy 130.757764 76.491418)
|
||||
(xy 130.828526 76.485656)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
|
@ -0,0 +1,490 @@
|
|||
{
|
||||
"board": {
|
||||
"3dviewports": [],
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"board_outline_line_width": 0.09999999999999999,
|
||||
"copper_line_width": 0.3,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.30479999999999996,
|
||||
"copper_text_upright": true,
|
||||
"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.09999999999999999,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": true,
|
||||
"pads": {
|
||||
"drill": 0.762,
|
||||
"height": 1.524,
|
||||
"width": 1.524
|
||||
},
|
||||
"silk_line_width": 0.3,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.5,
|
||||
"silk_text_size_v": 1.5,
|
||||
"silk_text_thickness": 0.3,
|
||||
"silk_text_upright": true,
|
||||
"zones": {
|
||||
"45_degree_only": false,
|
||||
"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": "error",
|
||||
"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": "error",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_edge_clearance": "warning",
|
||||
"silk_over_copper": "error",
|
||||
"silk_overlap": "error",
|
||||
"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"
|
||||
},
|
||||
"rule_severitieslegacy_courtyards_overlap": true,
|
||||
"rule_severitieslegacy_no_courtyard_defined": false,
|
||||
"rules": {
|
||||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_connection": 0.20099999999999998,
|
||||
"min_copper_edge_clearance": 0.01,
|
||||
"min_hole_clearance": 0.0,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.508,
|
||||
"min_microvia_drill": 0.127,
|
||||
"min_resolved_spokes": 2,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_text_height": 0.7999999999999999,
|
||||
"min_text_thickness": 0.12,
|
||||
"min_through_hole_diameter": 0.508,
|
||||
"min_track_width": 0.2032,
|
||||
"min_via_annular_width": 0.049999999999999996,
|
||||
"min_via_diameter": 0.889,
|
||||
"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,
|
||||
0.4,
|
||||
1.0
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false,
|
||||
"zones_use_no_outline": true
|
||||
},
|
||||
"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_label_syntax": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"extra_units": "error",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"lib_symbol_issues": "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",
|
||||
"unannotated": "error",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "small_conn.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.254,
|
||||
"diff_pair_gap": 0.4,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.4,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.508,
|
||||
"microvia_drill": 0.127,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.635,
|
||||
"via_diameter": 1.651,
|
||||
"via_drill": 0.635,
|
||||
"wire_width": 6.0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"net_colors": null
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "sonde xilinx.net",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"vmrl": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"drawing": {
|
||||
"default_bus_thickness": 12.0,
|
||||
"default_junction_size": 40.0,
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"default_wire_thickness": 6.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,
|
||||
"pin_symbol_size": 25.0,
|
||||
"text_offset_ratio": 0.3
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"net_format_name": "",
|
||||
"ngspice": {
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 0
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [
|
||||
[
|
||||
"5ade2176-b41a-41ec-91fe-ba9644669489",
|
||||
""
|
||||
]
|
||||
],
|
||||
"text_variables": {}
|
||||
}
|
|
@ -45,6 +45,7 @@ set( QA_PCBNEW_SRCS
|
|||
drc/test_drc_courtyard_invalid.cpp
|
||||
drc/test_drc_courtyard_overlap.cpp
|
||||
drc/test_drc_regressions.cpp
|
||||
drc/test_drc_copper_conn.cpp
|
||||
drc/test_solder_mask_bridging.cpp
|
||||
|
||||
plugins/altium/test_altium_rule_transformer.cpp
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* 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
|
||||
{
|
||||
DRC_REGRESSION_TEST_FIXTURE() :
|
||||
m_settingsManager( true /* headless */ )
|
||||
{ }
|
||||
|
||||
SETTINGS_MANAGER m_settingsManager;
|
||||
std::unique_ptr<BOARD> m_board;
|
||||
};
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( DRCCopperConn, DRC_REGRESSION_TEST_FIXTURE )
|
||||
{
|
||||
// Check for minimum copper connection errors
|
||||
|
||||
std::vector<wxString> tests =
|
||||
{
|
||||
"issue9870"
|
||||
};
|
||||
|
||||
for( const wxString& relPath : tests )
|
||||
{
|
||||
KI_TEST::LoadBoard( m_settingsManager, relPath, m_board );
|
||||
KI_TEST::FillZones( m_board.get() );
|
||||
|
||||
std::vector<DRC_ITEM> violations;
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
// Disable DRC tests not useful or not handled in this testcase
|
||||
bds.m_DRCSeverities[ DRCE_INVALID_OUTLINE ] = SEVERITY::RPT_SEVERITY_IGNORE;
|
||||
bds.m_DRCSeverities[ DRCE_UNCONNECTED_ITEMS ] = 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_DRILL_OUT_OF_RANGE ] = SEVERITY::RPT_SEVERITY_IGNORE;
|
||||
bds.m_DRCSeverities[ DRCE_VIA_DIAMETER ] = SEVERITY::RPT_SEVERITY_IGNORE;
|
||||
// These DRC tests are not useful and do not work because they need a footprint library
|
||||
// associated to the board
|
||||
bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_ISSUES ] = SEVERITY::RPT_SEVERITY_IGNORE;
|
||||
bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE;
|
||||
|
||||
bds.m_DRCEngine->SetViolationHandler(
|
||||
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
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() == 12 )
|
||||
{
|
||||
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
|
||||
BOOST_TEST_MESSAGE( wxString::Format( "DRC connection width: %s, passed", relPath ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<KIID, EDA_ITEM*> itemMap;
|
||||
m_board->FillItemMap( itemMap );
|
||||
|
||||
for( const DRC_ITEM& item : violations )
|
||||
{
|
||||
BOOST_TEST_MESSAGE( item.ShowReport( EDA_UNITS::INCHES, RPT_SEVERITY_ERROR,
|
||||
itemMap ) );
|
||||
}
|
||||
|
||||
BOOST_ERROR( wxString::Format( "DRC connection width: %s, failed", relPath ) );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue