Defer DRC rule function eval to make use of short-circuit bools.

The lemon parser doesn't lend itself to short-circuiting booleans,
but if we defer processing until we fetch the second value when
processing the TR_OP_BOOLEAN opcode then we get to piggy-back on
C++'s boolean short-circuiting.
This commit is contained in:
Jeff Young 2021-08-21 15:24:20 +01:00
parent 1e23ce1c95
commit 048e13f423
2 changed files with 332 additions and 280 deletions

View File

@ -187,20 +187,23 @@ public:
VALUE() : VALUE() :
m_type( VT_UNDEFINED ), m_type( VT_UNDEFINED ),
m_valueDbl( 0 ), m_valueDbl( 0 ),
m_stringIsWildcard( false ) m_stringIsWildcard( false ),
m_isDeferredDbl( false )
{}; {};
VALUE( const wxString& aStr, bool aIsWildcard = false ) : VALUE( const wxString& aStr, bool aIsWildcard = false ) :
m_type( VT_STRING ), m_type( VT_STRING ),
m_valueDbl( 0 ), m_valueDbl( 0 ),
m_valueStr( aStr ), m_valueStr( aStr ),
m_stringIsWildcard( aIsWildcard ) m_stringIsWildcard( aIsWildcard ),
m_isDeferredDbl( false )
{}; {};
VALUE( const double aVal ) : VALUE( const double aVal ) :
m_type( VT_NUMERIC ), m_type( VT_NUMERIC ),
m_valueDbl( aVal ), m_valueDbl( aVal ),
m_stringIsWildcard( false ) m_stringIsWildcard( false ),
m_isDeferredDbl( false )
{}; {};
virtual ~VALUE() virtual ~VALUE()
@ -208,6 +211,12 @@ public:
virtual double AsDouble() const virtual double AsDouble() const
{ {
if( m_isDeferredDbl )
{
m_valueDbl = m_lambdaDbl();
m_isDeferredDbl = false;
}
return m_valueDbl; return m_valueDbl;
} }
@ -229,6 +238,13 @@ public:
m_valueDbl = aValue; m_valueDbl = aValue;
} }
void SetDeferredEval( std::function<double()> aLambda )
{
m_type = VT_NUMERIC;
m_lambdaDbl = aLambda;
m_isDeferredDbl = true;
}
void Set( const wxString& aValue ) void Set( const wxString& aValue )
{ {
m_type = VT_STRING; m_type = VT_STRING;
@ -245,10 +261,13 @@ public:
} }
private: private:
VAR_TYPE_T m_type; VAR_TYPE_T m_type;
double m_valueDbl; mutable double m_valueDbl;
wxString m_valueStr; wxString m_valueStr;
bool m_stringIsWildcard; bool m_stringIsWildcard;
mutable bool m_isDeferredDbl;
std::function<double()> m_lambdaDbl;
}; };
class VAR_REF class VAR_REF

View File

@ -98,67 +98,73 @@ static void existsOnLayer( LIBEVAL::CONTEXT* aCtx, void *self )
return; return;
} }
const wxString& layerName = arg->AsString(); result->SetDeferredEval(
wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices(); [item, arg, &aCtx]() -> double
if( aCtx->HasErrorCallback() )
{
/*
* Interpreted version
*/
bool anyMatch = false;
for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
{
wxPGChoiceEntry& entry = layerMap[ii];
if( entry.GetText().Matches( layerName ) )
{ {
anyMatch = true; const wxString& layerName = arg->AsString();
wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
if( item->IsOnLayer( ToLAYER_ID( entry.GetValue() ) ) ) if( aCtx->HasErrorCallback())
{ {
result->Set( 1.0 ); /*
return; * Interpreted version
*/
bool anyMatch = false;
for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
{
wxPGChoiceEntry& entry = layerMap[ ii ];
if( entry.GetText().Matches( layerName ))
{
anyMatch = true;
if( item->IsOnLayer( ToLAYER_ID( entry.GetValue())))
return 1.0;
}
}
if( !anyMatch )
{
aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s'" ),
layerName ) );
}
} }
} else
} {
/*
* Compiled version
*/
if( !anyMatch ) BOARD* board = item->GetBoard();
aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s'" ), layerName ) ); std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
} auto i = board->m_LayerExpressionCache.find( layerName );
else LSET mask;
{
/*
* Compiled version
*/
BOARD* board = item->GetBoard(); if( i == board->m_LayerExpressionCache.end() )
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex ); {
auto i = board->m_LayerExpressionCache.find( layerName ); for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
LSET mask; {
wxPGChoiceEntry& entry = layerMap[ ii ];
if( i == board->m_LayerExpressionCache.end() ) if( entry.GetText().Matches( layerName ) )
{ mask.set( ToLAYER_ID( entry.GetValue() ) );
for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii ) }
{
wxPGChoiceEntry& entry = layerMap[ii];
if( entry.GetText().Matches( layerName ) ) board->m_LayerExpressionCache[ layerName ] = mask;
mask.set( ToLAYER_ID( entry.GetValue() ) ); }
} else
{
mask = i->second;
}
board->m_LayerExpressionCache[ layerName ] = mask; if( ( item->GetLayerSet() & mask ).any() )
} return 1.0;
else }
{
mask = i->second;
}
if( ( item->GetLayerSet() & mask ).any() ) return 0.0;
result->Set( 1.0 ); } );
}
} }
@ -183,7 +189,7 @@ static void isPlated( LIBEVAL::CONTEXT* aCtx, void* self )
static bool insideFootprintCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, static bool insideFootprintCourtyard( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox,
std::shared_ptr<SHAPE> aItemShape, PCB_EXPR_CONTEXT* aCtx, std::shared_ptr<SHAPE>& aItemShape, PCB_EXPR_CONTEXT* aCtx,
FOOTPRINT* aFootprint, PCB_LAYER_ID aSide = UNDEFINED_LAYER ) FOOTPRINT* aFootprint, PCB_LAYER_ID aSide = UNDEFINED_LAYER )
{ {
SHAPE_POLY_SET footprintCourtyard; SHAPE_POLY_SET footprintCourtyard;
@ -235,21 +241,14 @@ static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( !item ) if( !item )
return; return;
BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> shape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
auto insideFootprint = auto insideFootprint =
[&]( FOOTPRINT* footprint ) -> bool [&context]( BOARD_ITEM* item, const EDA_RECT& itemBBox,
std::shared_ptr<SHAPE>& itemShape, FOOTPRINT* footprint ) -> bool
{ {
if( !footprint ) if( !footprint )
return false; return false;
BOARD* board = item->GetBoard();
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex ); std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item ); std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item );
auto i = board->m_InsideCourtyardCache.find( key ); auto i = board->m_InsideCourtyardCache.find( key );
@ -257,36 +256,49 @@ static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( i != board->m_InsideCourtyardCache.end() ) if( i != board->m_InsideCourtyardCache.end() )
return i->second; return i->second;
bool res = insideFootprintCourtyard( item, itemBBox, shape, context, footprint ); bool res = insideFootprintCourtyard( item, itemBBox, itemShape, context,
footprint );
board->m_InsideCourtyardCache[ key ] = res; board->m_InsideCourtyardCache[ key ] = res;
return res; return res;
}; };
if( arg->AsString() == "A" ) result->SetDeferredEval(
{ [item, arg, &context, &insideFootprint]() -> double
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) ) ) )
result->Set( 1.0 );
}
else if( arg->AsString() == "B" )
{
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) ) ) )
result->Set( 1.0 );
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{ {
if( insideFootprint( candidate ) ) BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> itemShape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
if( arg->AsString() == "A" )
{ {
result->Set( 1.0 ); FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
return; return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
} }
} else if( arg->AsString() == "B" )
} {
} FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{
if( insideFootprint( item, itemBBox, itemShape, candidate ) )
return 1.0;
}
}
}
return 0.0;
} );
} }
@ -316,21 +328,14 @@ static void insideFrontCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( !item ) if( !item )
return; return;
BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> shape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
auto insideFootprint = auto insideFootprint =
[&]( FOOTPRINT* footprint ) -> bool [&context]( BOARD_ITEM* item, const EDA_RECT& itemBBox,
std::shared_ptr<SHAPE>& itemShape, FOOTPRINT* footprint ) -> bool
{ {
if( !footprint ) if( !footprint )
return false; return false;
BOARD* board = item->GetBoard();
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex ); std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item ); std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item );
auto i = board->m_InsideFCourtyardCache.find( key ); auto i = board->m_InsideFCourtyardCache.find( key );
@ -338,37 +343,49 @@ static void insideFrontCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( i != board->m_InsideFCourtyardCache.end() ) if( i != board->m_InsideFCourtyardCache.end() )
return i->second; return i->second;
bool res = insideFootprintCourtyard( item, itemBBox, shape, context, footprint, bool res = insideFootprintCourtyard( item, itemBBox, itemShape, context,
F_Cu ); footprint, F_Cu );
board->m_InsideFCourtyardCache[ key ] = res; board->m_InsideFCourtyardCache[ key ] = res;
return res; return res;
}; };
if( arg->AsString() == "A" ) result->SetDeferredEval(
{ [item, arg, &context, &insideFootprint]() -> double
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) ) ) )
result->Set( 1.0 );
}
else if( arg->AsString() == "B" )
{
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) ) ) )
result->Set( 1.0 );
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{ {
if( insideFootprint( candidate ) ) BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> itemShape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
if( arg->AsString() == "A" )
{ {
result->Set( 1.0 ); FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
return; return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
} }
} else if( arg->AsString() == "B" )
} {
} FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{
if( insideFootprint( item, itemBBox, itemShape, candidate ) )
return 1.0;
}
}
}
return 0.0;
} );
} }
@ -397,21 +414,14 @@ static void insideBackCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( !item ) if( !item )
return; return;
BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> shape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
auto insideFootprint = auto insideFootprint =
[&]( FOOTPRINT* footprint ) -> bool [&context]( BOARD_ITEM* item, const EDA_RECT& itemBBox,
std::shared_ptr<SHAPE>& itemShape, FOOTPRINT* footprint ) -> bool
{ {
if( !footprint ) if( !footprint )
return false; return false;
BOARD* board = item->GetBoard();
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex ); std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item ); std::pair<BOARD_ITEM*, BOARD_ITEM*> key( footprint, item );
auto i = board->m_InsideBCourtyardCache.find( key ); auto i = board->m_InsideBCourtyardCache.find( key );
@ -419,37 +429,49 @@ static void insideBackCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
if( i != board->m_InsideBCourtyardCache.end() ) if( i != board->m_InsideBCourtyardCache.end() )
return i->second; return i->second;
bool res = insideFootprintCourtyard( item, itemBBox, shape, context, footprint, bool res = insideFootprintCourtyard( item, itemBBox, itemShape, context,
B_Cu ); footprint, B_Cu );
board->m_InsideBCourtyardCache[ key ] = res; board->m_InsideBCourtyardCache[ key ] = res;
return res; return res;
}; };
if( arg->AsString() == "A" ) result->SetDeferredEval(
{ [item, arg, &context, &insideFootprint]() -> double
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) ) ) )
result->Set( 1.0 );
}
else if( arg->AsString() == "B" )
{
if( insideFootprint( dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) ) ) )
result->Set( 1.0 );
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{ {
if( insideFootprint( candidate ) ) BOARD* board = item->GetBoard();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> itemShape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
if( arg->AsString() == "A" )
{ {
result->Set( 1.0 ); FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 0 ) );
return; return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
} }
} else if( arg->AsString() == "B" )
} {
} FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( context->GetItem( 1 ) );
return insideFootprint( item, itemBBox, itemShape, footprint ) ? 1.0 : 0.0;
}
else
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference().Matches( arg->AsString() ) )
{
if( insideFootprint( item, itemBBox, itemShape, candidate ) )
return 1.0;
}
}
}
return 0.0;
} );
} }
@ -479,19 +501,12 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( !item ) if( !item )
return; return;
BOARD* board = item->GetBoard();
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
EDA_RECT itemBBox;
std::shared_ptr<SHAPE> shape;
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
else
itemBBox = item->GetBoundingBox();
auto itemIsInsideArea = auto itemIsInsideArea =
[&]( ZONE* area ) -> bool [&context]( BOARD_ITEM* item, ZONE* area, const EDA_RECT& itemBBox ) -> bool
{ {
BOARD* board = area->GetBoard();
std::shared_ptr<SHAPE> shape;
if( !area->GetCachedBoundingBox().Intersects( itemBBox ) ) if( !area->GetCachedBoundingBox().Intersects( itemBBox ) )
return false; return false;
@ -499,7 +514,8 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
// exclude touching. This is particularly important for detecting copper fills // exclude touching. This is particularly important for detecting copper fills
// as they will be exactly touching along the entire border. // as they will be exactly touching along the entire border.
SHAPE_POLY_SET areaOutline = *area->Outline(); SHAPE_POLY_SET areaOutline = *area->Outline();
areaOutline.Deflate( bds.GetDRCEpsilon(), 0, SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS ); areaOutline.Deflate( board->GetDesignSettings().GetDRCEpsilon(), 0,
SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
if( item->GetFlags() & HOLE_PROXY ) if( item->GetFlags() & HOLE_PROXY )
{ {
@ -527,8 +543,11 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 ) if( ( footprint->GetFlags() & MALFORMED_COURTYARDS ) != 0 )
{ {
if( aCtx->HasErrorCallback() ) if( context->HasErrorCallback() )
aCtx->ReportError( _( "Footprint's courtyard is not a single, closed shape." ) ); {
context->ReportError( _( "Footprint's courtyard is not a single, "
"closed shape." ) );
}
return false; return false;
} }
@ -539,8 +558,8 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( courtyard.OutlineCount() == 0 ) if( courtyard.OutlineCount() == 0 )
{ {
if( aCtx->HasErrorCallback() ) if( context->HasErrorCallback() )
aCtx->ReportError( _( "Footprint has no front courtyard." ) ); context->ReportError( _( "Footprint has no front courtyard." ) );
return false; return false;
} }
@ -556,8 +575,8 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( courtyard.OutlineCount() == 0 ) if( courtyard.OutlineCount() == 0 )
{ {
if( aCtx->HasErrorCallback() ) if( context->HasErrorCallback() )
aCtx->ReportError( _( "Footprint has no back courtyard." ) ); context->ReportError( _( "Footprint has no back courtyard." ) );
return false; return false;
} }
@ -602,11 +621,12 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
}; };
auto checkArea = auto checkArea =
[&]( ZONE* area ) -> bool [&itemIsInsideArea]( BOARD_ITEM* item, const EDA_RECT& itemBBox, ZONE* area ) -> bool
{ {
if( !area || area == item || area->GetParent() == item ) if( !area || area == item || area->GetParent() == item )
return false; return false;
BOARD* board = area->GetBoard();
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex ); std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
std::pair<BOARD_ITEM*, BOARD_ITEM*> key( area, item ); std::pair<BOARD_ITEM*, BOARD_ITEM*> key( area, item );
auto i = board->m_InsideAreaCache.find( key ); auto i = board->m_InsideAreaCache.find( key );
@ -614,86 +634,86 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( i != board->m_InsideAreaCache.end() ) if( i != board->m_InsideAreaCache.end() )
return i->second; return i->second;
bool isInside = itemIsInsideArea( area ); bool isInside = itemIsInsideArea( item, area, itemBBox );
board->m_InsideAreaCache[ key ] = isInside; board->m_InsideAreaCache[ key ] = isInside;
return isInside; return isInside;
}; };
if( arg->AsString() == "A" ) result->SetDeferredEval(
{ [item, arg, &context, &checkArea]() -> double
if( checkArea( dynamic_cast<ZONE*>( context->GetItem( 0 ) ) ) )
result->Set( 1.0 );
}
else if( arg->AsString() == "B" )
{
if( checkArea( dynamic_cast<ZONE*>( context->GetItem( 1 ) ) ) )
result->Set( 1.0 );
}
else if( KIID::SniffTest( arg->AsString() ) )
{
KIID target( arg->AsString() );
for( ZONE* area : board->Zones() )
{
// Only a single zone can match the UUID; exit once we find a match whether
// "inside" or not
if( area->m_Uuid == target )
{ {
if( checkArea( area ) ) BOARD* board = item->GetBoard();
result->Set( 1.0 ); EDA_RECT itemBBox;
return; if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
} itemBBox = static_cast<ZONE*>( item )->GetCachedBoundingBox();
} else
itemBBox = item->GetBoundingBox();
for( FOOTPRINT* footprint : board->Footprints() ) if( arg->AsString() == "A" )
{
for( ZONE* area : footprint->Zones() )
{
// Only a single zone can match the UUID; exit once we find a match whether
// "inside" or not
if( area->m_Uuid == target )
{ {
if( checkArea( area ) ) ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 0 ) );
result->Set( 1.0 ); return checkArea( item, itemBBox, zone ) ? 1.0 : 0.0;
return;
} }
} else if( arg->AsString() == "B" )
}
}
else // Match on zone name
{
for( ZONE* area : board->Zones() )
{
if( area->GetZoneName().Matches( arg->AsString() ) )
{
// Many zones can match the name; exit only when we find an "inside"
if( checkArea( area ) )
{ {
result->Set( 1.0 ); ZONE* zone = dynamic_cast<ZONE*>( context->GetItem( 1 ) );
return; return checkArea( item, itemBBox, zone ) ? 1.0 : 0.0;
} }
} else if( KIID::SniffTest( arg->AsString() ) )
}
for( FOOTPRINT* footprint : board->Footprints() )
{
for( ZONE* area : footprint->Zones() )
{
// Many zones can match the name; exit only when we find an "inside"
if( area->GetZoneName().Matches( arg->AsString() ) )
{ {
if( checkArea( area ) ) KIID target( arg->AsString());
for( ZONE* area : board->Zones() )
{ {
result->Set( 1.0 ); // Only a single zone can match the UUID; exit once we find a match whether
return; // "inside" or not
if( area->m_Uuid == target )
return checkArea( item, itemBBox, area ) ? 1.0 : 0.0;
} }
for( FOOTPRINT* footprint : board->Footprints() )
{
for( ZONE* area : footprint->Zones() )
{
// Only a single zone can match the UUID; exit once we find a match
// whether "inside" or not
if( area->m_Uuid == target )
return checkArea( item, itemBBox, area ) ? 1.0 : 0.0;
}
}
return 0.0;
} }
} else // Match on zone name
} {
} for( ZONE* area : board->Zones())
{
if( area->GetZoneName().Matches( arg->AsString() ) )
{
// Many zones can match the name; exit only when we find an "inside"
if( checkArea( item, itemBBox, area ) )
return 1.0;
}
}
for( FOOTPRINT* footprint : board->Footprints() )
{
for( ZONE* area : footprint->Zones() )
{
// Many zones can match the name; exit only when we find an "inside"
if( area->GetZoneName().Matches( arg->AsString() ) )
{
if( checkArea( item, itemBBox, area ) )
return 1.0;
}
}
}
return 0.0;
}
} );
} }
@ -721,21 +741,24 @@ static void memberOf( LIBEVAL::CONTEXT* aCtx, void* self )
if( !item ) if( !item )
return; return;
PCB_GROUP* group = item->GetParentGroup(); result->SetDeferredEval(
[item, arg]() -> double
{
PCB_GROUP* group = item->GetParentGroup();
if( !group && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T ) if( !group && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
group = item->GetParent()->GetParentGroup(); group = item->GetParent()->GetParentGroup();
while( group ) while( group )
{ {
if( group->GetName().Matches( arg->AsString() ) ) if( group->GetName().Matches( arg->AsString() ) )
{ return 1.0;
result->Set( 1.0 );
return;
}
group = group->GetParentGroup(); group = group->GetParentGroup();
} }
return 0.0;
} );
} }
@ -781,17 +804,24 @@ static void isCoupledDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
result->Set( 0.0 ); result->Set( 0.0 );
aCtx->Push( result ); aCtx->Push( result );
if( a && b ) result->SetDeferredEval(
{ [a, b]() -> double
NETINFO_ITEM* netinfo = a->GetNet(); {
wxString coupledNet, dummy; if( a && b )
{
NETINFO_ITEM* netinfo = a->GetNet();
wxString coupledNet, dummy;
if( netinfo && DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy ) != 0 ) if( netinfo
{ && DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy )
if( b->GetNetname() == coupledNet ) && b->GetNetname() == coupledNet )
result->Set( 1.0 ); {
} return 1.0;
} }
}
return 0.0;
} );
} }
@ -805,6 +835,9 @@ static void inDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
result->Set( 0.0 ); result->Set( 0.0 );
aCtx->Push( result ); aCtx->Push( result );
if( !item || !item->GetBoard() )
return;
if( !arg ) if( !arg )
{ {
if( aCtx->HasErrorCallback() ) if( aCtx->HasErrorCallback() )
@ -816,27 +849,27 @@ static void inDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
return; return;
} }
if( item && item->IsConnected() ) result->SetDeferredEval(
{ [item, arg]() -> double
NETINFO_ITEM* netinfo = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNet(); {
if( item && item->IsConnected() )
{
NETINFO_ITEM* netinfo = static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNet();
wxString refName = netinfo->GetNetname(); wxString refName = netinfo->GetNetname();
wxString baseName, coupledNet; wxString baseName, coupledNet;
int polarity = DRC_ENGINE::MatchDpSuffix( refName, coupledNet, baseName );
int polarity = DRC_ENGINE::MatchDpSuffix( refName, coupledNet, baseName ); if( polarity != 0
&& item->GetBoard()->FindNet( coupledNet )
&& baseName.Matches( arg->AsString() ) )
{
return 1.0;
}
}
if( polarity == 0 ) return 0.0;
return; } );
if( BOARD* board = item->GetBoard() )
{
if( !board->FindNet( coupledNet ) )
return;
}
if( baseName.Matches( arg->AsString() ) )
result->Set( 1.0 );
}
} }