mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-02-18 22:19:53 +00:00
Recommendation is to avoid using the year nomenclature as this information is already encoded in the git repo. Avoids needing to repeatly update. Also updates AUTHORS.txt from current repo with contributor names
1138 lines
40 KiB
C++
1138 lines
40 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2022 Chetan Subhash Shinde<chetanshinde2001@gmail.com>
|
|
* Copyright (C) 2023 CERN
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* @brief Loads the asc file and asy files.
|
|
*/
|
|
|
|
#include "sch_io/ltspice/ltspice_schematic.h"
|
|
|
|
#include <sch_io/ltspice/sch_io_ltspice_parser.h>
|
|
#include <sch_screen.h>
|
|
#include <wx/log.h>
|
|
#include <wx/dir.h>
|
|
#include <wildcards_and_files_ext.h>
|
|
#include <sch_sheet.h>
|
|
#include <schematic.h>
|
|
#include <project.h>
|
|
#include <richio.h>
|
|
|
|
|
|
void LTSPICE_SCHEMATIC::Load( SCHEMATIC* aSchematic, SCH_SHEET* aRootSheet,
|
|
const wxFileName& aLibraryFileName, REPORTER* aReporter )
|
|
{
|
|
std::map<wxString, wxString> mapOfAscFiles;
|
|
std::map<wxString, wxString> mapOfAsyFiles;
|
|
|
|
// Library paths to search (Give highest priority to files contained in same directory)
|
|
GetAscAndAsyFilePaths( aLibraryFileName.GetPath(), false, mapOfAscFiles, mapOfAsyFiles );
|
|
|
|
// TODO: Custom paths go here (non-recursive)
|
|
|
|
// Default LTspice libs
|
|
GetAscAndAsyFilePaths( m_ltspiceDataDir.GetPathWithSep() + wxS( "sub" ), true, mapOfAscFiles,
|
|
mapOfAsyFiles );
|
|
|
|
GetAscAndAsyFilePaths( m_ltspiceDataDir.GetPathWithSep() + wxS( "sym" ), true, mapOfAscFiles,
|
|
mapOfAsyFiles );
|
|
|
|
m_schematic = aSchematic;
|
|
|
|
std::queue<wxString> ascFileQueue;
|
|
ascFileQueue.push( aLibraryFileName.GetName().Lower() );
|
|
|
|
LTSPICE_FILE rootAscFile( ascFileQueue.front(), { 0, 0 } );
|
|
|
|
rootAscFile.Sheet = aRootSheet;
|
|
rootAscFile.Screen = new SCH_SCREEN();
|
|
|
|
int parentSheetIndex = 0;
|
|
|
|
// Asc files who are subschematic in nature
|
|
std::vector<LTSPICE_FILE> ascFiles;
|
|
|
|
ascFiles.push_back( rootAscFile );
|
|
|
|
while( !ascFileQueue.empty() )
|
|
{
|
|
SCH_SCREEN* screen = nullptr;
|
|
|
|
// Reading the .asc file
|
|
wxString ascFilePath = mapOfAscFiles[ ascFileQueue.front() ];
|
|
wxString buffer = SafeReadFile( ascFilePath, "r" );
|
|
|
|
std::vector<LTSPICE_FILE> newSubSchematicElements = GetSchematicElements( buffer );
|
|
|
|
alg::delete_if( newSubSchematicElements,
|
|
[&mapOfAscFiles]( const LTSPICE_FILE& ii )
|
|
{
|
|
return mapOfAscFiles[ii.ElementName].IsEmpty();
|
|
} );
|
|
|
|
for( LTSPICE_FILE& newSubSchematicElement : newSubSchematicElements )
|
|
{
|
|
wxString asyName = newSubSchematicElement.ElementName;
|
|
auto it = mapOfAsyFiles.find( asyName );
|
|
|
|
if( it == mapOfAsyFiles.end() )
|
|
continue;
|
|
|
|
wxString asyBuffer = SafeReadFile( it->second, "r" );
|
|
|
|
if( IsAsySubsheet( asyBuffer ) )
|
|
{
|
|
if( !screen )
|
|
screen = new SCH_SCREEN( m_schematic );
|
|
|
|
newSubSchematicElement.ParentIndex = parentSheetIndex;
|
|
newSubSchematicElement.Screen = screen;
|
|
newSubSchematicElement.Sheet = new SCH_SHEET();
|
|
|
|
ascFileQueue.push( newSubSchematicElement.ElementName );
|
|
ascFiles.push_back( newSubSchematicElement );
|
|
}
|
|
}
|
|
|
|
ascFileQueue.pop();
|
|
|
|
parentSheetIndex++;
|
|
}
|
|
|
|
for( unsigned int i = 0; i < ascFiles.size(); i++ )
|
|
{
|
|
// Reading the .asc file
|
|
wxString buffer = SafeReadFile( mapOfAscFiles[ascFiles[i].ElementName], wxS( "r" ) );
|
|
|
|
// Getting the keywords to read
|
|
{
|
|
std::vector<LTSPICE_FILE> sourceFiles = GetSchematicElements( buffer );
|
|
|
|
m_fileCache[ wxS( "asyFiles" ) ] = ReadAsyFiles( sourceFiles, mapOfAsyFiles );
|
|
m_fileCache[ wxS( "ascFiles" ) ][ wxS( "parentFile" ) ] = buffer;
|
|
|
|
for( const LTSPICE_FILE& file : sourceFiles )
|
|
wxASSERT( file.Sheet == nullptr && file.Screen == nullptr );
|
|
}
|
|
|
|
SCH_SHEET_PATH curSheetPath;
|
|
SCH_IO_LTSPICE_PARSER parser( this );
|
|
|
|
if( i > 0 )
|
|
{
|
|
SCH_SHEET* curSheet = ascFiles[i].Sheet;
|
|
std::map tempAsyMap = ReadAsyFile( ascFiles[i], mapOfAsyFiles );
|
|
wxString ascFileName = ascFiles[i].ElementName;
|
|
LT_ASC dummyAsc;
|
|
LT_SYMBOL tempSymbol = SymbolBuilder( ascFileName, tempAsyMap[ascFileName], dummyAsc );
|
|
LIB_SYMBOL tempLibSymbol( ascFiles[i].ElementName );
|
|
|
|
parser.CreateSymbol( tempSymbol, &tempLibSymbol );
|
|
|
|
BOX2I bbox = tempLibSymbol.GetBoundingBox();
|
|
|
|
curSheet->SetSize( bbox.GetSize() );
|
|
curSheet->SetPosition( parser.ToKicadCoords( ascFiles[i].Offset ) + bbox.GetOrigin() );
|
|
curSheet->SetParent( ascFiles[ascFiles[i].ParentIndex].Sheet );
|
|
|
|
SCH_FIELD& sheetNameField = curSheet->GetFields()[SHEETNAME];
|
|
SCH_FIELD& fileNameSheet = curSheet->GetFields()[SHEETFILENAME];
|
|
wxString sheetName = wxString::Format( wxS( "%s-subsheet-%d" ),
|
|
ascFiles[i].ElementName,
|
|
i );
|
|
|
|
sheetNameField.SetText( sheetName );
|
|
fileNameSheet.SetText( sheetName + ".kicad_sch" );
|
|
|
|
curSheet->SetScreen( ascFiles[i].Screen );
|
|
|
|
curSheetPath = ascFiles[ascFiles[i].ParentIndex].SheetPath;
|
|
curSheetPath.push_back( curSheet );
|
|
|
|
ascFiles[i].SheetPath = curSheetPath;
|
|
|
|
ascFiles[ascFiles[i].ParentIndex].Sheet->GetScreen()->Append( curSheet );
|
|
|
|
curSheet->GetScreen()->SetFileName( m_schematic->Prj().GetProjectPath() + sheetName
|
|
+ ".kicad_sch" );
|
|
}
|
|
else
|
|
{
|
|
SCH_SHEET* curSheet = ascFiles[i].Sheet;
|
|
|
|
ascFiles[i].SheetPath.push_back( curSheet );
|
|
curSheetPath = ascFiles[i].SheetPath;
|
|
}
|
|
|
|
std::vector<wxString> subSchematicAsyFiles;
|
|
|
|
for( const LTSPICE_FILE& ascFile : ascFiles )
|
|
subSchematicAsyFiles.push_back( ascFile.ElementName );
|
|
|
|
try
|
|
{
|
|
std::vector<LTSPICE_SCHEMATIC::LT_ASC> lt_ascs = StructureBuilder();
|
|
parser.Parse( &curSheetPath, lt_ascs, subSchematicAsyFiles );
|
|
}
|
|
catch( IO_ERROR& e )
|
|
{
|
|
aReporter->Report( e.What(), RPT_SEVERITY_ERROR );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void LTSPICE_SCHEMATIC::GetAscAndAsyFilePaths( const wxDir& aDir, bool aRecursive,
|
|
std::map<wxString, wxString>& aMapOfAscFiles,
|
|
std::map<wxString, wxString>& aMapOfAsyFiles,
|
|
const wxString& aBase )
|
|
{
|
|
wxString filename;
|
|
|
|
{
|
|
bool cont = aDir.GetFirst( &filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN );
|
|
|
|
while( cont )
|
|
{
|
|
wxFileName path( aDir.GetName(), filename );
|
|
|
|
auto logToMap = [&]( std::map<wxString, wxString>& aMapToLogTo, const wxString& aKey )
|
|
{
|
|
if( aMapToLogTo.count( aKey ) )
|
|
{
|
|
if( m_reporter )
|
|
{
|
|
m_reporter->Report( wxString::Format(
|
|
_( "File at '%s' was ignored. Using previously found "
|
|
"file at '%s' instead." ),
|
|
path.GetFullPath(), aMapToLogTo.at( aKey ) ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aMapToLogTo.emplace( aKey, path.GetFullPath() );
|
|
}
|
|
};
|
|
|
|
wxString elementName1 = ( aBase + path.GetName() ).Lower();
|
|
wxString elementName2 = path.GetName().Lower();
|
|
wxString extension = path.GetExt().Lower();
|
|
|
|
if( extension == wxS( "asc" ) )
|
|
{
|
|
logToMap( aMapOfAscFiles, elementName1 );
|
|
|
|
if( !aBase.IsEmpty() )
|
|
logToMap( aMapOfAscFiles, elementName2 );
|
|
}
|
|
else if( extension == wxS( "asy" ) )
|
|
{
|
|
logToMap( aMapOfAsyFiles, elementName1 );
|
|
|
|
if( !aBase.IsEmpty() )
|
|
logToMap( aMapOfAsyFiles, elementName2 );
|
|
}
|
|
|
|
cont = aDir.GetNext( &filename );
|
|
}
|
|
}
|
|
|
|
if( aRecursive )
|
|
{
|
|
bool cont = aDir.GetFirst( &filename, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN );
|
|
|
|
while( cont )
|
|
{
|
|
wxFileName path( aDir.GetName(), filename );
|
|
wxDir subDir( path.GetFullPath() );
|
|
|
|
GetAscAndAsyFilePaths( subDir, true, aMapOfAscFiles, aMapOfAsyFiles,
|
|
filename + wxS( "/" ) );
|
|
|
|
cont = aDir.GetNext( &filename );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
std::map<wxString, wxString>
|
|
LTSPICE_SCHEMATIC::ReadAsyFile( const LTSPICE_FILE& aSourceFile,
|
|
const std::map<wxString, wxString>& aAsyFileMap )
|
|
{
|
|
std::map<wxString, wxString> resultantMap;
|
|
|
|
wxString fileName = aSourceFile.ElementName;
|
|
|
|
if( aAsyFileMap.count( fileName ) )
|
|
resultantMap[fileName] = SafeReadFile( aAsyFileMap.at( fileName ), wxS( "r" ) );
|
|
|
|
return resultantMap;
|
|
}
|
|
|
|
|
|
std::map<wxString, wxString>
|
|
LTSPICE_SCHEMATIC::ReadAsyFiles( const std::vector<LTSPICE_FILE>& aSourceFiles,
|
|
const std::map<wxString, wxString>& aAsyFileMap )
|
|
{
|
|
std::map<wxString, wxString> resultantMap;
|
|
|
|
for( const LTSPICE_FILE& source : aSourceFiles )
|
|
{
|
|
wxString fileName = source.ElementName;
|
|
|
|
if( aAsyFileMap.count( fileName ) )
|
|
resultantMap[fileName] = SafeReadFile( aAsyFileMap.at( fileName ), wxS( "r" ) );
|
|
}
|
|
|
|
return resultantMap;
|
|
}
|
|
|
|
|
|
std::vector<LTSPICE_FILE> LTSPICE_SCHEMATIC::GetSchematicElements( const wxString& aAscFile )
|
|
{
|
|
std::vector<LTSPICE_FILE> resultantArray;
|
|
wxArrayString lines = wxSplit( aAscFile, '\n' );
|
|
|
|
for( const wxString& line : lines )
|
|
{
|
|
wxArrayString tokens = wxSplit( line, ' ' );
|
|
|
|
if( !tokens.IsEmpty() && tokens[0].Upper() == wxS( "SYMBOL" ) )
|
|
{
|
|
wxString elementName( tokens[1] );
|
|
long posX, posY;
|
|
|
|
tokens[2].ToLong( &posX );
|
|
tokens[3].ToLong( &posY );
|
|
|
|
elementName.Replace( '\\', '/' );
|
|
|
|
LTSPICE_FILE asyFile( elementName, VECTOR2I( (int) posX, (int) posY ) );
|
|
|
|
resultantArray.push_back( asyFile );
|
|
}
|
|
}
|
|
|
|
return resultantArray;
|
|
}
|
|
|
|
|
|
bool LTSPICE_SCHEMATIC::IsAsySubsheet( const wxString& aAsyFile )
|
|
{
|
|
wxStringTokenizer lines( aAsyFile, "\n" );
|
|
|
|
while( lines.HasMoreTokens() )
|
|
{
|
|
wxStringTokenizer parts( lines.GetNextToken(), " " );
|
|
|
|
if( parts.GetNextToken().IsSameAs( wxS( "SYMATTR" ), false )
|
|
&& parts.GetNextToken().IsSameAs( wxS( "Prefix" ), false ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
int LTSPICE_SCHEMATIC::integerCheck( const wxString& aToken, int aLineNumber,
|
|
const wxString& aFileName )
|
|
{
|
|
long result;
|
|
|
|
if( !aToken.ToLong( &result ) )
|
|
{
|
|
THROW_IO_ERROR( wxString::Format( _( "Expecting integer at line %d in file %s" ),
|
|
aLineNumber,
|
|
aFileName ) );
|
|
}
|
|
|
|
return (int) result;
|
|
}
|
|
|
|
|
|
VECTOR2I LTSPICE_SCHEMATIC::pointCheck( const wxString& aTokenX, const wxString& aTokenY,
|
|
int aLineNumber, const wxString& aFileName )
|
|
{
|
|
return VECTOR2I( integerCheck( aTokenX, aLineNumber, aFileName ),
|
|
integerCheck( aTokenY, aLineNumber, aFileName ) );
|
|
}
|
|
|
|
|
|
void LTSPICE_SCHEMATIC::tokensSizeRangeCheck( size_t aActualSize, int aExpectedMin,
|
|
int aExpectedMax, int aLineNumber,
|
|
const wxString& aFileName )
|
|
{
|
|
if( (int) aActualSize < aExpectedMin )
|
|
{
|
|
THROW_IO_ERROR( wxString::Format( _( "Expected data missing on line %d in file %s" ),
|
|
aLineNumber,
|
|
aFileName ) );
|
|
}
|
|
else if( (int) aActualSize > aExpectedMax )
|
|
{
|
|
THROW_IO_ERROR( wxString::Format( _( "Extra data found on line %d in file %s" ),
|
|
aLineNumber,
|
|
aFileName ) );
|
|
}
|
|
}
|
|
|
|
|
|
void LTSPICE_SCHEMATIC::aggregateAttributeValue( wxArrayString& aTokens, int aIndex )
|
|
{
|
|
// Merges a value which is across multiple tokens into one token with spaces in between.
|
|
for( int i = aIndex + 1; i < (int) aTokens.GetCount(); i++ )
|
|
aTokens[ aIndex ] += " " + aTokens[i];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::LINESTYLE LTSPICE_SCHEMATIC::getLineStyle( int aValue )
|
|
{
|
|
std::map<int, LINESTYLE> lineStyleMap;
|
|
|
|
lineStyleMap[0] = LINESTYLE::SOLID;
|
|
lineStyleMap[1] = LINESTYLE::DASH;
|
|
lineStyleMap[2] = LINESTYLE::DOT;
|
|
lineStyleMap[3] = LINESTYLE::DASHDOT;
|
|
lineStyleMap[4] = LINESTYLE::DASHDOTDOT;
|
|
|
|
if( lineStyleMap.find( aValue ) == lineStyleMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting 0, 1, 2, 3 or 4" ) );
|
|
|
|
return lineStyleMap[ aValue ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::LINEWIDTH LTSPICE_SCHEMATIC::getLineWidth( const wxString& aValue )
|
|
{
|
|
std::map<wxString, LINEWIDTH> lineWidthMap;
|
|
|
|
lineWidthMap["NORMAL"] = LINEWIDTH::Normal;
|
|
lineWidthMap["WIDE"] = LINEWIDTH::Wide;
|
|
|
|
if( lineWidthMap.find( aValue.Upper() ) == lineWidthMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting NORMAL or WIDE" ) );
|
|
|
|
return lineWidthMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::POLARITY LTSPICE_SCHEMATIC::getPolarity( const wxString& aValue )
|
|
{
|
|
std::map<wxString, POLARITY> polarityMap;
|
|
|
|
polarityMap["I"] = POLARITY::INPUT;
|
|
polarityMap["O"] = POLARITY::OUTPUT;
|
|
polarityMap["B"] = POLARITY::BIDIR;
|
|
polarityMap["IN"] = POLARITY::INPUT;
|
|
polarityMap["OUT"] = POLARITY::OUTPUT;
|
|
polarityMap["BIDIR"] = POLARITY::BIDIR;
|
|
|
|
if( polarityMap.find( aValue.Upper() ) == polarityMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting I, O, B, IN, OUT or BIDIR" ) );
|
|
|
|
return polarityMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::ORIENTATION LTSPICE_SCHEMATIC::getSymbolRotationOrMirror( const wxString& aValue )
|
|
{
|
|
std::map<wxString, ORIENTATION> rotationMirrorMap;
|
|
|
|
rotationMirrorMap["R0"] = ORIENTATION::R0;
|
|
rotationMirrorMap["R90"] = ORIENTATION::R90;
|
|
rotationMirrorMap["R180"] = ORIENTATION::R180;
|
|
rotationMirrorMap["R270"] = ORIENTATION::R270;
|
|
|
|
rotationMirrorMap["M0"] = ORIENTATION::M0;
|
|
rotationMirrorMap["M90"] = ORIENTATION::M90;
|
|
rotationMirrorMap["M180"] = ORIENTATION::M180;
|
|
rotationMirrorMap["M270"] = ORIENTATION::M270;
|
|
|
|
if( rotationMirrorMap.find( aValue.Upper() ) == rotationMirrorMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting R0, R90, R18, R270, M0, M90, M180 or M270" ) );
|
|
|
|
return rotationMirrorMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::JUSTIFICATION LTSPICE_SCHEMATIC::getTextJustification( const wxString& aValue )
|
|
{
|
|
std::map<wxString, JUSTIFICATION> justificationMap;
|
|
|
|
justificationMap["LEFT"] = JUSTIFICATION::LEFT;
|
|
justificationMap["CENTER"] = JUSTIFICATION::CENTER;
|
|
justificationMap["RIGHT"] = JUSTIFICATION::RIGHT;
|
|
justificationMap["VLEFT"] = JUSTIFICATION::VLEFT;
|
|
justificationMap["VRIGHT"] = JUSTIFICATION::VRIGHT;
|
|
justificationMap["VCENTER"] = JUSTIFICATION::VCENTER;
|
|
justificationMap["BOTTOM"] = JUSTIFICATION::BOTTOM;
|
|
justificationMap["TOP"] = JUSTIFICATION::TOP;
|
|
justificationMap["VBOTTOM"] = JUSTIFICATION::VBOTTOM;
|
|
justificationMap["VTOP"] = JUSTIFICATION::VTOP;
|
|
|
|
if( justificationMap.find( aValue.Upper() ) == justificationMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting LEFT, CENTER, RIGHT, TOP, BOTTOM, VLEFT, VRIGHT, VCENTER, VTOP or VBOTTOM" ) );
|
|
|
|
return justificationMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::JUSTIFICATION LTSPICE_SCHEMATIC::getPinJustification( const wxString& aValue )
|
|
{
|
|
std::map<wxString, JUSTIFICATION> pinJustificationMap;
|
|
|
|
pinJustificationMap["BOTTOM"] = JUSTIFICATION::BOTTOM;
|
|
pinJustificationMap["NONE"] = JUSTIFICATION::NONE;
|
|
pinJustificationMap["LEFT"] = JUSTIFICATION::LEFT;
|
|
pinJustificationMap["RIGHT"] = JUSTIFICATION::RIGHT;
|
|
pinJustificationMap["TOP"] = JUSTIFICATION::TOP;
|
|
pinJustificationMap["VBOTTOM"] = JUSTIFICATION::VBOTTOM;
|
|
pinJustificationMap["VLEFT"] = JUSTIFICATION::VLEFT;
|
|
pinJustificationMap["VRIGHT"] = JUSTIFICATION::VRIGHT;
|
|
pinJustificationMap["VCENTER"] = JUSTIFICATION::VCENTER;
|
|
pinJustificationMap["VTOP"] = JUSTIFICATION::VTOP;
|
|
|
|
if( pinJustificationMap.find( aValue.Upper() ) == pinJustificationMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting NONE, BOTTOM, TOP, LEFT, RIGHT, VBOTTOM, VTOP, VCENTER, VLEFT or VRIGHT" ) );
|
|
|
|
return pinJustificationMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::SYMBOLTYPE LTSPICE_SCHEMATIC::getSymbolType( const wxString& aValue )
|
|
{
|
|
std::map<wxString, SYMBOLTYPE> symbolTypeMap;
|
|
|
|
symbolTypeMap["CELL"] = SYMBOLTYPE::CELL;
|
|
symbolTypeMap["BLOCK"] = SYMBOLTYPE::BLOCK;
|
|
|
|
if( symbolTypeMap.find( aValue.Upper() ) == symbolTypeMap.end() )
|
|
THROW_IO_ERROR( _( "Expecting CELL or BLOCK" ) );
|
|
|
|
return symbolTypeMap[ aValue.Upper() ];
|
|
}
|
|
|
|
|
|
void LTSPICE_SCHEMATIC::removeCarriageReturn( wxString& elementFromLine )
|
|
{
|
|
if( elementFromLine.EndsWith( '\r' ) )
|
|
elementFromLine = elementFromLine.BeforeLast( '\r' );
|
|
}
|
|
|
|
|
|
LTSPICE_SCHEMATIC::LT_SYMBOL LTSPICE_SCHEMATIC::SymbolBuilder( const wxString& aAscFileName,
|
|
LT_ASC& aAscFile )
|
|
{
|
|
const std::map<wxString, wxString>& asyFiles = m_fileCache[ wxS( "asyFiles" ) ];
|
|
|
|
if( !asyFiles.count( aAscFileName.Lower() ) )
|
|
THROW_IO_ERROR( wxString::Format( _( "Symbol '%s.asy' not found" ), aAscFileName ) );
|
|
|
|
return SymbolBuilder( aAscFileName, asyFiles.at( aAscFileName.Lower() ), aAscFile );
|
|
}
|
|
|
|
LTSPICE_SCHEMATIC::LT_SYMBOL LTSPICE_SCHEMATIC::SymbolBuilder( const wxString& aAscFileName,
|
|
const wxString& aAsyFileContent,
|
|
LT_ASC& aAscFile )
|
|
{
|
|
LT_SYMBOL lt_symbol;
|
|
int lineNumber = 1;
|
|
|
|
lt_symbol.Name = aAscFileName;
|
|
lt_symbol.SymbolType = LTSPICE_SCHEMATIC::SYMBOLTYPE::CELL;
|
|
lt_symbol.SymbolOrientation = LTSPICE_SCHEMATIC::ORIENTATION::R0;
|
|
|
|
for( wxString line : wxSplit( aAsyFileContent, '\n' ) )
|
|
{
|
|
removeCarriageReturn( line );
|
|
|
|
wxArrayString tokens = wxSplit( line, ' ' );
|
|
|
|
if( tokens.IsEmpty() )
|
|
continue;
|
|
|
|
wxString element = tokens[0].Upper();
|
|
|
|
if( element == "LINE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, aAscFileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString startPointX = tokens[2];
|
|
wxString startPointY = tokens[3];
|
|
wxString endPointX = tokens[4];
|
|
wxString endPointY = tokens[5];
|
|
|
|
LINE lt_line;
|
|
lt_line.LineWidth = getLineWidth( lineWidth );
|
|
lt_line.Start = pointCheck( startPointX, startPointY, lineNumber, aAscFileName );
|
|
lt_line.End = pointCheck( endPointX, endPointY, lineNumber, aAscFileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, aAscFileName );
|
|
}
|
|
|
|
lt_line.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
lt_symbol.Lines.push_back( lt_line );
|
|
}
|
|
else if( element == "RECTANGLE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, aAscFileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
|
|
RECTANGLE rect;
|
|
rect.LineWidth = getLineWidth( lineWidth );
|
|
rect.BotRight = pointCheck( botRightX, botRightY, lineNumber, aAscFileName );
|
|
rect.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, aAscFileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, aAscFileName );
|
|
}
|
|
|
|
rect.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
lt_symbol.Rectangles.push_back( rect );
|
|
}
|
|
else if( element == "CIRCLE" )
|
|
{
|
|
/**
|
|
* The Circle is enclosed in the square which is represented by bottomRight and
|
|
* topLeft coordinates.
|
|
*/
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, aAscFileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
|
|
CIRCLE circle;
|
|
circle.LineWidth = getLineWidth( lineWidth );
|
|
circle.BotRight = pointCheck( botRightX, botRightY, lineNumber, aAscFileName );
|
|
circle.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, aAscFileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, aAscFileName );
|
|
}
|
|
|
|
circle.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
lt_symbol.Circles.push_back( circle );
|
|
}
|
|
else if( element == "ARC" )
|
|
{
|
|
/**
|
|
* The Arc is enclosed in the square given by above coordinates and its start and end
|
|
* coordinates are given.
|
|
* The arc is drawn counterclockwise from the starting point to the ending point.
|
|
*/
|
|
tokensSizeRangeCheck( tokens.size(), 10, 11, lineNumber, aAscFileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
wxString arcStartPointX = tokens[6];
|
|
wxString arcStartPointY = tokens[7];
|
|
wxString arcEndPointX = tokens[8];
|
|
wxString arcEndPointY = tokens[9];
|
|
|
|
ARC arc;
|
|
arc.LineWidth = getLineWidth( lineWidth );
|
|
arc.BotRight = pointCheck( botRightX, botRightY, lineNumber, aAscFileName );
|
|
arc.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, aAscFileName );
|
|
arc.ArcStart = pointCheck( arcStartPointX, arcStartPointY, lineNumber, aAscFileName );
|
|
arc.ArcEnd = pointCheck( arcEndPointX, arcEndPointY, lineNumber, aAscFileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 11 )
|
|
{
|
|
wxString lineStyle = tokens[10];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, aAscFileName );
|
|
}
|
|
|
|
arc.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
lt_symbol.Arcs.push_back( arc );
|
|
}
|
|
else if( element == "WINDOW" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 6, lineNumber, aAscFileName );
|
|
|
|
wxString number = tokens[1];
|
|
wxString windowPosX = tokens[2];
|
|
wxString windowPosY = tokens[3];
|
|
wxString justification = tokens[4];
|
|
wxString fontSize = tokens[5];
|
|
|
|
LT_WINDOW window;
|
|
window.WindowNumber = integerCheck( number, lineNumber, aAscFileName );
|
|
window.Position = pointCheck( windowPosX, windowPosY, lineNumber, aAscFileName );
|
|
window.Justification = getTextJustification( justification );
|
|
window.FontSize = integerCheck( fontSize, lineNumber, aAscFileName );
|
|
|
|
// LTSpice appears to ignore hidden property from .asy files
|
|
if( window.FontSize == 0 )
|
|
window.FontSize = 2;
|
|
|
|
lt_symbol.Windows.push_back( window );
|
|
}
|
|
else if( element == "SYMATTR" )
|
|
{
|
|
aggregateAttributeValue( tokens, 2 );
|
|
|
|
tokensSizeRangeCheck( tokens.size(), 3, INT_MAX, lineNumber, aAscFileName );
|
|
|
|
wxString key = tokens[1];
|
|
wxString value = tokens[2];
|
|
|
|
if( value == wxS( "\"\"" ) )
|
|
value = wxEmptyString;
|
|
|
|
lt_symbol.SymAttributes[ key.Upper() ] = value;
|
|
}
|
|
else if( element == "PIN" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 5, 5, lineNumber, aAscFileName );
|
|
|
|
wxString pinLocationX = tokens[1];
|
|
wxString pinLocationY = tokens[2];
|
|
wxString Justification = tokens[3];
|
|
wxString nameOffSet = tokens[4];
|
|
|
|
LT_PIN pin;
|
|
pin.PinLocation = pointCheck( pinLocationX, pinLocationY, lineNumber,aAscFileName );
|
|
pin.PinJustification = getPinJustification( Justification );
|
|
pin.NameOffSet = integerCheck( nameOffSet, lineNumber, aAscFileName );
|
|
|
|
lt_symbol.Pins.push_back( pin );
|
|
}
|
|
else if( element == "PINATTR" )
|
|
{
|
|
aggregateAttributeValue( tokens, 2 );
|
|
|
|
tokensSizeRangeCheck( tokens.size(), 3, INT_MAX, lineNumber, aAscFileName );
|
|
|
|
wxString name = tokens[1];
|
|
wxString Value = tokens[2];
|
|
|
|
lt_symbol.Pins.back().PinAttribute.insert( { name, Value } );
|
|
}
|
|
else if( element == "SYMBOLTYPE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 2, 2, lineNumber, aAscFileName );
|
|
|
|
wxString symbolType = tokens[1];
|
|
|
|
lt_symbol.SymbolType = getSymbolType( symbolType );
|
|
}
|
|
|
|
lineNumber++;
|
|
}
|
|
|
|
return lt_symbol;
|
|
}
|
|
|
|
|
|
std::vector<LTSPICE_SCHEMATIC::LT_ASC> LTSPICE_SCHEMATIC::StructureBuilder()
|
|
{
|
|
// Initialising Symbol Struct
|
|
|
|
std::vector<LT_ASC> ascFiles;
|
|
|
|
for( const auto& [ fileName, contents ] : m_fileCache[ wxS( "ascFiles" ) ] )
|
|
{
|
|
LT_ASC ascFile;
|
|
std::vector<LT_SYMBOL> symbolArray;
|
|
|
|
ascFile.SheetSize = VECTOR2I( 0, 0 );
|
|
ascFile.Symbols = symbolArray;
|
|
ascFile.Version = 0;
|
|
ascFile.SheetNumber = 0;
|
|
|
|
int lineNumber = 1;
|
|
|
|
for( wxString line : wxSplit( contents, '\n' ) )
|
|
{
|
|
removeCarriageReturn( line );
|
|
|
|
wxArrayString tokens = wxSplit( line, ' ' );
|
|
|
|
if( tokens.IsEmpty() )
|
|
continue;
|
|
|
|
wxString element = tokens[0].Upper();
|
|
|
|
if( element == "SHEET" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 4, 4, lineNumber, fileName );
|
|
|
|
wxString sheetNumber = tokens[1];
|
|
wxString sheetWidth = tokens[2];
|
|
wxString sheetHeight = tokens[3];
|
|
|
|
ascFile.SheetNumber = integerCheck( sheetNumber, lineNumber, fileName );
|
|
ascFile.SheetSize = pointCheck( sheetWidth, sheetHeight, lineNumber, fileName );
|
|
}
|
|
else if( element == "SYMBOL" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 5, 5, lineNumber, fileName );
|
|
|
|
wxString symbolName = tokens[1];
|
|
wxString posX = tokens[2];
|
|
wxString posY = tokens[3];
|
|
wxString rotate_mirror_option = tokens[4];
|
|
|
|
symbolName.Replace( '\\', '/' );
|
|
|
|
LT_SYMBOL lt_symbol = SymbolBuilder( symbolName, ascFile );
|
|
lt_symbol.Offset = pointCheck( posX, posY, lineNumber, fileName );
|
|
lt_symbol.SymbolOrientation = getSymbolRotationOrMirror( rotate_mirror_option );
|
|
|
|
ascFile.Symbols.push_back( lt_symbol );
|
|
ascFile.BoundingBox.Merge( lt_symbol.Offset );
|
|
}
|
|
else if( element == "WIRE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 5, 5, lineNumber, fileName );
|
|
|
|
wxString startPointX = tokens[1];
|
|
wxString startPointY = tokens[2];
|
|
wxString endPointX = tokens[3];
|
|
wxString endPointY = tokens[4];
|
|
|
|
WIRE wire;
|
|
wire.Start = pointCheck( startPointX, startPointY, lineNumber, fileName );
|
|
wire.End = pointCheck( endPointX, endPointY, lineNumber, fileName );
|
|
|
|
ascFile.Wires.push_back( wire );
|
|
ascFile.BoundingBox.Merge( wire.Start );
|
|
ascFile.BoundingBox.Merge( wire.End );
|
|
}
|
|
else if( element == "FLAG" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 4, 4, lineNumber, fileName );
|
|
|
|
wxString posX = tokens[1];
|
|
wxString posY = tokens[2];
|
|
wxString name = tokens[3];
|
|
|
|
FLAG flag;
|
|
flag.Offset = pointCheck( posX, posY, lineNumber, fileName );
|
|
flag.Value = name;
|
|
flag.FontSize = 2;
|
|
|
|
ascFile.Flags.push_back( flag );
|
|
ascFile.BoundingBox.Merge( flag.Offset );
|
|
}
|
|
else if( element == "DATAFLAG" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 4, 4, lineNumber, fileName );
|
|
|
|
wxString posX = tokens[1];
|
|
wxString posY = tokens[2];
|
|
wxString expression = tokens[3];
|
|
|
|
DATAFLAG flag;
|
|
flag.Offset = pointCheck( posX, posY, lineNumber, fileName );
|
|
flag.Expression = expression;
|
|
flag.FontSize = 2;
|
|
|
|
ascFile.DataFlags.push_back( flag );
|
|
ascFile.BoundingBox.Merge( flag.Offset );
|
|
}
|
|
else if( element == "WINDOW" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 6, lineNumber, fileName );
|
|
|
|
wxString number = tokens[1];
|
|
wxString windowPosX = tokens[2];
|
|
wxString windowPosY = tokens[3];
|
|
wxString justification = tokens[4];
|
|
wxString fontSize = tokens[5];
|
|
|
|
int windowNumber = integerCheck( number, lineNumber, fileName );
|
|
LT_WINDOW* window = nullptr;
|
|
|
|
// Overwrite an existing window from the symbol definition
|
|
for( LT_WINDOW& candidate : ascFile.Symbols.back().Windows )
|
|
{
|
|
if( candidate.WindowNumber == windowNumber )
|
|
{
|
|
window = &candidate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !window )
|
|
{
|
|
ascFile.Symbols.back().Windows.emplace_back( LT_WINDOW() );
|
|
window = &ascFile.Symbols.back().Windows.back();
|
|
}
|
|
|
|
window->WindowNumber = windowNumber;
|
|
window->Position = pointCheck( windowPosX, windowPosY, lineNumber, fileName );
|
|
window->Justification = getTextJustification( justification );
|
|
window->FontSize = integerCheck( fontSize, lineNumber, fileName );
|
|
|
|
ascFile.BoundingBox.Merge( window->Position );
|
|
}
|
|
else if( element == "SYMATTR" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 3, INT_MAX, lineNumber, fileName );
|
|
|
|
aggregateAttributeValue( tokens, 2 );
|
|
|
|
wxString name = tokens[1];
|
|
wxString value = tokens[2];
|
|
|
|
if( value == wxS( "\"\"" ) )
|
|
value = wxEmptyString;
|
|
|
|
ascFile.Symbols.back().SymAttributes[ name.Upper() ] = value;
|
|
}
|
|
else if( element == "LINE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, fileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString startPointX = tokens[2];
|
|
wxString startPointY = tokens[3];
|
|
wxString endPointX = tokens[4];
|
|
wxString endPointY = tokens[5];
|
|
|
|
LINE lt_line;
|
|
lt_line.LineWidth = getLineWidth( lineWidth );
|
|
lt_line.Start = pointCheck( startPointX, startPointY, lineNumber, fileName );
|
|
lt_line.End = pointCheck( endPointX, endPointY, lineNumber, fileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, fileName );
|
|
}
|
|
|
|
lt_line.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
ascFile.Lines.push_back( lt_line );
|
|
ascFile.BoundingBox.Merge( lt_line.Start );
|
|
ascFile.BoundingBox.Merge( lt_line.End );
|
|
}
|
|
else if( element == "RECTANGLE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, fileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
|
|
RECTANGLE rect;
|
|
rect.LineWidth = getLineWidth( tokens[1] );
|
|
rect.BotRight = pointCheck( botRightX, botRightY, lineNumber, fileName );
|
|
rect.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, fileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, fileName );
|
|
}
|
|
|
|
rect.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
ascFile.Rectangles.push_back( rect );
|
|
ascFile.BoundingBox.Merge( rect.TopLeft );
|
|
ascFile.BoundingBox.Merge( rect.BotRight );
|
|
}
|
|
else if( element == "CIRCLE" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 6, 7, lineNumber, fileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
|
|
CIRCLE circle;
|
|
circle.LineWidth = getLineWidth( lineWidth );
|
|
circle.BotRight = pointCheck( botRightX, botRightY, lineNumber, fileName );
|
|
circle.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, fileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 7 )
|
|
{
|
|
wxString lineStyle = tokens[6];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, fileName );
|
|
}
|
|
|
|
circle.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
ascFile.Circles.push_back( circle );
|
|
ascFile.BoundingBox.Merge( circle.TopLeft );
|
|
ascFile.BoundingBox.Merge( circle.BotRight );
|
|
}
|
|
else if( element == "ARC" )
|
|
{
|
|
/**
|
|
* The Arc is enclosed in the square given by above coordinates and its start and
|
|
* end coordinates are given.
|
|
* The arc is drawn counterclockwise from the starting point to the ending point.
|
|
*/
|
|
tokensSizeRangeCheck( tokens.size(), 10, 11, lineNumber, fileName );
|
|
|
|
wxString lineWidth = tokens[1];
|
|
wxString botRightX = tokens[2];
|
|
wxString botRightY = tokens[3];
|
|
wxString topLeftX = tokens[4];
|
|
wxString topRightY = tokens[5];
|
|
wxString arcStartPointX = tokens[6];
|
|
wxString arcStartPointY = tokens[7];
|
|
wxString arcEndPointX = tokens[8];
|
|
wxString arcEndPointY = tokens[9];
|
|
|
|
ARC arc;
|
|
arc.LineWidth = getLineWidth( lineWidth );
|
|
arc.BotRight = pointCheck( botRightX, botRightY, lineNumber, fileName );
|
|
arc.TopLeft = pointCheck( topLeftX, topRightY, lineNumber, fileName );
|
|
arc.ArcEnd = pointCheck( arcStartPointX, arcStartPointY, lineNumber, fileName );
|
|
arc.ArcStart = pointCheck( arcEndPointX, arcEndPointY, lineNumber, fileName );
|
|
|
|
int lineStyleNumber = 0; // default
|
|
|
|
if( tokens.size() == 11 )
|
|
{
|
|
wxString lineStyle = tokens[10];
|
|
lineStyleNumber = integerCheck( lineStyle, lineNumber, fileName );
|
|
}
|
|
|
|
arc.LineStyle = getLineStyle( lineStyleNumber );
|
|
|
|
ascFile.Arcs.push_back( arc );
|
|
ascFile.BoundingBox.Merge( arc.TopLeft );
|
|
ascFile.BoundingBox.Merge( arc.BotRight );
|
|
}
|
|
else if( element == "IOPIN" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 4, 4, lineNumber, fileName );
|
|
|
|
wxString pinLocationX = tokens[1];
|
|
wxString pinLocationY = tokens[2];
|
|
wxString pinPolarity = tokens[3];
|
|
|
|
IOPIN iopin;
|
|
iopin.Location = pointCheck( pinLocationX, pinLocationY, lineNumber, fileName );
|
|
iopin.Polarity = getPolarity( pinPolarity );
|
|
|
|
ascFile.Iopins.push_back( iopin );
|
|
ascFile.BoundingBox.Merge( iopin.Location );
|
|
}
|
|
else if( element == "TEXT" )
|
|
{
|
|
aggregateAttributeValue( tokens, 5 );
|
|
|
|
tokensSizeRangeCheck( tokens.size(), 6, INT_MAX, lineNumber, fileName );
|
|
|
|
wxString positionX = tokens[1];
|
|
wxString positionY = tokens[2];
|
|
wxString justification = tokens[3];
|
|
wxString fontSize = tokens[4];
|
|
wxString value = tokens[5];
|
|
|
|
TEXT text;
|
|
text.Offset = pointCheck( positionX, positionY, lineNumber, fileName );
|
|
text.Justification = getTextJustification( justification );
|
|
text.FontSize = integerCheck( fontSize, lineNumber, fileName );
|
|
|
|
if( value.StartsWith( wxS( "!" ), &text.Value ) )
|
|
text.Value.Replace( wxS( "! " ), wxS( "\n" ) ); // replace subsequent ! with \n
|
|
else if( value.StartsWith( wxS( ";" ), &text.Value ) )
|
|
text.Value.Replace( wxS( "; " ), wxS( "\n" ) ); // replace subsequent ; with \n
|
|
else
|
|
text.Value = value;
|
|
|
|
text.Value.Replace( wxS( "\\n" ), wxS( "\n" ) );
|
|
|
|
ascFile.Texts.push_back( text );
|
|
ascFile.BoundingBox.Merge( text.Offset );
|
|
}
|
|
else if( element == "BUSTAP" )
|
|
{
|
|
tokensSizeRangeCheck( tokens.size(), 5, 5, lineNumber, fileName );
|
|
|
|
wxString startPointX = tokens[1];
|
|
wxString startPointY = tokens[2];
|
|
wxString endPointX = tokens[3];
|
|
wxString endPointY = tokens[4];
|
|
|
|
BUSTAP bustap;
|
|
bustap.Start = pointCheck( startPointX, startPointY, lineNumber, fileName );
|
|
bustap.End = pointCheck( endPointX, endPointY, lineNumber, fileName );
|
|
|
|
ascFile.Bustap.push_back( bustap );
|
|
ascFile.BoundingBox.Merge( bustap.Start );
|
|
ascFile.BoundingBox.Merge( bustap.End );
|
|
}
|
|
else if( element == "VERSION" )
|
|
{
|
|
wxString versionNumber = tokens[1];
|
|
ascFile.Version = integerCheck( versionNumber, lineNumber, fileName );
|
|
}
|
|
|
|
lineNumber++;
|
|
}
|
|
|
|
ascFiles.push_back( ascFile );
|
|
}
|
|
|
|
return ascFiles;
|
|
}
|
|
|
|
|