Check for zone-zone overlap

Instead of just checking for the zone outline, we adjust to check the
full fill area of the zones for intersection and overlaps

(cherry picked from commit 954b265839)
This commit is contained in:
Seth Hillbrand 2023-07-06 19:23:28 -07:00
parent 90d1695bbc
commit cadea90109
6 changed files with 968 additions and 96 deletions

View File

@ -364,6 +364,14 @@ public:
return A + ( B - A ) / 2; return A + ( B - A ) / 2;
} }
bool operator<( const SEG& aSeg ) const
{
if( A == aSeg.A )
return B < aSeg.B;
return A < aSeg.A;
}
private: private:
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const; bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;

View File

@ -836,6 +836,11 @@ public:
return ( t1.m_Pos != t2.m_Pos || t1.m_Size != t2.m_Size ); return ( t1.m_Pos != t2.m_Pos || t1.m_Size != t2.m_Size );
} }
const bool IsValid() const
{
return m_init;
}
private: private:
Vec m_Pos; // Rectangle Origin Vec m_Pos; // Rectangle Origin
Vec m_Size; // Rectangle Size Vec m_Size; // Rectangle Size

View File

@ -28,6 +28,7 @@
#include <pcb_shape.h> #include <pcb_shape.h>
#include <pad.h> #include <pad.h>
#include <pcb_track.h> #include <pcb_track.h>
#include <thread_pool.h>
#include <zone.h> #include <zone.h>
#include <geometry/seg.h> #include <geometry/seg.h>
@ -41,6 +42,8 @@
#include <drc/drc_test_provider_clearance_base.h> #include <drc/drc_test_provider_clearance_base.h>
#include <pcb_dimension.h> #include <pcb_dimension.h>
#include <future>
/* /*
Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their
electrical clearance. electrical clearance.
@ -993,19 +996,81 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ); bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ); bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT );
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET* boardOutline = nullptr;
DRC_CONSTRAINT constraint; DRC_CONSTRAINT constraint;
int zone2zoneClearance; bool cancelled = false;
std::vector<std::map<PCB_LAYER_ID, std::vector<SEG>>> poly_segments;
if( m_board->GetBoardPolygonOutlines( buffer ) ) poly_segments.resize( m_board->m_DRCCopperZones.size() );
boardOutline = &buffer;
// Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the required clearance, and the layer
using report_data = std::tuple<int, int, VECTOR2I, int, int, PCB_LAYER_ID>;
const int invalid_zone = -1;
std::vector<std::future<report_data>> futures;
thread_pool& tp = GetKiCadThreadPool();
auto checkZones = [testClearance, testIntersects, &poly_segments, &cancelled, invalid_zone]
( int zoneA, int zoneB,
int zone2zoneClearance, PCB_LAYER_ID layer ) -> report_data
{
// Iterate through all the segments of refSmoothedPoly
std::map<VECTOR2I, int> conflictPoints;
std::vector<SEG>& refSegments = poly_segments[zoneA][layer];
std::vector<SEG>& testSegments = poly_segments[zoneB][layer];
bool reported = false;
auto invalid_result = std::make_tuple( invalid_zone, invalid_zone, VECTOR2I(), 0, 0, F_Cu );
for( SEG& refSegment : refSegments )
{
int ax1 = refSegment.A.x;
int ay1 = refSegment.A.y;
int ax2 = refSegment.B.x;
int ay2 = refSegment.B.y;
// Iterate through all the segments in smoothed_polys[ia2]
for( SEG& testSegment : testSegments )
{
// Build test segment
VECTOR2I pt;
int bx1 = testSegment.A.x;
int by1 = testSegment.A.y;
int bx2 = testSegment.B.x;
int by2 = testSegment.B.y;
// We have ensured that the A segment starts before the B segment, so if the
// A segment ends before the B segment starts, we can skip to the next A
if( ax2 < bx1 )
break;
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
ax1, ay1, ax2, ay2, 0,
zone2zoneClearance, &pt.x, &pt.y );
if( d < zone2zoneClearance )
{
if( d == 0 && testIntersects )
reported = true;
else if( testClearance )
reported = true;
if( reported )
return std::make_tuple( zoneA, zoneB, pt, d, zone2zoneClearance, layer );
}
if( cancelled )
return invalid_result;
}
}
return invalid_result;
};
for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id ) for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
{ {
PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id ); PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( layer_id );
std::vector<SHAPE_POLY_SET> smoothed_polys; int zone2zoneClearance;
smoothed_polys.resize( m_board->m_DRCCopperZones.size() );
// Skip over layers not used on the current board // Skip over layers not used on the current board
if( !m_board->IsLayerEnabled( layer ) ) if( !m_board->IsLayerEnabled( layer ) )
@ -1015,12 +1080,30 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
{ {
if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) ) if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) )
{ {
m_board->m_DRCCopperZones[ii]->BuildSmoothedPoly( smoothed_polys[ii], layer, SHAPE_POLY_SET poly =
boardOutline ); *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer );
std::vector<SEG>& poly_segs = poly_segments[ii][layer];
poly.Fracture( SHAPE_POLY_SET::PM_FAST );
poly.BuildBBoxCaches();
poly_segs.reserve( poly.FullPointCount() );
for( auto it = poly.IterateSegmentsWithHoles(); it; it++ )
{
SEG seg = *it;
if( seg.A.x > seg.B.x )
seg.Reverse();
poly_segs.push_back( seg );
}
std::sort( poly_segs.begin(), poly_segs.end() );
} }
} }
// iterate through all areas std::vector<std::pair<int, int>> zonePairs;
for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ ) for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ )
{ {
if( !reportProgress( layer_id * m_board->m_DRCCopperZones.size() + ia, if( !reportProgress( layer_id * m_board->m_DRCCopperZones.size() + ia,
@ -1046,102 +1129,62 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
if( zoneA->GetNetCode() == zoneB->GetNetCode() && zoneA->GetNetCode() >= 0 ) if( zoneA->GetNetCode() == zoneB->GetNetCode() && zoneA->GetNetCode() >= 0 )
continue; continue;
// test for different priorities
if( zoneA->GetAssignedPriority() != zoneB->GetAssignedPriority() )
continue;
// rule areas may overlap at will // rule areas may overlap at will
if( zoneA->GetIsRuleArea() || zoneB->GetIsRuleArea() ) if( zoneA->GetIsRuleArea() || zoneB->GetIsRuleArea() )
continue; continue;
// Examine a candidate zone: compare zoneB to zoneA // Examine a candidate zone: compare zoneB to zoneA
SHAPE_POLY_SET* polyA = m_board->m_DRCCopperZones[ia]->GetFill( layer );
SHAPE_POLY_SET* polyB = m_board->m_DRCCopperZones[ia2]->GetFill( layer );
if( !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
continue;
// Get clearance used in zone to zone test. // Get clearance used in zone to zone test.
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer ); constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
zone2zoneClearance = constraint.GetValue().Min(); zone2zoneClearance = constraint.GetValue().Min();
if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE ) if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE || zone2zoneClearance <= 0 )
continue; continue;
if( testIntersects ) futures.push_back( tp.submit( checkZones, ia, ia2, zone2zoneClearance, layer ) );
{
// test for some corners of zoneA inside zoneB
for( auto it = smoothed_polys[ia].IterateWithHoles(); it; it++ )
{
VECTOR2I currentVertex = *it;
wxPoint pt( currentVertex.x, currentVertex.y );
if( smoothed_polys[ia2].Contains( currentVertex ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
drce->SetItems( zoneA, zoneB );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pt, layer );
}
}
// test for some corners of zoneB inside zoneA
for( auto it = smoothed_polys[ia2].IterateWithHoles(); it; it++ )
{
VECTOR2I currentVertex = *it;
wxPoint pt( currentVertex.x, currentVertex.y );
if( smoothed_polys[ia].Contains( currentVertex ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_ZONES_INTERSECT );
drce->SetItems( zoneB, zoneA );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pt, layer );
} }
} }
} }
// Iterate through all the segments of refSmoothedPoly for( auto& task : futures )
std::map<VECTOR2I, int> conflictPoints;
for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
{ {
// Build ref segment if( !task.valid() )
SEG refSegment = *refIt; continue;
// Iterate through all the segments in smoothed_polys[ia2] std::future_status result;
for( auto it = smoothed_polys[ia2].IterateSegmentsWithHoles(); it; it++ )
while( true )
{ {
// Build test segment result = task.wait_for( std::chrono::milliseconds( 200 ) );
SEG testSegment = *it;
VECTOR2I pt;
int ax1, ay1, ax2, ay2; if( m_drcEngine->IsCancelled() )
ax1 = refSegment.A.x;
ay1 = refSegment.A.y;
ax2 = refSegment.B.x;
ay2 = refSegment.B.y;
int bx1, by1, bx2, by2;
bx1 = testSegment.A.x;
by1 = testSegment.A.y;
bx2 = testSegment.B.x;
by2 = testSegment.B.y;
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
ax1, ay1, ax2, ay2, 0,
zone2zoneClearance, &pt.x, &pt.y );
if( d < zone2zoneClearance )
{ {
if( conflictPoints.count( pt ) ) cancelled = true;
conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d ); break;
else
conflictPoints[ pt ] = d;
}
}
} }
for( const std::pair<const VECTOR2I, int>& conflict : conflictPoints ) if( result == std::future_status::ready )
{ {
int actual = conflict.second; report_data data = task.get();
int zoneA_id = std::get<0>( data );
int zoneB_id = std::get<1>( data );
VECTOR2I pt = std::get<2>( data );
int actual = std::get<3>( data );
int required = std::get<4>( data );
PCB_LAYER_ID layer = std::get<5>( data );
if( zoneA_id != invalid_zone )
{
ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_id];
ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_id];
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
std::shared_ptr<DRC_ITEM> drce; std::shared_ptr<DRC_ITEM> drce;
if( actual <= 0 && testIntersects ) if( actual <= 0 && testIntersects )
@ -1153,7 +1196,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
drce = DRC_ITEM::Create( DRCE_CLEARANCE ); drce = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ), wxString msg = formatMsg( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(), constraint.GetName(),
zone2zoneClearance, required,
std::max( actual, 0 ) ); std::max( actual, 0 ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg ); drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
@ -1164,13 +1207,13 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
drce->SetItems( zoneA, zoneB ); drce->SetItems( zoneA, zoneB );
drce->SetViolatingRule( constraint.GetParentRule() ); drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, conflict.first, layer ); reportViolation( drce, pt, layer );
} }
} }
if( m_drcEngine->IsCancelled() ) break;
return;
} }
} }
} }
} }

View File

@ -0,0 +1,524 @@
(kicad_pcb (version 20230620) (generator pcbnew)
(general
(thickness 1.6)
)
(paper "A4")
(layers
(0 "F.Cu" signal)
(31 "B.Cu" signal)
(32 "B.Adhes" user "B.Adhesive")
(33 "F.Adhes" user "F.Adhesive")
(34 "B.Paste" user)
(35 "F.Paste" user)
(36 "B.SilkS" user "B.Silkscreen")
(37 "F.SilkS" user "F.Silkscreen")
(38 "B.Mask" user)
(39 "F.Mask" user)
(40 "Dwgs.User" user "User.Drawings")
(41 "Cmts.User" user "User.Comments")
(42 "Eco1.User" user "User.Eco1")
(43 "Eco2.User" user "User.Eco2")
(44 "Edge.Cuts" user)
(45 "Margin" user)
(46 "B.CrtYd" user "B.Courtyard")
(47 "F.CrtYd" user "F.Courtyard")
(48 "B.Fab" user)
(49 "F.Fab" user)
(50 "User.1" user)
(51 "User.2" user)
(52 "User.3" user)
(53 "User.4" user)
(54 "User.5" user)
(55 "User.6" user)
(56 "User.7" user)
(57 "User.8" user)
(58 "User.9" user)
)
(setup
(pad_to_mask_clearance 0)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(plot_on_all_layers_selection 0x0000000_00000000)
(disableapertmacros false)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(dashed_line_dash_ratio 12.000000)
(dashed_line_gap_ratio 3.000000)
(svgprecision 4)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(pdf_front_fp_property_popups true)
(pdf_back_fp_property_popups true)
(dxfpolygonmode true)
(dxfimperialunits true)
(dxfusepcbnewfont true)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(sketchpadsonfab false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
(net 1 "A")
(net 2 "B")
(footprint "TestPoint:TestPoint_Pad_1.0x1.0mm" (layer "F.Cu")
(tstamp 0662cfad-e2af-4a28-8e06-54487b2d060f)
(at 126.383886 85.958221)
(descr "SMD rectangular pad as test Point, square 1.0mm side length")
(tags "test point SMD pad rectangle square")
(property "Reference" "REF**" (at 0 -1.448 0 unlocked) (layer "F.SilkS") (tstamp a9c377d9-d9a8-4957-9ef2-653acbec4dad)
(effects (font (size 1 1) (thickness 0.1)))
)
(property "Value" "TestPoint_Pad_1.0x1.0mm" (at 0 1.55 0 unlocked) (layer "F.Fab") (tstamp 8722d65f-d023-4ca1-9653-ede49a60bc5e)
(effects (font (size 1 1) (thickness 0.15)))
)
(property "Footprint" "TestPoint:TestPoint_Pad_1.0x1.0mm" (at 0 0 0 unlocked) (layer "F.Fab") hide (tstamp 1f52001b-ae94-49e9-b2b5-6673a1b966af)
(effects (font (size 1 1) (thickness 0.15)))
)
(property "Datasheet" "" (at 0 0 0 unlocked) (layer "F.Fab") hide (tstamp 2cc1d293-3904-4185-9d78-14af283b2a39)
(effects (font (size 1 1) (thickness 0.15)))
)
(property "Description" "" (at 0 0 0 unlocked) (layer "F.Fab") hide (tstamp 8d2540c1-292c-4170-86dd-0959865683a2)
(effects (font (size 1 1) (thickness 0.15)))
)
(attr exclude_from_pos_files exclude_from_bom)
(fp_line (start -0.7 -0.7) (end 0.7 -0.7)
(stroke (width 0.12) (type solid)) (layer "F.SilkS") (tstamp de5cbed9-338f-4fba-aa6e-c8a10dd46598))
(fp_line (start -0.7 0.7) (end -0.7 -0.7)
(stroke (width 0.12) (type solid)) (layer "F.SilkS") (tstamp 0004140c-4466-41de-a8de-f1da559892df))
(fp_line (start 0.7 -0.7) (end 0.7 0.7)
(stroke (width 0.12) (type solid)) (layer "F.SilkS") (tstamp 6d11ed56-9675-4b43-9e47-1493d54e3ac3))
(fp_line (start 0.7 0.7) (end -0.7 0.7)
(stroke (width 0.12) (type solid)) (layer "F.SilkS") (tstamp 20542c66-768b-43a3-a7a6-10c5c62bb528))
(fp_line (start -1 -1) (end -1 1)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 78bcf185-2b20-4fc4-9289-1b0fa982c740))
(fp_line (start -1 -1) (end 1 -1)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 058a4358-6342-4f80-80a8-3dbc570a4ca7))
(fp_line (start 1 1) (end -1 1)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 1b5c24fb-0c0f-45c4-a0b6-2789970f4a7a))
(fp_line (start 1 1) (end 1 -1)
(stroke (width 0.05) (type solid)) (layer "F.CrtYd") (tstamp 2a79ab99-848f-4e4a-9a6a-b6833477e773))
(fp_text user "${REFERENCE}" (at 0 -1.45 0) (layer "F.Fab") (tstamp a858b269-27f4-4723-ba2d-fa8cdd0a9779)
(effects (font (size 1 1) (thickness 0.15)))
)
(pad "1" smd rect (at 0 0) (size 1 1) (layers "F.Cu" "F.Mask")
(net 1 "A")
(tstamp ff356f6c-417c-45fd-8338-965175a521e8)
)
)
(footprint "TestPoint:TestPoint_Pad_1.0x1.0mm" (layer "B.Cu")
(tstamp 42ed20a1-6256-4072-835a-a4bd28a9f9a8)
(at 128.622292 85.304594 180)
(descr "SMD rectangular pad as test Point, square 1.0mm side length")
(tags "test point SMD pad rectangle square")
(property "Reference" "REF**" (at 0 1.448 0 unlocked) (layer "B.SilkS") (tstamp 3467d764-46ee-4a7d-803e-52e5934180a2)
(effects (font (size 1 1) (thickness 0.1)) (justify mirror))
)
(property "Value" "TestPoint_Pad_1.0x1.0mm" (at 0 -1.55 0 unlocked) (layer "B.Fab") (tstamp a61e917b-111f-4d17-9565-6ae0b5832d32)
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
)
(property "Footprint" "TestPoint:TestPoint_Pad_1.0x1.0mm" (at 0 0 0 unlocked) (layer "B.Fab") hide (tstamp dd971483-3b14-41dd-be84-dd65b929cd2b)
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
)
(property "Datasheet" "" (at 0 0 0 unlocked) (layer "B.Fab") hide (tstamp 093cf8e6-f50b-4ee6-900c-63d6c741c2dd)
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
)
(property "Description" "" (at 0 0 0 unlocked) (layer "B.Fab") hide (tstamp ed3395ab-2567-4809-9ce8-0af0ac4a06cd)
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
)
(attr exclude_from_pos_files exclude_from_bom)
(fp_line (start 0.7 0.7) (end -0.7 0.7)
(stroke (width 0.12) (type solid)) (layer "B.SilkS") (tstamp 477ea467-832b-4e6a-9280-640c8709aedd))
(fp_line (start 0.7 -0.7) (end 0.7 0.7)
(stroke (width 0.12) (type solid)) (layer "B.SilkS") (tstamp 6f8c6994-cad2-429a-a1c5-43413d1196e8))
(fp_line (start -0.7 0.7) (end -0.7 -0.7)
(stroke (width 0.12) (type solid)) (layer "B.SilkS") (tstamp 585c91fb-6706-4683-bcd7-6beb6cecefd8))
(fp_line (start -0.7 -0.7) (end 0.7 -0.7)
(stroke (width 0.12) (type solid)) (layer "B.SilkS") (tstamp 30b86a99-e8ac-45bd-b9f8-3f1f188d9521))
(fp_line (start 1 1) (end 1 -1)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp fcf86568-6d87-4044-8c2f-405cf9649f0e))
(fp_line (start 1 1) (end -1 1)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp bdcd4fd5-3c51-46b9-952d-edfef4ece6f5))
(fp_line (start -1 -1) (end 1 -1)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp d8a94b9c-85fe-4c07-80d1-074ae82400dd))
(fp_line (start -1 -1) (end -1 1)
(stroke (width 0.05) (type solid)) (layer "B.CrtYd") (tstamp 2bdb98a7-177c-4399-b91b-0e73fdfb39e3))
(fp_text user "${REFERENCE}" (at 0 1.45 180) (layer "B.Fab") (tstamp 3361ae7f-450d-488d-bc3e-4c7d82969fd2)
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
)
(pad "1" smd rect (at 0 0 180) (size 1 1) (layers "B.Cu" "B.Mask")
(net 2 "B")
(tstamp 8285774c-eb9a-4524-aae8-d1d472cd8c36)
)
)
(gr_rect (start 120.188564 80.549407) (end 134.184964 91.096551)
(stroke (width 0.05) (type default)) (fill none) (layer "Edge.Cuts") (tstamp 24026c1a-e66c-43d9-874c-745b91ba08d9))
(gr_text "Without refilling, \nthe inner zone \nis located too close" (at 122.336593 82.233874 0) (layer "Cmts.User") (tstamp 5bc9367f-80d0-476c-b99a-6c82dbf59fbc)
(effects (font (size 0.5 0.5) (thickness 0.125)) (justify left bottom))
)
(via (at 131.802386 81.865308) (size 0.6) (drill 0.3) (layers "F.Cu" "B.Cu") (free) (net 2) (tstamp 2b81f30e-99a8-4345-9760-67513bc8c623))
(zone (net 1) (net_name "A") (layer "F.Cu") (tstamp fd8091a8-712f-4b09-81f9-cc203a1012a5) (hatch edge 0.5)
(priority 1)
(connect_pads (clearance 0.5))
(min_thickness 0.25) (filled_areas_thickness no)
(fill yes (thermal_gap 0.5) (thermal_bridge_width 0.5))
(polygon
(pts
(xy 122.70769 82.894624)
(xy 127.682194 82.784966)
(xy 127.742008 89.07537)
(xy 122.647877 88.736426)
)
)
(filled_polygon
(layer "F.Cu")
(pts
(xy 127.624117 82.805935)
(xy 127.671025 82.857718)
(xy 127.683387 82.910524)
(xy 127.706143 85.303649)
(xy 127.687097 85.370873)
(xy 127.634731 85.417127)
(xy 127.56567 85.427728)
(xy 127.501841 85.399309)
(xy 127.465967 85.348161)
(xy 127.413944 85.20868)
(xy 127.41394 85.208673)
(xy 127.32778 85.093579)
(xy 127.327777 85.093576)
(xy 127.212683 85.007416)
(xy 127.212676 85.007412)
(xy 127.077969 84.95717)
(xy 127.077962 84.957168)
(xy 127.018434 84.950767)
(xy 126.72059 84.950767)
(xy 126.72059 86.950767)
(xy 127.018418 86.950767)
(xy 127.018434 86.950766)
(xy 127.077962 86.944365)
(xy 127.077969 86.944363)
(xy 127.212676 86.894121)
(xy 127.212683 86.894117)
(xy 127.327777 86.807957)
(xy 127.32778 86.807954)
(xy 127.41394 86.69286)
(xy 127.413944 86.692853)
(xy 127.464186 86.558146)
(xy 127.464188 86.558139)
(xy 127.470358 86.500757)
(xy 127.497096 86.436205)
(xy 127.554488 86.396357)
(xy 127.624313 86.393864)
(xy 127.684402 86.429517)
(xy 127.715677 86.491996)
(xy 127.717641 86.512833)
(xy 127.740735 88.941582)
(xy 127.721689 89.008806)
(xy 127.669323 89.05506)
(xy 127.608509 89.066487)
(xy 122.764839 88.744208)
(xy 122.699254 88.720117)
(xy 122.657106 88.664391)
(xy 122.649077 88.619212)
(xy 122.66616 86.950766)
(xy 122.673839 86.200767)
(xy 125.47059 86.200767)
(xy 125.47059 86.498611)
(xy 125.476991 86.558139)
(xy 125.476993 86.558146)
(xy 125.527235 86.692853)
(xy 125.527239 86.69286)
(xy 125.613399 86.807954)
(xy 125.613402 86.807957)
(xy 125.728496 86.894117)
(xy 125.728503 86.894121)
(xy 125.86321 86.944363)
(xy 125.863217 86.944365)
(xy 125.922745 86.950766)
(xy 125.922762 86.950767)
(xy 126.220589 86.950767)
(xy 126.22059 86.200767)
(xy 125.47059 86.200767)
(xy 122.673839 86.200767)
(xy 122.678958 85.700767)
(xy 125.47059 85.700767)
(xy 126.220589 85.700767)
(xy 126.22059 84.950767)
(xy 125.922745 84.950767)
(xy 125.863217 84.957168)
(xy 125.86321 84.95717)
(xy 125.728503 85.007412)
(xy 125.728496 85.007416)
(xy 125.613402 85.093576)
(xy 125.613399 85.093579)
(xy 125.527239 85.208673)
(xy 125.527235 85.20868)
(xy 125.476993 85.343387)
(xy 125.476991 85.343394)
(xy 125.47059 85.402922)
(xy 125.47059 85.700767)
(xy 122.678958 85.700767)
(xy 122.70646 83.014675)
(xy 122.72683 82.947844)
(xy 122.7801 82.902632)
(xy 122.82772 82.891978)
(xy 127.55666 82.787733)
)
)
)
(zone (net 2) (net_name "B") (layers "F&B.Cu") (tstamp cbf3ce30-83db-44ed-be70-44935fea7e57) (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))
(polygon
(pts
(xy 118.583563 79.871518)
(xy 118.513781 92.023664)
(xy 135.590585 92.063539)
(xy 135.002417 80.190525)
)
)
(filled_polygon
(layer "F.Cu")
(pts
(xy 133.627503 81.069592)
(xy 133.673258 81.122396)
(xy 133.684464 81.173907)
(xy 133.684464 90.472051)
(xy 133.664779 90.53909)
(xy 133.611975 90.584845)
(xy 133.560464 90.596051)
(xy 120.813064 90.596051)
(xy 120.746025 90.576366)
(xy 120.70027 90.523562)
(xy 120.689064 90.472051)
(xy 120.689064 88.6215)
(xy 122.056899 88.6215)
(xy 122.064671 88.715117)
(xy 122.072702 88.760304)
(xy 122.097652 88.850836)
(xy 122.097653 88.850838)
(xy 122.097654 88.850841)
(xy 122.167233 88.976779)
(xy 122.167235 88.976782)
(xy 122.167237 88.976785)
(xy 122.189915 89.006769)
(xy 122.209381 89.032505)
(xy 122.209388 89.032515)
(xy 122.311632 89.133746)
(xy 122.438254 89.202072)
(xy 122.503839 89.226163)
(xy 122.644575 89.256047)
(xy 127.488245 89.578326)
(xy 127.488246 89.578325)
(xy 127.488248 89.578326)
(xy 127.522856 89.576259)
(xy 127.615155 89.570747)
(xy 127.675969 89.55932)
(xy 127.796972 89.520317)
(xy 127.917267 89.441382)
(xy 127.940871 89.420532)
(xy 127.969625 89.395136)
(xy 127.969636 89.395125)
(xy 128.062819 89.285496)
(xy 128.121342 89.154055)
(xy 128.140388 89.086831)
(xy 128.159508 88.94423)
(xy 128.157329 88.715115)
(xy 128.136313 86.504804)
(xy 128.135208 86.483479)
(xy 128.132242 86.452014)
(xy 128.132241 86.452014)
(xy 128.126441 86.409695)
(xy 128.081003 86.273178)
(xy 128.049728 86.210699)
(xy 128.049724 86.210693)
(xy 127.967674 86.092518)
(xy 127.96767 86.092514)
(xy 127.864369 86.009269)
(xy 127.824521 85.951877)
(xy 127.822027 85.882052)
(xy 127.857679 85.821963)
(xy 127.874151 85.809042)
(xy 127.882675 85.803449)
(xy 127.909751 85.779533)
(xy 127.935033 85.757203)
(xy 127.935044 85.757192)
(xy 128.028227 85.647563)
(xy 128.08675 85.516122)
(xy 128.105796 85.448898)
(xy 128.124916 85.306296)
(xy 128.10216 82.913171)
(xy 128.088876 82.802755)
(xy 128.076514 82.749949)
(xy 128.0394 82.645096)
(xy 127.958963 82.5258)
(xy 127.954746 82.521145)
(xy 127.924494 82.487748)
(xy 127.919398 82.4801)
(xy 127.801268 82.382215)
(xy 127.801267 82.382214)
(xy 127.669103 82.325344)
(xy 127.669102 82.325343)
(xy 127.669096 82.325341)
(xy 127.669094 82.32534)
(xy 127.601645 82.307141)
(xy 127.458816 82.28981)
(xy 127.458815 82.28981)
(xy 123.267027 82.382214)
(xy 122.729875 82.394055)
(xy 122.729861 82.394056)
(xy 122.630671 82.406123)
(xy 122.630635 82.406129)
(xy 122.583048 82.416776)
(xy 122.583034 82.416779)
(xy 122.583029 82.416781)
(xy 122.583022 82.416783)
(xy 122.583023 82.416783)
(xy 122.488125 82.44814)
(xy 122.366292 82.524685)
(xy 122.313028 82.569892)
(xy 122.31301 82.569909)
(xy 122.217699 82.677654)
(xy 122.217693 82.677663)
(xy 122.15659 82.807909)
(xy 122.156587 82.807916)
(xy 122.156588 82.807916)
(xy 122.136218 82.874747)
(xy 122.136216 82.874755)
(xy 122.12896 82.921791)
(xy 122.114282 83.016951)
(xy 122.08678 85.703046)
(xy 122.085536 85.824418)
(xy 122.081661 86.203046)
(xy 122.056899 88.621498)
(xy 122.056899 88.6215)
(xy 120.689064 88.6215)
(xy 120.689064 81.173907)
(xy 120.708749 81.106868)
(xy 120.761553 81.061113)
(xy 120.813064 81.049907)
(xy 133.560464 81.049907)
)
)
(filled_polygon
(layer "B.Cu")
(pts
(xy 133.627503 81.069592)
(xy 133.673258 81.122396)
(xy 133.684464 81.173907)
(xy 133.684464 90.472051)
(xy 133.664779 90.53909)
(xy 133.611975 90.584845)
(xy 133.560464 90.596051)
(xy 120.813064 90.596051)
(xy 120.746025 90.576366)
(xy 120.70027 90.523562)
(xy 120.689064 90.472051)
(xy 120.689064 85.554594)
(xy 127.622292 85.554594)
(xy 127.622292 85.852438)
(xy 127.628693 85.911966)
(xy 127.628695 85.911973)
(xy 127.678937 86.04668)
(xy 127.678941 86.046687)
(xy 127.765101 86.161781)
(xy 127.765104 86.161784)
(xy 127.880198 86.247944)
(xy 127.880205 86.247948)
(xy 128.014912 86.29819)
(xy 128.014919 86.298192)
(xy 128.074447 86.304593)
(xy 128.074464 86.304594)
(xy 128.372292 86.304594)
(xy 128.372292 85.554594)
(xy 128.872292 85.554594)
(xy 128.872292 86.304594)
(xy 129.17012 86.304594)
(xy 129.170136 86.304593)
(xy 129.229664 86.298192)
(xy 129.229671 86.29819)
(xy 129.364378 86.247948)
(xy 129.364385 86.247944)
(xy 129.479479 86.161784)
(xy 129.479482 86.161781)
(xy 129.565642 86.046687)
(xy 129.565646 86.04668)
(xy 129.615888 85.911973)
(xy 129.61589 85.911966)
(xy 129.622291 85.852438)
(xy 129.622292 85.852421)
(xy 129.622292 85.554594)
(xy 128.872292 85.554594)
(xy 128.372292 85.554594)
(xy 127.622292 85.554594)
(xy 120.689064 85.554594)
(xy 120.689064 85.054594)
(xy 127.622292 85.054594)
(xy 128.372292 85.054594)
(xy 128.372292 84.304594)
(xy 128.872292 84.304594)
(xy 128.872292 85.054594)
(xy 129.622292 85.054594)
(xy 129.622292 84.756766)
(xy 129.622291 84.756749)
(xy 129.61589 84.697221)
(xy 129.615888 84.697214)
(xy 129.565646 84.562507)
(xy 129.565642 84.5625)
(xy 129.479482 84.447406)
(xy 129.479479 84.447403)
(xy 129.364385 84.361243)
(xy 129.364378 84.361239)
(xy 129.229671 84.310997)
(xy 129.229664 84.310995)
(xy 129.170136 84.304594)
(xy 128.872292 84.304594)
(xy 128.372292 84.304594)
(xy 128.074447 84.304594)
(xy 128.014919 84.310995)
(xy 128.014912 84.310997)
(xy 127.880205 84.361239)
(xy 127.880198 84.361243)
(xy 127.765104 84.447403)
(xy 127.765101 84.447406)
(xy 127.678941 84.5625)
(xy 127.678937 84.562507)
(xy 127.628695 84.697214)
(xy 127.628693 84.697221)
(xy 127.622292 84.756749)
(xy 127.622292 85.054594)
(xy 120.689064 85.054594)
(xy 120.689064 81.173907)
(xy 120.708749 81.106868)
(xy 120.761553 81.061113)
(xy 120.813064 81.049907)
(xy 133.560464 81.049907)
)
)
)
)

View File

@ -0,0 +1,232 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.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": false,
"pads": {
"drill": 0.0,
"height": 1.0,
"width": 1.0
},
"silk_line_width": 0.09999999999999999,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.09999999999999999,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.09999999999999999,
"min_via_diameter": 0.5,
"solder_mask_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": [],
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "intersectingzones.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": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"legacy_lib_dir": "",
"legacy_lib_list": []
},
"sheets": [],
"text_variables": {}
}

View File

@ -191,3 +191,63 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
} }
} }
} }
BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressionsNoFill, DRC_REGRESSION_TEST_FIXTURE )
{
// These documents at one time failed to catch DRC errors that they should have but only
// when the zones were filled. In other words, refilling the zone will fix the error, but
// DRC should have caught it regardless
std::vector< std::pair<wxString, int> > tests =
{
{ "intersectingzones", 1 } // zones are too close to each other
};
for( const std::pair<wxString, int>& entry : tests )
{
KI_TEST::LoadBoard( m_settingsManager, entry.first, m_board );
std::vector<DRC_ITEM> violations;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// Disable DRC tests not useful in this testcase
bds.m_DRCSeverities[ DRCE_COPPER_SLIVER ] = SEVERITY::RPT_SEVERITY_IGNORE;
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, int aLayer )
{
PCB_MARKER temp( aItem, aPos );
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
violations.push_back( *aItem );
} );
bds.m_DRCEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
if( violations.size() == entry.second )
{
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
BOOST_TEST_MESSAGE( wxString::Format( "DRC regression: %s, passed", entry.first ) );
}
else
{
BOOST_CHECK_EQUAL( violations.size(), entry.second );
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 regression: %s, failed", entry.first ) );
}
}
}