|
|
|
@ -53,8 +53,8 @@ bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const |
|
|
|
{ |
|
|
|
wxLogTrace( DRC_COURTYARD_TRACE, "Running DRC: Courtyard" ); |
|
|
|
|
|
|
|
// Detects missing (or malformed) footprint courtyard,
|
|
|
|
// and for footprint with courtyard, courtyards overlap.
|
|
|
|
// Detects missing (or malformed) footprint courtyards and courtyard incursions (for those
|
|
|
|
// with a courtyard).
|
|
|
|
wxString msg; |
|
|
|
bool success = true; |
|
|
|
|
|
|
|
@ -63,18 +63,19 @@ bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const |
|
|
|
{ |
|
|
|
if( footprint->BuildPolyCourtyard() ) |
|
|
|
{ |
|
|
|
if( !aBoard.GetDesignSettings().Ignore( DRCE_MISSING_COURTYARD ) ) |
|
|
|
if( !aBoard.GetDesignSettings().Ignore( DRCE_MISSING_COURTYARD ) |
|
|
|
&& footprint->GetPolyCourtyardFront().OutlineCount() == 0 |
|
|
|
&& footprint->GetPolyCourtyardBack().OutlineCount() == 0 ) |
|
|
|
{ |
|
|
|
int outlineCount = footprint->GetPolyCourtyardFront().OutlineCount() |
|
|
|
+ footprint->GetPolyCourtyardBack().OutlineCount(); |
|
|
|
|
|
|
|
if( outlineCount == 0 ) |
|
|
|
{ |
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MISSING_COURTYARD ); |
|
|
|
drcItem->SetItems( footprint ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) ); |
|
|
|
success = false; |
|
|
|
} |
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_MISSING_COURTYARD ); |
|
|
|
drcItem->SetItems( footprint ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, footprint->GetPosition() ) ); |
|
|
|
success = false; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
footprint->GetPolyCourtyardFront().BuildBBoxCaches(); |
|
|
|
footprint->GetPolyCourtyardBack().BuildBBoxCaches(); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
@ -93,79 +94,108 @@ bool DRC_COURTYARD_TESTER::RunDRC( BOARD& aBoard ) const |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if( aBoard.GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) ) |
|
|
|
return success; |
|
|
|
|
|
|
|
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for courtyard overlap" ); |
|
|
|
|
|
|
|
// Now test for overlapping on top layer:
|
|
|
|
SHAPE_POLY_SET courtyard; // temporary storage of the courtyard of current footprint
|
|
|
|
|
|
|
|
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ ) |
|
|
|
if( !aBoard.GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS ) ) |
|
|
|
{ |
|
|
|
MODULE* footprint = *it1; |
|
|
|
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for courtyard overlap" ); |
|
|
|
|
|
|
|
if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 ) |
|
|
|
continue; // No courtyard defined
|
|
|
|
|
|
|
|
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ ) |
|
|
|
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ ) |
|
|
|
{ |
|
|
|
MODULE* candidate = *it2; |
|
|
|
MODULE* footprint = *it1; |
|
|
|
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront(); |
|
|
|
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack(); |
|
|
|
|
|
|
|
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 ) |
|
|
|
continue; // No courtyards defined
|
|
|
|
|
|
|
|
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ ) |
|
|
|
{ |
|
|
|
MODULE* test = *it2; |
|
|
|
SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront(); |
|
|
|
SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack(); |
|
|
|
SHAPE_POLY_SET intersection; |
|
|
|
bool overlap = false; |
|
|
|
wxPoint pos; |
|
|
|
|
|
|
|
if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0 |
|
|
|
&& footprintFront.BBoxFromCaches().Intersects( testFront.BBoxFromCaches() ) ) |
|
|
|
{ |
|
|
|
intersection.RemoveAllContours(); |
|
|
|
intersection.Append( footprintFront ); |
|
|
|
|
|
|
|
// Build the common area between footprint and the test:
|
|
|
|
intersection.BooleanIntersection( testFront, SHAPE_POLY_SET::PM_FAST ); |
|
|
|
|
|
|
|
// If the intersection exists then they overlap
|
|
|
|
if( intersection.OutlineCount() > 0 ) |
|
|
|
{ |
|
|
|
overlap = true; |
|
|
|
pos = (wxPoint) intersection.CVertex( 0, 0, -1 ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if( candidate->GetPolyCourtyardFront().OutlineCount() == 0 ) |
|
|
|
continue; // No courtyard defined
|
|
|
|
if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0 |
|
|
|
&& footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) ) |
|
|
|
{ |
|
|
|
intersection.RemoveAllContours(); |
|
|
|
intersection.Append( footprintBack ); |
|
|
|
|
|
|
|
courtyard.RemoveAllContours(); |
|
|
|
courtyard.Append( footprint->GetPolyCourtyardFront() ); |
|
|
|
intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST ); |
|
|
|
|
|
|
|
// Build the common area between footprint and the candidate:
|
|
|
|
courtyard.BooleanIntersection( candidate->GetPolyCourtyardFront(), |
|
|
|
SHAPE_POLY_SET::PM_FAST ); |
|
|
|
if( intersection.OutlineCount() > 0 ) |
|
|
|
{ |
|
|
|
overlap = true; |
|
|
|
pos = (wxPoint) intersection.CVertex( 0, 0, -1 ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// If no overlap, courtyard is empty (no common area).
|
|
|
|
// Therefore if a common polygon exists, this is a DRC error
|
|
|
|
if( courtyard.OutlineCount() ) |
|
|
|
{ |
|
|
|
//Overlap between footprint and candidate
|
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_OVERLAPPING_FOOTPRINTS ); |
|
|
|
drcItem->SetItems( footprint, candidate ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) courtyard.CVertex( 0, 0, -1 ) ) ); |
|
|
|
success = false; |
|
|
|
if( overlap ) |
|
|
|
{ |
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_OVERLAPPING_FOOTPRINTS ); |
|
|
|
drcItem->SetItems( footprint, test ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, pos ) ); |
|
|
|
success = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Test for overlapping on bottom layer:
|
|
|
|
for( auto it1 = aBoard.Modules().begin(); it1 != aBoard.Modules().end(); it1++ ) |
|
|
|
if( !aBoard.GetDesignSettings().Ignore( DRCE_PTH_IN_COURTYARD ) |
|
|
|
|| !aBoard.GetDesignSettings().Ignore( DRCE_NPTH_IN_COURTYARD ) ) |
|
|
|
{ |
|
|
|
MODULE* footprint = *it1; |
|
|
|
|
|
|
|
if( footprint->GetPolyCourtyardBack().OutlineCount() == 0 ) |
|
|
|
continue; // No courtyard defined
|
|
|
|
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for through-holes in courtyards" ); |
|
|
|
|
|
|
|
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ ) |
|
|
|
for( MODULE* footprint : aBoard.Modules() ) |
|
|
|
{ |
|
|
|
MODULE* candidate = *it2; |
|
|
|
|
|
|
|
if( candidate->GetPolyCourtyardBack().OutlineCount() == 0 ) |
|
|
|
continue; // No courtyard defined
|
|
|
|
|
|
|
|
courtyard.RemoveAllContours(); |
|
|
|
courtyard.Append( footprint->GetPolyCourtyardBack() ); |
|
|
|
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront(); |
|
|
|
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack(); |
|
|
|
|
|
|
|
// Build the common area between footprint and the candidate:
|
|
|
|
courtyard.BooleanIntersection( candidate->GetPolyCourtyardBack(), |
|
|
|
SHAPE_POLY_SET::PM_FAST ); |
|
|
|
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 ) |
|
|
|
continue; // No courtyards defined
|
|
|
|
|
|
|
|
// If no overlap, courtyard is empty (no common area).
|
|
|
|
// Therefore if a common polygon exists, this is a DRC error
|
|
|
|
if( courtyard.OutlineCount() ) |
|
|
|
for( MODULE* candidate : aBoard.Modules() ) |
|
|
|
{ |
|
|
|
//Overlap between footprint and candidate
|
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_OVERLAPPING_FOOTPRINTS ); |
|
|
|
drcItem->SetItems( footprint, candidate ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, (wxPoint) courtyard.CVertex( 0, 0, -1 ) ) ); |
|
|
|
success = false; |
|
|
|
if( footprint == candidate ) |
|
|
|
continue; |
|
|
|
|
|
|
|
for( D_PAD* pad : candidate->Pads() ) |
|
|
|
{ |
|
|
|
if( pad->GetDrillSize().x == 0 || pad->GetDrillSize().y == 0 ) |
|
|
|
continue; |
|
|
|
|
|
|
|
wxPoint pos = pad->GetPosition(); |
|
|
|
|
|
|
|
if( footprintFront.Contains( pos, -1, 0, true /* use bbox caches */ ) |
|
|
|
|| footprintBack.Contains( pos, -1, 0, true /* use bbox caches */ ) ) |
|
|
|
{ |
|
|
|
int code = pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED ? |
|
|
|
DRCE_NPTH_IN_COURTYARD : |
|
|
|
DRCE_PTH_IN_COURTYARD; |
|
|
|
DRC_ITEM* drcItem = new DRC_ITEM( code ); |
|
|
|
drcItem->SetItems( footprint, pad ); |
|
|
|
HandleMarker( new MARKER_PCB( drcItem, pos ) ); |
|
|
|
success = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|