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:
parent
1e23ce1c95
commit
048e13f423
|
@ -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
|
||||||
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue