Fix a couple of DRC bugs where the bbox wasn't inflated for largestClearance.
Also removes a case of double-testing a pad with a non-plated hole.
This commit is contained in:
parent
909358e643
commit
1a672aba56
|
@ -298,7 +298,12 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !aItem->GetBoundingBox().Intersects( aZone->GetCachedBoundingBox() ) )
|
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
||||||
|
EDA_RECT worstCaseBBox = itemBBox;
|
||||||
|
|
||||||
|
worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
|
||||||
|
|
||||||
|
if( !worstCaseBBox.Intersects( aZone->GetCachedBoundingBox() ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||||
|
@ -307,55 +312,38 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
||||||
if( !testClearance && !testHoles )
|
if( !testClearance && !testHoles )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ aZone ].get();
|
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ aZone ].get();
|
||||||
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
|
||||||
DRC_CONSTRAINT constraint;
|
if( !zoneTree )
|
||||||
DRC_CONSTRAINT_T constraintType = CLEARANCE_CONSTRAINT;
|
return;
|
||||||
int clearance = -1;
|
|
||||||
int actual;
|
DRC_CONSTRAINT constraint;
|
||||||
VECTOR2I pos;
|
int clearance = -1;
|
||||||
bool unflashedPad = false;
|
int actual;
|
||||||
bool platedHole = false;
|
VECTOR2I pos;
|
||||||
|
|
||||||
if( aItem->Type() == PCB_PAD_T )
|
if( aItem->Type() == PCB_PAD_T )
|
||||||
{
|
{
|
||||||
unflashedPad = !static_cast<PAD*>( aItem )->FlashLayer( aLayer );
|
PAD* pad = static_cast<PAD*>( aItem );
|
||||||
|
bool flashedPad = pad->FlashLayer( aLayer );
|
||||||
|
bool platedHole = pad->HasHole() && pad->GetAttribute() == PAD_ATTRIB::PTH;
|
||||||
|
|
||||||
if( unflashedPad && !aItem->HasHole() )
|
if( !flashedPad && !platedHole )
|
||||||
return;
|
testClearance = false;
|
||||||
|
|
||||||
platedHole = static_cast<PAD*>( aItem )->GetAttribute() == PAD_ATTRIB::PTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( zoneTree && testClearance )
|
if( testClearance )
|
||||||
{
|
{
|
||||||
if( unflashedPad && !platedHole )
|
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aItem, aZone, aLayer );
|
||||||
constraintType = HOLE_CLEARANCE_CONSTRAINT;
|
|
||||||
|
|
||||||
constraint = m_drcEngine->EvalRules( constraintType, aItem, aZone, aLayer );
|
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer, FLASHING::DEFAULT );
|
||||||
|
|
||||||
if( unflashedPad )
|
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
|
||||||
{
|
std::max( 0, clearance - m_drcEpsilon ), &actual, &pos ) )
|
||||||
std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
|
|
||||||
int size = hole->GetWidth();
|
|
||||||
|
|
||||||
// Note: drill size represents finish size, which means the actual hole size is
|
|
||||||
// 2x the plating thickness larger.
|
|
||||||
if( platedHole )
|
|
||||||
size += 2 * m_board->GetDesignSettings().GetHolePlatingThickness();
|
|
||||||
|
|
||||||
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( zoneTree && zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
|
|
||||||
std::max( 0, clearance - m_drcEpsilon ),
|
|
||||||
&actual, &pos ) )
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -373,7 +361,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( zoneTree && testHoles && aItem->HasHole() )
|
if( testHoles && aItem->HasHole() )
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
||||||
|
|
||||||
|
@ -433,7 +421,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||||
if( !reportProgress( ii++, m_board->Tracks().size(), progressDelta ) )
|
if( !reportProgress( ii++, m_board->Tracks().size(), progressDelta ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for( PCB_LAYER_ID layer : track->GetLayerSet().Seq() )
|
for( PCB_LAYER_ID layer : LSET( track->GetLayerSet() & LSET::AllCuMask() ).Seq() )
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
|
std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
|
||||||
|
|
||||||
|
|
|
@ -177,27 +177,46 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOX2I frontBBox = frontA.BBoxFromCaches();
|
BOX2I frontA_worstCaseBBox = frontA.BBoxFromCaches();
|
||||||
BOX2I backBBox = backA.BBoxFromCaches();
|
BOX2I backA_worstCaseBBox = backA.BBoxFromCaches();
|
||||||
|
|
||||||
frontBBox.Inflate( m_largestCourtyardClearance );
|
frontA_worstCaseBBox.Inflate( m_largestCourtyardClearance );
|
||||||
backBBox.Inflate( m_largestCourtyardClearance );
|
backA_worstCaseBBox.Inflate( m_largestCourtyardClearance );
|
||||||
|
|
||||||
EDA_RECT fpABBox = fpA->GetBoundingBox();
|
EDA_RECT fpA_bbox = fpA->GetBoundingBox();
|
||||||
|
|
||||||
for( auto itB = itA + 1; itB != m_board->Footprints().end(); itB++ )
|
for( auto itB = itA + 1; itB != m_board->Footprints().end(); itB++ )
|
||||||
{
|
{
|
||||||
FOOTPRINT* fpB = *itB;
|
FOOTPRINT* fpB = *itB;
|
||||||
EDA_RECT fpBBBox = fpB->GetBoundingBox();
|
|
||||||
const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
|
const SHAPE_POLY_SET& frontB = fpB->GetCourtyard( F_CrtYd );
|
||||||
const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
|
const SHAPE_POLY_SET& backB = fpB->GetCourtyard( B_CrtYd );
|
||||||
DRC_CONSTRAINT constraint;
|
|
||||||
int clearance;
|
if( frontB.OutlineCount() == 0 && backB.OutlineCount() == 0
|
||||||
int actual;
|
&& m_drcEngine->IsErrorLimitExceeded( DRCE_PTH_IN_COURTYARD )
|
||||||
VECTOR2I pos;
|
&& m_drcEngine->IsErrorLimitExceeded( DRCE_NPTH_IN_COURTYARD ) )
|
||||||
|
{
|
||||||
|
// No courtyards defined and no hole testing against other footprint's courtyards
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOX2I frontB_worstCaseBBox = frontB.BBoxFromCaches();
|
||||||
|
BOX2I backB_worstCaseBBox = backB.BBoxFromCaches();
|
||||||
|
|
||||||
|
frontB_worstCaseBBox.Inflate( m_largestCourtyardClearance );
|
||||||
|
backB_worstCaseBBox.Inflate( m_largestCourtyardClearance );
|
||||||
|
|
||||||
|
EDA_RECT fpB_bbox = fpB->GetBoundingBox();
|
||||||
|
DRC_CONSTRAINT constraint;
|
||||||
|
int clearance;
|
||||||
|
int actual;
|
||||||
|
VECTOR2I pos;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check courtyard-to-courtyard collisions on front of board.
|
||||||
|
//
|
||||||
|
|
||||||
if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
|
if( frontA.OutlineCount() > 0 && frontB.OutlineCount() > 0
|
||||||
&& frontBBox.Intersects( frontB.BBoxFromCaches() ) )
|
&& frontA_worstCaseBBox.Intersects( frontB.BBoxFromCaches() ) )
|
||||||
{
|
{
|
||||||
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, F_Cu );
|
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, F_Cu );
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
|
@ -226,8 +245,12 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check courtyard-to-courtyard collisions on back of board.
|
||||||
|
//
|
||||||
|
|
||||||
if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
|
if( backA.OutlineCount() > 0 && backB.OutlineCount() > 0
|
||||||
&& backBBox.Intersects( backB.BBoxFromCaches() ) )
|
&& backA_worstCaseBBox.Intersects( backB.BBoxFromCaches() ) )
|
||||||
{
|
{
|
||||||
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
|
constraint = m_drcEngine->EvalRules( COURTYARD_CLEARANCE_CONSTRAINT, fpA, fpB, B_Cu );
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
|
@ -256,6 +279,13 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check pad-hole-to-courtyard collisions on front and back of board.
|
||||||
|
//
|
||||||
|
// NB: via holes are not checked. There is a presumption that a physical object goes
|
||||||
|
// through a pad hole, which is not the case for via holes.
|
||||||
|
//
|
||||||
|
|
||||||
auto testPadAgainstCourtyards =
|
auto testPadAgainstCourtyards =
|
||||||
[&]( const PAD* pad, const FOOTPRINT* fp )
|
[&]( const PAD* pad, const FOOTPRINT* fp )
|
||||||
{
|
{
|
||||||
|
@ -292,15 +322,15 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if( ( frontA.OutlineCount() > 0 && frontA.BBoxFromCaches().Intersects( fpBBBox ) )
|
if( ( frontA.OutlineCount() > 0 && frontA_worstCaseBBox.Intersects( fpB_bbox ) )
|
||||||
|| ( backA.OutlineCount() > 0 && backA.BBoxFromCaches().Intersects( fpBBBox ) ) )
|
|| ( backA.OutlineCount() > 0 && backA_worstCaseBBox.Intersects( fpB_bbox ) ) )
|
||||||
{
|
{
|
||||||
for( const PAD* padB : fpB->Pads() )
|
for( const PAD* padB : fpB->Pads() )
|
||||||
testPadAgainstCourtyards( padB, fpA );
|
testPadAgainstCourtyards( padB, fpA );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( frontB.OutlineCount() > 0 && frontB.BBoxFromCaches().Intersects( fpABBox ) )
|
if( ( frontB.OutlineCount() > 0 && frontB.BBoxFromCaches().Intersects( fpA_bbox ) )
|
||||||
|| ( backB.OutlineCount() > 0 && backB.BBoxFromCaches().Intersects( fpABBox ) ) )
|
|| ( backB.OutlineCount() > 0 && backB.BBoxFromCaches().Intersects( fpA_bbox ) ) )
|
||||||
{
|
{
|
||||||
for( const PAD* padA : fpA->Pads() )
|
for( const PAD* padA : fpA->Pads() )
|
||||||
testPadAgainstCourtyards( padA, fpB );
|
testPadAgainstCourtyards( padA, fpB );
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool testItemAgainstItem( BOARD_ITEM* item, SHAPE* itemShape, PCB_LAYER_ID layer,
|
bool testItemAgainstItem( BOARD_ITEM* aItem, SHAPE* aItemShape, PCB_LAYER_ID aLayer,
|
||||||
BOARD_ITEM* other );
|
BOARD_ITEM* other );
|
||||||
|
|
||||||
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
|
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
|
||||||
|
@ -119,6 +119,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
||||||
|
|
||||||
static const LSET courtyards( 2, F_CrtYd, B_CrtYd );
|
static const LSET courtyards( 2, F_CrtYd, B_CrtYd );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate a count for use in progress reporting.
|
||||||
|
//
|
||||||
|
|
||||||
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
{
|
{
|
||||||
|
@ -126,6 +130,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate a BOARD_ITEM RTree.
|
||||||
|
//
|
||||||
|
|
||||||
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
{
|
{
|
||||||
|
@ -158,6 +166,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
||||||
progressDelta = 100;
|
progressDelta = 100;
|
||||||
ii = 0;
|
ii = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Run clearance checks -between- items.
|
||||||
|
//
|
||||||
|
|
||||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE )
|
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE )
|
||||||
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE ) )
|
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE ) )
|
||||||
{
|
{
|
||||||
|
@ -222,6 +234,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
||||||
count = 0;
|
count = 0;
|
||||||
ii = 0;
|
ii = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate a count for progress reporting.
|
||||||
|
//
|
||||||
|
|
||||||
forEachGeometryItem( { PCB_ZONE_T, PCB_FP_ZONE_T, PCB_SHAPE_T, PCB_FP_SHAPE_T },
|
forEachGeometryItem( { PCB_ZONE_T, PCB_FP_ZONE_T, PCB_SHAPE_T, PCB_FP_SHAPE_T },
|
||||||
LSET::AllCuMask(),
|
LSET::AllCuMask(),
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
|
@ -236,6 +252,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Run clearance checks -within- polygonal items.
|
||||||
|
//
|
||||||
|
|
||||||
forEachGeometryItem( { PCB_ZONE_T, PCB_FP_ZONE_T, PCB_SHAPE_T, PCB_FP_SHAPE_T },
|
forEachGeometryItem( { PCB_ZONE_T, PCB_FP_ZONE_T, PCB_SHAPE_T, PCB_FP_SHAPE_T },
|
||||||
LSET::AllCuMask(),
|
LSET::AllCuMask(),
|
||||||
[&]( BOARD_ITEM* item ) -> bool
|
[&]( BOARD_ITEM* item ) -> bool
|
||||||
|
@ -507,7 +527,9 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAYER
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN* firstOutline = &fill.Outline( outlineIdx );
|
SHAPE_LINE_CHAIN* firstOutline = &fill.Outline( outlineIdx );
|
||||||
|
|
||||||
|
//
|
||||||
// Step one: outline to outline clearance violations
|
// Step one: outline to outline clearance violations
|
||||||
|
//
|
||||||
|
|
||||||
for( int ii = outlineIdx + 1; ii < fill.OutlineCount(); ++ii )
|
for( int ii = outlineIdx + 1; ii < fill.OutlineCount(); ++ii )
|
||||||
{
|
{
|
||||||
|
@ -541,7 +563,9 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAYER
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// Step two: interior hole clearance violations
|
// Step two: interior hole clearance violations
|
||||||
|
//
|
||||||
|
|
||||||
for( int holeIdx = 0; holeIdx < fill.HoleCount( outlineIdx ); ++holeIdx )
|
for( int holeIdx = 0; holeIdx < fill.HoleCount( outlineIdx ); ++holeIdx )
|
||||||
{
|
{
|
||||||
|
@ -554,9 +578,9 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAYER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item,
|
bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* aItem,
|
||||||
SHAPE* itemShape,
|
SHAPE* aItemShape,
|
||||||
PCB_LAYER_ID layer,
|
PCB_LAYER_ID aLayer,
|
||||||
BOARD_ITEM* other )
|
BOARD_ITEM* other )
|
||||||
{
|
{
|
||||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||||
|
@ -566,17 +590,17 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
int actual;
|
int actual;
|
||||||
VECTOR2I pos;
|
VECTOR2I pos;
|
||||||
|
|
||||||
std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( layer );
|
std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer );
|
||||||
|
|
||||||
if( testClearance )
|
if( testClearance )
|
||||||
{
|
{
|
||||||
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, item, other, layer );
|
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, aItem, other, aLayer );
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
||||||
{
|
{
|
||||||
if( itemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
|
if( aItemShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -587,10 +611,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
MessageTextFromValue( userUnits(), actual ) );
|
MessageTextFromValue( userUnits(), actual ) );
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||||
drce->SetItems( item, other );
|
drce->SetItems( aItem, other );
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
reportViolation( drce, pos, layer );
|
reportViolation( drce, pos, aLayer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,19 +624,19 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
|
std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
|
||||||
clearance = 0;
|
clearance = 0;
|
||||||
|
|
||||||
if( item->Type() == PCB_VIA_T )
|
if( aItem->Type() == PCB_VIA_T )
|
||||||
{
|
{
|
||||||
if( item->GetLayerSet().Contains( layer ) )
|
if( aItem->GetLayerSet().Contains( aLayer ) )
|
||||||
itemHoleShape = item->GetEffectiveHoleShape();
|
itemHoleShape = aItem->GetEffectiveHoleShape();
|
||||||
}
|
}
|
||||||
else if( item->HasHole() )
|
else if( aItem->HasHole() )
|
||||||
{
|
{
|
||||||
itemHoleShape = item->GetEffectiveHoleShape();
|
itemHoleShape = aItem->GetEffectiveHoleShape();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( other->Type() == PCB_VIA_T )
|
if( other->Type() == PCB_VIA_T )
|
||||||
{
|
{
|
||||||
if( other->GetLayerSet().Contains( layer ) )
|
if( other->GetLayerSet().Contains( aLayer ) )
|
||||||
otherHoleShape = other->GetEffectiveHoleShape();
|
otherHoleShape = other->GetEffectiveHoleShape();
|
||||||
}
|
}
|
||||||
else if( other->HasHole() )
|
else if( other->HasHole() )
|
||||||
|
@ -622,8 +646,8 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
|
|
||||||
if( itemHoleShape || otherHoleShape )
|
if( itemHoleShape || otherHoleShape )
|
||||||
{
|
{
|
||||||
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, other, item,
|
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, other, aItem,
|
||||||
layer );
|
aLayer );
|
||||||
clearance = constraint.GetValue().Min();
|
clearance = constraint.GetValue().Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,13 +664,13 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
MessageTextFromValue( userUnits(), actual ) );
|
MessageTextFromValue( userUnits(), actual ) );
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||||
drce->SetItems( item, other );
|
drce->SetItems( aItem, other );
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
reportViolation( drce, pos, layer );
|
reportViolation( drce, pos, aLayer );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( otherHoleShape && otherHoleShape->Collide( itemShape, clearance, &actual, &pos ) )
|
if( otherHoleShape && otherHoleShape->Collide( aItemShape, clearance, &actual, &pos ) )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -657,10 +681,10 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
||||||
MessageTextFromValue( userUnits(), actual ) );
|
MessageTextFromValue( userUnits(), actual ) );
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||||
drce->SetItems( item, other );
|
drce->SetItems( aItem, other );
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
reportViolation( drce, pos, layer );
|
reportViolation( drce, pos, aLayer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,68 +701,113 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aIt
|
||||||
if( !zone->GetLayerSet().test( aLayer ) )
|
if( !zone->GetLayerSet().test( aLayer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
|
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
||||||
|
EDA_RECT worstCaseBBox = itemBBox;
|
||||||
|
|
||||||
|
worstCaseBBox.Inflate( m_board->m_DRCMaxClearance );
|
||||||
|
|
||||||
|
if( !worstCaseBBox.Intersects( zone->GetCachedBoundingBox() ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
||||||
|
bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
|
||||||
|
|
||||||
|
if( !testClearance && !testHoles )
|
||||||
|
return;
|
||||||
|
|
||||||
|
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
|
||||||
|
DRC_CONSTRAINT constraint;
|
||||||
|
bool colliding;
|
||||||
|
int clearance = -1;
|
||||||
|
int actual;
|
||||||
|
VECTOR2I pos;
|
||||||
|
|
||||||
|
if( testClearance )
|
||||||
{
|
{
|
||||||
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
|
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, aItem, zone,
|
||||||
bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
|
aLayer );
|
||||||
|
clearance = constraint.GetValue().Min();
|
||||||
|
}
|
||||||
|
|
||||||
if( !testClearance && !testHoles )
|
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
||||||
return;
|
{
|
||||||
|
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
||||||
|
|
||||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
|
if( aItem->Type() == PCB_PAD_T )
|
||||||
EDA_RECT itemBBox = aItem->GetBoundingBox();
|
|
||||||
DRC_CONSTRAINT constraint;
|
|
||||||
bool colliding;
|
|
||||||
int clearance = -1;
|
|
||||||
int actual;
|
|
||||||
VECTOR2I pos;
|
|
||||||
|
|
||||||
if( testClearance )
|
|
||||||
{
|
{
|
||||||
constraint = m_drcEngine->EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, aItem, zone,
|
PAD* pad = static_cast<PAD*>( aItem );
|
||||||
aLayer );
|
|
||||||
clearance = constraint.GetValue().Min();
|
if( !pad->FlashLayer( aLayer ) )
|
||||||
|
{
|
||||||
|
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
||||||
|
int size = hole->GetWidth();
|
||||||
|
|
||||||
|
// Note: drill size represents finish size, which means the actual hole
|
||||||
|
// size is the plating thickness larger.
|
||||||
|
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||||
|
size += m_board->GetDesignSettings().GetHolePlatingThickness();
|
||||||
|
|
||||||
|
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && clearance > 0 )
|
if( zoneTree )
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
colliding = zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer, clearance,
|
||||||
|
&actual, &pos );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
colliding = zone->Outline()->Collide( itemShape.get(), clearance, &actual, &pos );
|
||||||
|
}
|
||||||
|
|
||||||
if( aItem->Type() == PCB_PAD_T )
|
if( colliding )
|
||||||
|
{
|
||||||
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
||||||
|
wxString msg;
|
||||||
|
|
||||||
|
msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||||
|
constraint.GetName(),
|
||||||
|
MessageTextFromValue( userUnits(), clearance ),
|
||||||
|
MessageTextFromValue( userUnits(), actual ) );
|
||||||
|
|
||||||
|
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||||
|
drce->SetItems( aItem, zone );
|
||||||
|
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||||
|
|
||||||
|
reportViolation( drce, pos, aLayer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( testHoles )
|
||||||
|
{
|
||||||
|
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
||||||
|
|
||||||
|
if( aItem->Type() == PCB_VIA_T )
|
||||||
|
{
|
||||||
|
if( aItem->GetLayerSet().Contains( aLayer ) )
|
||||||
|
holeShape = aItem->GetEffectiveHoleShape();
|
||||||
|
}
|
||||||
|
else if( aItem->HasHole() )
|
||||||
|
{
|
||||||
|
holeShape = aItem->GetEffectiveHoleShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( holeShape )
|
||||||
|
{
|
||||||
|
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, aItem,
|
||||||
|
zone, aLayer );
|
||||||
|
clearance = constraint.GetValue().Min();
|
||||||
|
|
||||||
|
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE
|
||||||
|
&& clearance > 0
|
||||||
|
&& zoneTree->QueryColliding( itemBBox, holeShape.get(), aLayer, clearance,
|
||||||
|
&actual, &pos ) )
|
||||||
{
|
{
|
||||||
PAD* pad = static_cast<PAD*>( aItem );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
||||||
|
|
||||||
if( !pad->FlashLayer( aLayer ) )
|
|
||||||
{
|
|
||||||
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
|
||||||
int size = hole->GetWidth();
|
|
||||||
|
|
||||||
// Note: drill size represents finish size, which means the actual hole
|
|
||||||
// size is the plating thickness larger.
|
|
||||||
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
|
||||||
size += m_board->GetDesignSettings().GetHolePlatingThickness();
|
|
||||||
|
|
||||||
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( zoneTree )
|
|
||||||
{
|
|
||||||
colliding = zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
|
|
||||||
clearance, &actual, &pos );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
colliding = zone->Outline()->Collide( itemShape.get(), clearance, &actual,
|
|
||||||
&pos );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( colliding )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
|
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
|
||||||
msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
||||||
|
@ -753,48 +822,6 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aIt
|
||||||
reportViolation( drce, pos, aLayer );
|
reportViolation( drce, pos, aLayer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( testHoles )
|
|
||||||
{
|
|
||||||
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
|
||||||
|
|
||||||
if( aItem->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
if( aItem->GetLayerSet().Contains( aLayer ) )
|
|
||||||
holeShape = aItem->GetEffectiveHoleShape();
|
|
||||||
}
|
|
||||||
else if( aItem->HasHole() )
|
|
||||||
{
|
|
||||||
holeShape = aItem->GetEffectiveHoleShape();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( holeShape )
|
|
||||||
{
|
|
||||||
constraint = m_drcEngine->EvalRules( PHYSICAL_HOLE_CLEARANCE_CONSTRAINT, aItem,
|
|
||||||
zone, aLayer );
|
|
||||||
clearance = constraint.GetValue().Min();
|
|
||||||
|
|
||||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE
|
|
||||||
&& clearance > 0
|
|
||||||
&& zoneTree->QueryColliding( itemBBox, holeShape.get(), aLayer,
|
|
||||||
clearance, &actual, &pos ) )
|
|
||||||
{
|
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
|
|
||||||
wxString msg;
|
|
||||||
|
|
||||||
msg.Printf( _( "(%s clearance %s; actual %s)" ),
|
|
||||||
constraint.GetName(),
|
|
||||||
MessageTextFromValue( userUnits(), clearance ),
|
|
||||||
MessageTextFromValue( userUnits(), actual ) );
|
|
||||||
|
|
||||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
|
||||||
drce->SetItems( aItem, zone );
|
|
||||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
|
||||||
|
|
||||||
reportViolation( drce, pos, aLayer );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_drcEngine->IsCancelled() )
|
if( m_drcEngine->IsCancelled() )
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addItemToRTrees( BOARD_ITEM* item );
|
void addItemToRTrees( BOARD_ITEM* aItem );
|
||||||
void buildRTrees();
|
void buildRTrees();
|
||||||
|
|
||||||
void testSilkToMaskClearance();
|
void testSilkToMaskClearance();
|
||||||
|
@ -97,7 +97,7 @@ private:
|
||||||
int m_maxError;
|
int m_maxError;
|
||||||
int m_largestClearance;
|
int m_largestClearance;
|
||||||
|
|
||||||
std::unique_ptr<DRC_RTREE> m_tesselatedTree;
|
std::unique_ptr<DRC_RTREE> m_fullSolderMaskRTree;
|
||||||
std::unique_ptr<DRC_RTREE> m_itemTree;
|
std::unique_ptr<DRC_RTREE> m_itemTree;
|
||||||
|
|
||||||
std::unordered_map<PTR_PTR_CACHE_KEY, LSET> m_checkedPairs;
|
std::unordered_map<PTR_PTR_CACHE_KEY, LSET> m_checkedPairs;
|
||||||
|
@ -109,13 +109,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* item )
|
void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
|
||||||
{
|
{
|
||||||
ZONE* solderMask = m_board->m_SolderMask;
|
ZONE* solderMask = m_board->m_SolderMask;
|
||||||
|
|
||||||
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
|
if( aItem->Type() == PCB_ZONE_T || aItem->Type() == PCB_FP_ZONE_T )
|
||||||
{
|
{
|
||||||
ZONE* zone = static_cast<ZONE*>( item );
|
ZONE* zone = static_cast<ZONE*>( aItem );
|
||||||
|
|
||||||
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
||||||
{
|
{
|
||||||
|
@ -126,35 +126,35 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* item )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( item->Type() == PCB_PAD_T )
|
else if( aItem->Type() == PCB_PAD_T )
|
||||||
{
|
{
|
||||||
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
||||||
{
|
{
|
||||||
if( item->IsOnLayer( layer ) )
|
if( aItem->IsOnLayer( layer ) )
|
||||||
{
|
{
|
||||||
PAD* pad = static_cast<PAD*>( item );
|
PAD* pad = static_cast<PAD*>( aItem );
|
||||||
int clearance = ( m_webWidth / 2 ) + pad->GetSolderMaskExpansion();
|
int clearance = ( m_webWidth / 2 ) + pad->GetSolderMaskExpansion();
|
||||||
|
|
||||||
item->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
|
aItem->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
|
||||||
clearance, m_maxError, ERROR_OUTSIDE );
|
clearance, m_maxError, ERROR_OUTSIDE );
|
||||||
|
|
||||||
m_itemTree->Insert( item, layer, m_largestClearance );
|
m_itemTree->Insert( aItem, layer, m_largestClearance );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( item->Type() == PCB_VIA_T )
|
else if( aItem->Type() == PCB_VIA_T )
|
||||||
{
|
{
|
||||||
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
||||||
{
|
{
|
||||||
if( item->IsOnLayer( layer ) )
|
if( aItem->IsOnLayer( layer ) )
|
||||||
{
|
{
|
||||||
PCB_VIA* via = static_cast<PCB_VIA*>( item );
|
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
||||||
int clearance = ( m_webWidth / 2 ) + via->GetSolderMaskExpansion();
|
int clearance = ( m_webWidth / 2 ) + via->GetSolderMaskExpansion();
|
||||||
|
|
||||||
via->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
|
via->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ), layer,
|
||||||
clearance, m_maxError, ERROR_OUTSIDE );
|
clearance, m_maxError, ERROR_OUTSIDE );
|
||||||
|
|
||||||
m_itemTree->Insert( item, layer, m_largestClearance );
|
m_itemTree->Insert( aItem, layer, m_largestClearance );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,13 +162,13 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* item )
|
||||||
{
|
{
|
||||||
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
|
||||||
{
|
{
|
||||||
if( item->IsOnLayer( layer ) )
|
if( aItem->IsOnLayer( layer ) )
|
||||||
{
|
{
|
||||||
item->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ),
|
aItem->TransformShapeWithClearanceToPolygon( *solderMask->GetFill( layer ),
|
||||||
layer, m_webWidth / 2, m_maxError,
|
layer, m_webWidth / 2, m_maxError,
|
||||||
ERROR_OUTSIDE );
|
ERROR_OUTSIDE );
|
||||||
|
|
||||||
m_itemTree->Insert( item, layer, m_largestClearance );
|
m_itemTree->Insert( aItem, layer, m_largestClearance );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees()
|
||||||
solderMask->GetFill( F_Mask )->RemoveAllContours();
|
solderMask->GetFill( F_Mask )->RemoveAllContours();
|
||||||
solderMask->GetFill( B_Mask )->RemoveAllContours();
|
solderMask->GetFill( B_Mask )->RemoveAllContours();
|
||||||
|
|
||||||
m_tesselatedTree = std::make_unique<DRC_RTREE>();
|
m_fullSolderMaskRTree = std::make_unique<DRC_RTREE>();
|
||||||
m_itemTree = std::make_unique<DRC_RTREE>();
|
m_itemTree = std::make_unique<DRC_RTREE>();
|
||||||
|
|
||||||
forEachGeometryItem( s_allBasicItems, layers,
|
forEachGeometryItem( s_allBasicItems, layers,
|
||||||
|
@ -221,8 +221,8 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees()
|
||||||
|
|
||||||
solderMask->CacheTriangulation();
|
solderMask->CacheTriangulation();
|
||||||
|
|
||||||
m_tesselatedTree->Insert( solderMask, F_Mask );
|
m_fullSolderMaskRTree->Insert( solderMask, F_Mask );
|
||||||
m_tesselatedTree->Insert( solderMask, B_Mask );
|
m_fullSolderMaskRTree->Insert( solderMask, B_Mask );
|
||||||
|
|
||||||
m_checkedPairs.clear();
|
m_checkedPairs.clear();
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,8 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testSilkToMaskClearance()
|
||||||
|
|
||||||
std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
|
std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
|
||||||
|
|
||||||
if( m_tesselatedTree->QueryColliding( itemBBox, itemShape.get(), layer,
|
if( m_fullSolderMaskRTree->QueryColliding( itemBBox, itemShape.get(), layer,
|
||||||
clearance, &actual, &pos ) )
|
clearance, &actual, &pos ) )
|
||||||
{
|
{
|
||||||
auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
|
auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE );
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -577,64 +577,59 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testMaskItemAgainstZones( BOARD_ITEM* aItem,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aItem->GetBoundingBox().Intersects( zone->GetCachedBoundingBox() ) )
|
EDA_RECT inflatedBBox( aItemBBox );
|
||||||
|
int clearance = m_board->GetDesignSettings().m_SolderMaskToCopperClearance;
|
||||||
|
|
||||||
|
if( aItem->Type() == PCB_PAD_T )
|
||||||
|
clearance += static_cast<PAD*>( aItem )->GetSolderMaskExpansion();
|
||||||
|
else if( aItem->Type() == PCB_VIA_T )
|
||||||
|
clearance += static_cast<PCB_VIA*>( aItem )->GetSolderMaskExpansion();
|
||||||
|
|
||||||
|
inflatedBBox.Inflate( clearance );
|
||||||
|
|
||||||
|
if( !inflatedBBox.Intersects( zone->GetCachedBoundingBox() ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
|
||||||
|
int actual;
|
||||||
|
VECTOR2I pos;
|
||||||
|
|
||||||
|
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aMaskLayer );
|
||||||
|
|
||||||
|
if( zoneTree && zoneTree->QueryColliding( aItemBBox, itemShape.get(), aTargetLayer,
|
||||||
|
clearance, &actual, &pos ) )
|
||||||
{
|
{
|
||||||
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTreeCache[ zone ].get();
|
wxString msg;
|
||||||
int clearance = m_board->GetDesignSettings().m_SolderMaskToCopperClearance;
|
BOARD_ITEM* colliding = nullptr;
|
||||||
int actual;
|
|
||||||
VECTOR2I pos;
|
|
||||||
|
|
||||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aMaskLayer );
|
if( aMaskLayer == F_Mask )
|
||||||
|
msg = _( "Front solder mask aperture bridges items with different nets" );
|
||||||
|
else
|
||||||
|
msg = _( "Rear solder mask aperture bridges items with different nets" );
|
||||||
|
|
||||||
if( aItem->Type() == PCB_PAD_T )
|
// Simple mask apertures aren't associated with copper items, so they only constitute
|
||||||
|
// a bridge when they expose other copper items having at least two distinct nets.
|
||||||
|
if( isMaskAperture( aItem ) && zoneNet >= 0 )
|
||||||
{
|
{
|
||||||
PAD* pad = static_cast<PAD*>( aItem );
|
if( checkMaskAperture( aItem, zone, aTargetLayer, zoneNet, &colliding ) )
|
||||||
|
|
||||||
clearance += pad->GetSolderMaskExpansion();
|
|
||||||
}
|
|
||||||
else if( aItem->Type() == PCB_VIA_T )
|
|
||||||
{
|
|
||||||
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
|
||||||
|
|
||||||
clearance += via->GetSolderMaskExpansion();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( zoneTree && zoneTree->QueryColliding( aItemBBox, itemShape.get(), aTargetLayer,
|
|
||||||
clearance, &actual, &pos ) )
|
|
||||||
{
|
|
||||||
wxString msg;
|
|
||||||
BOARD_ITEM* colliding = nullptr;
|
|
||||||
|
|
||||||
if( aMaskLayer == F_Mask )
|
|
||||||
msg = _( "Front solder mask aperture bridges items with different nets" );
|
|
||||||
else
|
|
||||||
msg = _( "Rear solder mask aperture bridges items with different nets" );
|
|
||||||
|
|
||||||
// Simple mask apertures aren't associated with copper items, so they only
|
|
||||||
// constitute a bridge when they expose other copper items having at least
|
|
||||||
// two distinct nets.
|
|
||||||
if( isMaskAperture( aItem ) && zoneNet >= 0 )
|
|
||||||
{
|
|
||||||
if( checkMaskAperture( aItem, zone, aTargetLayer, zoneNet, &colliding ) )
|
|
||||||
{
|
|
||||||
auto drce = DRC_ITEM::Create( DRCE_SOLDERMASK_BRIDGE );
|
|
||||||
|
|
||||||
drce->SetErrorMessage( msg );
|
|
||||||
drce->SetItems( aItem, colliding, zone );
|
|
||||||
drce->SetViolatingRule( &m_bridgeRule );
|
|
||||||
reportViolation( drce, pos, aTargetLayer );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
auto drce = DRC_ITEM::Create( DRCE_SOLDERMASK_BRIDGE );
|
auto drce = DRC_ITEM::Create( DRCE_SOLDERMASK_BRIDGE );
|
||||||
|
|
||||||
drce->SetErrorMessage( msg );
|
drce->SetErrorMessage( msg );
|
||||||
drce->SetItems( aItem, zone );
|
drce->SetItems( aItem, colliding, zone );
|
||||||
drce->SetViolatingRule( &m_bridgeRule );
|
drce->SetViolatingRule( &m_bridgeRule );
|
||||||
reportViolation( drce, pos, aTargetLayer );
|
reportViolation( drce, pos, aTargetLayer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto drce = DRC_ITEM::Create( DRCE_SOLDERMASK_BRIDGE );
|
||||||
|
|
||||||
|
drce->SetErrorMessage( msg );
|
||||||
|
drce->SetItems( aItem, zone );
|
||||||
|
drce->SetViolatingRule( &m_bridgeRule );
|
||||||
|
reportViolation( drce, pos, aTargetLayer );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_drcEngine->IsCancelled() )
|
if( m_drcEngine->IsCancelled() )
|
||||||
|
@ -722,8 +717,8 @@ bool DRC_TEST_PROVIDER_SOLDER_MASK::Run()
|
||||||
m_largestClearance = std::max( m_largestClearance, pad->GetSolderMaskExpansion() );
|
m_largestClearance = std::max( m_largestClearance, pad->GetSolderMaskExpansion() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order is important here: m_webWidth must be added in before m_largestCourtyardClearance is maxed
|
// Order is important here: m_webWidth must be added in before m_largestCourtyardClearance is
|
||||||
// with the various SILK_CLEARANCE_CONSTRAINTS.
|
// maxed with the various SILK_CLEARANCE_CONSTRAINTS.
|
||||||
m_largestClearance += m_largestClearance + m_webWidth;
|
m_largestClearance += m_largestClearance + m_webWidth;
|
||||||
|
|
||||||
DRC_CONSTRAINT worstClearanceConstraint;
|
DRC_CONSTRAINT worstClearanceConstraint;
|
||||||
|
|
|
@ -92,8 +92,10 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
||||||
if( m_drcEngine->IsCancelled() )
|
if( m_drcEngine->IsCancelled() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
// Quick tests for "connected":
|
// Quick tests for "connected":
|
||||||
//
|
//
|
||||||
|
|
||||||
if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
|
if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -105,8 +107,10 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
||||||
if( !pad->FlashLayer( aLayer ) )
|
if( !pad->FlashLayer( aLayer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
//
|
||||||
// If those passed, do a thorough test:
|
// If those passed, do a thorough test:
|
||||||
//
|
//
|
||||||
|
|
||||||
constraint = bds.m_DRCEngine->EvalZoneConnection( pad, aZone, aLayer );
|
constraint = bds.m_DRCEngine->EvalZoneConnection( pad, aZone, aLayer );
|
||||||
ZONE_CONNECTION conn = constraint.m_ZoneConnection;
|
ZONE_CONNECTION conn = constraint.m_ZoneConnection;
|
||||||
|
|
||||||
|
@ -139,8 +143,10 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
||||||
if( spokes >= minCount ) // We already have enough
|
if( spokes >= minCount ) // We already have enough
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
//
|
||||||
// See if there are any other manual spokes added:
|
// See if there are any other manual spokes added:
|
||||||
//
|
//
|
||||||
|
|
||||||
for( PCB_TRACK* track : connectivity->GetConnectedTracks( pad ) )
|
for( PCB_TRACK* track : connectivity->GetConnectedTracks( pad ) )
|
||||||
{
|
{
|
||||||
if( padOutline.PointInside( track->GetStart() ) )
|
if( padOutline.PointInside( track->GetStart() ) )
|
||||||
|
@ -155,8 +161,10 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// And finally report it if there aren't enough:
|
// And finally report it if there aren't enough:
|
||||||
//
|
//
|
||||||
|
|
||||||
if( spokes < minCount )
|
if( spokes < minCount )
|
||||||
{
|
{
|
||||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_STARVED_THERMAL );
|
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_STARVED_THERMAL );
|
||||||
|
|
Loading…
Reference in New Issue