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 ); addFpBody( fpBBox.GetOrigin(), fpBBox.GetEnd(), layerMask );
// Trace pads + clearance areas. // 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 ); addPad( pad, margin );
} }
} }
@ -414,9 +414,9 @@ void AR_AUTOPLACER::genModuleOnRoutingMatrix( MODULE* Module )
CELL_IS_MODULE, AR_MATRIX::WRITE_OR_CELL ); CELL_IS_MODULE, AR_MATRIX::WRITE_OR_CELL );
// Trace pads + clearance areas. // 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 ); 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 2: Rules
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings * 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(); BOARD* board = GetBoard();
int clearance = 0; int clearance = 0;
@ -122,7 +123,7 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c
// LEVEL 2: Rules // LEVEL 2: Rules
// //
if( GetRuleClearance( aItem, &clearance, aSource ) ) if( GetRuleClearance( aItem, aLayer, &clearance, aSource ) )
return clearance; return clearance;
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings // 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, bool BOARD_CONNECTED_ITEM::GetRuleClearance( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer,
wxString* aSource ) const 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 ) 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; return true;
} }

View File

@ -161,20 +161,24 @@ public:
* returned clearance is the greater of this object's NETCLASS clearance and * 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 * aItem's NETCLASS clearance. If \a aItem is NULL, then this objects clearance
* is returned. * is returned.
* @param aLayer the layer in question
* @param aItem is an optional BOARD_ITEM * @param aItem is an optional BOARD_ITEM
* @param aSource [out] optionally reports the source as a user-readable string * @param aSource [out] optionally reports the source as a user-readable string
* @return int - the clearance in internal units. * @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 * Function GetRuleClearance
* returns any rule-based clearance. * returns any rule-based clearance.
* @param aLayer the current layer under test
* @param aClearance [out] the clearance value in internal units * @param aClearance [out] the clearance value in internal units
* @param aSource [out] reports the source as a user-readable string * @param aSource [out] reports the source as a user-readable string
* @return true if a rule was fired * @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 * Function GetLocalClearanceOverrides

View File

@ -822,7 +822,13 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
clearance = std::max( clearance, netclass.second->GetClearance() ); clearance = std::max( clearance, netclass.second->GetClearance() );
for( const DRC_RULE* rule : m_DRCRules ) 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; return clearance;
} }

View File

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

View File

@ -133,15 +133,16 @@ void TRACK::GetWidthConstraints( int* aMin, int* aMax, wxString* aSource ) const
// Not currently implemented // Not currently implemented
// LEVEL 2: Rules // 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; *aMin = constraint->m_Value.Min();
*aMax = rule->m_TrackConstraint.Max; *aMax = constraint->m_Value.Max();
if( aSource ) if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name ); *aSource = wxString::Format( _( "'%s' rule" ), *aSource );
return; 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 ) 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 else
{ {
@ -493,7 +495,7 @@ unsigned int TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
const BOX2I TRACK::ViewBBox() const const BOX2I TRACK::ViewBBox() const
{ {
BOX2I bbox = GetBoundingBox(); BOX2I bbox = GetBoundingBox();
bbox.Inflate( 2 * GetClearance() ); bbox.Inflate( 2 * GetClearance( GetLayer() ) );
return bbox; 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 ) ); msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source ); 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 ); 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 ) ); msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source ); msg2.Printf( _( "(from %s)" ), source );
aList.emplace_back( msg, msg2, BLACK ); aList.emplace_back( msg, msg2, BLACK );
int minAnnulus = GetMinAnnulus( &source ); int minAnnulus = GetMinAnnulus( GetLayer(), &source );
msg.Printf( _( "Min Annulus: %s" ), MessageTextFromValue( units, minAnnulus, true ) ); msg.Printf( _( "Min Annulus: %s" ), MessageTextFromValue( units, minAnnulus, true ) );
msg2.Printf( _( "(from %s)" ), source ); msg2.Printf( _( "(from %s)" ), source );

View File

@ -442,7 +442,7 @@ public:
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif #endif
int GetMinAnnulus( wxString* aSource ) const; int GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const;
/** /**
* Function SetDrill * 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; wxString source;
int keepouts = 0; int keepouts = 0;
@ -370,41 +370,42 @@ int ZONE_CONTAINER::GetKeepouts( std::map<int, wxString>* aSources ) const
setFlag( DISALLOW_ZONES ); 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 ) 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 ); setFlag( DISALLOW_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_MICRO_VIAS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_MICRO_VIAS ) > 0 )
setFlag( DISALLOW_MICRO_VIAS ); setFlag( DISALLOW_MICRO_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_BB_VIAS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_BB_VIAS ) > 0 )
setFlag( DISALLOW_BB_VIAS ); setFlag( DISALLOW_BB_VIAS );
if( ( rule->m_DisallowFlags & DISALLOW_TRACKS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_TRACKS ) > 0 )
setFlag( DISALLOW_TRACKS ); setFlag( DISALLOW_TRACKS );
if( ( rule->m_DisallowFlags & DISALLOW_PADS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_PADS ) > 0 )
setFlag( DISALLOW_PADS ); setFlag( DISALLOW_PADS );
if( ( rule->m_DisallowFlags & DISALLOW_ZONES ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_ZONES ) > 0 )
setFlag( DISALLOW_ZONES ); setFlag( DISALLOW_ZONES );
if( ( rule->m_DisallowFlags & DISALLOW_TEXTS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_TEXTS ) > 0 )
setFlag( DISALLOW_TEXTS ); setFlag( DISALLOW_TEXTS );
if( ( rule->m_DisallowFlags & DISALLOW_GRAPHICS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_GRAPHICS ) > 0 )
setFlag( DISALLOW_GRAPHICS ); setFlag( DISALLOW_GRAPHICS );
if( ( rule->m_DisallowFlags & DISALLOW_HOLES ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_HOLES ) > 0 )
setFlag( DISALLOW_HOLES ); setFlag( DISALLOW_HOLES );
if( ( rule->m_DisallowFlags & DISALLOW_FOOTPRINTS ) > 0 ) if( ( constraint->m_DisallowFlags & DISALLOW_FOOTPRINTS ) > 0 )
setFlag( DISALLOW_FOOTPRINTS ); 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 ); aList.emplace_back( _( "Filled Area" ), msg, BLUE );
wxString source; wxString source;
int clearance = GetClearance( nullptr, &source ); int clearance = GetClearance( GetLayer(), nullptr, &source );
msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) ); msg.Printf( _( "Min Clearance: %s" ), MessageTextFromValue( units, clearance, true ) );
msg2.Printf( _( "(from %s)" ), source ); msg2.Printf( _( "(from %s)" ), source );
@ -1374,6 +1375,8 @@ static struct ZONE_CONTAINER_DESC
//&ZONE_CONTAINER::SetIsFilled, &ZONE_CONTAINER::IsFilled ) ); //&ZONE_CONTAINER::SetIsFilled, &ZONE_CONTAINER::IsFilled ) );
propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Min Thickness" ), propMgr.AddProperty( new PROPERTY<ZONE_CONTAINER, int>( _( "Min Thickness" ),
&ZONE_CONTAINER::SetMinThickness, &ZONE_CONTAINER::GetMinThickness, PROPERTY_DISPLAY::DISTANCE ) ); &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 // TODO pad connection, thermal relief gap, thermal relief copper bridge
} }
} _ZONE_CONTAINER_DESC; } _ZONE_CONTAINER_DESC;

View File

@ -723,7 +723,7 @@ public:
* flag. * flag.
* @return a bitset of DISALLOW_* flags. * @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 SetIsKeepout( bool aEnable ) { m_isKeepout = aEnable; }
void SetDoNotAllowCopperPour( bool aEnable ) { m_doNotAllowCopperPour = aEnable; } void SetDoNotAllowCopperPour( bool aEnable ) { m_doNotAllowCopperPour = aEnable; }

View File

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

View File

@ -502,10 +502,7 @@ void DRC::testPadClearances( BOARD_COMMIT& aCommit )
static DRAWSEGMENT dummyEdge; static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts ); dummyEdge.SetLayer( Edge_Cuts );
if( pad->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) ) pad->GetRuleClearance( &dummyEdge, pad->GetLayer(), &minClearance, &m_clearanceSource );
{
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
}
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) 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 // 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 // obtain that value is now part of the zone object itself by way of
// ZONE_CONTAINER::GetClearance(). // 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 // Keepout areas have no clearance, so set zone2zoneClearance to 1
// ( zone2zoneClearance = 0 can create problems in test functions) // ( 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() ); SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
// Test tracks and vias // Test tracks and vias
for( auto track : m_pcb->Tracks() ) for( TRACK* track : m_pcb->Tracks() )
{ {
if( !track->IsOnLayer( aItem->GetLayer() ) ) if( !track->IsOnLayer( aItem->GetLayer() ) )
continue; continue;
int minClearance = track->GetClearance( aItem, &m_clearanceSource ); int minClearance = track->GetClearance( track->GetLayer(), aItem, &m_clearanceSource );
int actual = INT_MAX; int actual = INT_MAX;
wxPoint pos; wxPoint pos;
@ -954,7 +952,7 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
} }
// Test pads // Test pads
for( auto pad : m_pcb->GetPads() ) for( D_PAD* pad : m_pcb->GetPads() )
{ {
if( !pad->IsOnLayer( aItem->GetLayer() ) ) if( !pad->IsOnLayer( aItem->GetLayer() ) )
continue; continue;
@ -963,7 +961,7 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
if( drawItem && pad->GetParent() == drawItem->GetParent() ) if( drawItem && pad->GetParent() == drawItem->GetParent() )
continue; continue;
int minClearance = pad->GetClearance( aItem, &m_clearanceSource ); int minClearance = pad->GetClearance( aItem->GetLayer(), aItem, &m_clearanceSource );
int actual = INT_MAX; int actual = INT_MAX;
// Fast test to detect a pad candidate inside the text bounding box // 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 ) if( pad->GetDrillSize().x )
{ {
int minClearance = aRefPad->GetClearance( nullptr, &m_clearanceSource ); int minClearance = aRefPad->GetClearance( aRefPad->GetLayer(), nullptr,
&m_clearanceSource );
int actual; int actual;
if( aRefPad->Collide( pad->GetEffectiveHoleShape(), minClearance, &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 ) if( aRefPad->GetDrillSize().x )
{ {
int minClearance = pad->GetClearance( nullptr, &m_clearanceSource ); int minClearance = pad->GetClearance( pad->GetLayer(), nullptr,
&m_clearanceSource );
int actual; int actual;
if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) ) if( pad->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) )
@ -1216,7 +1216,9 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
continue; continue;
} }
int minClearance = aRefPad->GetClearance( pad, &m_clearanceSource ); for( PCB_LAYER_ID layer : aRefPad->GetLayerSet().Seq() )
{
int minClearance = aRefPad->GetClearance( layer, pad, &m_clearanceSource );
int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon(); int clearanceAllowed = minClearance - m_pcb->GetDesignSettings().GetDRCEpsilon();
int actual; int actual;
@ -1237,6 +1239,7 @@ bool DRC::doPadToPadsDrc( BOARD_COMMIT& aCommit, D_PAD* aRefPad, D_PAD** aStart,
return false; return false;
} }
} }
}
return true; return true;
} }

View File

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

View File

@ -84,6 +84,8 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); 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;
int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y ); int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( holeSize == 0 ) if( holeSize == 0 )
@ -91,14 +93,19 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) ) if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{ {
int minHole = bds.m_MinThroughDrill; int minHole;
wxString minHoleSource = _( "board minimum" ); const DRC_CONSTRAINT* constraint = GetConstraint( aPad, nullptr, DRC_RULE_ID_HOLE_SIZE,
DRC_RULE* rule = GetRule( aPad, nullptr, HOLE_CONSTRAINT ); layer, &m_source );
if( rule ) if( constraint )
{ {
minHole = rule->m_MinHole; minHole = constraint->m_Value.Min();
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name ); m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
} }
if( holeSize < minHole ) 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 ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource, m_source,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, holeSize, true ) ); MessageTextFromValue( m_units, holeSize, true ) );
@ -132,16 +139,24 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); 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 ) ) if( !bds.Ignore( DRCE_TOO_SMALL_DRILL ) )
{ {
int minHole = bds.m_MinThroughDrill; int minHole;
wxString minHoleSource = _( "board minimum" ); const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_RULE_ID_HOLE_SIZE,
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT ); layer, &m_source );
if( rule ) if( constraint )
{ {
minHole = rule->m_MinHole; minHole = constraint->m_Value.Min();
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name ); m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MinThroughDrill;
m_source = _( "board minimum" );
} }
if( via->GetDrillValue() < minHole ) 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 ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource, m_source,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) ); MessageTextFromValue( m_units, via->GetDrillValue(), true ) );
@ -175,16 +190,25 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); 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 ) ) if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
{ {
int minHole = bds.m_MicroViasMinDrill; int minHole;
wxString minHoleSource = _( "board minimum" ); const DRC_CONSTRAINT* constraint = GetConstraint( via, nullptr, DRC_RULE_ID_HOLE_SIZE,
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT ); layer, &m_source );
if( rule ) if( constraint )
{ {
minHole = rule->m_MinHole; minHole = constraint->m_Value.Min();
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name ); m_source = wxString::Format( _( "'%s' rule" ), m_source );
}
else
{
minHole = bds.m_MicroViasMinDrill;
m_source = _( "board minimum" );
} }
if( via->GetDrillValue() < minHole ) 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 ); DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_MICROVIA_DRILL );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
minHoleSource, m_source,
MessageTextFromValue( m_units, minHole, true ), MessageTextFromValue( m_units, minHole, true ),
MessageTextFromValue( m_units, via->GetDrillValue(), true ) ); MessageTextFromValue( m_units, via->GetDrillValue(), true ) );

View File

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

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 // Test keepout areas for vias, tracks and pads inside keepout areas
for( ZONE_CONTAINER* area : areasToInspect ) 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 ) if( m_keepoutFlags > 0 )
{ {

View File

@ -23,13 +23,15 @@
#include <fctsys.h> #include <fctsys.h>
#include <drc/drc_rule.h>
#include <class_board.h> #include <class_board.h>
#include <class_board_item.h> #include <class_board_item.h>
#include <drc/drc_rule.h>
#include <pcb_expr_evaluator.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(); 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 ) for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
{ {
if( ( rule->m_ConstraintFlags & aConstraint ) > 0 ) if( !rule->m_LayerCondition.test( aLayer ) )
{ continue;
if( rule->m_Condition.EvaluateFor( aItem, bItem ) )
return rule;
if( bItem && rule->m_Condition.EvaluateFor( bItem, aItem ) ) for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
return rule; {
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() DRC_RULE_CONDITION::DRC_RULE_CONDITION()
{ {
m_ucode = nullptr; 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 // An unconditional rule is always true
if( m_Expression.IsEmpty() ) 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* a = const_cast<BOARD_ITEM*>( aItemA );
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance(); 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 ); ctx.SetItems( a, b );
return m_ucode->Run( &ctx )->AsDouble() != 0.0; 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) if (!m_ucode)
m_ucode = new PCB_EXPR_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 ); bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext );
return ok;
if( ok )
return true;
return false;
} }

View File

@ -25,8 +25,8 @@
#define DRC_RULE_H #define DRC_RULE_H
#include <core/typeinfo.h> #include <core/typeinfo.h>
#include <netclass.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <netclass.h>
#include <libeval_compiler/libeval_compiler.h> #include <libeval_compiler/libeval_compiler.h>
@ -34,12 +34,6 @@ class BOARD_ITEM;
class PCB_EXPR_UCODE; 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_VIAS (1 << 0)
#define DISALLOW_MICRO_VIAS (1 << 1) #define DISALLOW_MICRO_VIAS (1 << 1)
#define DISALLOW_BB_VIAS (1 << 2) #define DISALLOW_BB_VIAS (1 << 2)
@ -52,6 +46,17 @@ class PCB_EXPR_UCODE;
#define DISALLOW_FOOTPRINTS (1 << 9) #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> template<class T=int>
class MINOPTMAX 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 class DRC_RULE_CONDITION
{ {
public: public:
DRC_RULE_CONDITION(); DRC_RULE_CONDITION();
~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 ); bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
public: public:
LSET m_LayerCondition;
wxString m_Expression; wxString m_Expression;
wxString m_TargetRuleName;
private: private:
PCB_EXPR_UCODE* m_ucode; PCB_EXPR_UCODE* m_ucode;
@ -100,40 +122,20 @@ private:
class DRC_RULE class DRC_RULE
{ {
public: public:
DRC_RULE() : DRC_RULE();
m_ConstraintFlags( 0 ), virtual ~DRC_RULE();
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;
};
public: public:
wxString m_Name; 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; LSET m_LayerCondition;
wxString m_TestProviderName;
DRC_RULE_CONDITION m_Condition; 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 #endif // DRC_RULE_H

View File

@ -178,49 +178,6 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
switch( token ) 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: case T_constraint:
parseConstraint( rule ); parseConstraint( rule );
break; break;
@ -273,34 +230,65 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
{ {
T token; aRule->m_Constraints.emplace_back( DRC_CONSTRAINT() );
int constraintType = 0;
DRC_CONSTRAINT& constraint = aRule->m_Constraints.back();
int value; int value;
wxString msg; wxString msg;
token = NextTok(); T token = NextTok();
if( (int) token == DSN_RIGHT ) if( (int) token == DSN_RIGHT )
{ {
reportError( _( "Missing constraint type.| Expected 'clearance', 'track_width', " reportError( _( "Missing constraint type.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ) ); "'annulus_width', 'hole' or 'disallow'." ) );
return; return;
} }
switch( token ) switch( token )
{ {
case T_clearance: constraintType = CLEARANCE_CONSTRAINT; break; case T_clearance: constraint.m_Type = DRC_RULE_ID_CLEARANCE; break;
case T_track_width: constraintType = TRACK_CONSTRAINT; break; case T_track_width: constraint.m_Type = DRC_RULE_ID_TRACK; break;
case T_annulus_width: constraintType = ANNULUS_CONSTRAINT; break; case T_annulus_width: constraint.m_Type = DRC_RULE_ID_ANNULUS; break;
case T_hole: constraintType = HOLE_CONSTRAINT; 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: default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'clearance', 'track_width', " msg.Printf( _( "Unrecognized item '%s'.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ), "'annulus_width', 'hole' or 'disallow'." ),
FromUTF8() ); FromUTF8() );
reportError( msg ); 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() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
@ -321,14 +309,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
} }
parseValueWithUnits( FromUTF8(), value ); parseValueWithUnits( FromUTF8(), value );
constraint.m_Value.SetMin( 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;
}
if( (int) NextTok() != DSN_RIGHT ) if( (int) NextTok() != DSN_RIGHT )
{ {
@ -348,12 +329,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
} }
parseValueWithUnits( FromUTF8(), value ); parseValueWithUnits( FromUTF8(), value );
constraint.m_Value.SetMax( value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Max = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Max = value; break;
}
if( (int) NextTok() != DSN_RIGHT ) if( (int) NextTok() != DSN_RIGHT )
{ {
@ -373,12 +349,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
} }
parseValueWithUnits( FromUTF8(), value ); parseValueWithUnits( FromUTF8(), value );
constraint.m_Value.SetOpt( value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Opt = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Opt = value; break;
}
if( (int) NextTok() != DSN_RIGHT ) if( (int) NextTok() != DSN_RIGHT )
{ {

View File

@ -468,13 +468,17 @@ void GERBER_JOBFILE_WRITER::addJSONDesignRules()
for( MODULE* module : m_pcb->Modules() ) for( MODULE* module : m_pcb->Modules() )
{ {
for( auto& pad : module->Pads() ) for( D_PAD* pad : module->Pads() )
{ {
if( ( pad->GetLayerSet() & LSET::InternalCuMask() ).any() ) for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
minPadClearanceInner = std::min( minPadClearanceInner, pad->GetClearance() ); {
int padClearance = pad->GetClearance( layer );
if( ( pad->GetLayerSet() & LSET::ExternalCuMask() ).any() ) if( layer == B_Cu || layer == F_Cu )
minPadClearanceOuter = std::min( minPadClearanceOuter, pad->GetClearance() ); minPadClearanceOuter = std::min( minPadClearanceOuter, padClearance );
else
minPadClearanceInner = std::min( minPadClearanceInner, padClearance );
}
} }
} }
@ -519,13 +523,16 @@ void GERBER_JOBFILE_WRITER::addJSONDesignRules()
if( zone->GetIsKeepout() || !zone->IsOnCopperLayer() ) if( zone->GetIsKeepout() || !zone->IsOnCopperLayer() )
continue; 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 ) if( layer == B_Cu || layer == F_Cu )
minclearanceOuter = std::min( minclearanceOuter, zclerance ); minclearanceOuter = std::min( minclearanceOuter, zclerance );
else else
minclearanceInner = std::min( minclearanceInner, zclerance ); minclearanceInner = std::min( minclearanceInner, zclerance );
} }
}
if( minclearanceOuter != INT_MAX ) if( minclearanceOuter != INT_MAX )
m_json["DesignRules"][0]["TrackToRegion"] = mapValue( minclearanceOuter ); m_json["DesignRules"][0]["TrackToRegion"] = mapValue( minclearanceOuter );

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() PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
{ {
auto registerFunc = [&]( const wxString& funcSignature, FPTR funcPtr ) auto registerFunc = [&]( const wxString& funcSignature, FPTR funcPtr )
@ -152,6 +209,7 @@ PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
registerFunc( "onLayer('x')", onLayer ); registerFunc( "onLayer('x')", onLayer );
registerFunc( "isPlated()", isPlated ); registerFunc( "isPlated()", isPlated );
registerFunc( "insideCourtyard('x')", insideCourtyard ); registerFunc( "insideCourtyard('x')", insideCourtyard );
registerFunc( "insideArea('x')", insideArea );
} }

View File

@ -52,7 +52,8 @@ public:
class PCB_EXPR_CONTEXT : public LIBEVAL::CONTEXT class PCB_EXPR_CONTEXT : public LIBEVAL::CONTEXT
{ {
public: public:
PCB_EXPR_CONTEXT() PCB_EXPR_CONTEXT( PCB_LAYER_ID aLayer ) :
m_layer( aLayer )
{ {
m_items[0] = nullptr; m_items[0] = nullptr;
m_items[1] = nullptr; m_items[1] = nullptr;
@ -69,8 +70,14 @@ public:
return m_items[index]; return m_items[index];
} }
PCB_LAYER_ID GetLayer() const
{
return m_layer;
}
private: 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->SetIsFill( false );
m_gal->SetIsStroke( true ); m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color ); 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->SetStrokeColor( color );
m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle, 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->SetIsFill( false );
m_gal->SetIsStroke( true ); m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color ); 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->SetIsStroke( true );
m_gal->SetIsFill( false ); m_gal->SetIsFill( false );
m_gal->SetStrokeColor( color ); m_gal->SetStrokeColor( color );
int clearance = aPad->GetClearance(); int clearance = aPad->GetClearance( aPad->GetLayer() );
const std::shared_ptr<SHAPE_COMPOUND> shapes = const std::shared_ptr<SHAPE_COMPOUND> shapes =
std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() ); 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() ) if( !(item->GetLayerSet() & lset ).any() )
continue; 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(), if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) ) ( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) )
@ -1761,11 +1762,11 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
return true; return true;
net = track->GetNetCode(); 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() ) ); int dist = KiROUND( GetLineLength( position, via->GetPosition() ) );
@ -1773,11 +1774,13 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
return true; return true;
} }
if( auto mod = dyn_cast<MODULE*>( item ) ) if( MODULE* mod = dyn_cast<MODULE*>( item ) )
{ {
for( D_PAD* pad : mod->Pads() ) for( D_PAD* pad : mod->Pads() )
{ {
int max_clearance = std::max( clearance, pad->GetClearance() ); for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
{
int max_clearance = std::max( clearance, pad->GetClearance( layer ) );
if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) ) if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
{ {
@ -1785,7 +1788,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
return true; return true;
net = pad->GetNetCode(); net = pad->GetNetCode();
clearance = pad->GetClearance(); clearance = pad->GetClearance( layer );
} }
if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
@ -1798,6 +1801,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
} }
} }
} }
}
return false; return false;
} }

View File

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

View File

@ -536,8 +536,7 @@ void DRC::testPadClearances( BOARD_COMMIT& aCommit )
static DRAWSEGMENT dummyEdge; static DRAWSEGMENT dummyEdge;
dummyEdge.SetLayer( Edge_Cuts ); dummyEdge.SetLayer( Edge_Cuts );
if( pad->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) ) pad->GetRuleClearance( &dummyEdge, pad->GetLayer(), &minClearance, &m_clearanceSource );
/* minClearance and m_clearanceSource set in GetRuleClearance() */;
for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) 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() ); dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
int minClearance; int minClearance;
DRC_RULE* rule = GetRule( aRefSeg, &dummypad, CLEARANCE_CONSTRAINT ); DRC_RULE* rule = GetRule( aRefSeg, &dummypad, DRC_RULE_ID_CLEARANCE );
if( rule ) if( rule )
{ {

View File

@ -93,7 +93,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
{ {
int minHole = bds.m_MinThroughDrill; int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" ); 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 ) if( rule )
{ {
@ -136,7 +136,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
{ {
int minHole = bds.m_MinThroughDrill; int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" ); 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 ) if( rule )
{ {
@ -179,7 +179,7 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
{ {
int minHole = bds.m_MicroViasMinDrill; int minHole = bds.m_MicroViasMinDrill;
wxString minHoleSource = _( "board minimum" ); 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 ) 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", drc_dbg( 8, " -> check condition '%s'\n",
(const char*) condition->m_Expression.c_str() ); (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 ) if( result )
{ {
drc_dbg( 8, " -> rule '%s' matches, triggered by condition '%s'\n", drc_dbg( 8, " -> rule '%s' matches, triggered by condition '%s'\n",

View File

@ -26,7 +26,6 @@
#include <class_board.h> #include <class_board.h>
#include <class_board_item.h> #include <class_board_item.h>
#include <drc_proto/drc_rule.h> #include <drc_proto/drc_rule.h>
#include <pcb_expr_evaluator.h> #include <pcb_expr_evaluator.h>
@ -37,14 +36,14 @@ test::DRC_RULE::DRC_RULE() :
m_Conditional( false ), m_Conditional( false ),
m_Priority( 0 ) m_Priority( 0 )
{ {
} }
test::DRC_RULE::~DRC_RULE() test::DRC_RULE::~DRC_RULE()
{ {
} }
test::DRC_RULE_CONDITION::DRC_RULE_CONDITION() test::DRC_RULE_CONDITION::DRC_RULE_CONDITION()
{ {
m_ucode = nullptr; 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* a = const_cast<BOARD_ITEM*>( aItemA );
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance(); 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 ); ctx.SetItems( a, b );
return m_ucode->Run( &ctx )->AsDouble() != 0.0; 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) if (!m_ucode)
m_ucode = new PCB_EXPR_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 ); bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext );
return ok; return ok;

View File

@ -34,7 +34,6 @@ class BOARD_ITEM;
namespace LIBEVAL namespace LIBEVAL
{ {
class UCODE; class UCODE;
class ERROR_STATUS;
}; };
class PCB_EXPR_UCODE; class PCB_EXPR_UCODE;
@ -42,14 +41,20 @@ class PCB_EXPR_UCODE;
namespace test 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_CLEARANCE = 0,
DRC_RULE_ID_HOLE_CLEARANCE, DRC_RULE_ID_HOLE_CLEARANCE,
DRC_RULE_ID_EDGE_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_IGNORE = 0,
DRC_SEVERITY_WARNING, DRC_SEVERITY_WARNING,
DRC_SEVERITY_ERROR DRC_SEVERITY_ERROR
@ -80,17 +85,48 @@ private:
bool m_hasMax = false; bool m_hasMax = false;
}; };
class DRC_CONSTRAINT 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; } const MINOPTMAX<int>& GetValue() const { return m_Value; }
bool Allowed() const { return m_Allow; } bool Allowed() const { return m_Allow; }
public: public:
DRC_RULE_ID_T m_Type;
MINOPTMAX<int> m_Value; MINOPTMAX<int> m_Value;
int m_DisallowFlags;
LSET m_LayerCondition;
bool m_Allow; 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 class DRC_RULE
{ {
public: public:
@ -116,36 +152,22 @@ public:
bool m_Unary; bool m_Unary;
wxString m_Name; wxString m_Name;
LSET m_LayerCondition;
wxString m_TestProviderName; wxString m_TestProviderName;
DRC_RULE_CONDITION m_Condition;
std::vector<DRC_CONSTRAINT> m_Constraints;
DRC_RULE_SEVERITY_T m_Severity; DRC_RULE_SEVERITY_T m_Severity;
bool m_Enabled; bool m_Enabled;
bool m_Conditional; bool m_Conditional;
int m_Priority; // 0 indicates automatic priority generation 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 //const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem,
{ // int aConstraint, PCB_LAYER_ID aLayer, wxString* aRuleName );
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 );
}; // namespace test }; // namespace test