Add hole-inside-courtyard DRC checks.
One for NPTH and one for PTH; both default to "ignore". Fixes https://gitlab.com/kicad/code/kicad/issues/3434
This commit is contained in:
parent
aedc624340
commit
13493437d0
|
@ -375,6 +375,11 @@ public:
|
|||
m_bbox.Inflate( m_width );
|
||||
}
|
||||
|
||||
const BOX2I BBoxFromCache() const
|
||||
{
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Collide()
|
||||
*
|
||||
|
|
|
@ -1042,6 +1042,8 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
*/
|
||||
void BuildBBoxCaches();
|
||||
|
||||
const BOX2I BBoxFromCaches() const;
|
||||
|
||||
/**
|
||||
* Returns true if a given subpolygon contains the point aP
|
||||
*
|
||||
|
@ -1236,9 +1238,6 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
void booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
|
||||
const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode );
|
||||
|
||||
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath,
|
||||
bool aIgnoreEdges, bool aUseBBoxCaches = false ) const;
|
||||
|
||||
/**
|
||||
* containsSingle function
|
||||
* Checks whether the point aP is inside the aSubpolyIndex-th polygon of the polyset. If
|
||||
|
|
|
@ -1185,6 +1185,22 @@ const BOX2I SHAPE_POLY_SET::BBox( int aClearance ) const
|
|||
}
|
||||
|
||||
|
||||
const BOX2I SHAPE_POLY_SET::BBoxFromCaches() const
|
||||
{
|
||||
BOX2I bb;
|
||||
|
||||
for( unsigned i = 0; i < m_polys.size(); i++ )
|
||||
{
|
||||
if( i == 0 )
|
||||
bb = m_polys[i][0].BBoxFromCache();
|
||||
else
|
||||
bb.Merge( m_polys[i][0].BBoxFromCache() );
|
||||
}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
bool SHAPE_POLY_SET::PointOnEdge( const VECTOR2I& aP ) const
|
||||
{
|
||||
// Iterate through all the polygons in the set
|
||||
|
|
|
@ -629,6 +629,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
|
|||
m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
|
||||
|
||||
m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
|
||||
m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
|
||||
m_DRCSeverities[ DRCE_NPTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;
|
||||
|
||||
m_DRCSeverities[ DRCE_MISSING_FOOTPRINT ] = RPT_SEVERITY_WARNING;
|
||||
m_DRCSeverities[ DRCE_DUPLICATE_FOOTPRINT ] = RPT_SEVERITY_WARNING;
|
||||
|
|
|
@ -478,7 +478,9 @@ void DRC::RunTests( wxTextCtrl* aMessages )
|
|||
// test courtyards
|
||||
if( !m_pcb->GetDesignSettings().Ignore( DRCE_OVERLAPPING_FOOTPRINTS )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_MISSING_COURTYARD )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_MALFORMED_COURTYARD ) )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_MALFORMED_COURTYARD )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_PTH_IN_COURTYARD )
|
||||
|| !m_pcb->GetDesignSettings().Ignore( DRCE_NPTH_IN_COURTYARD ) )
|
||||
{
|
||||
if( aMessages )
|
||||
{
|
||||
|
|
|
@ -87,6 +87,8 @@ enum PCB_DRC_CODE {
|
|||
DRCE_MISSING_COURTYARD, ///< footprint has no courtyard defined
|
||||
DRCE_MALFORMED_COURTYARD, ///< footprint has a courtyard but malformed
|
||||
///< (not convertible to a closed polygon with holes)
|
||||
DRCE_PTH_IN_COURTYARD,
|
||||
DRCE_NPTH_IN_COURTYARD,
|
||||
DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
|
||||
DRCE_INVALID_OUTLINE, ///< invalid board outline
|
||||
DRCE_MISSING_FOOTPRINT, ///< footprint not found for netlist item
|
||||
|
|
|
@ -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( candidate->GetPolyCourtyardFront().OutlineCount() == 0 )
|
||||
continue; // No courtyard defined
|
||||
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
|
||||
continue; // No courtyards defined
|
||||
|
||||
courtyard.RemoveAllContours();
|
||||
courtyard.Append( footprint->GetPolyCourtyardFront() );
|
||||
|
||||
// Build the common area between footprint and the candidate:
|
||||
courtyard.BooleanIntersection( candidate->GetPolyCourtyardFront(),
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// If no overlap, courtyard is empty (no common area).
|
||||
// Therefore if a common polygon exists, this is a DRC error
|
||||
if( courtyard.OutlineCount() )
|
||||
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ )
|
||||
{
|
||||
//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;
|
||||
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( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0
|
||||
&& footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) )
|
||||
{
|
||||
intersection.RemoveAllContours();
|
||||
intersection.Append( footprintBack );
|
||||
|
||||
intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
if( intersection.OutlineCount() > 0 )
|
||||
{
|
||||
overlap = true;
|
||||
pos = (wxPoint) intersection.CVertex( 0, 0, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
wxLogTrace( DRC_COURTYARD_TRACE, "Checking for through-holes in courtyards" );
|
||||
|
||||
if( footprint->GetPolyCourtyardBack().OutlineCount() == 0 )
|
||||
continue; // No courtyard defined
|
||||
|
||||
for( auto it2 = it1 + 1; it2 != aBoard.Modules().end(); it2++ )
|
||||
for( MODULE* footprint : aBoard.Modules() )
|
||||
{
|
||||
MODULE* candidate = *it2;
|
||||
SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront();
|
||||
SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack();
|
||||
|
||||
if( candidate->GetPolyCourtyardBack().OutlineCount() == 0 )
|
||||
continue; // No courtyard defined
|
||||
if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 )
|
||||
continue; // No courtyards defined
|
||||
|
||||
courtyard.RemoveAllContours();
|
||||
courtyard.Append( footprint->GetPolyCourtyardBack() );
|
||||
|
||||
// Build the common area between footprint and the candidate:
|
||||
courtyard.BooleanIntersection( candidate->GetPolyCourtyardBack(),
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,8 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
|
|||
case DRCE_OVERLAPPING_FOOTPRINTS: msg = _HKI( "Courtyards overlap" ); break;
|
||||
case DRCE_MISSING_COURTYARD: msg = _HKI( "Footprint has no courtyard defined" ); break;
|
||||
case DRCE_MALFORMED_COURTYARD: msg = _HKI( "Footprint has malformed courtyard" ); break;
|
||||
case DRCE_PTH_IN_COURTYARD: msg = _HKI( "PTH inside courtyard" ); break;
|
||||
case DRCE_NPTH_IN_COURTYARD: msg = _HKI( "NPTH inside courtyard" ); break;
|
||||
|
||||
case DRCE_DUPLICATE_FOOTPRINT: msg = _HKI( "Duplicate footprints" ); break;
|
||||
case DRCE_MISSING_FOOTPRINT: msg = _HKI( "Missing footprint" ); break;
|
||||
|
|
Loading…
Reference in New Issue