kicad/eeschema/sch_plugins/ltspice/ltspice_sch_parser.cpp

1295 lines
46 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 (C) 2022-2023 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 Parses the datastructure produced by the LTSPICE_SCHEMATIC into a KiCad
* schematic file.
*/
#include <sch_plugins/ltspice/ltspice_sch_parser.h>
#include <sch_plugins/ltspice/ltspice_schematic.h>
#include <sch_io_mgr.h>
#include <base_units.h>
#include <core/kicad_algo.h>
#include <schematic.h>
#include <sch_sheet.h>
#include <sch_sheet_pin.h>
#include <sch_line.h>
#include <lib_shape.h>
#include <sch_label.h>
#include <sch_edit_frame.h>
#include <sch_shape.h>
#include <sch_bus_entry.h>
#include <kiplatform/environment.h>
void LTSPICE_SCH_PARSER::Parse( SCH_SHEET_PATH* aSheet,
std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs,
const std::vector<wxString>& aAsyFileNames )
{
// Center created objects in Kicad page
BOX2I bbox;
for( const LTSPICE_SCHEMATIC::LT_ASC& asc : outLT_ASCs )
bbox.Merge( asc.BoundingBox );
m_originOffset = { 0, 0 };
bbox.SetOrigin( ToKicadCoords( bbox.GetOrigin() ) );
bbox.SetSize( ToKicadCoords( bbox.GetSize() ) );
VECTOR2I pageSize = aSheet->LastScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
int grid = schIUScale.MilsToIU( 50 );
int margin = grid * 10;
m_originOffset = ( pageSize / 2 ) - bbox.GetCenter();
if( bbox.GetWidth() > pageSize.x - margin )
m_originOffset.x = margin - bbox.GetLeft();
if( bbox.GetHeight() > pageSize.y - margin )
m_originOffset.y = margin - bbox.GetTop();
m_originOffset = ( m_originOffset / grid ) * grid;
readIncludes( outLT_ASCs );
CreateKicadSYMBOLs( aSheet, outLT_ASCs, aAsyFileNames );
CreateKicadSCH_ITEMs( aSheet, outLT_ASCs );
}
void LTSPICE_SCH_PARSER::readIncludes( std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs )
{
static wxString ltSubDir = KIPLATFORM::ENV::GetDocumentsPath() + wxS( "/LTspiceXVII/lib/sub/" );
wxString path;
for( const LTSPICE_SCHEMATIC::LT_ASC& asc : outLT_ASCs )
{
for( const LTSPICE_SCHEMATIC::TEXT& lt_text : asc.Texts )
{
for( wxString& line : wxSplit( lt_text.Value, '\n' ) )
{
if( line.StartsWith( wxS( ".inc " ), &path ) )
{
path.Replace( '\\', '/' );
wxFileName fileName( path );
if( fileName.IsAbsolute() )
{
m_includes[ fileName.GetName() ] = fileName.GetFullPath();
}
else
{
wxFileName absolute( ltSubDir + path );
m_includes[ absolute.GetName() ] = absolute.GetFullPath();
}
}
}
}
}
}
void LTSPICE_SCH_PARSER::CreateLines( LIB_SYMBOL* aSymbol, LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
int aIndex, LIB_SHAPE* shape )
{
LTSPICE_SCHEMATIC::LINE& lt_line = aLTSymbol.Lines[aIndex];
shape->AddPoint( ToInvertedKicadCoords( lt_line.End ) );
shape->AddPoint( ToInvertedKicadCoords( lt_line.Start ) );
shape->SetStroke( getStroke( lt_line.LineWidth, lt_line.LineStyle ) );
}
void LTSPICE_SCH_PARSER::CreateLines( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::LINE& lt_line = aLTSymbol.Lines[aIndex];
SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY );
shape->AddPoint( ToKicadCoords( lt_line.End ) );
shape->AddPoint( ToKicadCoords( lt_line.Start ) );
shape->SetStroke( getStroke( lt_line.LineWidth, lt_line.LineStyle ) );
shape->Move( ToKicadCoords( aLTSymbol.Offset ) + m_originOffset );
RotateMirrorShape( aLTSymbol, shape );
aSheet->LastScreen()->Append( shape );
}
void LTSPICE_SCH_PARSER::CreateKicadSYMBOLs( SCH_SHEET_PATH* aSheet,
std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs,
const std::vector<wxString>& aAsyFiles )
{
for( LTSPICE_SCHEMATIC::LT_ASC& lt_asc : outLT_ASCs )
{
std::vector<LTSPICE_SCHEMATIC::LT_SYMBOL> symbols = lt_asc.Symbols;
std::map<wxString, LIB_SYMBOL*> existingSymbol;
std::map<wxString, SCH_SYMBOL*> existingSchematicSymbol;
for( LTSPICE_SCHEMATIC::LT_SYMBOL& lt_symbol : symbols )
{
if( !alg::contains( aAsyFiles, lt_symbol.Name ) )
{
LIB_SYMBOL* lib_symbol;
if( existingSymbol.count( lt_symbol.Name ) == 0 )
{
lib_symbol = new LIB_SYMBOL( lt_symbol.Name );
CreateSymbol( lt_symbol, lib_symbol );
existingSymbol.emplace( lt_symbol.Name, lib_symbol );
}
else
{
lib_symbol = existingSymbol[lt_symbol.Name];
}
LIB_ID libId( wxS( "ltspice" ), lt_symbol.Name );
SCH_SYMBOL* sch_symbol = new SCH_SYMBOL( *lib_symbol, libId, aSheet, 1 );
CreateFields( lt_symbol, sch_symbol, aSheet );
for( int j = 0; j < (int) lt_symbol.Wires.size(); j++ )
CreateWires( lt_symbol, j, aSheet );
sch_symbol->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
RotateMirror( lt_symbol, sch_symbol );
aSheet->LastScreen()->Append( sch_symbol );
}
else
{
for( int j = 0; j < (int) lt_symbol.Lines.size(); j++ )
CreateLines( lt_symbol, j, aSheet );
for( int j = 0; j < (int) lt_symbol.Circles.size(); j++ )
CreateCircle( lt_symbol, j, aSheet );
for( int j = 0; j < (int) lt_symbol.Arcs.size(); j++ )
CreateArc( lt_symbol, j, aSheet );
for( int j = 0; j < (int) lt_symbol.Rectangles.size(); j++ )
CreateRect( lt_symbol, j, aSheet );
// Calculating bounding box
BOX2I bbox;
std::vector<LTSPICE_FILE> tempVector;
LTSPICE_SCHEMATIC::LT_SYMBOL tempSymbol;
LTSPICE_FILE tempAsyFile( lt_symbol.Name + ".asy", { 0, 0 } );
LTSPICE_SCHEMATIC::LT_ASC dummyAsc;
tempVector.push_back( tempAsyFile );
tempSymbol = m_lt_schematic->SymbolBuilder( lt_symbol.Name, dummyAsc );
LIB_SYMBOL* tempLibSymbol = new LIB_SYMBOL( lt_symbol.Name );
CreateSymbol( tempSymbol, tempLibSymbol );
bbox = tempLibSymbol->GetBoundingBox();
int topLeftX = lt_symbol.Offset.x + ToLtSpiceCoords( bbox.GetOrigin().x );
int topLeftY = lt_symbol.Offset.y + ToLtSpiceCoords( bbox.GetOrigin().y );
int botRightX = lt_symbol.Offset.x
+ ToLtSpiceCoords( bbox.GetOrigin().x )
+ ToLtSpiceCoords( bbox.GetSize().x );
int botRightY = lt_symbol.Offset.y
+ ToLtSpiceCoords( bbox.GetOrigin().y )
+ ToLtSpiceCoords( bbox.GetSize().y );
for( LTSPICE_SCHEMATIC::LT_PIN& pin : lt_symbol.Pins )
{
VECTOR2I pinPos = pin.PinLocation;
for( LTSPICE_SCHEMATIC::WIRE& wire : lt_asc.Wires )
{
if( wire.Start == ( pinPos + lt_symbol.Offset ) )
{
//wire is vertical
if( wire.End.x == ( pinPos + lt_symbol.Offset ).x )
{
if( wire.End.y <= topLeftY )
wire.Start = VECTOR2I( wire.Start.x, topLeftY + 3 );
else if( wire.End.y >= botRightY )
wire.Start = VECTOR2I( wire.Start.x, botRightY );
else if( wire.End.y < botRightY && wire.End.y > topLeftY )
wire.Start = VECTOR2I( topLeftX, wire.Start.y );
}
//wire is horizontal
else if( wire.End.y == ( pinPos + lt_symbol.Offset ).y )
{
if( wire.End.x <= topLeftX )
wire.Start = VECTOR2I( topLeftX, wire.Start.y );
else if( wire.End.x >= botRightX )
wire.Start = VECTOR2I( botRightX, wire.Start.y );
else if( wire.End.x < botRightX && wire.End.x > topLeftX )
wire.Start = VECTOR2I( botRightX, wire.Start.y );
}
}
else if( wire.End == ( pinPos + lt_symbol.Offset ) )
{
//wire is Vertical
if( wire.Start.x == ( pinPos + lt_symbol.Offset ).x )
{
if( wire.Start.y <= topLeftY )
wire.End = VECTOR2I( wire.End.x, topLeftY );
else if( wire.Start.y > botRightY )
wire.End = VECTOR2I( wire.End.x, botRightY );
else if( wire.Start.y < botRightY && wire.End.y > topLeftY )
wire.End = VECTOR2I( wire.End.x, botRightY );
}
//wire is Horizontal
else if( wire.Start.y == ( pinPos + lt_symbol.Offset ).y )
{
if( wire.Start.x <= topLeftX )
wire.End = VECTOR2I( topLeftX, wire.End.y );
else if( wire.Start.x >= botRightX )
wire.End = VECTOR2I( botRightX, wire.End.y );
else if( wire.Start.x < botRightX && wire.Start.x > topLeftX )
wire.End = VECTOR2I( botRightX, wire.End.y );
}
}
}
}
}
}
}
}
void LTSPICE_SCH_PARSER::CreateSymbol( LTSPICE_SCHEMATIC::LT_SYMBOL& aLtSymbol,
LIB_SYMBOL* aLibSymbol )
{
for( int j = 0; j < (int) aLtSymbol.Lines.size(); j++ )
{
LIB_SHAPE* line = new LIB_SHAPE( aLibSymbol, SHAPE_T::POLY );
CreateLines( aLibSymbol, aLtSymbol, j, line );
aLibSymbol->AddDrawItem( line );
}
for( int j = 0; j < (int) aLtSymbol.Circles.size(); j++ )
{
LIB_SHAPE* circle = new LIB_SHAPE( aLibSymbol, SHAPE_T::CIRCLE );
CreateCircle( aLtSymbol, j, circle );
aLibSymbol->AddDrawItem( circle );
}
for( int j = 0; j < (int) aLtSymbol.Arcs.size(); j++ )
{
LIB_SHAPE* arc = new LIB_SHAPE( aLibSymbol, SHAPE_T::ARC );
CreateArc( aLtSymbol, j, arc );
aLibSymbol->AddDrawItem( arc );
}
for( int j = 0; j < (int) aLtSymbol.Rectangles.size(); j++ )
{
LIB_SHAPE* rectangle = new LIB_SHAPE( aLibSymbol, SHAPE_T::RECT );
CreateRect( aLtSymbol, j, rectangle );
aLibSymbol->AddDrawItem( rectangle );
}
for( int j = 0; j < (int) aLtSymbol.Pins.size(); j++ )
{
LIB_PIN* pin = new LIB_PIN( aLibSymbol );
CreatePin( aLtSymbol, j, pin );
aLibSymbol->AddDrawItem( pin );
}
}
int LTSPICE_SCH_PARSER::ToKicadCoords( int aCoordinate )
{
return schIUScale.MilsToIU( rescale( 50, aCoordinate, 16 ) );
}
VECTOR2I LTSPICE_SCH_PARSER::ToKicadCoords( const VECTOR2I& aPos )
{
return VECTOR2I( ToKicadCoords( aPos.x ), ToKicadCoords( aPos.y ) );
}
VECTOR2I LTSPICE_SCH_PARSER::ToInvertedKicadCoords( const VECTOR2I& aPos )
{
return VECTOR2I( ToKicadCoords( aPos.x ), -ToKicadCoords( aPos.y ) );
}
VECTOR2I LTSPICE_SCH_PARSER::ToKicadFontSize( int aLTFontSize )
{
auto MILS_SIZE =
[]( int mils )
{
return VECTOR2I( schIUScale.MilsToIU( mils ), schIUScale.MilsToIU( mils ) );
};
if( aLTFontSize == 1 )
return MILS_SIZE( 36 );
else if( aLTFontSize == 2 )
return MILS_SIZE( 42 );
else if( aLTFontSize == 3 )
return MILS_SIZE( 50 );
else if( aLTFontSize == 4 )
return MILS_SIZE( 60 );
else if( aLTFontSize == 5 )
return MILS_SIZE( 72 );
else if( aLTFontSize == 6 )
return MILS_SIZE( 88 );
else if( aLTFontSize == 7 )
return MILS_SIZE( 108 );
else
return ToKicadFontSize( 2 );
}
int LTSPICE_SCH_PARSER::ToLtSpiceCoords( int aCoordinate )
{
return schIUScale.IUToMils( rescale( 16, aCoordinate, 50 ) );
}
void LTSPICE_SCH_PARSER::RotateMirrorShape( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
SCH_SHAPE* aShape )
{
if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R90 )
{
aShape->Rotate( VECTOR2I() );
aShape->Rotate( VECTOR2I() );
aShape->Rotate( VECTOR2I() );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R180 )
{
aShape->Rotate( VECTOR2I() );
aShape->Rotate( VECTOR2I() );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R270 )
{
aShape->Rotate( VECTOR2I() );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M0 )
{
aShape->MirrorVertically( 0 );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M90 )
{
aShape->MirrorVertically( 0 );
aShape->Rotate( VECTOR2I() );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M180 )
{
aShape->MirrorHorizontally( 0 );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M270 )
{
aShape->MirrorVertically( 0 );
aShape->Rotate( VECTOR2I() );
aShape->Rotate( VECTOR2I() );
aShape->Rotate( VECTOR2I() );
}
}
void LTSPICE_SCH_PARSER::RotateMirror( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
SCH_SYMBOL* aSchSymbol )
{
if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R0 )
{
aSchSymbol->SetOrientation( SYM_ORIENT_0 );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R90 )
{
aSchSymbol->SetOrientation( SYM_ORIENT_180 );
aSchSymbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R180 )
{
aSchSymbol->SetOrientation( SYM_ORIENT_180 );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::R270 )
{
aSchSymbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M0 )
{
aSchSymbol->SetOrientation( SYM_MIRROR_Y );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M90 )
{
aSchSymbol->SetOrientation( SYM_MIRROR_Y );
aSchSymbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M180 )
{
aSchSymbol->SetOrientation( SYM_MIRROR_X );
}
else if( aLTSymbol.SymbolOrientation == LTSPICE_SCHEMATIC::ORIENTATION::M270 )
{
aSchSymbol->SetOrientation( SYM_MIRROR_Y );
aSchSymbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
}
void LTSPICE_SCH_PARSER::CreateWires( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
SCH_SHEET_PATH* aSheet )
{
SCH_LINE* segment = new SCH_LINE();
segment->SetLineWidth( getLineWidth( LTSPICE_SCHEMATIC::LINEWIDTH::Normal ) );
segment->SetLineStyle( PLOT_DASH_TYPE::SOLID );
segment->SetStartPoint( aLTSymbol.Wires[aIndex].Start );
segment->SetEndPoint( aLTSymbol.Wires[aIndex].End );
aSheet->LastScreen()->Append( segment );
}
void LTSPICE_SCH_PARSER::CreateKicadSCH_ITEMs( SCH_SHEET_PATH* aSheet,
std::vector<LTSPICE_SCHEMATIC::LT_ASC>& outLT_ASCs )
{
SCH_SCREEN* screen = aSheet->LastScreen();
for( LTSPICE_SCHEMATIC::LT_ASC& lt_asc : outLT_ASCs )
{
for( int j = 0; j < (int) lt_asc.Lines.size(); j++ )
CreateLine( lt_asc, j, aSheet );
for( int j = 0; j < (int) lt_asc.Circles.size(); j++ )
CreateCircle( lt_asc, j, aSheet );
for( int j = 0; j < (int) lt_asc.Arcs.size(); j++ )
CreateArc( lt_asc, j, aSheet );
for( int j = 0; j < (int) lt_asc.Rectangles.size(); j++ )
CreateRect( lt_asc, j, aSheet );
for( int j = 0; j < (int) lt_asc.Bustap.size(); j++ )
CreateBusEntry( lt_asc, j, aSheet );
/**
*
*NOTE: This current code is used for plotting sch sheet pins on the sheet, we are working on
* finding how to place the pin on the intersection of line and sheet.
*
*
if( aSubSchematicStructure )
{
SCH_HIERLABEL* sheetPin =
new SCH_SHEET_PIN( aRootSheet, VECTOR2I(), lt_asc.Flags[index].Value );
sheetPin->SetText( "PIN" );
sheetPin->SetPosition( VECTOR2I(
schIUScale.MilsToIU( rescale( 50, 592, 16 ) ),
schIUScale.MilsToIU( rescale( 50, 133, 16 ) ) ) );
sheetPin->SetVisible( true );
aRootSheet->AddPin( (SCH_SHEET_PIN*) sheetPin );
}*/
for( int j = 0; j < (int) lt_asc.Wires.size(); j++ )
CreateWire( lt_asc, j, aSheet, SCH_LAYER_ID::LAYER_WIRE );
for( int j = 0; j < (int) lt_asc.Iopins.size(); j++ )
CreatePin( lt_asc, j, aSheet );
for( const LTSPICE_SCHEMATIC::FLAG& lt_flag : lt_asc.Flags )
{
if( lt_flag.Value == wxS( "0" ) )
{
screen->Append( CreatePowerSymbol( lt_flag.Offset, lt_flag.Value, lt_flag.FontSize,
aSheet, lt_asc.Wires ) );
}
else
{
screen->Append( CreateSCH_LABEL( SCH_LABEL_T, lt_flag.Offset, lt_flag.Value,
lt_flag.FontSize ) );
}
}
for( const LTSPICE_SCHEMATIC::TEXT& lt_text : lt_asc.Texts )
{
screen->Append( CreateSCH_TEXT( lt_text.Offset, lt_text.Value, lt_text.FontSize,
lt_text.Justification ) );
}
for( const LTSPICE_SCHEMATIC::DATAFLAG& lt_flag : lt_asc.DataFlags )
{
screen->Append( CreateSCH_LABEL( SCH_DIRECTIVE_LABEL_T, lt_flag.Offset,
lt_flag.Expression, lt_flag.FontSize ) );
}
}
}
void LTSPICE_SCH_PARSER::CreateBusEntry( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::BUSTAP& bustap = aAscfile.Bustap[aIndex];
for( int k = 0; k < (int) aAscfile.Wires.size(); k++ )
{
if( ( aAscfile.Wires[k].Start == bustap.Start )
|| ( aAscfile.Wires[k].End == bustap.Start ) )
{
CreateWire( aAscfile, k, aSheet, SCH_LAYER_ID::LAYER_BUS );
aAscfile.Wires.erase( aAscfile.Wires.begin() + k );
}
}
SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( ToKicadCoords( { bustap.Start.x,
bustap.Start.y - 16 } ) );
busEntry->SetSize( { ToKicadCoords( 16 ), ToKicadCoords( 16 ) } );
aSheet->LastScreen()->Append( busEntry );
}
LABEL_FLAG_SHAPE getLabelShape( LTSPICE_SCHEMATIC::POLARITY aPolarity )
{
if( aPolarity == LTSPICE_SCHEMATIC::POLARITY::INPUT )
return LABEL_FLAG_SHAPE::L_INPUT;
else if( aPolarity == LTSPICE_SCHEMATIC::POLARITY::OUTPUT )
return LABEL_FLAG_SHAPE::L_OUTPUT;
else
return LABEL_FLAG_SHAPE::L_BIDI;
}
void LTSPICE_SCH_PARSER::CreatePin( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::IOPIN& iopin = aAscfile.Iopins[aIndex];
wxString ioPinName;
for( unsigned int k = 0; k < aAscfile.Flags.size(); k++ )
{
if( ( aAscfile.Flags[k].Offset.x == iopin.Location.x )
&& ( aAscfile.Flags[k].Offset.y == iopin.Location.y ) )
{
ioPinName = aAscfile.Flags[k].Value;
aAscfile.Flags.erase( aAscfile.Flags.begin() + k );
}
}
SCH_HIERLABEL* sheetPin = new SCH_HIERLABEL( ToKicadCoords( iopin.Location ) + m_originOffset,
ioPinName, SCH_HIER_LABEL_T );
sheetPin->SetShape( getLabelShape( iopin.Polarity ) );
aSheet->LastScreen()->Append( sheetPin );
}
void LTSPICE_SCH_PARSER::CreateLine( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::LINE& lt_line = aAscfile.Lines[aIndex];
SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY );
shape->AddPoint( ToInvertedKicadCoords( lt_line.End ) + m_originOffset );
shape->AddPoint( ToInvertedKicadCoords( lt_line.Start ) + m_originOffset );
shape->SetStroke( getStroke( lt_line.LineWidth, lt_line.LineStyle ) );
aSheet->LastScreen()->Append( shape );
}
void LTSPICE_SCH_PARSER::CreateCircle( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::CIRCLE& lt_circle = aAscfile.Circles[aIndex];
SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
VECTOR2I c = ( lt_circle.TopLeft + lt_circle.BotRight ) / 2;
int r = ( lt_circle.TopLeft.x - lt_circle.BotRight.x ) / 2;
circle->SetPosition( ToInvertedKicadCoords( c ) );
circle->SetEnd( ToInvertedKicadCoords( c ) + VECTOR2I( abs( ToKicadCoords( r ) ), 0 ) );
circle->SetStroke( getStroke( lt_circle.LineWidth, lt_circle.LineStyle ) );
aSheet->LastScreen()->Append( circle );
}
void LTSPICE_SCH_PARSER::CreateArc( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::ARC& lt_arc = aAscfile.Arcs[aIndex];
SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
arc->SetCenter( ToInvertedKicadCoords( ( lt_arc.TopLeft + lt_arc.BotRight ) / 2 ) );
arc->SetEnd( ToInvertedKicadCoords( lt_arc.ArcEnd ) );
arc->SetStart( ToInvertedKicadCoords( lt_arc.ArcStart ) );
arc->SetStroke( getStroke( lt_arc.LineWidth, lt_arc.LineStyle ) );
aSheet->LastScreen()->Append( arc );
}
void LTSPICE_SCH_PARSER::CreateRect( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::RECTANGLE& lt_rect = aAscfile.Rectangles[aIndex];
SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECT );
rectangle->SetPosition( ToInvertedKicadCoords( lt_rect.BotRight ) );
rectangle->SetEnd( ToInvertedKicadCoords( lt_rect.TopLeft ) );
rectangle->SetStroke( getStroke( lt_rect.LineWidth, lt_rect.LineStyle ) );
aSheet->LastScreen()->Append( rectangle );
}
int LTSPICE_SCH_PARSER::getLineWidth( const LTSPICE_SCHEMATIC::LINEWIDTH& aLineWidth )
{
if( aLineWidth == LTSPICE_SCHEMATIC::LINEWIDTH::Normal )
return schIUScale.MilsToIU( 6 );
else if( aLineWidth == LTSPICE_SCHEMATIC::LINEWIDTH::Wide )
return schIUScale.MilsToIU( 12 );
else
return schIUScale.MilsToIU( 6 );
}
PLOT_DASH_TYPE LTSPICE_SCH_PARSER::getLineStyle( const LTSPICE_SCHEMATIC::LINESTYLE& aLineStyle )
{
switch( aLineStyle )
{
case LTSPICE_SCHEMATIC::LINESTYLE::SOLID: return PLOT_DASH_TYPE::SOLID;
case LTSPICE_SCHEMATIC::LINESTYLE::DOT: return PLOT_DASH_TYPE::DOT;
case LTSPICE_SCHEMATIC::LINESTYLE::DASHDOTDOT: return PLOT_DASH_TYPE::DASHDOTDOT;
case LTSPICE_SCHEMATIC::LINESTYLE::DASHDOT: return PLOT_DASH_TYPE::DASHDOT;
case LTSPICE_SCHEMATIC::LINESTYLE::DASH: return PLOT_DASH_TYPE::DASH;
default: return PLOT_DASH_TYPE::SOLID;
}
}
STROKE_PARAMS LTSPICE_SCH_PARSER::getStroke( const LTSPICE_SCHEMATIC::LINEWIDTH& aLineWidth,
const LTSPICE_SCHEMATIC::LINESTYLE& aLineStyle )
{
return STROKE_PARAMS( getLineWidth( aLineWidth ), getLineStyle( aLineStyle ) );
}
SCH_TEXT* LTSPICE_SCH_PARSER::CreateSCH_TEXT( VECTOR2I aOffset, const wxString& aText,
int aFontSize,
LTSPICE_SCHEMATIC::JUSTIFICATION aJustification )
{
VECTOR2I pos = ToKicadCoords( aOffset ) + m_originOffset;
SCH_TEXT* textItem = new SCH_TEXT( pos, aText, SCH_TEXT_T );
textItem->SetTextSize( ToKicadFontSize( aFontSize ) );
textItem->SetVisible( true );
textItem->SetMultilineAllowed( true );
switch( aJustification )
{
case LTSPICE_SCHEMATIC::JUSTIFICATION::VLEFT:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
textItem->Move( { textItem->GetTextSize().x / 2, 0 } );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VTOP:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
textItem->Move( { -textItem->GetTextSize().x / 2, 0 } );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VBOTTOM:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::UP );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::LEFT:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
textItem->Move( { 0, textItem->GetTextSize().x / 2 } );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::TOP:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
textItem->Move( { 0, -textItem->GetTextSize().x / 2 } );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::BOTTOM:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VRIGHT:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::BOTTOM );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::RIGHT:
textItem->SetTextSpinStyle( TEXT_SPIN_STYLE::LEFT );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::CENTER:
textItem->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::NONE:
break;
}
return textItem;
}
void LTSPICE_SCH_PARSER::CreateWire( LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex,
SCH_SHEET_PATH* aSheet, SCH_LAYER_ID aLayer )
{
SCH_LINE* segment = new SCH_LINE();
segment->SetLineWidth( getLineWidth( LTSPICE_SCHEMATIC::LINEWIDTH::Normal ) );
segment->SetLineStyle( PLOT_DASH_TYPE::SOLID );
segment->SetLayer( aLayer );
segment->SetStartPoint( ToKicadCoords( aAscfile.Wires[aIndex].Start ) + m_originOffset );
segment->SetEndPoint( ToKicadCoords( aAscfile.Wires[aIndex].End ) + m_originOffset );
aSheet->LastScreen()->Append( segment );
}
SCH_SYMBOL* LTSPICE_SCH_PARSER::CreatePowerSymbol( const VECTOR2I& aOffset, const wxString& aValue,
int aFontSize, SCH_SHEET_PATH* aSheet,
std::vector<LTSPICE_SCHEMATIC::WIRE>& aWires )
{
LIB_SYMBOL* lib_symbol = new LIB_SYMBOL( wxS( "GND" ) );
LIB_SHAPE* shape = new LIB_SHAPE( lib_symbol, SHAPE_T::POLY );
shape->AddPoint( ToInvertedKicadCoords( { 16, 0 } ) );
shape->AddPoint( ToInvertedKicadCoords( { -16, 0 } ) );
shape->AddPoint( ToInvertedKicadCoords( { 0, 15 } ) );
shape->AddPoint( ToInvertedKicadCoords( { 16, 0 } ) );
shape->AddPoint( ToInvertedKicadCoords( { -16, 0 } ) );
shape->AddPoint( ToInvertedKicadCoords( { 0, 15 } ) );
shape->SetStroke( STROKE_PARAMS( getLineWidth( LTSPICE_SCHEMATIC::LINEWIDTH::Normal ),
PLOT_DASH_TYPE::SOLID ) );
lib_symbol->AddDrawItem( shape );
lib_symbol->SetPower();
LIB_PIN* pin = new LIB_PIN( lib_symbol );
pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
pin->SetPosition( ToInvertedKicadCoords( { 0, 0 } ) );
pin->SetLength( 5 );
pin->SetShape( GRAPHIC_PINSHAPE::LINE );
lib_symbol->AddDrawItem( pin );
LIB_ID libId( wxS( "ltspice" ), wxS( "GND" ) );
SCH_SYMBOL* sch_symbol = new SCH_SYMBOL( *lib_symbol, libId, aSheet, 1 );
sch_symbol->SetRef( aSheet, wxString::Format( wxS( "#GND%03d" ), m_powerSymbolIndex++ ) );
sch_symbol->GetField( REFERENCE_FIELD )->SetVisible( false );
sch_symbol->SetValueFieldText( wxS( "0" ) );
sch_symbol->GetField( VALUE_FIELD )->SetTextSize( ToKicadFontSize( aFontSize ) );
sch_symbol->GetField( VALUE_FIELD )->SetVisible( false );
sch_symbol->Move( ToKicadCoords( aOffset ) + m_originOffset );
for( LTSPICE_SCHEMATIC::WIRE& wire : aWires )
{
if( aOffset == wire.Start )
{
if( wire.Start.x == wire.End.x )
{
if( wire.Start.y < wire.End.y )
{
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
}
else
{
if( wire.Start.x < wire.End.x )
sch_symbol->SetOrientation( SYM_ROTATE_CLOCKWISE );
else if( wire.Start.x > wire.End.x )
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
}
else if( aOffset == wire.End )
{
if( wire.Start.x == wire.End.x )
{
if( wire.Start.y > wire.End.y )
{
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
}
}
else
{
if( wire.Start.x < wire.End.x )
sch_symbol->SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
else if( wire.Start.x > wire.End.x )
sch_symbol->SetOrientation( SYM_ROTATE_CLOCKWISE );
}
}
}
return sch_symbol;
}
SCH_LABEL_BASE* LTSPICE_SCH_PARSER::CreateSCH_LABEL( KICAD_T aType, const VECTOR2I& aOffset,
const wxString& aValue, int aFontSize )
{
SCH_LABEL_BASE* label = nullptr;
if( aType == SCH_LABEL_T )
{
label = new SCH_LABEL();
label->SetText( aValue );
label->SetTextSize( ToKicadFontSize( aFontSize ) );
label->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
}
else if( aType == SCH_DIRECTIVE_LABEL_T )
{
label = new SCH_DIRECTIVE_LABEL();
label->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT );
SCH_FIELD field( { 0, 0 }, -1, label, wxS( "DATAFLAG" ) );
field.SetText( aValue );
field.SetTextSize( ToKicadFontSize( aFontSize ) );
field.SetVisible( true );
label->AddField( field );
label->AutoplaceFields( nullptr, false );
}
else
{
UNIMPLEMENTED_FOR( aType );
}
label->SetPosition( ToKicadCoords( aOffset ) + m_originOffset );
label->SetVisible( true );
return label;
}
void LTSPICE_SCH_PARSER::CreateFields( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheet )
{
wxString libPath = KIPLATFORM::ENV::GetDocumentsPath() + wxS( "/LTspiceXVII/lib/" );
wxString symbolName = aLTSymbol.Name.Upper();
wxString type = aLTSymbol.SymAttributes[ wxS( "TYPE" ) ].Upper();
wxString prefix = aLTSymbol.SymAttributes[ wxS( "PREFIX" ) ].Upper();
wxString instName = aLTSymbol.SymAttributes[ wxS( "INSTNAME" ) ].Upper();
wxString value = aLTSymbol.SymAttributes[ wxS( "VALUE" ) ];
aSymbol->SetRef( aSheet, instName );
aSymbol->SetValueFieldText( value );
auto setupNonInferredPassive =
[&]( const wxString& aPrefix )
{
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( aPrefix );
aSymbol->AddField( deviceField );
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( aPrefix + wxS( "=${VALUE}" ) );
aSymbol->AddField( paramsField );
};
if( symbolName == wxS( "RES" ) )
{
if( !instName.StartsWith( 'R' ) )
setupNonInferredPassive( wxS( "R" ) );
}
else if( symbolName == wxS( "CAP" ) )
{
if( !instName.StartsWith( 'C' ) )
setupNonInferredPassive( wxS( "C" ) );
}
else if( symbolName == wxS( "IND" ) )
{
if( !instName.StartsWith( 'L' ) )
setupNonInferredPassive( wxS( "L" ) );
}
else if( symbolName == wxS( "VOLTAGE" ) || symbolName == wxS( "CURRENT" ) )
{
// inference had better work....
}
else
{
wxString libFile = aLTSymbol.SymAttributes[ wxS( "MODELFILE" ) ];
if( prefix == wxS( "X" ) )
{
// A prefix of X overrides the simulation model for other symbols (npn, etc.)
type = wxS( "X" );
}
else if( libFile.IsEmpty() )
{
if( type.IsEmpty() )
type = symbolName;
if( type == "DIODE" )
libFile = libPath + wxS( "cmp/standard.dio" );
else if( type == "NPN" || type == "PNP" )
libFile = libPath + wxS( "cmp/standard.bjt" );
else if( type == "NJF" || type == "PJF" )
libFile = libPath + wxS( "cmp/standard.jft" );
else if( type == "NMOS" || type == "PMOS" )
libFile = libPath + wxS( "cmp/standard.mos" );
}
if( libFile.IsEmpty() )
libFile = m_includes[ value ];
if( !libFile.IsEmpty() )
{
SCH_FIELD libField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Library" ) );
libField.SetText( libFile );
aSymbol->AddField( libField );
}
SCH_FIELD nameField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Name" ) );
nameField.SetText( wxS( "${VALUE}" ) );
aSymbol->AddField( nameField );
if( type == wxS( "X" ) )
{
SCH_FIELD deviceField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Device" ) );
deviceField.SetText( wxS( "SUBCKT" ) );
aSymbol->AddField( deviceField );
}
wxString spiceLine = aLTSymbol.SymAttributes[ wxS( "SPICELINE" ) ];
if( !spiceLine.IsEmpty() )
{
SCH_FIELD paramsField( { 0, 0 }, -1, aSymbol, wxS( "Sim.Params" ) );
paramsField.SetText( spiceLine );
aSymbol->AddField( paramsField );
}
}
for( LTSPICE_SCHEMATIC::LT_WINDOW& lt_window : aLTSymbol.Windows )
{
SCH_FIELD* field = nullptr;
switch( lt_window.WindowNumber )
{
case -1: /* PartNum */ break;
case 0: /* InstName */ field = aSymbol->GetField( REFERENCE_FIELD ); break;
case 1: /* Type */ break;
case 2: /* RefName */ break;
case 3: /* Value */ field = aSymbol->GetField( VALUE_FIELD ); break;
case 5: /* QArea */ break;
case 8: /* Width */ break;
case 9: /* Length */ break;
case 10: /* Multi */ break;
case 16: /* Nec */ break;
case 38: /* SpiceModel */ field = aSymbol->FindField( wxS( "Sim.Name" ) ); break;
case 39: /* SpiceLine */ field = aSymbol->FindField( wxS( "Sim.Params" ) ); break;
case 40: /* SpiceLine2 */ break;
/*
47 Def_Sub
50 Digital_Timing_Model
51 Digital_Extracts
52 Digital_IO_Model
53 Digital_Line
54 Digital_Primitive
55 Digital_MNTYMXDLY
56 Digital_IO_LEVEL
57 Digital_StdCell
58 Digital_File
105 Cell
106 W/L
107 PSIZE
108 NSIZE
109 sheets
110 sh#
111 Em_Scale
112 Epi
113 Sinker
114 Multi5
118 AQ
119 AQSUB
120 ZSIZE
121 ESR
123 Value2
124 COUPLE
125 Voltage
126 Area1
127 Area2
128 Area3
129 Area4
130 Multi1
131 Multi2
132 Multi3
133 Multi4
134 DArea
135 DPerim
136 CArea
137 CPerim
138 Shrink
139 Gate_Resize
142 BP
143 BN
144 Sim_Level
146 G_Voltage
150 SpiceLine3
153 D_VOLTAGES
156 Version
157 Comment
158 XDef_Sub
159 LVS_Area
162 User1
163 User2
164 User3
165 User4
166 User5
167 Root
168 Class
169 Geometry
170 WL_Delimiter
175 T1
176 T2
184 DsgnName
185 Designer
190 RTN
191 PWR
192 BW
201 CAPROWS
202 CAPCOLS
203 NF
204 SLICES
205 CUR
206 TEMPRISE
207 STRIPS
208 WEM
209 LEM
210 BASES
211 COLS
212 XDef_Tub
*/
default: break;
}
if( field )
{
field->SetPosition( ToKicadCoords( lt_window.Position ) );
field->SetTextSize( ToKicadFontSize( lt_window.FontSize ) );
if( lt_window.FontSize == 0 )
field->SetVisible( false );
switch( lt_window.Justification )
{
case LTSPICE_SCHEMATIC::JUSTIFICATION::LEFT:
field->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
field->SetTextAngle( ANGLE_HORIZONTAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::CENTER:
field->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
field->SetTextAngle( ANGLE_HORIZONTAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::RIGHT:
field->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
field->SetTextAngle( ANGLE_HORIZONTAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VLEFT:
field->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
field->SetTextAngle( ANGLE_VERTICAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VRIGHT:
field->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
field->SetTextAngle( ANGLE_VERTICAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VBOTTOM:
field->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
field->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
field->SetTextAngle( ANGLE_VERTICAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::VTOP:
field->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
field->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
field->SetTextAngle( ANGLE_VERTICAL );
break;
case LTSPICE_SCHEMATIC::JUSTIFICATION::NONE:
case LTSPICE_SCHEMATIC::JUSTIFICATION::BOTTOM:
case LTSPICE_SCHEMATIC::JUSTIFICATION::TOP:
break;
}
}
}
}
void LTSPICE_SCH_PARSER::CreateRect( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
LIB_SHAPE* aRectangle )
{
LTSPICE_SCHEMATIC::RECTANGLE& lt_rect = aLTSymbol.Rectangles[aIndex];
aRectangle->SetPosition( ToInvertedKicadCoords( lt_rect.BotRight ) );
aRectangle->SetEnd( ToInvertedKicadCoords( lt_rect.TopLeft ) );
aRectangle->SetStroke( getStroke( lt_rect.LineWidth, lt_rect.LineStyle ) );
}
void LTSPICE_SCH_PARSER::CreateRect( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::RECTANGLE& lt_rect = aLTSymbol.Rectangles[aIndex];
SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECT );
rectangle->SetPosition( ToInvertedKicadCoords( lt_rect.BotRight ) );
rectangle->SetEnd( ToInvertedKicadCoords( lt_rect.TopLeft ) );
rectangle->SetStroke( getStroke( lt_rect.LineWidth, lt_rect.LineStyle ) );
rectangle->Move( aLTSymbol.Offset );
RotateMirrorShape( aLTSymbol, rectangle );
aSheet->LastScreen()->Append( rectangle );
}
void LTSPICE_SCH_PARSER::CreatePin( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
LIB_PIN* aPin )
{
LTSPICE_SCHEMATIC::LT_PIN& lt_pin = aLTSymbol.Pins[aIndex];
wxString device = aLTSymbol.Name.Lower();
if( aLTSymbol.Pins.size() == 2 && ( device == wxS( "res" )
|| device == wxS( "cap" )
|| device == wxS( "ind" ) ) )
{
// drop A/B pin names from simple LRCs as they're not terribly useful (and prevent
// other pin names on the net from driving the net name).
}
else
{
aPin->SetName( lt_pin.PinAttribute[ wxS( "PinName" ) ] );
}
aPin->SetNumber( wxString::Format( wxS( "%d" ), aIndex + 1 ) );
aPin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
aPin->SetPosition( ToInvertedKicadCoords( lt_pin.PinLocation ) );
aPin->SetLength( 5 );
aPin->SetShape( GRAPHIC_PINSHAPE::LINE );
}
void LTSPICE_SCH_PARSER::CreateArc( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
LIB_SHAPE* aArc )
{
LTSPICE_SCHEMATIC::ARC& lt_arc = aLTSymbol.Arcs[aIndex];
aArc->SetCenter( ToInvertedKicadCoords( ( lt_arc.TopLeft + lt_arc.BotRight ) / 2 ) );
aArc->SetEnd( ToInvertedKicadCoords( lt_arc.ArcEnd ) );
aArc->SetStart( ToInvertedKicadCoords( lt_arc.ArcStart ) );
aArc->SetStroke( getStroke( lt_arc.LineWidth, lt_arc.LineStyle ) );
}
void LTSPICE_SCH_PARSER::CreateArc( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::ARC& lt_arc = aLTSymbol.Arcs[aIndex];
SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
arc->SetCenter( ToInvertedKicadCoords( ( lt_arc.TopLeft + lt_arc.BotRight ) / 2 ) );
arc->SetEnd( ToInvertedKicadCoords( lt_arc.ArcEnd ) );
arc->SetStart( ToInvertedKicadCoords( lt_arc.ArcStart ) );
arc->SetStroke( getStroke( lt_arc.LineWidth, lt_arc.LineStyle ) );
arc->Move( ToKicadCoords( aLTSymbol.Offset ) + m_originOffset );
RotateMirrorShape( aLTSymbol, arc );
aSheet->LastScreen()->Append( arc );
}
void LTSPICE_SCH_PARSER::CreateCircle( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
SCH_SHEET_PATH* aSheet )
{
LTSPICE_SCHEMATIC::CIRCLE& lt_circle = aLTSymbol.Circles[aIndex];
SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
VECTOR2I c = ( lt_circle.TopLeft + lt_circle.BotRight ) / 2;
int r = ( lt_circle.TopLeft.x - lt_circle.BotRight.x ) / 2;
circle->SetPosition( ToInvertedKicadCoords( c ) );
circle->SetEnd( ToInvertedKicadCoords( c ) + VECTOR2I( abs( ToKicadCoords( r ) ), 0 ) );
circle->SetStroke( getStroke( lt_circle.LineWidth, lt_circle.LineStyle ) );
circle->Move( aLTSymbol.Offset );
RotateMirrorShape( aLTSymbol, circle );
aSheet->LastScreen()->Append( circle );
}
void LTSPICE_SCH_PARSER::CreateCircle( LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol, int aIndex,
LIB_SHAPE* aCircle )
{
LTSPICE_SCHEMATIC::CIRCLE& lt_circle = aLTSymbol.Circles[aIndex];
VECTOR2I c = ( lt_circle.TopLeft + lt_circle.BotRight ) / 2;
int r = ( lt_circle.TopLeft.x - lt_circle.BotRight.x ) / 2;
aCircle->SetPosition( ToInvertedKicadCoords( c ) );
aCircle->SetEnd( ToInvertedKicadCoords( c ) + VECTOR2I( abs( ToKicadCoords( r ) ), 0 ) );
aCircle->SetStroke( getStroke( lt_circle.LineWidth, lt_circle.LineStyle ) );
}