drc_proto: follow up Jeff's changes in legacy DRC/board model
This commit is contained in:
parent
832a8c5bf7
commit
91b68e4578
|
@ -111,7 +111,7 @@ void test::DRC_ENGINE::inferImplicitRules()
|
|||
}
|
||||
|
||||
|
||||
static const int drc_debug_level = -10;
|
||||
static const int drc_debug_level = 2;
|
||||
|
||||
void test::drc_dbg( int level, const char* fmt, ... )
|
||||
{
|
||||
|
@ -156,6 +156,7 @@ bool test::DRC_ENGINE::CompileRules()
|
|||
|
||||
if( rule->GetPriority() == 0 )
|
||||
{
|
||||
drc_dbg(1,"DefaultRule for %d = %p\n", id, rule );
|
||||
m_ruleMap[ id ]->defaultRule = rule;
|
||||
continue;
|
||||
}
|
||||
|
@ -306,10 +307,16 @@ std::vector<test::DRC_RULE*> test::DRC_ENGINE::QueryRulesById( test::DRC_RULE_ID
|
|||
{
|
||||
std::vector<test::DRC_RULE*> rv;
|
||||
|
||||
rv.push_back( m_ruleMap[ruleID]->defaultRule );
|
||||
auto dr = m_ruleMap[ruleID]->defaultRule;
|
||||
assert( dr );
|
||||
|
||||
if ( dr )
|
||||
rv.push_back( dr );
|
||||
|
||||
for( auto rule : m_ruleMap[ruleID]->sortedRules )
|
||||
{
|
||||
assert( rule );
|
||||
assert( rule->rule );
|
||||
rv.push_back(rule->rule);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,85 +65,42 @@ class DRC_CONSTRAINT;
|
|||
/// DRC error codes:
|
||||
enum PCB_DRC_CODE
|
||||
{
|
||||
DRCE_FIRST = 1,
|
||||
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, ///< items are unconnected
|
||||
DRCE_TRACK_NEAR_HOLE, ///< thru hole is too close to track
|
||||
DRCE_TRACK_NEAR_PAD, ///< pad too close to track
|
||||
DRCE_TRACK_NEAR_VIA, ///< track too close to via
|
||||
DRCE_TRACK_NEAR_ZONE, ///< track & zone collide or are too close together
|
||||
DRCE_TRACK_NEAR_COPPER, ///< track & copper graphic collide or are too close
|
||||
DRCE_VIA_NEAR_VIA, ///< via too close to via
|
||||
DRCE_VIA_NEAR_TRACK, ///< via too close to track
|
||||
DRCE_VIA_NEAR_COPPER, ///< via and copper graphic collide or are too close
|
||||
DRCE_TRACK_ENDS, ///< track ends are too close
|
||||
DRCE_TRACK_SEGMENTS_TOO_CLOSE, ///< 2 parallel track segments too close: segm ends between segref ends
|
||||
DRCE_TRACKS_CROSSING, ///< tracks are crossing
|
||||
DRCE_TRACK_NEAR_EDGE, ///< track too close to board edge
|
||||
DRCE_VIA_NEAR_EDGE, ///< via too close to board edge
|
||||
DRCE_PAD_NEAR_EDGE, ///< pad too close to board edge
|
||||
DRCE_PAD_NEAR_PAD, ///< pad too close to pad
|
||||
DRCE_PAD_NEAR_COPPER, ///< pad and copper graphic collide or are too close
|
||||
DRCE_ZONES_INTERSECT, ///< copper area outlines intersect
|
||||
DRCE_ZONES_TOO_CLOSE, ///< copper area outlines are too close
|
||||
DRCE_ZONE_HAS_EMPTY_NET, ///< copper area has a net but no pads in nets, which is suspicious
|
||||
DRCE_DANGLING_VIA, ///< via which isn't connected to anything
|
||||
DRCE_DANGLING_TRACK, ///< track with at least one end not connected to anything
|
||||
DRCE_HOLE_NEAR_PAD, ///< hole too close to pad
|
||||
DRCE_HOLE_NEAR_TRACK, ///< hole too close to track
|
||||
DRCE_DRILLED_HOLES_TOO_CLOSE, ///< overlapping drilled holes break drill bits
|
||||
DRCE_TOO_SMALL_TRACK_WIDTH, ///< Too small track width
|
||||
DRCE_TOO_LARGE_TRACK_WIDTH, ///< Too small track width
|
||||
DRCE_TOO_SMALL_VIA, ///< Too small via size
|
||||
DRCE_TOO_SMALL_VIA_ANNULUS, ///< Via size and drill leave annulus too small
|
||||
DRCE_TOO_SMALL_VIA_DRILL, ///< Too small via drill
|
||||
DRCE_TOO_SMALL_PAD_DRILL, ///< Too small via drill
|
||||
DRCE_VIA_HOLE_BIGGER, ///< via's hole is bigger than its diameter
|
||||
DRCE_MICROVIA_NOT_ALLOWED, ///< micro vias are not allowed
|
||||
DRCE_MICROVIA_TOO_MANY_LAYERS, ///< micro via's layer pair incorrect (layers must be adjacent)
|
||||
DRCE_TOO_SMALL_MICROVIA, ///< Too small micro via size
|
||||
DRCE_TOO_SMALL_MICROVIA_DRILL, ///< Too small micro via drill
|
||||
DRCE_BURIED_VIA_NOT_ALLOWED, ///< buried vias are not allowed
|
||||
DRCE_NETCLASS_TRACKWIDTH, ///< netclass has TrackWidth < board.m_designSettings->m_TrackMinWidth
|
||||
DRCE_NETCLASS_CLEARANCE, ///< netclass has Clearance < board.m_designSettings->m_TrackClearance
|
||||
DRCE_NETCLASS_VIAANNULUS, ///< netclass ViaSize & ViaDrill leave annulus < board.m_designSettings->m_ViasMinAnnulus
|
||||
DRCE_NETCLASS_VIASIZE, ///< netclass has ViaSize < board.m_designSettings->m_ViasMinSize
|
||||
DRCE_NETCLASS_VIADRILLSIZE, ///< netclass has ViaDrillSize < board.m_designSettings->m_MinThroughDrill
|
||||
DRCE_NETCLASS_uVIASIZE, ///< netclass has ViaSize < board.m_designSettings->m_MicroViasMinSize
|
||||
DRCE_NETCLASS_uVIADRILLSIZE, ///< netclass has ViaSize < board.m_designSettings->m_MicroViasMinDrill
|
||||
DRCE_VIA_INSIDE_KEEPOUT,
|
||||
DRCE_MICROVIA_INSIDE_KEEPOUT,
|
||||
DRCE_BBVIA_INSIDE_KEEPOUT,
|
||||
DRCE_TRACK_INSIDE_KEEPOUT,
|
||||
DRCE_PAD_INSIDE_KEEPOUT,
|
||||
DRCE_FOOTPRINT_INSIDE_KEEPOUT,
|
||||
DRCE_HOLE_INSIDE_KEEPOUT,
|
||||
DRCE_TEXT_INSIDE_KEEPOUT,
|
||||
DRCE_GRAPHICS_INSIDE_KEEPOUT,
|
||||
DRCE_OVERLAPPING_FOOTPRINTS, ///< footprint courtyards overlap
|
||||
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_FIRST = 1,
|
||||
DRCE_UNCONNECTED_ITEMS = DRCE_FIRST, ///< items are unconnected
|
||||
DRCE_ALLOWED_ITEMS, ///< a disallowed item has been used
|
||||
DRCE_CLEARANCE, ///< items are too close together
|
||||
DRCE_HOLE_CLEARANCE,
|
||||
DRCE_TRACKS_CROSSING, ///< tracks are crossing
|
||||
DRCE_COPPER_EDGE_CLEARANCE, ///< a copper item is too close to the board edge
|
||||
DRCE_ZONES_INTERSECT, ///< copper area outlines intersect
|
||||
DRCE_ZONE_HAS_EMPTY_NET, ///< copper area has a net but no pads in nets, which is suspicious
|
||||
DRCE_DANGLING_VIA, ///< via which isn't connected to anything
|
||||
DRCE_DANGLING_TRACK, ///< track with at least one end not connected to anything
|
||||
DRCE_DRILLED_HOLES_TOO_CLOSE, ///< overlapping drilled holes break drill bits
|
||||
DRCE_TRACK_WIDTH, ///< Track width is too small or too large
|
||||
DRCE_TOO_SMALL_VIA, ///< Too small via size
|
||||
DRCE_VIA_ANNULUS, ///< Via size and drill leave annulus too small or too large
|
||||
DRCE_TOO_SMALL_DRILL, ///< Too small via or pad drill
|
||||
DRCE_VIA_HOLE_BIGGER, ///< via's hole is bigger than its diameter
|
||||
DRCE_PADSTACK, ///< something is wrong with a pad or via stackup
|
||||
DRCE_TOO_SMALL_MICROVIA, ///< Too small micro via size
|
||||
DRCE_TOO_SMALL_MICROVIA_DRILL, ///< Too small micro via drill
|
||||
DRCE_KEEPOUT, ///< A disallowed object is inside a keepout
|
||||
DRCE_OVERLAPPING_FOOTPRINTS, ///< footprint courtyards overlap
|
||||
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
|
||||
DRCE_DUPLICATE_FOOTPRINT, ///< more than one footprints found for netlist item
|
||||
DRCE_EXTRA_FOOTPRINT, ///< netlist item not found for footprint
|
||||
DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
|
||||
DRCE_INVALID_OUTLINE, ///< invalid board outline
|
||||
DRCE_MISSING_FOOTPRINT, ///< footprint not found for netlist item
|
||||
DRCE_DUPLICATE_FOOTPRINT, ///< more than one footprints found for netlist item
|
||||
DRCE_EXTRA_FOOTPRINT, ///< netlist item not found for footprint
|
||||
|
||||
DRCE_UNRESOLVED_VARIABLE,
|
||||
|
||||
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE,
|
||||
|
||||
// These are actually Cleanup Tracks and Vias actions, not DRCE errors
|
||||
CLEANUP_SHORT,
|
||||
CLEANUP_REDUNDANT_VIA,
|
||||
CLEANUP_DUPLICATE_TRACK,
|
||||
CLEANUP_MERGE_TRACKS,
|
||||
CLEANUP_DANGLING_TRACK,
|
||||
CLEANUP_DANGLING_VIA,
|
||||
CLEANUP_ZERO_LENGTH_TRACK,
|
||||
CLEANUP_TRACK_IN_PAD
|
||||
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <drc_proto/drc_rule.h>
|
||||
#include <drc_proto/drc_rule_parser.h>
|
||||
#include <drc_proto/drc_rules_lexer.h>
|
||||
#include <drc_proto/drc_engine.h> // drc_dbg
|
||||
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
|
@ -61,8 +63,6 @@ void test::DRC_RULES_PARSER::Parse(
|
|||
|
||||
token = NextTok();
|
||||
|
||||
printf("TOK %d %d\n", token, T_version );
|
||||
|
||||
if( !haveVersion && token != T_version )
|
||||
Expecting( "version" );
|
||||
|
||||
|
@ -81,35 +81,17 @@ void test::DRC_RULES_PARSER::Parse(
|
|||
break;
|
||||
|
||||
case T_rule:
|
||||
aRules.push_back( parseRULE() );
|
||||
{
|
||||
auto rule = parseRULE();
|
||||
drc_dbg(0, "Parsed rule: '%s' type '%s\n", (const char*) rule->GetName().c_str(), (const char*) rule->GetTestProviderName().c_str() );
|
||||
aRules.push_back( rule );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Expecting( "condition or rule" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// Hook up the selectors to their rules
|
||||
std::map<wxString, DRC_RULE*> ruleMap;
|
||||
|
||||
for( DRC_RULE* rule : aRules )
|
||||
ruleMap[ rule->m_Name ] = rule;
|
||||
|
||||
for( const std::pair<DRC_RULE_CONDITION*, wxString>& entry : conditionsRules )
|
||||
{
|
||||
if( ruleMap.count( entry.second ) )
|
||||
{
|
||||
entry.first->m_Rule = ruleMap[ entry.second ];
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString errText = wxString::Format( _( "Rule \"%s\" not found." ), entry.second );
|
||||
THROW_PARSE_ERROR( errText, CurSource(), "", 0, 0 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -94,211 +94,3 @@ wxPoint test::DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, cons
|
|||
return pt1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test if distance between a segment and a pad is > minClearance. Return the actual
|
||||
* distance if it is less.
|
||||
*/
|
||||
bool test::DRC_TEST_PROVIDER_CLEARANCE_BASE::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
|
||||
int minClearance, int* aActualDist )
|
||||
{
|
||||
if( ( pad->GetShape() == PAD_SHAPE_CIRCLE || pad->GetShape() == PAD_SHAPE_OVAL ) )
|
||||
{
|
||||
/* Treat an oval pad as a line segment along the hole's major axis,
|
||||
* shortened by half its minor axis.
|
||||
* A circular pad is just a degenerate case of an oval hole.
|
||||
*/
|
||||
wxPoint padStart, padEnd;
|
||||
int padWidth;
|
||||
|
||||
pad->GetOblongGeometry( pad->GetSize(), &padStart, &padEnd, &padWidth );
|
||||
padStart += pad->ShapePos();
|
||||
padEnd += pad->ShapePos();
|
||||
|
||||
SEG padSeg( padStart, padEnd );
|
||||
int widths = ( padWidth + refSegWidth ) / 2;
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
|
||||
// Avoid square-roots if possible (for performance)
|
||||
SEG::ecoord center2center_squared = refSeg.SquaredDistance( padSeg );
|
||||
|
||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
||||
{
|
||||
*aActualDist = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( ( pad->GetShape() == PAD_SHAPE_RECT || pad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
||||
&& ( (int) pad->GetOrientation() % 900 == 0 ) )
|
||||
{
|
||||
EDA_RECT padBBox = pad->GetBoundingBox();
|
||||
int widths = refSegWidth / 2;
|
||||
|
||||
// Note a ROUNDRECT pad with a corner radius = r can be treated as a smaller
|
||||
// RECT (size - 2*r) with a clearance increased by r
|
||||
if( pad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
||||
{
|
||||
padBBox.Inflate( - pad->GetRoundRectCornerRadius() );
|
||||
widths += pad->GetRoundRectCornerRadius();
|
||||
}
|
||||
|
||||
SHAPE_RECT padShape( padBBox.GetPosition(), padBBox.GetWidth(), padBBox.GetHeight() );
|
||||
int actual;
|
||||
|
||||
if( padShape.Collide( refSeg, minClearance + widths, &actual ) )
|
||||
{
|
||||
*aActualDist = std::max( 0, actual - widths );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // Convert the rest to polygons
|
||||
{
|
||||
SHAPE_POLY_SET polyset;
|
||||
|
||||
BOARD* board = pad->GetBoard();
|
||||
int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
|
||||
|
||||
pad->TransformShapeWithClearanceToPolygon( polyset, 0, maxError );
|
||||
|
||||
const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
|
||||
int widths = refSegWidth / 2;
|
||||
int actual;
|
||||
|
||||
if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
|
||||
(wxPoint) refSeg.A, (wxPoint) refSeg.B,
|
||||
minClearance + widths, &actual ) )
|
||||
{
|
||||
*aActualDist = std::max( 0, actual - widths );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool test::DRC_TEST_PROVIDER_CLEARANCE_BASE::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual )
|
||||
{
|
||||
int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
|
||||
|
||||
// Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
|
||||
if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
|
||||
return true;
|
||||
|
||||
int actual = INT_MAX;
|
||||
|
||||
for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
|
||||
{
|
||||
for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
|
||||
{
|
||||
int this_dist;
|
||||
|
||||
if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
|
||||
actual = std::min( actual, this_dist );
|
||||
}
|
||||
}
|
||||
|
||||
if( actual < INT_MAX )
|
||||
{
|
||||
// returns the actual clearance (clearance < aMinClearance) for diags:
|
||||
if( aActual )
|
||||
*aActual = std::max( 0, actual );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool test::DRC_TEST_PROVIDER_CLEARANCE_BASE::poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
|
||||
int aDist, int* aActual )
|
||||
{
|
||||
/* Test if the segment is contained in the polygon.
|
||||
* This case is not covered by the following check if the segment is
|
||||
* completely contained in the polygon (because edges don't intersect)!
|
||||
*/
|
||||
if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) )
|
||||
{
|
||||
*aActual = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ )
|
||||
{ // for all edges in polygon
|
||||
double d;
|
||||
|
||||
if( TestForIntersectionOfStraightLineSegments( aTref[ii].x, aTref[ii].y, aTref[jj].x,
|
||||
aTref[jj].y, aSegStart.x, aSegStart.y,
|
||||
aSegEnd.x, aSegEnd.y, NULL, NULL, &d ) )
|
||||
{
|
||||
*aActual = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( d < aDist )
|
||||
{
|
||||
*aActual = KiROUND( d );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* compare 2 convex polygons and return true if distance > aDist (if no error DRC)
|
||||
* i.e if for each edge of the first polygon distance from each edge of the other polygon
|
||||
* is >= aDist
|
||||
*/
|
||||
bool test::DRC_TEST_PROVIDER_CLEARANCE_BASE::poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount,
|
||||
int aAllowedDist, int* actualDist )
|
||||
{
|
||||
/* Test if one polygon is contained in the other and thus the polygon overlap.
|
||||
* This case is not covered by the following check if one polygone is
|
||||
* completely contained in the other (because edges don't intersect)!
|
||||
*/
|
||||
if( TestPointInsidePolygon( aTref, aTrefCount, aTtest[0] ) )
|
||||
{
|
||||
*actualDist = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( TestPointInsidePolygon( aTtest, aTtestCount, aTref[0] ) )
|
||||
{
|
||||
*actualDist = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ )
|
||||
{
|
||||
// for all edges in aTref
|
||||
for( int kk = 0, ll = aTtestCount - 1; kk < aTtestCount; ll = kk, kk++ )
|
||||
{
|
||||
// for all edges in aTtest
|
||||
double d;
|
||||
int intersect = TestForIntersectionOfStraightLineSegments(
|
||||
aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
|
||||
aTtest[kk].x, aTtest[kk].y, aTtest[ll].x, aTtest[ll].y,
|
||||
nullptr, nullptr, &d );
|
||||
|
||||
if( intersect )
|
||||
{
|
||||
*actualDist = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( d < aAllowedDist )
|
||||
{
|
||||
*actualDist = KiROUND( d );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -52,11 +52,11 @@ protected:
|
|||
|
||||
bool doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
|
||||
|
||||
bool checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
|
||||
int minClearance, int* aActualDist );
|
||||
bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual );
|
||||
bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
|
||||
int aDist, int* aActual );
|
||||
//bool checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
|
||||
// int minClearance, int* aActualDist );
|
||||
//bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual );
|
||||
//bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
|
||||
// int aDist, int* aActual );
|
||||
//bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount,
|
||||
// int aAllowedDist, int* actualDist );
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
|
||||
#include <drc_proto/drc_engine.h>
|
||||
#include <drc_proto/drc_item.h>
|
||||
|
@ -66,8 +67,12 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
|
|||
|
||||
for( auto rule : m_drcEngine->QueryRulesById( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE ) )
|
||||
{
|
||||
drc_dbg(1, "process rule %p\n", rule );
|
||||
if( rule->GetConstraint().m_Value.HasMin() )
|
||||
{
|
||||
m_largestClearance = std::max( m_largestClearance, rule->GetConstraint().m_Value.Min() );
|
||||
drc_dbg(1, "min-copper-clearance %d\n", rule->GetConstraint().m_Value.Min() );
|
||||
}
|
||||
}
|
||||
|
||||
ReportAux( "Worst clearance : %d nm", m_largestClearance );
|
||||
|
@ -126,88 +131,20 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperTextAndGraphics()
|
|||
|
||||
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
|
||||
{
|
||||
EDA_RECT bbox;
|
||||
std::vector<SEG> itemShape;
|
||||
int itemWidth;
|
||||
DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
|
||||
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
|
||||
EDA_RECT bbox;
|
||||
std::shared_ptr<SHAPE> itemShape;
|
||||
DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
|
||||
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
|
||||
|
||||
if( drawItem )
|
||||
{
|
||||
bbox = drawItem->GetBoundingBox();
|
||||
itemWidth = drawItem->GetWidth();
|
||||
|
||||
switch( drawItem->GetShape() )
|
||||
{
|
||||
case S_ARC:
|
||||
{
|
||||
SHAPE_ARC arc( drawItem->GetCenter(), drawItem->GetArcStart(),
|
||||
(double) drawItem->GetAngle() / 10.0 );
|
||||
|
||||
SHAPE_LINE_CHAIN l = arc.ConvertToPolyline();
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
itemShape.push_back( l.Segment( i ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case S_SEGMENT:
|
||||
itemShape.emplace_back( SEG( drawItem->GetStart(), drawItem->GetEnd() ) );
|
||||
break;
|
||||
|
||||
case S_CIRCLE:
|
||||
{
|
||||
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
|
||||
SHAPE_ARC circle( drawItem->GetCenter(), drawItem->GetEnd(), 360.0 );
|
||||
|
||||
SHAPE_LINE_CHAIN l = circle.ConvertToPolyline();
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
itemShape.push_back( l.Segment( i ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case S_CURVE:
|
||||
{
|
||||
drawItem->RebuildBezierToSegmentsPointsList( drawItem->GetWidth() );
|
||||
wxPoint start_pt = drawItem->GetBezierPoints()[0];
|
||||
|
||||
for( unsigned int jj = 1; jj < drawItem->GetBezierPoints().size(); jj++ )
|
||||
{
|
||||
wxPoint end_pt = drawItem->GetBezierPoints()[jj];
|
||||
itemShape.emplace_back( SEG( start_pt, end_pt ) );
|
||||
start_pt = end_pt;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case S_POLYGON:
|
||||
{
|
||||
SHAPE_LINE_CHAIN l = drawItem->GetPolyShape().Outline( 0 );
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
itemShape.push_back( l.Segment( i ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "unknown shape type" );
|
||||
break;
|
||||
}
|
||||
itemShape = drawItem->GetEffectiveShape();
|
||||
}
|
||||
else if( textItem )
|
||||
else if( textItem )
|
||||
{
|
||||
bbox = textItem->GetTextBox();
|
||||
itemWidth = textItem->GetEffectiveTextPenWidth();
|
||||
|
||||
std::vector<wxPoint> textShape;
|
||||
textItem->TransformTextShapeToSegmentList( textShape );
|
||||
|
||||
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
|
||||
itemShape.emplace_back( SEG( textShape[jj], textShape[jj+1] ) );
|
||||
itemShape = textItem->GetEffectiveShape();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -215,10 +152,10 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
|
|||
return;
|
||||
}
|
||||
|
||||
SHAPE_RECT rect_area( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
|
||||
SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
|
||||
|
||||
if( itemShape.empty() )
|
||||
return;
|
||||
//if( itemShape->Empty() )
|
||||
// return;
|
||||
|
||||
// Test tracks and vias
|
||||
for( auto track : m_board->Tracks() )
|
||||
|
@ -228,34 +165,24 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
|
|||
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aItem, track );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
int widths = ( track->GetWidth() + itemWidth ) / 2;
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
int actual = INT_MAX;
|
||||
wxPoint pos;
|
||||
|
||||
SEG trackSeg( track->GetStart(), track->GetEnd() );
|
||||
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||
|
||||
// Fast test to detect a track segment candidate inside the text bounding box
|
||||
if( !rect_area.Collide( trackSeg, center2centerAllowed ) )
|
||||
if( !bboxShape.Collide( &trackSeg, 0 ) )
|
||||
continue;
|
||||
|
||||
OPT<SEG> minSeg;
|
||||
SEG::ecoord center2center_squared = 0;
|
||||
if( !itemShape->Collide( &trackSeg, minClearance, &actual ) )
|
||||
continue;
|
||||
|
||||
for( const SEG& itemSeg : itemShape )
|
||||
pos = (wxPoint) itemShape->Centre();
|
||||
|
||||
if( actual < INT_MAX )
|
||||
{
|
||||
SEG::ecoord thisDist_squared = trackSeg.SquaredDistance( itemSeg );
|
||||
int errorCode = DRCE_CLEARANCE;
|
||||
|
||||
if( !minSeg || thisDist_squared < center2center_squared )
|
||||
{
|
||||
minSeg = itemSeg;
|
||||
center2center_squared = thisDist_squared;
|
||||
}
|
||||
}
|
||||
|
||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
||||
{
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
int errorCode = ( track->Type() == PCB_VIA_T ) ? DRCE_VIA_NEAR_COPPER
|
||||
: DRCE_TRACK_NEAR_COPPER;
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
|
||||
wxString msg;
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
@ -267,7 +194,6 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
|
|||
drcItem->SetItems( track, aItem );
|
||||
drcItem->SetViolatingRule( rule );
|
||||
|
||||
wxPoint pos = getLocation( track, minSeg.get() );
|
||||
ReportWithMarker( drcItem, pos );
|
||||
}
|
||||
}
|
||||
|
@ -285,36 +211,21 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
|
|||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aItem, pad );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
|
||||
int widths = itemWidth / 2;
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
int actual = INT_MAX;
|
||||
|
||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||
|
||||
// Fast test to detect a pad candidate inside the text bounding box
|
||||
// Finer test (time consumming) is made only for pads near the text.
|
||||
int bb_radius = pad->GetBoundingRadius() + minClearance;
|
||||
VECTOR2I shape_pos( pad->ShapePos() );
|
||||
|
||||
if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) )
|
||||
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
|
||||
continue;
|
||||
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& padOutline = pad->GetEffectivePolygon();
|
||||
OPT<SEG> minSeg;
|
||||
SEG::ecoord center2center_squared = 0;
|
||||
if( !pad->GetEffectiveShape()->Collide( itemShape.get(), minClearance, &actual ) )
|
||||
continue;
|
||||
|
||||
for( const SEG& itemSeg : itemShape )
|
||||
if( actual < INT_MAX )
|
||||
{
|
||||
SEG::ecoord thisCenter2center_squared = padOutline.SquaredDistance( itemSeg );
|
||||
|
||||
if( !minSeg || thisCenter2center_squared < center2center_squared )
|
||||
{
|
||||
minSeg = itemSeg;
|
||||
center2center_squared = thisCenter2center_squared;
|
||||
}
|
||||
}
|
||||
|
||||
if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
||||
{
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_COPPER );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_CLEARANCE );
|
||||
|
||||
wxString msg;
|
||||
|
||||
|
@ -366,7 +277,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
|
||||
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
|
||||
PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
|
||||
LSET refLayerSet = aRefSeg->GetLayerSet();
|
||||
|
||||
|
@ -414,11 +325,9 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
|
||||
int actual;
|
||||
|
||||
if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) )
|
||||
if( pad->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
|
||||
{
|
||||
actual = std::max( 0, actual );
|
||||
SEG padSeg( pad->GetPosition(), pad->GetPosition() );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_CLEARANCE );
|
||||
|
||||
wxString msg;
|
||||
|
||||
|
@ -431,9 +340,9 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
drcItem->SetItems( aRefSeg, pad );
|
||||
drcItem->SetViolatingRule( rule );
|
||||
|
||||
ReportWithMarker( drcItem, getLocation( aRefSeg, padSeg ) );
|
||||
ReportWithMarker( drcItem, pad->GetPosition() );
|
||||
|
||||
if( isErrorLimitExceeded( DRCE_TRACK_NEAR_PAD ) )
|
||||
if( isErrorLimitExceeded( DRCE_CLEARANCE ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -485,16 +394,10 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefSeg, track );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
|
||||
SEG trackSeg( track->GetStart(), track->GetEnd() );
|
||||
int widths = ( refSegWidth + track->GetWidth() ) / 2;
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
|
||||
// Avoid square-roots if possible (for performance)
|
||||
SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg );
|
||||
OPT_VECTOR2I intersection = refSeg.Intersect( trackSeg );
|
||||
|
||||
// Check two tracks crossing first as it reports a DRCE without distances
|
||||
if( intersection )
|
||||
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
|
||||
int actual;
|
||||
|
||||
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACKS_CROSSING );
|
||||
|
||||
|
@ -508,18 +411,11 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
if( isErrorLimitExceeded( DRCE_TRACKS_CROSSING ) )
|
||||
return;
|
||||
}
|
||||
else if( center2center_squared < SEG::Square( center2centerAllowed ) )
|
||||
else if( refSeg.Collide( &trackSeg, minClearance, &actual ) )
|
||||
{
|
||||
int errorCode = DRCE_TRACK_ENDS;
|
||||
wxPoint pos = getLocation( aRefSeg, trackSeg.GetSeg() );
|
||||
int errorCode = DRCE_CLEARANCE;
|
||||
|
||||
if( aRefSeg->Type() == PCB_VIA_T && track->Type() == PCB_VIA_T )
|
||||
errorCode = DRCE_VIA_NEAR_VIA;
|
||||
else if( aRefSeg->Type() == PCB_VIA_T || track->Type() == PCB_VIA_T )
|
||||
errorCode = DRCE_VIA_NEAR_TRACK;
|
||||
else if( refSeg.ApproxParallel( trackSeg ) )
|
||||
errorCode = DRCE_TRACK_SEGMENTS_TOO_CLOSE;
|
||||
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
|
||||
|
||||
wxString msg;
|
||||
|
@ -532,7 +428,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
drcItem->SetItems( aRefSeg, track );
|
||||
drcItem->SetViolatingRule( rule );
|
||||
|
||||
ReportWithMarker( drcItem, getLocation( aRefSeg, trackSeg ) );
|
||||
ReportWithMarker( drcItem, pos );
|
||||
|
||||
if( isErrorLimitExceeded( errorCode ) )
|
||||
return;
|
||||
|
@ -564,38 +460,35 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
|
|||
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefSeg, zone );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
int widths = refSegWidth / 2;
|
||||
|
||||
int widths = refSegWidth / 2;
|
||||
int center2centerAllowed = minClearance + widths;
|
||||
SHAPE_POLY_SET* outline =
|
||||
const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( layer ) );
|
||||
// to avoid false positive, due to rounding issues and approxiamtions
|
||||
// in distance and clearance calculations, use a small threshold for distance
|
||||
// (1 micron)
|
||||
#define THRESHOLD_DIST Millimeter2iu( 0.001 )
|
||||
|
||||
SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg );
|
||||
int allowedDist = minClearance + widths + THRESHOLD_DIST;
|
||||
int actual = INT_MAX;
|
||||
|
||||
// to avoid false positive, due to rounding issues and approxiamtions
|
||||
// in distance and clearance calculations, use a small threshold for distance
|
||||
// (1 micron)
|
||||
#define THRESHOLD_DIST Millimeter2iu( 0.001 )
|
||||
if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) )
|
||||
{
|
||||
actual = std::max( 0, actual - widths );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_CLEARANCE );
|
||||
wxString msg;
|
||||
|
||||
if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) )
|
||||
{
|
||||
int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE );
|
||||
wxString msg;
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
rule->GetName(),
|
||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
rule->GetName(),
|
||||
MessageTextFromValue( userUnits(), minClearance, true ),
|
||||
MessageTextFromValue( userUnits(), actual, true ) );
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( aRefSeg, zone );
|
||||
drcItem->SetViolatingRule( rule );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
drcItem->SetItems( aRefSeg, zone );
|
||||
drcItem->SetViolatingRule( rule );
|
||||
|
||||
ReportWithMarker( drcItem, getLocation( aRefSeg, zone ) );
|
||||
ReportWithMarker( drcItem, getLocation( aRefSeg, zone ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fixme: board edge clearance to another rule
|
||||
|
@ -656,16 +549,6 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D
|
|||
|
||||
LSET layerMask = aRefPad->GetLayerSet() & all_cu;
|
||||
|
||||
|
||||
// For hole testing we use a dummy pad which is given the shape of the hole. Note that
|
||||
// this pad must have a parent because some functions expect a non-null parent to find
|
||||
// the pad's board.
|
||||
MODULE dummymodule( m_drcEngine->GetBoard() ); // Creates a dummy parent
|
||||
D_PAD dummypad( &dummymodule );
|
||||
|
||||
// Ensure the hole is on all copper layers
|
||||
dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
|
||||
|
||||
for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
|
||||
{
|
||||
D_PAD* pad = *pad_list;
|
||||
|
@ -710,9 +593,9 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D
|
|||
int clearanceAllowed = minClearance - m_drcEngine->GetDesignSettings()->GetDRCEpsilon();
|
||||
int actual;
|
||||
|
||||
if( !checkClearancePadToPad( aRefPad, pad, clearanceAllowed, &actual ) )
|
||||
if( aRefPad->Collide( pad, clearanceAllowed, &actual ) )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_PAD );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_CLEARANCE );
|
||||
wxString msg;
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
/*m_clearanceSource fixme*/ "",
|
||||
|
@ -880,7 +763,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
|
|||
}
|
||||
else
|
||||
{
|
||||
drcItem = new DRC_ITEM( DRCE_ZONES_TOO_CLOSE );
|
||||
drcItem = new DRC_ITEM( DRCE_CLEARANCE );
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
@ -911,4 +794,4 @@ std::set<test::DRC_RULE_ID_T> test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetMatch
|
|||
namespace detail
|
||||
{
|
||||
static test::DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_COPPER_CLEARANCE> dummy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,28 @@ public:
|
|||
virtual std::set<test::DRC_RULE_ID_T> GetMatchingRuleIds() const override;
|
||||
|
||||
private:
|
||||
bool checkPad( D_PAD* aPad );
|
||||
bool checkVia( VIA* aVia );
|
||||
bool checkMicroVia( VIA* aVia );
|
||||
|
||||
void addHole( const wxPoint& aLocation, int aRadius, BOARD_ITEM* aOwner );
|
||||
bool checkHoles();
|
||||
|
||||
void testPadHoles();
|
||||
bool doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
|
||||
|
||||
struct DRILLED_HOLE
|
||||
{
|
||||
wxPoint m_location;
|
||||
int m_drillRadius = 0;
|
||||
BOARD_ITEM* m_owner = nullptr;
|
||||
};
|
||||
|
||||
EDA_UNITS m_units;
|
||||
BOARD* m_board;
|
||||
std::vector<DRILLED_HOLE> m_holes;
|
||||
int m_largestRadius;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -61,11 +80,15 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
|
|||
|
||||
for( auto rule : m_drcEngine->QueryRulesById( test::DRC_RULE_ID_T::DRC_RULE_ID_HOLE_CLEARANCE ) )
|
||||
{
|
||||
drc_dbg(1, "process rule %p\n", rule );
|
||||
if( rule->GetConstraint().m_Value.HasMin() )
|
||||
{
|
||||
drc_dbg(1, "min-hole-clearance %d\n", rule->GetConstraint().m_Value.Min() );
|
||||
m_largestClearance = std::max( m_largestClearance, rule->GetConstraint().m_Value.Min() );
|
||||
}
|
||||
}
|
||||
|
||||
ReportAux( "Worst clearance : %d nm", m_largestClearance );
|
||||
ReportAux( "Worst hole clearance : %d nm", m_largestClearance );
|
||||
|
||||
ReportStage( ("Testing pad/hole clearances"), 0, 2 );
|
||||
testPadHoles();
|
||||
|
@ -105,7 +128,7 @@ void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPadHoles()
|
|||
for( auto& pad : sortedPads )
|
||||
{
|
||||
int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
|
||||
drc_dbg(4,"-> %p\n", pad);
|
||||
drc_dbg(10,"-> %p\n", pad);
|
||||
doPadToPadHoleDrc( pad, &pad, listEnd, x_limit );
|
||||
}
|
||||
}
|
||||
|
@ -118,14 +141,6 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
|
|||
|
||||
LSET layerMask = aRefPad->GetLayerSet() & all_cu;
|
||||
|
||||
// For hole testing we use a dummy pad which is given the shape of the hole. Note that
|
||||
// this pad must have a parent because some functions expect a non-null parent to find
|
||||
// the pad's board.
|
||||
MODULE dummymodule( m_board ); // Creates a dummy parent
|
||||
D_PAD dummypad( &dummymodule );
|
||||
|
||||
// Ensure the hole is on all copper layers
|
||||
dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
|
||||
|
||||
for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
|
||||
{
|
||||
|
@ -134,24 +149,27 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
|
|||
if( pad == aRefPad )
|
||||
continue;
|
||||
|
||||
drc_dbg(4," chk against -> %p\n", pad);
|
||||
|
||||
|
||||
// drc_dbg(10," chk against -> %p\n", pad);
|
||||
|
||||
// We can stop the test when pad->GetPosition().x > x_limit
|
||||
// because the list is sorted by X values
|
||||
if( pad->GetPosition().x > x_limit )
|
||||
break;
|
||||
|
||||
drc_dbg(4," chk2 against -> %p ds %d %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
|
||||
// drc_dbg(10," chk2 against -> %p ds %d %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
|
||||
|
||||
drc_dbg(1," chk1 against -> %p x0 %d x2 %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
|
||||
|
||||
// No problem if pads which are on copper layers are on different copper layers,
|
||||
// (pads can be only on a technical layer, to build complex pads)
|
||||
// but their hole (if any ) can create DRC error because they are on all
|
||||
// copper layers, so we test them
|
||||
if( ( pad->GetLayerSet() & layerMask ) == 0 &&
|
||||
if( ( pad->GetLayerSet() & layerMask ) != 0 &&
|
||||
( pad->GetLayerSet() & all_cu ) != 0 &&
|
||||
( aRefPad->GetLayerSet() & all_cu ) != 0 )
|
||||
{
|
||||
drc_dbg(4," chk3 against -> %p\n", pad);
|
||||
|
||||
// if holes are in the same location and have the same size and shape,
|
||||
// this can be accepted
|
||||
|
@ -167,26 +185,25 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
|
|||
continue;
|
||||
}
|
||||
|
||||
drc_dbg(1," chk3 against -> %p x0 %d x2 %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
|
||||
|
||||
/* Here, we must test clearance between holes and pads
|
||||
* dummy pad size and shape is adjusted to pad drill size and shape
|
||||
* pad size and shape is adjusted to pad drill size and shape
|
||||
*/
|
||||
if( pad->GetDrillSize().x )
|
||||
{
|
||||
drc_dbg(4,"check pad %p\n", pad );
|
||||
// pad under testing has a hole, test this hole against pad reference
|
||||
dummypad.SetPosition( pad->GetPosition() );
|
||||
dummypad.SetSize( pad->GetDrillSize() );
|
||||
dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
|
||||
PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
|
||||
dummypad.SetOrientation( pad->GetOrientation() );
|
||||
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_HOLE_CLEARANCE, aRefPad, &dummypad );
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_HOLE_CLEARANCE, aRefPad, pad );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
int actual;
|
||||
|
||||
if( !checkClearancePadToPad( aRefPad, &dummypad, minClearance, &actual ) )
|
||||
drc_dbg(1,"check pad %p rule '%s' cl %d\n", pad, (const char*) rule->GetName().c_str(), minClearance );
|
||||
|
||||
// fixme: pad stacks...
|
||||
if( aRefPad->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_CLEARANCE );
|
||||
|
||||
wxString msg;
|
||||
|
||||
|
@ -206,20 +223,16 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
|
|||
|
||||
if( aRefPad->GetDrillSize().x ) // pad reference has a hole
|
||||
{
|
||||
drc_dbg(4,"check refpad %p\n", pad );
|
||||
dummypad.SetPosition( aRefPad->GetPosition() );
|
||||
dummypad.SetSize( aRefPad->GetDrillSize() );
|
||||
dummypad.SetShape( aRefPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
|
||||
PAD_SHAPE_OVAL : PAD_SHAPE_CIRCLE );
|
||||
dummypad.SetOrientation( aRefPad->GetOrientation() );
|
||||
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_HOLE_CLEARANCE, aRefPad, &dummypad );
|
||||
auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_HOLE_CLEARANCE, aRefPad, pad );
|
||||
auto minClearance = rule->GetConstraint().GetValue().Min();
|
||||
int actual;
|
||||
|
||||
if( !checkClearancePadToPad( pad, &dummypad, minClearance, &actual ) )
|
||||
drc_dbg(1,"check pad %p rule '%s' cl %d\n", aRefPad, (const char*) rule->GetName().c_str(), minClearance );
|
||||
|
||||
if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) )
|
||||
{
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_NEAR_PAD );
|
||||
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_HOLE_CLEARANCE );
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
|
||||
|
|
Loading…
Reference in New Issue