mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
There are two netclass name methods, which previously were not obvious in their uses. These have been renamed to now have: GetName() : Used for internal or tooling (e.g. netlist export) usage GetHumanReadableName() : Used for display to users (e.g. in infobars) Fixing the previous unclear naming will result in fewer bugs when users start using the multiple netclass functionality, as the incorrect usage had started creeping in to new code. Also this will help authors of new code select the correct name method.
635 lines
19 KiB
C++
635 lines
19 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
|
|
#include <cstdio>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <board.h>
|
|
#include <footprint.h>
|
|
#include <lset.h>
|
|
#include <board_connected_item.h>
|
|
#include <pcbexpr_evaluator.h>
|
|
#include <drc/drc_engine.h>
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Specialized Expression References
|
|
*/
|
|
|
|
BOARD_ITEM* PCBEXPR_VAR_REF::GetObject( const LIBEVAL::CONTEXT* aCtx ) const
|
|
{
|
|
wxASSERT( dynamic_cast<const PCBEXPR_CONTEXT*>( aCtx ) );
|
|
|
|
const PCBEXPR_CONTEXT* ctx = static_cast<const PCBEXPR_CONTEXT*>( aCtx );
|
|
BOARD_ITEM* item = ctx->GetItem( m_itemIndex );
|
|
return item;
|
|
}
|
|
|
|
|
|
class PCBEXPR_LAYER_VALUE : public LIBEVAL::VALUE
|
|
{
|
|
public:
|
|
PCBEXPR_LAYER_VALUE( PCB_LAYER_ID aLayer ) :
|
|
LIBEVAL::VALUE( LayerName( aLayer ) ),
|
|
m_layer( aLayer )
|
|
{};
|
|
|
|
virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
|
{
|
|
// For boards with user-defined layer names there will be 2 entries for each layer
|
|
// in the ENUM_MAP: one for the canonical layer name and one for the user layer name.
|
|
// We need to check against both.
|
|
|
|
wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
|
|
const wxString& layerName = b->AsString();
|
|
BOARD* board = static_cast<PCBEXPR_CONTEXT*>( aCtx )->GetBoard();
|
|
|
|
{
|
|
std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
|
|
|
|
auto i = board->m_LayerExpressionCache.find( layerName );
|
|
|
|
if( i != board->m_LayerExpressionCache.end() )
|
|
return i->second.Contains( m_layer );
|
|
}
|
|
|
|
LSET mask;
|
|
|
|
for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
|
|
{
|
|
wxPGChoiceEntry& entry = layerMap[ii];
|
|
|
|
if( entry.GetText().Matches( layerName ) )
|
|
mask.set( ToLAYER_ID( entry.GetValue() ) );
|
|
}
|
|
|
|
{
|
|
std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
|
|
board->m_LayerExpressionCache[ layerName ] = mask;
|
|
}
|
|
|
|
return mask.Contains( m_layer );
|
|
}
|
|
|
|
protected:
|
|
PCB_LAYER_ID m_layer;
|
|
};
|
|
|
|
|
|
class PCBEXPR_PINTYPE_VALUE : public LIBEVAL::VALUE
|
|
{
|
|
public:
|
|
PCBEXPR_PINTYPE_VALUE( const wxString& aPinTypeName ) :
|
|
LIBEVAL::VALUE( aPinTypeName )
|
|
{};
|
|
|
|
bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
|
{
|
|
const wxString& thisStr = AsString();
|
|
const wxString& otherStr = b->AsString();
|
|
|
|
// Case insensitive
|
|
if( thisStr.IsSameAs( otherStr, false ) )
|
|
return true;
|
|
|
|
// Wildcards
|
|
if( thisStr.Matches( otherStr ) )
|
|
return true;
|
|
|
|
// Handle cases where the netlist token is different from the EEschema token
|
|
wxString altStr;
|
|
|
|
if( thisStr == wxT( "tri_state" ) )
|
|
altStr = wxT( "Tri-state" );
|
|
else if( thisStr == wxT( "power_in" ) )
|
|
altStr = wxT( "Power input" );
|
|
else if( thisStr == wxT( "power_out" ) )
|
|
altStr = wxT( "Power output" );
|
|
else if( thisStr == wxT( "no_connect" ) )
|
|
altStr = wxT( "Unconnected" );
|
|
|
|
if( !altStr.IsEmpty() )
|
|
{
|
|
// Case insensitive
|
|
if( altStr.IsSameAs( otherStr, false ) )
|
|
return true;
|
|
|
|
// Wildcards
|
|
if( altStr.Matches( otherStr ) )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PCBEXPR_NETCLASS_VALUE : public LIBEVAL::VALUE
|
|
{
|
|
public:
|
|
PCBEXPR_NETCLASS_VALUE( BOARD_CONNECTED_ITEM* aItem ) :
|
|
LIBEVAL::VALUE( wxEmptyString ),
|
|
m_item( aItem )
|
|
{};
|
|
|
|
const wxString& AsString() const override
|
|
{
|
|
const_cast<PCBEXPR_NETCLASS_VALUE*>( this )->Set(
|
|
m_item->GetEffectiveNetClass()->GetName() );
|
|
return LIBEVAL::VALUE::AsString();
|
|
}
|
|
|
|
bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
|
|
{
|
|
return *( m_item->GetEffectiveNetClass() )
|
|
== *( bValue->m_item->GetEffectiveNetClass() );
|
|
}
|
|
else
|
|
{
|
|
return LIBEVAL::VALUE::EqualTo( aCtx, b );
|
|
}
|
|
}
|
|
|
|
bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
|
|
return m_item->GetEffectiveNetClass() != bValue->m_item->GetEffectiveNetClass();
|
|
else
|
|
return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
|
|
}
|
|
|
|
protected:
|
|
BOARD_CONNECTED_ITEM* m_item;
|
|
};
|
|
|
|
|
|
class PCBEXPR_COMPONENT_CLASS_VALUE : public LIBEVAL::VALUE
|
|
{
|
|
public:
|
|
PCBEXPR_COMPONENT_CLASS_VALUE( BOARD_ITEM* aItem ) :
|
|
LIBEVAL::VALUE( wxEmptyString ), m_item( dynamic_cast<FOOTPRINT*>( aItem ) )
|
|
{};
|
|
|
|
const wxString& AsString() const override
|
|
{
|
|
if( !m_item )
|
|
return LIBEVAL::VALUE::AsString();
|
|
|
|
if( const COMPONENT_CLASS* compClass = m_item->GetComponentClass() )
|
|
const_cast<PCBEXPR_COMPONENT_CLASS_VALUE*>( this )->Set( compClass->GetFullName() );
|
|
|
|
return LIBEVAL::VALUE::AsString();
|
|
}
|
|
|
|
bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue =
|
|
dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
|
|
{
|
|
if( !m_item || !bValue->m_item )
|
|
return LIBEVAL::VALUE::EqualTo( aCtx, b );
|
|
|
|
const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
|
|
const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
|
|
|
|
// Note this depends on COMPONENT_CLASS_MANAGER maintaining ownership
|
|
// of all unique component class objects
|
|
return aClass == bClass;
|
|
}
|
|
else
|
|
{
|
|
return LIBEVAL::VALUE::EqualTo( aCtx, b );
|
|
}
|
|
}
|
|
|
|
bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue =
|
|
dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
|
|
{
|
|
if( !m_item || !bValue->m_item )
|
|
return LIBEVAL::VALUE::EqualTo( aCtx, b );
|
|
|
|
const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
|
|
const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
|
|
|
|
// Note this depends on COMPONENT_CLASS_MANAGER maintaining ownership
|
|
// of all unique component class objects
|
|
return aClass != bClass;
|
|
}
|
|
else
|
|
{
|
|
return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
|
|
}
|
|
}
|
|
|
|
protected:
|
|
FOOTPRINT* m_item;
|
|
};
|
|
|
|
|
|
class PCBEXPR_NET_VALUE : public LIBEVAL::VALUE
|
|
{
|
|
public:
|
|
PCBEXPR_NET_VALUE( BOARD_CONNECTED_ITEM* aItem ) :
|
|
LIBEVAL::VALUE( wxEmptyString ),
|
|
m_item( aItem )
|
|
{};
|
|
|
|
const wxString& AsString() const override
|
|
{
|
|
const_cast<PCBEXPR_NET_VALUE*>( this )->Set( m_item->GetNetname() );
|
|
return LIBEVAL::VALUE::AsString();
|
|
}
|
|
|
|
bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
|
|
return m_item->GetNetCode() == bValue->m_item->GetNetCode();
|
|
else
|
|
return LIBEVAL::VALUE::EqualTo( aCtx, b );
|
|
}
|
|
|
|
bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
|
|
{
|
|
if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
|
|
return m_item->GetNetCode() != bValue->m_item->GetNetCode();
|
|
else
|
|
return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
|
|
}
|
|
|
|
protected:
|
|
BOARD_CONNECTED_ITEM* m_item;
|
|
};
|
|
|
|
|
|
LIBEVAL::VALUE* PCBEXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
|
{
|
|
PCBEXPR_CONTEXT* context = static_cast<PCBEXPR_CONTEXT*>( aCtx );
|
|
|
|
if( m_type == LIBEVAL::VT_NULL )
|
|
return LIBEVAL::VALUE::MakeNullValue();
|
|
|
|
if( m_itemIndex == 2 )
|
|
return new PCBEXPR_LAYER_VALUE( context->GetLayer() );
|
|
|
|
BOARD_ITEM* item = GetObject( aCtx );
|
|
|
|
if( !item )
|
|
return new LIBEVAL::VALUE();
|
|
|
|
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
|
|
|
|
if( it == m_matchingTypes.end() )
|
|
{
|
|
// Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
|
|
// simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
|
|
// value when the property doesn't appear on a particular object.
|
|
|
|
return new LIBEVAL::VALUE();
|
|
}
|
|
else
|
|
{
|
|
if( m_type == LIBEVAL::VT_NUMERIC )
|
|
{
|
|
if( m_isOptional )
|
|
{
|
|
auto val = item->Get<std::optional<int>>( it->second );
|
|
|
|
if( val.has_value() )
|
|
return new LIBEVAL::VALUE( static_cast<double>( val.value() ) );
|
|
|
|
return LIBEVAL::VALUE::MakeNullValue();
|
|
}
|
|
|
|
return new LIBEVAL::VALUE( static_cast<double>( item->Get<int>( it->second ) ) );
|
|
}
|
|
else
|
|
{
|
|
wxString str;
|
|
|
|
if( !m_isEnum )
|
|
{
|
|
str = item->Get<wxString>( it->second );
|
|
|
|
if( it->second->Name() == wxT( "Pin Type" ) )
|
|
return new PCBEXPR_PINTYPE_VALUE( str );
|
|
else
|
|
return new LIBEVAL::VALUE( str );
|
|
}
|
|
else
|
|
{
|
|
const wxAny& any = item->Get( it->second );
|
|
PCB_LAYER_ID layer;
|
|
|
|
if( it->second->Name() == wxT( "Layer" )
|
|
|| it->second->Name() == wxT( "Layer Top" )
|
|
|| it->second->Name() == wxT( "Layer Bottom" ) )
|
|
{
|
|
if( any.GetAs<PCB_LAYER_ID>( &layer ) )
|
|
return new PCBEXPR_LAYER_VALUE( layer );
|
|
else if( any.GetAs<wxString>( &str ) )
|
|
return new PCBEXPR_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
|
|
}
|
|
else
|
|
{
|
|
if( any.GetAs<wxString>( &str ) )
|
|
return new LIBEVAL::VALUE( str );
|
|
}
|
|
}
|
|
|
|
return new LIBEVAL::VALUE();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
LIBEVAL::VALUE* PCBEXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
|
{
|
|
BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
|
|
|
|
if( !item )
|
|
return new LIBEVAL::VALUE();
|
|
|
|
return new PCBEXPR_NETCLASS_VALUE( item );
|
|
}
|
|
|
|
|
|
LIBEVAL::VALUE* PCBEXPR_COMPONENT_CLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
|
{
|
|
BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( GetObject( aCtx ) );
|
|
|
|
if( !item || item->Type() != PCB_FOOTPRINT_T )
|
|
return new LIBEVAL::VALUE();
|
|
|
|
return new PCBEXPR_COMPONENT_CLASS_VALUE( item );
|
|
}
|
|
|
|
|
|
LIBEVAL::VALUE* PCBEXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
|
{
|
|
BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
|
|
|
|
if( !item )
|
|
return new LIBEVAL::VALUE();
|
|
|
|
return new PCBEXPR_NET_VALUE( item );
|
|
}
|
|
|
|
|
|
LIBEVAL::VALUE* PCBEXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
|
{
|
|
BOARD_ITEM* item = GetObject( aCtx );
|
|
|
|
if( !item )
|
|
return new LIBEVAL::VALUE();
|
|
|
|
return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
|
|
}
|
|
|
|
|
|
LIBEVAL::FUNC_CALL_REF PCBEXPR_UCODE::CreateFuncCall( const wxString& aName )
|
|
{
|
|
PCBEXPR_BUILTIN_FUNCTIONS& registry = PCBEXPR_BUILTIN_FUNCTIONS::Instance();
|
|
|
|
return registry.Get( aName.Lower() );
|
|
}
|
|
|
|
|
|
std::unique_ptr<LIBEVAL::VAR_REF> PCBEXPR_UCODE::CreateVarRef( const wxString& aVar,
|
|
const wxString& aField )
|
|
{
|
|
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
|
std::unique_ptr<PCBEXPR_VAR_REF> vref;
|
|
|
|
if( aVar.IsSameAs( wxT( "null" ), false ) )
|
|
{
|
|
vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
|
|
vref->SetType( LIBEVAL::VT_NULL );
|
|
return vref;
|
|
}
|
|
|
|
// Check for a couple of very common cases and compile them straight to "object code".
|
|
|
|
if( aField.CmpNoCase( wxT( "NetClass" ) ) == 0 )
|
|
{
|
|
if( aVar == wxT( "A" ) )
|
|
return std::make_unique<PCBEXPR_NETCLASS_REF>( 0 );
|
|
else if( aVar == wxT( "B" ) )
|
|
return std::make_unique<PCBEXPR_NETCLASS_REF>( 1 );
|
|
else
|
|
return nullptr;
|
|
}
|
|
else if( aField.CmpNoCase( wxT( "ComponentClass" ) ) == 0 )
|
|
{
|
|
if( aVar == wxT( "A" ) )
|
|
return std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 0 );
|
|
else if( aVar == wxT( "B" ) )
|
|
return std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 1 );
|
|
else
|
|
return nullptr;
|
|
}
|
|
else if( aField.CmpNoCase( wxT( "NetName" ) ) == 0 )
|
|
{
|
|
if( aVar == wxT( "A" ) )
|
|
return std::make_unique<PCBEXPR_NETNAME_REF>( 0 );
|
|
else if( aVar == wxT( "B" ) )
|
|
return std::make_unique<PCBEXPR_NETNAME_REF>( 1 );
|
|
else
|
|
return nullptr;
|
|
}
|
|
else if( aField.CmpNoCase( wxT( "Type" ) ) == 0 )
|
|
{
|
|
if( aVar == wxT( "A" ) )
|
|
return std::make_unique<PCBEXPR_TYPE_REF>( 0 );
|
|
else if( aVar == wxT( "B" ) )
|
|
return std::make_unique<PCBEXPR_TYPE_REF>( 1 );
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if( aVar == wxT( "A" ) || aVar == wxT( "AB" ) )
|
|
vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
|
|
else if( aVar == wxT( "B" ) )
|
|
vref = std::make_unique<PCBEXPR_VAR_REF>( 1 );
|
|
else if( aVar == wxT( "L" ) )
|
|
vref = std::make_unique<PCBEXPR_VAR_REF>( 2 );
|
|
else
|
|
return nullptr;
|
|
|
|
if( aField.length() == 0 ) // return reference to base object
|
|
return vref;
|
|
|
|
wxString field( aField );
|
|
field.Replace( wxT( "_" ), wxT( " " ) );
|
|
|
|
for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
|
|
{
|
|
if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
|
|
{
|
|
PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field );
|
|
|
|
if( prop )
|
|
{
|
|
vref->AddAllowedClass( cls.type, prop );
|
|
|
|
if( prop->TypeHash() == TYPE_HASH( int ) )
|
|
{
|
|
vref->SetType( LIBEVAL::VT_NUMERIC );
|
|
}
|
|
else if( prop->TypeHash() == TYPE_HASH( std::optional<int> ) )
|
|
{
|
|
vref->SetType( LIBEVAL::VT_NUMERIC );
|
|
vref->SetIsOptional();
|
|
}
|
|
else if( prop->TypeHash() == TYPE_HASH( bool ) )
|
|
{
|
|
vref->SetType( LIBEVAL::VT_NUMERIC );
|
|
}
|
|
else if( prop->TypeHash() == TYPE_HASH( wxString ) )
|
|
{
|
|
vref->SetType( LIBEVAL::VT_STRING );
|
|
}
|
|
else if ( prop->HasChoices() )
|
|
{ // it's an enum, we treat it as string
|
|
vref->SetType( LIBEVAL::VT_STRING );
|
|
vref->SetIsEnum( true );
|
|
}
|
|
else
|
|
{
|
|
wxString msg = wxString::Format( wxT( "PCBEXPR_UCODE::createVarRef: Unknown "
|
|
"property type %s from %s." ),
|
|
cls.name,
|
|
field );
|
|
wxFAIL_MSG( msg );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
|
|
vref->SetType( LIBEVAL::VT_PARSE_ERROR );
|
|
|
|
return vref;
|
|
}
|
|
|
|
|
|
BOARD* PCBEXPR_CONTEXT::GetBoard() const
|
|
{
|
|
if( m_items[0] )
|
|
return m_items[0]->GetBoard();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Unit Resolvers
|
|
*/
|
|
|
|
const std::vector<wxString>& PCBEXPR_UNIT_RESOLVER::GetSupportedUnits() const
|
|
{
|
|
static const std::vector<wxString> pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ) };
|
|
|
|
return pcbUnits;
|
|
}
|
|
|
|
|
|
wxString PCBEXPR_UNIT_RESOLVER::GetSupportedUnitsMessage() const
|
|
{
|
|
return _( "must be mm, in, or mil" );
|
|
}
|
|
|
|
|
|
double PCBEXPR_UNIT_RESOLVER::Convert( const wxString& aString, int unitId ) const
|
|
{
|
|
double v = wxAtof( aString );
|
|
|
|
switch( unitId )
|
|
{
|
|
case 0: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MILS, aString );
|
|
case 1: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MILLIMETRES, aString );
|
|
case 2: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::INCHES, aString );
|
|
default: return v;
|
|
}
|
|
};
|
|
|
|
|
|
const std::vector<wxString>& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnits() const
|
|
{
|
|
static const std::vector<wxString> emptyUnits;
|
|
|
|
return emptyUnits;
|
|
}
|
|
|
|
|
|
double PCBEXPR_UNITLESS_RESOLVER::Convert( const wxString& aString, int unitId ) const
|
|
{
|
|
return wxAtof( aString );
|
|
};
|
|
|
|
|
|
PCBEXPR_COMPILER::PCBEXPR_COMPILER( LIBEVAL::UNIT_RESOLVER* aUnitResolver )
|
|
{
|
|
m_unitResolver.reset( aUnitResolver );
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* PCB Expression Evaluator
|
|
*/
|
|
|
|
PCBEXPR_EVALUATOR::PCBEXPR_EVALUATOR( LIBEVAL::UNIT_RESOLVER* aUnitResolver ) :
|
|
m_result( 0 ),
|
|
m_compiler( aUnitResolver ),
|
|
m_ucode(),
|
|
m_errorStatus()
|
|
{
|
|
}
|
|
|
|
|
|
PCBEXPR_EVALUATOR::~PCBEXPR_EVALUATOR()
|
|
{
|
|
}
|
|
|
|
|
|
bool PCBEXPR_EVALUATOR::Evaluate( const wxString& aExpr )
|
|
{
|
|
PCBEXPR_UCODE ucode;
|
|
PCBEXPR_CONTEXT preflightContext( NULL_CONSTRAINT, F_Cu );
|
|
|
|
if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
|
|
return false;
|
|
|
|
PCBEXPR_CONTEXT evaluationContext( NULL_CONSTRAINT, F_Cu );
|
|
LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
|
|
|
|
if( result->GetType() == LIBEVAL::VT_NUMERIC )
|
|
m_result = KiROUND( result->AsDouble() );
|
|
|
|
return true;
|
|
}
|
|
|