altium: make special string parsing on pcb a bit more generic

Only special strings starting with a dot are supported. Parsing of concatenated special strings using quotes needs to be implemented, but at least a few test-cases are already there now.
This commit is contained in:
Thomas Pointhuber 2023-10-01 15:10:09 +02:00
parent 34769cec63
commit 7005dd7c48
5 changed files with 130 additions and 33 deletions

View File

@ -83,8 +83,8 @@ wxString AltiumPropertyToKiCadString( const wxString& aString )
// https://www.altium.com/documentation/altium-designer/sch-obj-textstringtext-string-ad#!special-strings
wxString AltiumSpecialStringsToKiCadVariables( const wxString& aString,
const std::map<wxString, wxString>& aOverrides )
wxString AltiumSchSpecialStringsToKiCadVariables( const wxString& aString,
const std::map<wxString, wxString>& aOverrides )
{
if( aString.IsEmpty() || aString.at( 0 ) != '=' )
{
@ -143,6 +143,35 @@ wxString AltiumSpecialStringsToKiCadVariables( const wxString&
return result;
}
// https://www.altium.com/documentation/altium-designer/text-objects-pcb
wxString AltiumPcbSpecialStringsToKiCadStrings( const wxString& aString,
const std::map<wxString, wxString>& aOverrides )
{
if( aString.IsEmpty() )
{
return aString;
}
// special case: string starts with dot -> whole string is special string
if( aString.at( 0 ) == '.' )
{
wxString specialString = aString.substr( 1 );
specialString.UpperCase(); // matching is implemented using upper case strings
auto overrideIt = aOverrides.find( specialString );
if( overrideIt != aOverrides.end() )
specialString = overrideIt->second;
return wxString::Format( wxT( "${%s}" ), specialString );
}
// TODO: implement Concatenated special strings using apostrophe "'".
return aString;
}
wxString AltiumPinNamesToKiCad( wxString& aString )
{
wxString output;

View File

@ -37,8 +37,11 @@ LIB_ID AltiumToKiCadLibID( const wxString& aLibName, const wxString& aLibReferen
wxString AltiumPropertyToKiCadString( const wxString& aString );
wxString AltiumSpecialStringsToKiCadVariables( const wxString& aString,
const std::map<wxString, wxString>& aOverrides );
wxString AltiumSchSpecialStringsToKiCadVariables( const wxString& aString,
const std::map<wxString, wxString>& aOverrides );
wxString AltiumPcbSpecialStringsToKiCadStrings( const wxString& aString,
const std::map<wxString, wxString>& aOverrides );
wxString AltiumPinNamesToKiCad( wxString& aString );
VECTOR2I AltiumGetEllipticalPos( double aMajor, double aMinor, double aAngleRadians );

View File

@ -1238,7 +1238,7 @@ void SCH_ALTIUM_PLUGIN::ParseLabel( const std::map<wxString, wxString>& aPropert
if( aSymbol.empty() && elem.ownerpartid == ALTIUM_COMPONENT_NONE )
{
std::map<wxString, wxString> variableMap = {
static const std::map<wxString, wxString> variableMap = {
{ "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
{ "SHEETNUMBER", "#" },
{ "SHEETTOTAL", "##" },
@ -1251,7 +1251,7 @@ void SCH_ALTIUM_PLUGIN::ParseLabel( const std::map<wxString, wxString>& aPropert
{ "PROJECTNAME", "PROJECTNAME" },
};
wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
SetTextPositioning( textItem, elem.justification, elem.orientation );
@ -3571,7 +3571,7 @@ void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aPro
ASCH_PARAMETER elem( aProperties );
// TODO: fill in replacements from variant, sheet and project
std::map<wxString, wxString> variableMap = {
static const std::map<wxString, wxString> variableMap = {
{ "COMMENT", "VALUE" },
{ "VALUE", "ALTIUM_VALUE" },
};
@ -3655,7 +3655,7 @@ void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aPro
field = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldIdx, symbol, fieldName ) );
}
wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
field->SetText( kicadText );
field->SetPosition( elem.location + m_sheetOffset );
field->SetVisible( !elem.isHidden );
@ -3720,7 +3720,7 @@ void SCH_ALTIUM_PLUGIN::ParseLibParameter( const std::map<wxString, wxString>& a
field = new_field;
}
wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
field->SetText( kicadText );

View File

@ -3292,15 +3292,14 @@ void ALTIUM_PCB::ConvertTexts6ToBoardItemOnLayer( const ATEXT6& aElem, PCB_LAYER
{
PCB_TEXT* pcbText = new PCB_TEXT( m_board );
// TODO: improve parsing of variables
wxString trimmedText = aElem.text;
trimmedText.Trim();
static const std::map<wxString, wxString> variableMap = {
{ "LAYER_NAME", "LAYER" },
{ "PRINT_DATE", "CURRENT_DATE"},
};
if( trimmedText.CmpNoCase( wxT( ".Layer_Name" ) ) == 0 )
pcbText->SetText( wxT( "${LAYER}" ) );
else
pcbText->SetText( aElem.text );
wxString kicadText = AltiumPcbSpecialStringsToKiCadStrings( aElem.text, variableMap );
pcbText->SetText(kicadText);
pcbText->SetLayer( aLayer );
pcbText->SetPosition( aElem.position );
pcbText->SetTextAngle( EDA_ANGLE( aElem.rotation, DEGREES_T ) );
@ -3330,19 +3329,17 @@ void ALTIUM_PCB::ConvertTexts6ToFootprintItemOnLayer( FOOTPRINT* aFootprint, con
aFootprint->Add( fpText, ADD_MODE::APPEND );
}
// TODO: improve parsing of variables
wxString trimmedText = aElem.text;
trimmedText.Trim();
static const std::map<wxString, wxString> variableMap = {
{ "DESIGNATOR", "REFERENCE" },
{ "COMMENT", "VALUE" },
{ "VALUE", "ALTIUM_VALUE" },
{ "LAYER_NAME", "LAYER" },
{ "PRINT_DATE", "CURRENT_DATE"},
};
if( !aElem.isDesignator && trimmedText.CmpNoCase( wxT( ".Designator" ) ) == 0 )
fpText->SetText( wxT( "${REFERENCE}" ) );
else if( !aElem.isComment && trimmedText.CmpNoCase( wxT( ".Comment" ) ) == 0 )
fpText->SetText( wxT( "${VALUE}" ) );
else if( trimmedText.CmpNoCase( wxT( ".Layer_Name" ) ) == 0 )
fpText->SetText( wxT( "${LAYER}" ) );
else
fpText->SetText( aElem.text );
wxString kicadText = AltiumPcbSpecialStringsToKiCadStrings( aElem.text, variableMap );
fpText->SetText(kicadText);
fpText->SetKeepUpright( false );
fpText->SetLayer( aLayer );
fpText->SetPosition( aElem.position );

View File

@ -52,7 +52,7 @@ struct SPECIAL_STRINGS_TO_KICAD
/**
* A list of valid test strings and the expected results
*/
static const std::vector<SPECIAL_STRINGS_TO_KICAD> special_string_to_kicad_property = {
static const std::vector<SPECIAL_STRINGS_TO_KICAD> sch_special_string_to_kicad_property = {
// Empty
{ "", "", {} },
// No Special Strings
@ -84,7 +84,7 @@ static const std::vector<SPECIAL_STRINGS_TO_KICAD> special_string_to_kicad_prope
{ "=A+B", "${A}${B}", {} },
{ "=A+B", "${C}${B}", { { "A", "C" } } },
{ "=A+B", "${C}${D}", { { "A", "C" }, { "B", "D" } } },
// Case insensitive special strings
// Case-insensitive special strings
{ "=A", "${C}", { { "A", "C" } } },
{ "=a", "${C}", { { "A", "C" } } },
{ "=AB", "${C}", { { "AB", "C" } } },
@ -132,15 +132,83 @@ static const std::vector<SPECIAL_STRINGS_TO_KICAD> special_string_to_kicad_prope
/**
* Test conversation from Altium Special String to a KiCad String with variables
* Test conversation from Altium Schematic Special String to a KiCad String with variables
*/
BOOST_AUTO_TEST_CASE( AltiumSpecialStringsToKiCadVariablesProperties )
BOOST_AUTO_TEST_CASE( AltiumSchSpecialStringsToKiCadVariablesProperties )
{
for( const auto& c : special_string_to_kicad_property )
for( const auto& c : sch_special_string_to_kicad_property )
{
BOOST_TEST_CONTEXT( wxString::Format( wxT( "'%s' -> '%s'" ), c.input, c.exp_result ) )
{
wxString result = AltiumSpecialStringsToKiCadVariables( c.input, c.override );
wxString result = AltiumSchSpecialStringsToKiCadVariables( c.input, c.override );
// These are all valid
BOOST_CHECK_EQUAL( result, c.exp_result );
}
}
}
/**
* A list of valid test strings and the expected results
*/
static const std::vector<SPECIAL_STRINGS_TO_KICAD> pcb_special_string_to_kicad_property = {
// Empty
{ "", "", {} },
// No Special Strings
{ "A", "A", {} },
{ " A", " A", {} },
{ "A ", "A ", {} },
{ "A=B", "A=B", {} },
{ "A=B+C", "A=B+C", {} },
{ "A\nB", "A\nB", {} },
{ "A\tB", "A\tB", {} },
{ "This is a long text with spaces", "This is a long text with spaces", {} },
// Text format (underscore,...), TODO: add
// Escaping, TODO: add
{ "'", "'", {} },
{ "'A'", "'A'", {} },
{ "$", "$", {} },
{ "{", "{", {} },
{ "}", "}", {} },
{ "${A}", "${A}", {} }, // TODO: correct substitution
// Simple special strings starting with dot
{ ".A", "${A}", {} },
{ ".A", "${C}", { { "A", "C" } } },
{ ".A_B", "${A_B}", {} },
// Concatenated special strings
/*{ "'.A'", "${A}", {} },
{ "'.A''.B'", "${A}${B}", {} },
{ "'.A''.B'", "${C}${B}", { { "A", "C" } } },
{ "'.A''.B'", "${C}${D}", { { "A", "C" }, { "B", "D" } } },
{ "A='.A', B='.B'", "A=${A}, B=${B}", {} },*/
// Case-insensitive special strings
{ ".A", "${C}", { { "A", "C" } } },
{ ".a", "${C}", { { "A", "C" } } },
{ ".AB", "${C}", { { "AB", "C" } } },
{ ".aB", "${C}", { { "AB", "C" } } },
{ ".Ab", "${C}", { { "AB", "C" } } },
{ ".ab", "${C}", { { "AB", "C" } } },
// Some special cases we do not know yet how to handle correctly. But we should not crash ;)
{ "''", "''", {} },
{ " .", " .", {} },
{ ". ", "${ }", {} },
{ ". A", "${ A}", {} },
{ ".A ", "${A }", {} },
{ " .A", " .A", {} },
{ "...", "${..}", {} },
};
/**
* Test conversation from Altium Board Special String to a KiCad String with variables
*/
BOOST_AUTO_TEST_CASE( AltiumPcbSpecialStringsToKiCadStringsProperties )
{
for( const auto& c : pcb_special_string_to_kicad_property )
{
BOOST_TEST_CONTEXT( wxString::Format( wxT( "'%s' -> '%s'" ), c.input, c.exp_result ) )
{
wxString result = AltiumPcbSpecialStringsToKiCadStrings( c.input, c.override );
// These are all valid
BOOST_CHECK_EQUAL( result, c.exp_result );