Update DRC rules to new layer and disallow grammars.

Also adds support for hooking rules up to named zones.

Fixes https://gitlab.com/kicad/code/kicad/issues/2041
This commit is contained in:
Jeff Young 2020-08-07 21:18:33 +01:00
parent 406de56964
commit e5b50d90a7
30 changed files with 509 additions and 336 deletions

View File

@ -360,9 +360,9 @@ void AR_AUTOPLACER::buildFpAreas( MODULE* aFootprint, int aFpClearance )
addFpBody( fpBBox.GetOrigin(), fpBBox.GetEnd(), layerMask );
// Trace pads + clearance areas.
for( auto pad : aFootprint->Pads() )
for( D_PAD* pad : aFootprint->Pads() )
{
int margin = (m_matrix.m_GridRouting / 2) + pad->GetClearance();
int margin = (m_matrix.m_GridRouting / 2) + pad->GetClearance( pad->GetLayer() );
addPad( pad, margin );
}
}
@ -414,9 +414,9 @@ void AR_AUTOPLACER::genModuleOnRoutingMatrix( MODULE* Module )
CELL_IS_MODULE, AR_MATRIX::WRITE_OR_CELL );
// Trace pads + clearance areas.
for( auto pad : Module->Pads() )
for( D_PAD* pad : Module->Pads() )
{
int margin = (m_matrix.m_GridRouting / 2) + pad->GetClearance();
int margin = (m_matrix.m_GridRouting / 2) + pad->GetClearance( pad->GetLayer() );
m_matrix.PlacePad( pad, CELL_IS_MODULE, margin, AR_MATRIX::WRITE_OR_CELL );
}

View File

@ -92,7 +92,8 @@ NETCLASS* BOARD_CONNECTED_ITEM::GetEffectiveNetclass() const
* LEVEL 2: Rules
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings
*/
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
wxString* aSource ) const
{
BOARD* board = GetBoard();
int clearance = 0;
@ -122,7 +123,7 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c
// LEVEL 2: Rules
//
if( GetRuleClearance( aItem, &clearance, aSource ) )
if( GetRuleClearance( aItem, aLayer, &clearance, aSource ) )
return clearance;
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings
@ -163,17 +164,18 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c
}
bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, int* aClearance,
wxString* aSource ) const
bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer,
int* aClearance, wxString* aSource ) const
{
DRC_RULE* rule = GetRule( this, aItem, CLEARANCE_CONSTRAINT );
const DRC_CONSTRAINT* constraint = GetConstraint( this, aItem, DRC_RULE_ID_CLEARANCE, aLayer,
aSource );
if( rule )
if( constraint )
{
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
*aSource = wxString::Format( _( "'%s' rule" ), *aSource );
*aClearance = rule->m_Clearance.Min;
*aClearance = constraint->m_Value.Min();
return true;
}

View File

@ -161,20 +161,24 @@ public:
* returned clearance is the greater of this object's NETCLASS clearance and
* aItem's NETCLASS clearance. If \a aItem is NULL, then this objects clearance
* is returned.
* @param aLayer the layer in question
* @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units.
*/
virtual int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const;
virtual int GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem = nullptr,
wxString* aSource = nullptr ) const;
/**
* Function GetRuleClearance
* returns any rule-based clearance.
* @param aLayer the current layer under test
* @param aClearance [out] the clearance value in internal units
* @param aSource [out] reports the source as a user-readable string
* @return true if a rule was fired
*/
virtual bool GetRuleClearance( BOARD_ITEM* aItem, int* aClearance, wxString* aSource ) const;
virtual bool GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int* aClearance,
wxString* aSource ) const;
/**
* Function GetLocalClearanceOverrides

View File

@ -822,7 +822,13 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
clearance = std::max( clearance, netclass.second->GetClearance() );
for( const DRC_RULE* rule : m_DRCRules )
clearance = std::max( clearance, rule->m_Clearance.Min );
{
for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
{
if( constraint.m_Type == DRC_RULE_ID_CLEARANCE )
clearance = std::max( clearance, constraint.m_Value.Min() );
}
}
return clearance;
}

View File

@ -825,7 +825,7 @@ void D_PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>
}
wxString source;
int clearance = GetClearance( nullptr, &source );
int clearance = GetClearance( GetLayer(), nullptr, &source );
msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source );

View File

@ -133,15 +133,16 @@ void TRACK::GetWidthConstraints( int* aMin, int* aMax, wxString* aSource ) const
// Not currently implemented
// LEVEL 2: Rules
DRC_RULE* rule = GetRule( this, nullptr, TRACK_CONSTRAINT );
const DRC_CONSTRAINT* constraint = GetConstraint( this, nullptr, DRC_RULE_ID_TRACK, m_Layer,
aSource );
if( rule )
if( constraint )
{
*aMin = rule->m_TrackConstraint.Min;
*aMax = rule->m_TrackConstraint.Max;
*aMin = constraint->m_Value.Min();
*aMax = constraint->m_Value.Max();
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
*aSource = wxString::Format( _( "'%s' rule" ), *aSource );
return;
}
@ -160,16 +161,17 @@ void TRACK::GetWidthConstraints( int* aMin, int* aMax, wxString* aSource ) const
}
int VIA::GetMinAnnulus( wxString* aSource ) const
int VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
{
DRC_RULE* rule = GetRule( this, nullptr, ANNULUS_CONSTRAINT );
const DRC_CONSTRAINT* constraint = GetConstraint( this, nullptr, DRC_RULE_ID_ANNULUS, aLayer,
aSource );
if( rule )
if( constraint )
{
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
*aSource = wxString::Format( _( "'%s' rule" ), *aSource );
return rule->m_MinAnnulusWidth;
return constraint->m_Value.Min();
}
else
{
@ -493,7 +495,7 @@ unsigned int TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
const BOX2I TRACK::ViewBBox() const
{
BOX2I bbox = GetBoundingBox();
bbox.Inflate( 2 * GetClearance() );
bbox.Inflate( 2 * GetClearance( GetLayer() ) );
return bbox;
}
@ -612,7 +614,7 @@ void TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>
}
}
int clearance = GetClearance( nullptr, &source );
int clearance = GetClearance( GetLayer(), nullptr, &source );
msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source );
@ -685,13 +687,13 @@ void VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>&
aList.emplace_back( _( "Drill" ), msg, RED );
int clearance = GetClearance( nullptr, &source );
int clearance = GetClearance( GetLayer(), nullptr, &source );
msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source );
aList.emplace_back( msg, msg2, BLACK );
int minAnnulus = GetMinAnnulus( &source );
int minAnnulus = GetMinAnnulus( GetLayer(), &source );
msg.Printf( _( "Min Annulus: %s" ), MessageTextFromValue( units, minAnnulus, true ) );
msg2.Printf( _( "(from %s)" ), source );

View File

@ -442,7 +442,7 @@ public:
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
int GetMinAnnulus( wxString* aSource ) const;
int GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const;
/**
* Function SetDrill

View File

@ -336,7 +336,7 @@ int ZONE_CONTAINER::GetThermalReliefCopperBridge( D_PAD* aPad ) const
}
int ZONE_CONTAINER::GetKeepouts( std::map<int, wxString>* aSources ) const
int ZONE_CONTAINER::GetKeepouts( PCB_LAYER_ID aLayer, std::map<int, wxString>* aSources ) const
{
wxString source;
int keepouts = 0;
@ -370,41 +370,42 @@ int ZONE_CONTAINER::GetKeepouts( std::map<int, wxString>* aSources ) const
setFlag( DISALLOW_ZONES );
}
DRC_RULE* rule = GetRule( this, nullptr, DISALLOW_CONSTRAINT );
const DRC_CONSTRAINT* constraint = GetConstraint( this, nullptr, DRC_RULE_ID_DISALLOW, aLayer,
&source );
if( rule )
if( constraint )
{
if( aSources )
source = wxString::Format( _( "'%s' rule" ), rule->m_Name );
source = wxString::Format( _( "'%s' rule" ), source );
if( ( rule->m_DisallowFlags & DISALLOW_VIAS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_VIAS ) > 0 )
setFlag( DISALLOW_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_MICRO_VIAS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_MICRO_VIAS ) > 0 )
setFlag( DISALLOW_MICRO_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_BB_VIAS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_BB_VIAS ) > 0 )
setFlag( DISALLOW_BB_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_TRACKS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_TRACKS ) > 0 )
setFlag( DISALLOW_TRACKS );
if( ( rule->m_DisallowFlags & DISALLOW_PADS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_PADS ) > 0 )
setFlag( DISALLOW_PADS );
if( ( rule->m_DisallowFlags & DISALLOW_ZONES ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_ZONES ) > 0 )
setFlag( DISALLOW_ZONES );
if( ( rule->m_DisallowFlags & DISALLOW_TEXTS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_TEXTS ) > 0 )
setFlag( DISALLOW_TEXTS );
if( ( rule->m_DisallowFlags & DISALLOW_GRAPHICS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_GRAPHICS ) > 0 )
setFlag( DISALLOW_GRAPHICS );
if( ( rule->m_DisallowFlags & DISALLOW_HOLES ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_HOLES ) > 0 )
setFlag( DISALLOW_HOLES );
if( ( rule->m_DisallowFlags & DISALLOW_FOOTPRINTS ) > 0 )
if( ( constraint->m_DisallowFlags & DISALLOW_FOOTPRINTS ) > 0 )
setFlag( DISALLOW_FOOTPRINTS );
}
@ -678,7 +679,7 @@ void ZONE_CONTAINER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
aList.emplace_back( _( "Filled Area" ), msg, BLUE );
wxString source;
int clearance = GetClearance( nullptr, &source );
int clearance = GetClearance( GetLayer(), nullptr, &source );
msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source );
@ -1374,6 +1375,8 @@ static struct ZONE_CONTAINER_DESC
//&ZONE_CONTAINER::SetIsFilled, &ZONE_CONTAINER::IsFilled ) );
propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Min Thickness" ),
&ZONE_CONTAINER::SetMinThickness, &ZONE_CONTAINER::GetMinThickness, PROPERTY_DISPLAY::DISTANCE ) );
propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, wxString>( _( "Name" ),
&ZONE_CONTAINER::SetZoneName, &ZONE_CONTAINER::GetZoneName ) );
// TODO pad connection, thermal relief gap, thermal relief copper bridge
}
} _ZONE_CONTAINER_DESC;

View File

@ -723,7 +723,7 @@ public:
* flag.
* @return a bitset of DISALLOW_* flags.
*/
int GetKeepouts( std::map<int, wxString>* aSources = nullptr ) const;
int GetKeepouts( PCB_LAYER_ID aLayer, std::map<int, wxString>* aSources = nullptr ) const;
void SetIsKeepout( bool aEnable ) { m_isKeepout = aEnable; }
void SetDoNotAllowCopperPour( bool aEnable ) { m_doNotAllowCopperPour = aEnable; }

View File

@ -179,20 +179,37 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
if( sexprs.empty() )
tokens = "rule version";
else if( sexprs.top() == "rule" )
tokens = "condition constraint disallow layer";
tokens = "condition constraint layer";
else if( sexprs.top() == "constraint" )
tokens = "max min opt";
}
else if( context == SEXPR_TOKEN )
{
if( sexprs.empty() )
/* badly formed grammar */;
{
/* badly formed grammar */
}
else if( sexprs.top() == "constraint" )
tokens = "annulus_width clearance hole track_width";
else if( sexprs.top() == "disallow" )
{
tokens = "annulus_width clearance disallow hole track_width";
}
else if( sexprs.top() == "disallow"
|| sexprs.top() == "buried_via"
|| sexprs.top() == "graphic"
|| sexprs.top() == "hole"
|| sexprs.top() == "micro_via"
|| sexprs.top() == "pad"
|| sexprs.top() == "text"
|| sexprs.top() == "track"
|| sexprs.top() == "via"
|| sexprs.top() == "zone" )
{
tokens = "buried_via graphic hole micro_via pad text track via zone";
}
else if( sexprs.top() == "layer" )
{
tokens = "inner outer \"x\"";
}
}
else if( context == STRING && expr_context == STRUCT_REF )
{
@ -327,11 +344,16 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
msg << _( "Rule Clauses" );
msg << "</b>"
"<pre>"
"(disallow &lt;item_type>)\r"
"(constraint &lt;constraint_type> ...)\r"
"(condition \"&lt;expression>\")\r"
"\r</pre>"
"<b>";
msg << _( "Constraint Types" );
msg << "</b>"
"<pre>"
"clearance annulus_width track_width hole dissallow\r"
"\r</pre>"
"<b>";
msg << _( "Item Types" );
msg << "</b>"
"<pre>"
@ -340,17 +362,11 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
"hole buried_via graphic\r"
"\r</pre>"
"<b>";
msg << _( "Constraint Types" );
msg << "</b>"
"<pre>"
"clearance annulus_width track_width hole\r"
"\r</pre>"
"<b>";
msg << _( "Examples" );
msg << "</b>"
"<pre>"
"(rule \"copper keepout\"\r"
" (disallow track) (disallow via) (disallow zone)\r"
" (constraint disallow track via zone)\r"
" (condition \"A.name == 'no_copper'\"))\r"
"\r"
"(rule \"BGA neckdown\"\r"

View File

@ -502,10 +502,7 @@ void DRC::testPadClearances( BOARD_COMMIT& aCommit )
static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts );
if( pad->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
{
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
}
pad->GetRuleClearance( &dummyEdge, pad->GetLayer(), &minClearance, &m_clearanceSource );
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
{
@ -723,7 +720,8 @@ void DRC::testZones( BOARD_COMMIT& aCommit )
// Get clearance used in zone to zone test. The policy used to
// obtain that value is now part of the zone object itself by way of
// ZONE_CONTAINER::GetClearance().
int zone2zoneClearance = zoneRef->GetClearance( zoneToTest, &m_clearanceSource );
int zone2zoneClearance = zoneRef->GetClearance( zoneRef->GetLayer(), zoneToTest,
&m_clearanceSource );
// Keepout areas have no clearance, so set zone2zoneClearance to 1
// ( zone2zoneClearance = 0 can create problems in test functions)
@ -907,12 +905,12 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
// Test tracks and vias
for( auto track : m_pcb->Tracks() )
for( TRACK* track : m_pcb->Tracks() )
{
if( !track->IsOnLayer( aItem->GetLayer() ) )
continue;
int minClearance = track->GetClearance( aItem, &m_clearanceSource );
int minClearance = track->GetClearance( track->GetLayer(), aItem, &m_clearanceSource );
int actual = INT_MAX;
wxPoint pos;
@ -954,7 +952,7 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
}
// Test pads
for( auto pad : m_pcb->GetPads() )
for( D_PAD* pad : m_pcb->GetPads() )
{
if( !pad->IsOnLayer( aItem->GetLayer() ) )
continue;
@ -963,7 +961,7 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
if( drawItem && pad->GetParent() == drawItem->GetParent() )
continue;
int minClearance = pad->GetClearance( aItem, &m_clearanceSource );
int minClearance = pad->GetClearance( aItem->GetLayer(), aItem, &m_clearanceSource );
int actual = INT_MAX;
// Fast test to detect a pad candidate inside the text bounding box
@ -1136,7 +1134,8 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
if( pad->GetDrillSize().x )
{
int minClearance = aRefPad->GetClearance( nullptr, &m_clearanceSource );
int minClearance = aRefPad->GetClearance( aRefPad->GetLayer(), nullptr,
&m_clearanceSource );
int actual;
if( aRefPad->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) )
@ -1159,7 +1158,8 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
if( aRefPad->GetDrillSize().x )
{
int minClearance = pad->GetClearance( nullptr, &m_clearanceSource );
int minClearance = pad->GetClearance( pad->GetLayer(), nullptr,
&m_clearanceSource );
int actual;
if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) )
@ -1216,25 +1216,28 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
continue;
}
int minClearance = aRefPad->GetClearance( pad, &m_clearanceSource );
int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon();
int actual;
if( aRefPad->Collide( pad, clearanceAllowed, &actual ) )
for( PCB_LAYER_ID layer : aRefPad->GetLayerSet().Seq() )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
int minClearance = aRefPad->GetClearance( layer, pad, &m_clearanceSource );
int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon();
int actual;
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
if( aRefPad->Collide( pad, clearanceAllowed, &actual ) )
{
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefPad, pad );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() );
addMarkerToPcb( aCommit, marker );
return false;
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefPad, pad );
MARKER_PCB* marker = new MARKER_PCB( drcItem, aRefPad->GetPosition() );
addMarkerToPcb( aCommit, marker );
return false;
}
}
}

View File

@ -57,7 +57,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
{
VIA *refvia = static_cast<VIA*>( aRefSeg );
int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
int minAnnulus = refvia->GetMinAnnulus( &m_clearanceSource );
int minAnnulus = refvia->GetMinAnnulus( refvia->GetLayer(), &m_clearanceSource );
// test if the via size is smaller than minimum
if( refvia->GetViaType() == VIATYPE::MICROVIA )
@ -280,20 +280,22 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( pad->GetDrillSize().x > 0 )
{
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
DRC_RULE* rule = GetRule( aRefSeg, pad, CLEARANCE_CONSTRAINT );
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
const DRC_CONSTRAINT* constraint = GetConstraint( aRefSeg, pad,
DRC_RULE_ID_CLEARANCE, refLayer,
&m_clearanceSource );
int minClearance;
int actual;
if( rule )
if( constraint )
{
m_clearanceSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
minClearance = rule->m_Clearance.Min;
m_clearanceSource = wxString::Format( _( "'%s' rule" ), m_clearanceSource );
minClearance = constraint->m_Value.Min();
}
else
{
minClearance = aRefSeg->GetClearance( nullptr, &m_clearanceSource );
minClearance = aRefSeg->GetClearance( refLayer, nullptr,
&m_clearanceSource );
}
if( slot->Collide( &refSeg, minClearance + bds.GetDRCEpsilon(), &actual ) )
@ -316,7 +318,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
}
}
int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), pad,
&m_clearanceSource );
int actual;
if( pad->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
@ -383,7 +386,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
if( !trackBB.Intersects( refSegBB ) )
continue;
int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), track,
&m_clearanceSource );
int actual;
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
@ -447,7 +451,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
// (1 micron)
#define THRESHOLD_DIST Millimeter2iu( 0.001 )
int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
int minClearance = aRefSeg->GetClearance( aRefSeg->GetLayer(), zone,
&m_clearanceSource );
int widths = refSegWidth / 2;
int allowedDist = minClearance + widths + THRESHOLD_DIST;
int actual;
@ -483,10 +488,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts );
if( aRefSeg->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
{
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
}
aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance,
&m_clearanceSource );
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
int halfWidth = refSegWidth / 2;

View File

@ -84,21 +84,28 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
// drilled holes go all the way through, so which layer we use shouldn't matter
PCB_LAYER_ID layer = F_Cu;
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( holeSize == 0 )
return true;
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( aPad, nullptr, HOLE_CONSTRAINT );
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( aPad, nullptr, DRC_RULE_ID_HOLE_SIZE,
layer, &m_source );
if( rule )
if( constraint )
{
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
}
if( holeSize < minHole )
@ -106,7 +113,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource,
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, holeSize, true ) );
@ -132,16 +139,24 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// drilled holes go all the way through, so which layer we use shouldn't matter
PCB_LAYER_ID layer = F_Cu;
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_RULE_ID_HOLE_SIZE,
layer, &m_source );
if( rule )
if( constraint )
{
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
}
if( via->GetDrillValue() < minHole )
@ -149,7 +164,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource,
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
@ -175,16 +190,25 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// while microvia holes don't necessarily go all the way through, they can't be different
// sizes on different layers so we should still be safe enough using a fixed layer.
PCB_LAYER_ID layer = F_Cu;
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
{
int minHole = bds.m_MicroViasMinDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
int minHole;
const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_RULE_ID_HOLE_SIZE,
layer, &m_source );
if( rule )
if( constraint )
{
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
minHole = constraint->m_Value.Min();
m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MicroViasMinDrill;
m_source = _( "board minimum" );
}
if( via->GetDrillValue() < minHole )
@ -192,7 +216,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource,
m_source,
MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) );

View File

@ -62,7 +62,8 @@ private:
std::vector<DRILLED_HOLE> m_holes;
int m_largestRadius;
wxString m_msg; // Construct only once for performance
wxString m_source; // Construct only once for performance
wxString m_msg; // Construct only once for performance
};
#endif // DRC_DRILLED_HOLE_TESTER__H

View File

@ -51,7 +51,8 @@ bool DRC_KEEPOUT_TESTER::RunDRC( EDA_UNITS aUnits, BOARD& aBoard )
// Test keepout areas for vias, tracks and pads inside keepout areas
for( ZONE_CONTAINER* area : areasToInspect )
{
m_keepoutFlags = area->GetKeepouts( &m_sources );
// JEY TODO: our existing keepout strategy needs a work-over for rules....
m_keepoutFlags = area->GetKeepouts( F_Cu, &m_sources );
if( m_keepoutFlags > 0 )
{

View File

@ -23,13 +23,15 @@
#include <fctsys.h>
#include <drc/drc_rule.h>
#include <class_board.h>
#include <class_board_item.h>
#include <drc/drc_rule.h>
#include <pcb_expr_evaluator.h>
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint )
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName )
{
BOARD* board = aItem->GetBoard();
@ -38,13 +40,32 @@ DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstr
for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
{
if( ( rule->m_ConstraintFlags & aConstraint ) > 0 )
{
if( rule->m_Condition.EvaluateFor( aItem, bItem ) )
return rule;
if( !rule->m_LayerCondition.test( aLayer ) )
continue;
if( bItem && rule->m_Condition.EvaluateFor( bItem, aItem ) )
return rule;
for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
{
if( constraint.m_Type != aConstraint )
continue;
if( !rule->m_LayerCondition.test( aLayer ) )
continue;
if( rule->m_Condition.EvaluateFor( aItem, bItem, aLayer ) )
{
if( aRuleName )
*aRuleName = rule->m_Name;
return &constraint;
}
if( bItem && rule->m_Condition.EvaluateFor( bItem, aItem, aLayer ) )
{
if( aRuleName )
*aRuleName = rule->m_Name;
return &constraint;
}
}
}
@ -52,6 +73,17 @@ DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstr
}
DRC_RULE::DRC_RULE() :
m_LayerCondition( LSET::AllLayersMask() )
{
}
DRC_RULE::~DRC_RULE()
{
}
DRC_RULE_CONDITION::DRC_RULE_CONDITION()
{
m_ucode = nullptr;
@ -64,7 +96,8 @@ DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
}
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB )
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
PCB_LAYER_ID aLayer )
{
// An unconditional rule is always true
if( m_Expression.IsEmpty() )
@ -77,7 +110,7 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
PCB_EXPR_CONTEXT ctx;
PCB_EXPR_CONTEXT ctx( aLayer );
ctx.SetItems( a, b );
return m_ucode->Run( &ctx )->AsDouble() != 0.0;
@ -91,14 +124,10 @@ bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSou
if (!m_ucode)
m_ucode = new PCB_EXPR_UCODE;
PCB_EXPR_CONTEXT preflightContext;
PCB_EXPR_CONTEXT preflightContext( F_Cu );
bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext );
if( ok )
return true;
return false;
return ok;
}

View File

@ -25,8 +25,8 @@
#define DRC_RULE_H
#include <core/typeinfo.h>
#include <netclass.h>
#include <layers_id_colors_and_visibility.h>
#include <netclass.h>
#include <libeval_compiler/libeval_compiler.h>
@ -34,12 +34,6 @@ class BOARD_ITEM;
class PCB_EXPR_UCODE;
#define CLEARANCE_CONSTRAINT (1 << 0)
#define ANNULUS_CONSTRAINT (1 << 1)
#define TRACK_CONSTRAINT (1 << 2)
#define HOLE_CONSTRAINT (1 << 3)
#define DISALLOW_CONSTRAINT (1 << 4)
#define DISALLOW_VIAS (1 << 0)
#define DISALLOW_MICRO_VIAS (1 << 1)
#define DISALLOW_BB_VIAS (1 << 2)
@ -52,6 +46,17 @@ class PCB_EXPR_UCODE;
#define DISALLOW_FOOTPRINTS (1 << 9)
enum DRC_RULE_ID_T
{
DRC_RULE_ID_UNKNOWN = -1,
DRC_RULE_ID_CLEARANCE = 0,
DRC_RULE_ID_HOLE_SIZE,
DRC_RULE_ID_ANNULUS,
DRC_RULE_ID_TRACK,
DRC_RULE_ID_DISALLOW
};
template<class T=int>
class MINOPTMAX
{
@ -78,19 +83,36 @@ private:
};
class DRC_CONSTRAINT
{
public:
DRC_CONSTRAINT() :
m_Type( DRC_RULE_ID_UNKNOWN ),
m_DisallowFlags( 0 ),
m_LayerCondition( LSET::AllLayersMask() )
{}
const MINOPTMAX<int>& GetValue() const { return m_Value; }
public:
DRC_RULE_ID_T m_Type;
MINOPTMAX<int> m_Value;
int m_DisallowFlags;
LSET m_LayerCondition;
};
class DRC_RULE_CONDITION
{
public:
DRC_RULE_CONDITION();
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer );
bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
public:
LSET m_LayerCondition;
wxString m_Expression;
wxString m_TargetRuleName;
private:
PCB_EXPR_UCODE* m_ucode;
@ -100,40 +122,20 @@ private:
class DRC_RULE
{
public:
DRC_RULE() :
m_ConstraintFlags( 0 ),
m_DisallowFlags( 0 ),
m_Clearance( { 0, 0, INT_MAX / 2 } ),
m_MinAnnulusWidth( 0 ),
m_TrackConstraint( { 0, 0, INT_MAX / 2 } ),
m_MinHole( 0 )
{ }
struct MINOPTMAX
{
int Min;
int Opt;
int Max;
};
DRC_RULE();
virtual ~DRC_RULE();
public:
wxString m_Name;
int m_ConstraintFlags;
int m_DisallowFlags;
// A 0 value means the property is not modified by this rule.
// A positive value is a minimum.
MINOPTMAX m_Clearance;
int m_MinAnnulusWidth;
MINOPTMAX m_TrackConstraint;
int m_MinHole;
LSET m_LayerCondition;
DRC_RULE_CONDITION m_Condition;
wxString m_Name;
LSET m_LayerCondition;
wxString m_TestProviderName;
DRC_RULE_CONDITION m_Condition;
std::vector<DRC_CONSTRAINT> m_Constraints;
};
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint );
const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName );
#endif // DRC_RULE_H

View File

@ -178,49 +178,6 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
switch( token )
{
case T_disallow:
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing disallowed type.| Expected 'track', 'via', 'micro_via', "
"'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ) );
break;
}
else if( (int) token == DSN_STRING )
{
token = GetCurStrAsToken();
}
switch( token )
{
case T_track: rule->m_DisallowFlags |= DISALLOW_TRACKS; break;
case T_via: rule->m_DisallowFlags |= DISALLOW_VIAS; break;
case T_micro_via: rule->m_DisallowFlags |= DISALLOW_MICRO_VIAS; break;
case T_buried_via: rule->m_DisallowFlags |= DISALLOW_BB_VIAS; break;
case T_pad: rule->m_DisallowFlags |= DISALLOW_PADS; break;
case T_zone: rule->m_DisallowFlags |= DISALLOW_ZONES; break;
case T_text: rule->m_DisallowFlags |= DISALLOW_TEXTS; break;
case T_graphic: rule->m_DisallowFlags |= DISALLOW_GRAPHICS; break;
case T_hole: rule->m_DisallowFlags |= DISALLOW_HOLES; break;
case T_footprint: rule->m_DisallowFlags |= DISALLOW_FOOTPRINTS; break;
default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'track', 'via', 'micro_via', "
"'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ),
FromUTF8() );
reportError( msg );
}
rule->m_ConstraintFlags = DISALLOW_CONSTRAINT;
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_constraint:
parseConstraint( rule );
break;
@ -273,34 +230,65 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
{
T token;
int constraintType = 0;
int value;
wxString msg;
aRule->m_Constraints.emplace_back( DRC_CONSTRAINT() );
token = NextTok();
DRC_CONSTRAINT& constraint = aRule->m_Constraints.back();
int value;
wxString msg;
T token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing constraint type.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ) );
"'annulus_width', 'hole' or 'disallow'." ) );
return;
}
switch( token )
{
case T_clearance: constraintType = CLEARANCE_CONSTRAINT; break;
case T_track_width: constraintType = TRACK_CONSTRAINT; break;
case T_annulus_width: constraintType = ANNULUS_CONSTRAINT; break;
case T_hole: constraintType = HOLE_CONSTRAINT; break;
case T_clearance: constraint.m_Type = DRC_RULE_ID_CLEARANCE; break;
case T_track_width: constraint.m_Type = DRC_RULE_ID_TRACK; break;
case T_annulus_width: constraint.m_Type = DRC_RULE_ID_ANNULUS; break;
case T_hole: constraint.m_Type = DRC_RULE_ID_HOLE_SIZE; break;
case T_disallow: constraint.m_Type = DRC_RULE_ID_DISALLOW; break;
default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ),
"'annulus_width', 'hole' or 'disallow'." ),
FromUTF8() );
reportError( msg );
}
aRule->m_ConstraintFlags |= constraintType;
if( constraint.m_Type == DRC_RULE_ID_DISALLOW )
{
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( (int) token == DSN_STRING )
token = GetCurStrAsToken();
switch( token )
{
case T_track: constraint.m_DisallowFlags |= DISALLOW_TRACKS; break;
case T_via: constraint.m_DisallowFlags |= DISALLOW_VIAS; break;
case T_micro_via: constraint.m_DisallowFlags |= DISALLOW_MICRO_VIAS; break;
case T_buried_via: constraint.m_DisallowFlags |= DISALLOW_BB_VIAS; break;
case T_pad: constraint.m_DisallowFlags |= DISALLOW_PADS; break;
case T_zone: constraint.m_DisallowFlags |= DISALLOW_ZONES; break;
case T_text: constraint.m_DisallowFlags |= DISALLOW_TEXTS; break;
case T_graphic: constraint.m_DisallowFlags |= DISALLOW_GRAPHICS; break;
case T_hole: constraint.m_DisallowFlags |= DISALLOW_HOLES; break;
case T_footprint: constraint.m_DisallowFlags |= DISALLOW_FOOTPRINTS; break;
default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'track', 'via', 'micro_via', "
"'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ),
FromUTF8() );
reportError( msg );
parseUnknown();
}
}
return;
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
@ -321,14 +309,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Min = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Min = value; break;
case ANNULUS_CONSTRAINT: aRule->m_MinAnnulusWidth = value; break;
case HOLE_CONSTRAINT: aRule->m_MinHole = value; break;
}
constraint.m_Value.SetMin( value );
if( (int) NextTok() != DSN_RIGHT )
{
@ -348,12 +329,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Max = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Max = value; break;
}
constraint.m_Value.SetMax( value );
if( (int) NextTok() != DSN_RIGHT )
{
@ -373,12 +349,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Opt = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Opt = value; break;
}
constraint.m_Value.SetOpt( value );
if( (int) NextTok() != DSN_RIGHT )
{

View File

@ -468,13 +468,17 @@ void GERBER_JOBFILE_WRITER::addJSONDesignRules()
for( MODULE* module : m_pcb->Modules() )
{
for( auto& pad : module->Pads() )
for( D_PAD* pad : module->Pads() )
{
if( ( pad->GetLayerSet() & LSET::InternalCuMask() ).any() )
minPadClearanceInner = std::min( minPadClearanceInner, pad->GetClearance() );
for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
{
int padClearance = pad->GetClearance( layer );
if( ( pad->GetLayerSet() & LSET::ExternalCuMask() ).any() )
minPadClearanceOuter = std::min( minPadClearanceOuter, pad->GetClearance() );
if( layer == B_Cu || layer == F_Cu )
minPadClearanceOuter = std::min( minPadClearanceOuter, padClearance );
else
minPadClearanceInner = std::min( minPadClearanceInner, padClearance );
}
}
}
@ -519,12 +523,15 @@ void GERBER_JOBFILE_WRITER::addJSONDesignRules()
if( zone->GetIsKeepout() || !zone->IsOnCopperLayer() )
continue;
int zclerance = zone->GetClearance();
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
int zclerance = zone->GetClearance( layer );
if( zone->GetLayer() == B_Cu || zone->GetLayer() == F_Cu )
minclearanceOuter = std::min( minclearanceOuter, zclerance );
else
minclearanceInner = std::min( minclearanceInner, zclerance );
if( layer == B_Cu || layer == F_Cu )
minclearanceOuter = std::min( minclearanceOuter, zclerance );
else
minclearanceInner = std::min( minclearanceInner, zclerance );
}
}
if( minclearanceOuter != INT_MAX )

View File

@ -140,6 +140,63 @@ static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
}
static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
{
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
LIBEVAL::VALUE* arg = aCtx->Pop();
LIBEVAL::VALUE* result = aCtx->AllocValue();
result->Set( 0.0 );
aCtx->Push( result );
if( !arg )
{
aCtx->ReportError( wxString::Format( _( "Missing argument to '%s'" ),
wxT( "insideArea()" ) ) );
return;
}
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
ZONE_CONTAINER* zone = nullptr;
if( !item )
return;
if( arg->AsString() == "A" )
{
zone = dynamic_cast<ZONE_CONTAINER*>( context->GetItem( 0 ) );
}
else if( arg->AsString() == "B" )
{
zone = dynamic_cast<ZONE_CONTAINER*>( context->GetItem( 1 ) );
}
else
{
for( ZONE_CONTAINER* candidate : item->GetBoard()->Zones() )
{
if( candidate->GetZoneName().Matches( arg->AsString() ) )
{
zone = candidate;
break;
}
}
}
if( zone )
{
SHAPE_POLY_SET zonePoly = zone->GetFilledPolysList( context->GetLayer() );
SHAPE_POLY_SET testPoly;
item->TransformShapeWithClearanceToPolygon( testPoly, 0 );
testPoly.BooleanIntersection( zonePoly, SHAPE_POLY_SET::PM_FAST );
if( testPoly.OutlineCount() )
result->Set( 1.0 );
}
}
PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
{
auto registerFunc = [&]( const wxString& funcSignature, FPTR funcPtr )
@ -152,6 +209,7 @@ PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
registerFunc( "onLayer('x')", onLayer );
registerFunc( "isPlated()", isPlated );
registerFunc( "insideCourtyard('x')", insideCourtyard );
registerFunc( "insideArea('x')", insideArea );
}

View File

@ -52,7 +52,8 @@ public:
class PCB_EXPR_CONTEXT : public LIBEVAL::CONTEXT
{
public:
PCB_EXPR_CONTEXT()
PCB_EXPR_CONTEXT( PCB_LAYER_ID aLayer ) :
m_layer( aLayer )
{
m_items[0] = nullptr;
m_items[1] = nullptr;
@ -69,8 +70,14 @@ public:
return m_items[index];
}
PCB_LAYER_ID GetLayer() const
{
return m_layer;
}
private:
BOARD_ITEM* m_items[2];
BOARD_ITEM* m_items[2];
PCB_LAYER_ID m_layer;
};

View File

@ -508,7 +508,8 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color );
m_gal->DrawSegment( start, end, width + aTrack->GetClearance() * 2 );
m_gal->DrawSegment( start, end,
width + aTrack->GetClearance( ToLAYER_ID( aLayer ) ) * 2 );
}
}
}
@ -547,7 +548,7 @@ void PCB_PAINTER::draw( const ARC* aArc, int aLayer )
m_gal->SetStrokeColor( color );
m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle,
width + aArc->GetClearance() * 2 );
width + aArc->GetClearance( ToLAYER_ID( aLayer ) ) * 2 );
}
}
}
@ -688,7 +689,7 @@ void PCB_PAINTER::draw( const VIA* aVia, int aLayer )
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color );
m_gal->DrawCircle( center, radius + aVia->GetClearance() );
m_gal->DrawCircle( center, radius + aVia->GetClearance( aVia->GetLayer() ) );
}
}
@ -894,7 +895,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
m_gal->SetIsStroke( true );
m_gal->SetIsFill( false );
m_gal->SetStrokeColor( color );
int clearance = aPad->GetClearance();
int clearance = aPad->GetClearance( aPad->GetLayer() );
const std::shared_ptr<SHAPE_COMPOUND> shapes =
std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );

View File

@ -1750,9 +1750,10 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
if( !(item->GetLayerSet() & lset ).any() )
continue;
if( auto track = dyn_cast<TRACK*>( item ) )
if( TRACK* track = dyn_cast<TRACK*>( item ) )
{
int max_clearance = std::max( clearance, track->GetClearance() );
int max_clearance = std::max( clearance,
track->GetClearance( track->GetLayer() ) );
if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) )
@ -1761,11 +1762,11 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
return true;
net = track->GetNetCode();
clearance = track->GetClearance();
clearance = track->GetClearance( track->GetLayer() );
}
}
if( auto via = dyn_cast<VIA*>( item ) )
if( VIA* via = dyn_cast<VIA*>( item ) )
{
int dist = KiROUND( GetLineLength( position, via->GetPosition() ) );
@ -1773,27 +1774,30 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
return true;
}
if( auto mod = dyn_cast<MODULE*>( item ) )
if( MODULE* mod = dyn_cast<MODULE*>( item ) )
{
for( D_PAD* pad : mod->Pads() )
{
int max_clearance = std::max( clearance, pad->GetClearance() );
if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
{
if( net && pad->GetNetCode() != net )
return true;
int max_clearance = std::max( clearance, pad->GetClearance( layer ) );
net = pad->GetNetCode();
clearance = pad->GetClearance();
}
if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
{
if( net && pad->GetNetCode() != net )
return true;
if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
int dist = KiROUND( GetLineLength( position, pad->GetPosition() ) );
net = pad->GetNetCode();
clearance = pad->GetClearance( layer );
}
if( dist < drillRadius + pad->GetDrillSize().x / 2 + holeToHoleMin )
return true;
if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
int dist = KiROUND( GetLineLength( position, pad->GetPosition() ) );
if( dist < drillRadius + pad->GetDrillSize().x / 2 + holeToHoleMin )
return true;
}
}
}
}

View File

@ -656,7 +656,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( pad->GetNetCode() > 0 && pad->GetNetCode() == aZone->GetNetCode() )
gap = std::max( zone_clearance, aZone->GetThermalReliefGap( pad ) );
else
gap = aZone->GetClearance( pad );
gap = aZone->GetClearance( aLayer, pad );
addKnockout( pad, gap, aHoles );
}
@ -676,7 +676,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( track->GetBoundingBox().Intersects( zone_boundingbox ) )
{
int gap = aZone->GetClearance( track ) + extra_margin;
int gap = aZone->GetClearance( aLayer, track ) + extra_margin;
track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def );
}
@ -695,7 +695,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
{
bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts );
int gap = aZone->GetClearance( aItem );
int gap = aZone->GetClearance( aLayer, aItem );
addKnockout( aItem, gap, ignoreLineWidth, aHoles );
}
@ -739,7 +739,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
int gap = 0;
if( !zone->GetIsKeepout() && aZone->GetNetCode() != zone->GetNetCode() )
gap = aZone->GetClearance( zone );
gap = aZone->GetClearance( aLayer, zone );
zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, gap );
}

View File

@ -536,8 +536,7 @@ void DRC::testPadClearances( BOARD_COMMIT& aCommit )
static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts );
if( pad->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
pad->GetRuleClearance( &dummyEdge, pad->GetLayer(), &minClearance, &m_clearanceSource );
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
{

View File

@ -391,7 +391,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
int minClearance;
DRC_RULE* rule = GetRule( aRefSeg, &dummypad, CLEARANCE_CONSTRAINT );
DRC_RULE* rule = GetRule( aRefSeg, &dummypad, DRC_RULE_ID_CLEARANCE );
if( rule )
{

View File

@ -93,7 +93,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
{
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( aPad, nullptr, HOLE_CONSTRAINT );
DRC_RULE* rule = GetRule( aPad, nullptr, DRC_RULE_ID_HOLE_SIZE );
if( rule )
{
@ -136,7 +136,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
{
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
DRC_RULE* rule = GetRule( via, nullptr, DRC_RULE_ID_HOLE_SIZE );
if( rule )
{
@ -179,7 +179,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
{
int minHole = bds.m_MicroViasMinDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
DRC_RULE* rule = GetRule( via, nullptr, DRC_RULE_ID_HOLE_SIZE );
if( rule )
{

View File

@ -245,7 +245,7 @@ test::DRC_RULE* test::DRC_ENGINE::EvalRulesForItems( test::DRC_RULE_ID_T ruleID,
drc_dbg( 8, " -> check condition '%s'\n",
(const char*) condition->m_Expression.c_str() );
bool result = condition->EvaluateFor( a, b );
bool result = condition->EvaluateFor( a, b, F_Cu ); // FIXME: need the actual layer
if( result )
{
drc_dbg( 8, " -> rule '%s' matches, triggered by condition '%s'\n",

View File

@ -26,7 +26,6 @@
#include <class_board.h>
#include <class_board_item.h>
#include <drc_proto/drc_rule.h>
#include <pcb_expr_evaluator.h>
@ -37,14 +36,14 @@ test::DRC_RULE::DRC_RULE() :
m_Conditional( false ),
m_Priority( 0 )
{
}
test::DRC_RULE::~DRC_RULE()
{
}
test::DRC_RULE_CONDITION::DRC_RULE_CONDITION()
{
m_ucode = nullptr;
@ -57,11 +56,20 @@ test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
}
bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB )
bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
PCB_LAYER_ID aLayer )
{
// An unconditional rule is always true
if( m_Expression.IsEmpty() )
return true;
// A rule which failed to compile is always false
if( !m_ucode )
return false;
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
PCB_EXPR_CONTEXT ctx;
PCB_EXPR_CONTEXT ctx( aLayer );
ctx.SetItems( a, b );
return m_ucode->Run( &ctx )->AsDouble() != 0.0;
@ -75,7 +83,7 @@ bool test::DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, in
if (!m_ucode)
m_ucode = new PCB_EXPR_UCODE;
LIBEVAL::CONTEXT preflightContext;
PCB_EXPR_CONTEXT preflightContext( F_Cu );
bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext );
return ok;

View File

@ -34,7 +34,6 @@ class BOARD_ITEM;
namespace LIBEVAL
{
class UCODE;
class ERROR_STATUS;
};
class PCB_EXPR_UCODE;
@ -42,14 +41,20 @@ class PCB_EXPR_UCODE;
namespace test
{
enum class DRC_RULE_ID_T {
enum class DRC_RULE_ID_T
{
DRC_RULE_ID_UNKNOWN = -1,
DRC_RULE_ID_CLEARANCE = 0,
DRC_RULE_ID_HOLE_CLEARANCE,
DRC_RULE_ID_EDGE_CLEARANCE,
DRC_RULE_ID_HOLE_SIZE
DRC_RULE_ID_HOLE_SIZE,
DRC_RULE_ID_ANNULUS,
DRC_RULE_ID_TRACK,
DRC_RULE_ID_DISALLOW
};
enum class DRC_RULE_SEVERITY_T {
enum class DRC_RULE_SEVERITY_T
{
DRC_SEVERITY_IGNORE = 0,
DRC_SEVERITY_WARNING,
DRC_SEVERITY_ERROR
@ -80,17 +85,48 @@ private:
bool m_hasMax = false;
};
class DRC_CONSTRAINT
{
public:
public:
DRC_CONSTRAINT() :
m_Type( DRC_RULE_ID_T::DRC_RULE_ID_UNKNOWN ),
m_DisallowFlags( 0 ),
m_LayerCondition( LSET::AllLayersMask() )
{
}
const MINOPTMAX<int>& GetValue() const { return m_Value; }
bool Allowed() const { return m_Allow; }
public:
MINOPTMAX<int> m_Value;
bool m_Allow;
public:
DRC_RULE_ID_T m_Type;
MINOPTMAX<int> m_Value;
int m_DisallowFlags;
LSET m_LayerCondition;
bool m_Allow;
};
class DRC_RULE_CONDITION
{
public:
DRC_RULE_CONDITION();
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer );
bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 );
public:
wxString m_Expression;
wxString m_TargetRuleName;
private:
PCB_EXPR_UCODE* m_ucode;
};
class DRC_RULE
{
public:
@ -115,37 +151,23 @@ public:
public:
bool m_Unary;
wxString m_Name;
wxString m_TestProviderName;
wxString m_Name;
LSET m_LayerCondition;
wxString m_TestProviderName;
DRC_RULE_CONDITION m_Condition;
std::vector<DRC_CONSTRAINT> m_Constraints;
DRC_RULE_SEVERITY_T m_Severity;
bool m_Enabled;
bool m_Conditional;
int m_Priority; // 0 indicates automatic priority generation
DRC_CONSTRAINT m_Constraint;
DRC_CONSTRAINT m_Constraint; // FIXME: move to m_Constraints
};
class DRC_RULE_CONDITION
{
public:
DRC_RULE_CONDITION();
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 );
public:
LSET m_LayerCondition;
wxString m_Expression;
wxString m_TargetRuleName;
private:
PCB_EXPR_UCODE* m_ucode;
};
//DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint );
//const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
// int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName );
}; // namespace test