KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_ltspice_parser.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2022 Chetan Subhash Shinde<[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
26
27#include <core/map_helpers.h>
30#include <schematic.h>
31#include <sch_collectors.h>
32#include <sch_line.h>
33#include <sch_label.h>
34#include <sch_text.h>
35#include <sch_edit_frame.h>
36#include <sch_shape.h>
37#include <sch_sheet.h>
38#include <sch_sheet_pin.h>
39#include <sch_bus_entry.h>
40#include <string_utils.h>
41#include <trigo.h>
42#include <wx/buffer.h>
43#include <wx/ffile.h>
44#include <wx/filename.h>
45#include <wx/strconv.h>
46#include <wx/tokenzr.h>
47#include <wx/txtstrm.h>
48#include <wx/wfstream.h>
49#include <sim/spice_value.h>
50#include <fmt/format.h>
51#include <cmath>
52#include <set>
53
54
55// Split PWL argument strings on whitespace while keeping quoted spans intact.
56// Example input: REPEAT FOREVER FILE="data 3.txt" ENDREPEAT
57// Example tokens: [REPEAT] [FOREVER] [FILE="data 3.txt"] [ENDREPEAT]
58static std::vector<wxString> tokenizeQuoted( const wxString& aText )
59{
60 std::vector<wxString> tokens;
61 wxString token;
62 bool inQuotes = false;
63
64 for( wxUniChar ch : aText )
65 {
66 if( ch == '"' )
67 inQuotes = !inQuotes;
68
69 if( !inQuotes && wxIsspace( ch ) )
70 {
71 if( !token.IsEmpty() )
72 {
73 tokens.push_back( token );
74 token.clear();
75 }
76 }
77 else
78 {
79 token += ch;
80 }
81 }
82
83 if( !token.IsEmpty() )
84 tokens.push_back( token );
85
86 return tokens;
87}
88
89
90// LTspice .tran -> ngspice .tran. Tstep 0 or omitted -> (Tstop-Tstart)/10000.
91// Time values are rewritten; trailing modifiers (uic, steady, ...) are kept as-is.
92static wxString convertLtSpiceTextToNgspice( const wxString& aText )
93{
94 wxArrayString outLines;
95
96 for( wxString line : wxSplit( aText, '\n', '\0' ) )
97 {
98 wxArrayString tok = wxSplit( line, ' ', '\0' );
99
100 if( !tok.IsEmpty() && tok[0].IsSameAs( wxS( ".tran" ), false ) )
101 {
102 wxArrayString args; // <Tstep> <Tstop> [Tstart [dTmax]] [modifiers]
103 wxArrayString modifiers; // uic / LTspice-only flags, preserved
104
105 const std::set<wxString> c_modifiers = { "UIC", "STEADY", "NODISCARD", "STARTUP", "STEP" };
106
107 for( size_t i = 1; i < tok.size(); ++i )
108 {
109 if( tok[i].IsEmpty() )
110 continue;
111
112 wxString u = tok[i].Upper();
113
114 if( modifiers.IsEmpty() && !c_modifiers.contains( u ) )
115 args.Add( tok[i] );
116 else
117 modifiers.Add( tok[i] );
118 }
119
120 if( !args.IsEmpty() )
121 {
122 // LTspice syntax:
123 // .TRAN <Tstep> <Tstop> [Tstart [dTmax]] [modifiers]
124 // .TRAN <Tstop> [modifiers]
125
126 // ngspice syntax:
127 // .tran tstep tstop <tstart <tmax>> <uic>
128 const bool hasTstep = args.size() >= 2;
129
130 wxString tstepStr = hasTstep ? args[0] : wxString();
131 wxString tstopStr = hasTstep ? args[1] : args[0];
132 wxString tstartStr = ( args.size() > 2 ) ? args[2] : wxString();
133 wxString dtmaxStr = ( args.size() > 3 ) ? args[3] : wxString();
134
135 double tstep = SPICE_VALUE( tstepStr ).ToDouble();
136 double tstop = SPICE_VALUE( tstopStr ).ToDouble();
137 double tstart = SPICE_VALUE( tstartStr ).ToDouble();
138
139 if( tstep == 0.0 )
140 tstepStr = SPICE_VALUE( ( tstop - tstart ) / 10000.0 ).ToSpiceString();
141
142 line = wxS( ".tran " ) + tstepStr + wxS( " " ) + tstopStr;
143
144 if( !tstartStr.IsEmpty() )
145 line << wxS( " " ) << tstartStr;
146
147 if( !dtmaxStr.IsEmpty() )
148 line << wxS( " " ) << dtmaxStr;
149
150 for( const wxString& mod : modifiers )
151 line << wxS( " " ) << mod;
152 }
153 }
154
155 outLines.Add( line );
156 }
157
158 return wxJoin( outLines, '\n', '\0' );
159}
160
161
162// Convert an LTspice PWL data file to an ngspice-friendly version.
163// Input semantics: "+t" is relative and plain "t" is absolute time.
164// Output semantics: emit relative step durations on every line.
165static bool convertPwlFileToNgspice( const wxFileName& aSourceFile, const wxFileName& aDestFile )
166{
167 wxFFileInputStream inputStream( aSourceFile.GetFullPath() );
168
169 if( !inputStream.IsOk() )
170 return false;
171
172 wxFFileOutputStream outputStream( aDestFile.GetFullPath() );
173
174 if( !outputStream.IsOk() )
175 return false;
176
177 wxTextInputStream textIn( inputStream, wxS( " \t" ), wxConvUTF8 );
178 wxTextOutputStream textOut( outputStream, wxEOL_UNIX, wxConvUTF8 );
179 double prevAbsoluteTime = 0.0;
180
181 while( inputStream.CanRead() )
182 {
183 wxString line = textIn.ReadLine();
184 line.Trim( true ).Trim( false );
185
186 // Convert comments to # format known by ngspice
187 wxString commentRest;
188 if( line.StartsWith( wxS( "*" ), &commentRest ) || line.StartsWith( wxS( ";" ), &commentRest ) )
189 {
190 textOut << wxS( "#" ) << commentRest << '\n';
191 continue;
192 }
193
194 wxStringTokenizer pointTokenizer( line, wxS( " \t" ), wxTOKEN_STRTOK );
195
196 if( pointTokenizer.CountTokens() < 2 )
197 {
198 textOut << line << '\n';
199 continue;
200 }
201
202 wxString timeToken = pointTokenizer.GetNextToken();
203 wxString valueToken = pointTokenizer.GetNextToken();
204
205 // LTspice semantics: "+t" means offset from previous point, plain "t"
206 // means absolute time from 0.
207 // Example: 0 0, +100n 0, 300n 1 => absolute times 0, 100n, 300n.
208 wxString timeRest = timeToken;
209 bool isRelative = timeToken.StartsWith( wxS( "+" ), &timeRest );
210
211 if( timeRest.IsEmpty() )
212 {
213 textOut << line << '\n';
214 continue;
215 }
216
217 // Parse LTspice time token to seconds
218 SPICE_VALUE spiceValue( timeRest );
219 double timeValueSeconds = spiceValue.ToDouble();
220
221 // Convert to relative time
222 double absoluteTime = isRelative ? prevAbsoluteTime + timeValueSeconds : timeValueSeconds;
223 double relativeTime = absoluteTime - prevAbsoluteTime;
224 prevAbsoluteTime = absoluteTime;
225
226 // Format seconds using explicit engineering notation (e.g. 1e-7 -> 100e-9).
227 wxString relativeTimeStr = wxS( "0" );
228
229 if( relativeTime != 0.0 )
230 {
231 double absSeconds = std::fabs( relativeTime );
232 int exp10 = static_cast<int>( std::floor( std::log10( absSeconds ) ) );
233 int engExp = exp10 - ( ( exp10 % 3 + 3 ) % 3 );
234 double mantissa = relativeTime / std::pow( 10.0, engExp );
235
236 relativeTimeStr = wxString::FromUTF8( fmt::format( "{:.9g}e{}", mantissa, engExp ) );
237 }
238
239 textOut << relativeTimeStr << '\t' << valueToken << '\n';
240 }
241
242 return outputStream.IsOk();
243}
244
245
247 const std::vector<wxString>& aUniqueAscNames,
248 std::map<wxString, SCH_SCREEN*>& aMapOfScreens, VECTOR2I aOriginOffset )
249{
250 m_originOffset = aOriginOffset;
251
252 CreateKicadSymbolsAndSubsheets( aAscfile, aScreen, aUniqueAscNames, aMapOfScreens );
253 CreateKicadSCH_ITEMs( aAscfile, aScreen );
254
255 SCHEMATIC* schematic = aScreen->Schematic();
256
257 if( schematic && schematic->RootScreen() == aScreen )
258 {
259 // Convert LTspice standard device libs to UTF-8 into ltspice_cmp/ and .include them.
260 wxString projectPath = schematic->Project().GetProjectPath();
261 wxString includeText;
262
263 if( !projectPath.IsEmpty() )
264 {
265 wxFileName cmpDir( m_lt_schematic->GetLTspiceDataDir().GetFullPath(), wxEmptyString );
266 cmpDir.AppendDir( wxS( "cmp" ) );
267
268 wxFileName outDir( projectPath, wxEmptyString );
269 outDir.AppendDir( wxS( "ltspice_cmp" ) );
270 outDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
271
272 for( const wxString name :
273 { wxS( "standard.dio" ), wxS( "standard.bjt" ), wxS( "standard.jft" ), wxS( "standard.mos" ) } )
274 {
275 includeText << wxS( ".include ltspice_cmp/" ) << name << wxS( "\n" );
276
277 wxFileName src = cmpDir;
278 src.SetFullName( name );
279
280 if( !src.FileExists() )
281 continue;
282
283 wxFileName dst = outDir;
284 dst.SetFullName( name );
285
286 if( dst.FileExists() )
287 continue;
288
289 wxFFile in( src.GetFullPath(), wxS( "rb" ) );
290
291 if( !in.IsOpened() )
292 continue;
293
294 wxFileOffset len = in.Length();
295
296 if( len <= 0 )
297 continue;
298
299 wxMemoryBuffer buffer( static_cast<size_t>( len ) );
300 void* writePtr = buffer.GetWriteBuf( static_cast<size_t>( len ) );
301
302 if( !writePtr || in.Read( writePtr, len ) != static_cast<size_t>( len ) )
303 continue;
304
305 buffer.UngetWriteBuf( static_cast<size_t>( len ) );
306
307 const char* data = static_cast<const char*>( buffer.GetData() );
308 wxString text;
309
310 // UTF-16 LE looks like c \0 c \0 ...; else try UTF-8, then CP1252.
311 if( len >= 4 && ( len % 2 ) == 0 && data[1] == 0 && data[3] == 0 )
312 text = wxString( data, wxMBConvUTF16LE(), len );
313 else
314 text = wxString::FromUTF8( data, len );
315
316 if( text.empty() )
317 text = wxString( data, wxCSConv( wxFONTENCODING_CP1252 ), len );
318
319 wxFFile out( dst.GetFullPath(), wxS( "wb" ) );
320
321 if( !out.IsOpened() )
322 continue;
323
324 out.Write( text, wxConvUTF8 );
325 }
326 }
327
328 // Add filesource subcircuit template for PWL file sources
329 includeText << wxS( "\n" );
330 includeText << wxS( ".subckt pwl_file outp outn file=\"\" timerelative=1\n" );
331 includeText << wxS( "Afs %vd([outp outn]) filesrc\n" );
332 includeText << wxS( ".model filesrc filesource (file={file} amploffset=[0] amplscale=[1] timeoffset=0 "
333 "timescale=1 timerelative={timerelative})\n" );
334 includeText << wxS( ".ends\n" );
335
336 if( !includeText.IsEmpty() )
337 {
338 SCH_TEXT* textItem = new SCH_TEXT( VECTOR2I( 0, 0 ), includeText );
339
340 textItem->SetVisible( true );
341 textItem->SetMultilineAllowed( true );
344
345 aScreen->Append( textItem );
346 }
347 }
348}
349
350
352 int aIndex, SCH_SHAPE* shape )
353{
354 const LTSPICE_SCHEMATIC::LINE& lt_line = aLTSymbol.Lines[aIndex];
355
356 shape->AddPoint( ToKicadCoords( lt_line.End ) );
357 shape->AddPoint( ToKicadCoords( lt_line.Start ) );
358 shape->SetStroke( getStroke( lt_line.LineWidth, lt_line.LineStyle ) );
359}
360
361
363 const std::vector<wxString>& aUniqueAscNames,
364 std::map<wxString, SCH_SCREEN*>& aMapOfScreens )
365{
366 std::map<wxString, LIB_SYMBOL*> existingSymbol;
367
368 for( LTSPICE_SCHEMATIC::LT_SYMBOL& lt_symbol : aAscfile.Symbols )
369 {
370 wxString libName = m_lt_schematic->GetSymbolName( lt_symbol.Name );
371
372 if( lt_symbol.AsyKey.IsEmpty() || !alg::contains( aUniqueAscNames, lt_symbol.AsyKey ) )
373 {
374 LIB_SYMBOL* lib_symbol;
375
376 if( existingSymbol.count( libName ) == 0 )
377 {
378 lib_symbol = new LIB_SYMBOL( libName );
379
380 CreateSymbol( lt_symbol, lib_symbol );
381
382 existingSymbol.emplace( libName, lib_symbol );
383 }
384 else
385 {
386 lib_symbol = existingSymbol[libName];
387 }
388
389 LIB_ID libId( wxS( "ltspice" ), libName );
390 SCH_SYMBOL* sch_symbol = new SCH_SYMBOL( *lib_symbol, libId, nullptr, 1 );
391
392 AddSymFields( lt_symbol, sch_symbol );
393 AssignSymOrientation( lt_symbol, sch_symbol );
394
395 sch_symbol->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
396
397 aScreen->Append( sch_symbol );
398 }
399 else
400 {
401 for( int j = 0; j < (int) lt_symbol.Lines.size(); j++ )
402 {
403 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY );
404
405 CreateSymLine( nullptr, lt_symbol, j, shape );
406 RotateMirrorItem( lt_symbol, shape );
407 shape->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
408
409 aScreen->Append( shape );
410 }
411
412 for( int j = 0; j < (int) lt_symbol.Circles.size(); j++ )
413 {
414 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::CIRCLE );
415
416 CreateSymCircle( lt_symbol, j, shape );
417 RotateMirrorItem( lt_symbol, shape );
418 shape->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
419
420 aScreen->Append( shape );
421 }
422
423 for( int j = 0; j < (int) lt_symbol.Arcs.size(); j++ )
424 {
425 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::ARC );
426
427 CreateSymArc( lt_symbol, j, shape );
428 RotateMirrorItem( lt_symbol, shape );
429 shape->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
430
431 aScreen->Append( shape );
432 }
433
434 for( int j = 0; j < (int) lt_symbol.Rectangles.size(); j++ )
435 {
436 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::RECTANGLE );
437
438 CreateSymRect( lt_symbol, j, shape );
439 RotateMirrorItem( lt_symbol, shape );
440 shape->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
441
442 aScreen->Append( shape );
443 }
444
445 for( int j = 0; j < (int) lt_symbol.Texts.size(); j++ )
446 {
447 SCH_TEXT* text = new SCH_TEXT( VECTOR2I(), wxEmptyString );
448
449 CreateSymText( lt_symbol, j, text );
450 RotateMirrorItem( lt_symbol, text );
451 text->Move( ToKicadCoords( lt_symbol.Offset ) + m_originOffset );
452
453 aScreen->Append( text );
454 }
455
456 SCH_SHEET* sch_sheet = AddAscSymAsSubsheet( aAscfile, lt_symbol, aScreen );
457
458 if( aMapOfScreens.contains( lt_symbol.AsyKey ) )
459 sch_sheet->SetScreen( aMapOfScreens.at( lt_symbol.AsyKey ) );
460 }
461 }
462}
463
464
466{
467 for( int j = 0; j < (int) aLtSymbol.Lines.size(); j++ )
468 {
470
471 CreateSymLine( aLibSymbol, aLtSymbol, j, line );
472 aLibSymbol->AddDrawItem( line );
473 }
474
475 for( int j = 0; j < (int) aLtSymbol.Circles.size(); j++ )
476 {
478
479 CreateSymCircle( aLtSymbol, j, circle );
480 aLibSymbol->AddDrawItem( circle );
481 }
482
483 for( int j = 0; j < (int) aLtSymbol.Arcs.size(); j++ )
484 {
486
487 CreateSymArc( aLtSymbol, j, arc );
488 aLibSymbol->AddDrawItem( arc );
489 }
490
491 for( int j = 0; j < (int) aLtSymbol.Rectangles.size(); j++ )
492 {
494
495 CreateSymRect( aLtSymbol, j, rectangle );
496 aLibSymbol->AddDrawItem( rectangle );
497 }
498
499 for( int j = 0; j < (int) aLtSymbol.Texts.size(); j++ )
500 {
501 SCH_TEXT* text = new SCH_TEXT( VECTOR2I(), wxEmptyString, LAYER_DEVICE );
502
503 CreateSymText( aLtSymbol, j, text );
504 aLibSymbol->AddDrawItem( text );
505 }
506
507 for( int j = 0; j < (int) aLtSymbol.Pins.size(); j++ )
508 {
509 SCH_PIN* pin = new SCH_PIN( aLibSymbol );
510
511 CreateSymPin( aLtSymbol, j, pin );
512 aLibSymbol->AddDrawItem( pin );
513 }
514
515 aLibSymbol->SetShowPinNumbers( false );
516}
517
518
520{
521 return schIUScale.MilsToIU( rescale( 50, aCoordinate, 16 ) );
522}
523
524
526{
527 return VECTOR2I( ToKicadCoords( aPos.x ), ToKicadCoords( aPos.y ) );
528}
529
530
532{
533 auto MILS_SIZE =
534 []( int mils )
535 {
536 return VECTOR2I( schIUScale.MilsToIU( mils ), schIUScale.MilsToIU( mils ) );
537 };
538
539 if( aLTFontSize == 0 ) return MILS_SIZE( 20 );
540 else if( aLTFontSize == 1 ) return MILS_SIZE( 36 );
541 else if( aLTFontSize == 2 ) return MILS_SIZE( 42 );
542 else if( aLTFontSize == 3 ) return MILS_SIZE( 50 );
543 else if( aLTFontSize == 4 ) return MILS_SIZE( 60 );
544 else if( aLTFontSize == 5 ) return MILS_SIZE( 72 );
545 else if( aLTFontSize == 6 ) return MILS_SIZE( 88 );
546 else if( aLTFontSize == 7 ) return MILS_SIZE( 108 );
547 else return ToKicadFontSize( 2 );
548}
549
550
552{
553 return schIUScale.IUToMils( rescale( 16, aCoordinate, 50 ) );
554}
555
556
561
562
564{
565 VECTOR2I p = aPoint;
566
567 switch( aLTSymbol.SymbolOrientation )
568 {
570 RotatePoint( p, -ANGLE_90 );
571 break;
572
574 RotatePoint( p, -ANGLE_180 );
575 break;
576
578 RotatePoint( p, -ANGLE_270 );
579 break;
580
582 p.x = -p.x;
583 break;
584
586 p.y = -p.y;
587 RotatePoint( p, -ANGLE_90 );
588 break;
589
591 p.y = -p.y;
592 break;
593
595 p.y = -p.y;
596 RotatePoint( p, -ANGLE_270 );
597 break;
598
599 default:
600 break;
601 }
602
603 return p;
604}
605
606
608{
610 {
611 aItem->Rotate( VECTOR2I(), false );
612 }
614 {
615 aItem->Rotate( VECTOR2I(), false );
616 aItem->Rotate( VECTOR2I(), false );
617 }
619 {
620 aItem->Rotate( VECTOR2I(), true );
621 }
623 {
624 aItem->MirrorHorizontally( 0 );
625 }
627 {
628 aItem->MirrorVertically( 0 );
629 aItem->Rotate( VECTOR2I(), false );
630 }
632 {
633 aItem->MirrorVertically( 0 );
634 }
636 {
637 aItem->MirrorVertically( 0 );
638 aItem->Rotate( VECTOR2I(), true );
639 }
640}
641
642
644{
646 {
647 aSchSymbol->SetOrientation( SYM_ORIENT_0 );
648 }
650 {
651 aSchSymbol->SetOrientation( SYM_ORIENT_180 );
653 }
655 {
656 aSchSymbol->SetOrientation( SYM_ORIENT_180 );
657 }
659 {
661 }
663 {
664 aSchSymbol->SetOrientation( SYM_MIRROR_Y );
665 }
667 {
668 aSchSymbol->SetOrientation( SYM_MIRROR_Y );
670 }
672 {
673 aSchSymbol->SetOrientation( SYM_MIRROR_X );
674 }
676 {
677 aSchSymbol->SetOrientation( SYM_MIRROR_Y );
679 }
680}
681
682
684{
685 for( int j = 0; j < (int) aAscfile.Lines.size(); j++ )
686 AddAscLine( aAscfile, j, aScreen );
687
688 for( int j = 0; j < (int) aAscfile.Circles.size(); j++ )
689 AddAscCircle( aAscfile, j, aScreen );
690
691 for( int j = 0; j < (int) aAscfile.Arcs.size(); j++ )
692 AddAscArc( aAscfile, j, aScreen );
693
694 for( int j = 0; j < (int) aAscfile.Rectangles.size(); j++ )
695 AddAscRect( aAscfile, j, aScreen );
696
697 for( int j = 0; j < (int) aAscfile.Bustap.size(); j++ )
698 AddAscBusEntry( aAscfile, j, aScreen );
699
700 for( int j = 0; j < (int) aAscfile.Wires.size(); j++ )
701 AddAscWire( aAscfile, j, aScreen, SCH_LAYER_ID::LAYER_WIRE );
702
703 for( int j = 0; j < (int) aAscfile.Iopins.size(); j++ )
704 AddAscIopin( aAscfile, j, aScreen );
705
706 for( const LTSPICE_SCHEMATIC::FLAG& lt_flag : aAscfile.Flags )
707 {
708 if( lt_flag.Value == wxS( "0" ) )
709 {
710 aScreen->Append(
711 CreatePowerSymbol( lt_flag.Offset, lt_flag.Value, lt_flag.FontSize, aScreen, aAscfile.Wires ) );
712 }
713 else
714 {
715 KICAD_T labelType = aScreen->Schematic()->RootScreen() == aScreen ? SCH_GLOBAL_LABEL_T : SCH_LABEL_T;
716
717 aScreen->Append( CreateSCH_LABEL( labelType, lt_flag.Offset, lt_flag.Value, lt_flag.FontSize, aScreen ) );
718 }
719 }
720
721 for( const LTSPICE_SCHEMATIC::TEXT& lt_text : aAscfile.Texts )
722 {
723 aScreen->Append( CreateSCH_TEXT( lt_text.Offset, convertLtSpiceTextToNgspice( lt_text.Value ), lt_text.FontSize,
724 lt_text.Justification ) );
725 }
726
727 for( const LTSPICE_SCHEMATIC::DATAFLAG& lt_flag : aAscfile.DataFlags )
728 {
729 aScreen->Append( CreateSCH_LABEL( SCH_DIRECTIVE_LABEL_T, lt_flag.Offset, lt_flag.Expression, lt_flag.FontSize,
730 aScreen ) );
731 }
732}
733
734
736{
737 LTSPICE_SCHEMATIC::BUSTAP& bustap = aAscfile.Bustap[aIndex];
738
739 for( int k = 0; k < (int) aAscfile.Wires.size(); k++ )
740 {
741 if( ( aAscfile.Wires[k].Start == bustap.Start ) || ( aAscfile.Wires[k].End == bustap.Start ) )
742 {
743 AddAscWire( aAscfile, k, aScreen, SCH_LAYER_ID::LAYER_BUS );
744 aAscfile.Wires.erase( aAscfile.Wires.begin() + k );
745 }
746 }
747
748 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( ToKicadCoords( { bustap.Start.x, bustap.Start.y - 16 } ) );
749
750 busEntry->SetSize( { ToKicadCoords( 16 ), ToKicadCoords( 16 ) } );
751
752 aScreen->Append( busEntry );
753}
754
755
767
768
770{
771 // Detect label orientation based on connections
772 std::set<SPIN_STYLE> preferredSpins;
773
774 SCH_COLLECTOR collector;
775 collector.Collect( aScreen, { SCH_LINE_T, SCH_PIN_T, SCH_SHEET_PIN_T }, aLabelPos );
776
777 for( EDA_ITEM* item : collector )
778 {
779 if( SCH_LINE* wire = dynamic_cast<SCH_LINE*>( item ) )
780 {
781 if( !wire->IsWire() )
782 continue;
783
784 BOX2I wireBox;
785 wireBox.Merge( wire->GetStartPoint() );
786 wireBox.Merge( wire->GetEndPoint() );
787
788 VECTOR2I minPt = wireBox.GetOrigin();
789 VECTOR2I maxPt = wireBox.GetEnd();
790
791 if( wireBox.GetWidth() >= wireBox.GetHeight() ) // Mostly horizontal
792 {
793 if( aLabelPos == minPt )
794 preferredSpins.emplace( SPIN_STYLE::LEFT );
795 else if( aLabelPos == maxPt )
796 preferredSpins.emplace( SPIN_STYLE::RIGHT );
797 else
798 preferredSpins.emplace( SPIN_STYLE::UP );
799 }
800 else // Mostly vertical
801 {
802 if( aLabelPos == minPt )
803 preferredSpins.emplace( SPIN_STYLE::UP );
804 else if( aLabelPos == maxPt )
805 preferredSpins.emplace( SPIN_STYLE::BOTTOM );
806 else
807 preferredSpins.emplace( SPIN_STYLE::LEFT );
808 }
809 }
810 else if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item ) )
811 {
812 TRANSFORM transform;
813
814 if( const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( pin->GetParentSymbol() ) )
815 transform = symbol->GetTransform();
816
817 switch( pin->PinDrawOrient( transform ) )
818 {
819 case PIN_ORIENTATION::PIN_RIGHT: preferredSpins.emplace( SPIN_STYLE::LEFT ); break;
820 case PIN_ORIENTATION::PIN_LEFT: preferredSpins.emplace( SPIN_STYLE::RIGHT ); break;
821 case PIN_ORIENTATION::PIN_UP: preferredSpins.emplace( SPIN_STYLE::BOTTOM ); break;
822 case PIN_ORIENTATION::PIN_DOWN: preferredSpins.emplace( SPIN_STYLE::UP ); break;
823 default: break;
824 }
825 }
826 else if( SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( item ) )
827 {
828 switch( sheetPin->GetSpinStyle() )
829 {
830 case SPIN_STYLE::LEFT: preferredSpins.emplace( SPIN_STYLE::RIGHT ); break;
831 case SPIN_STYLE::RIGHT: preferredSpins.emplace( SPIN_STYLE::LEFT ); break;
832 case SPIN_STYLE::BOTTOM: preferredSpins.emplace( SPIN_STYLE::UP ); break;
833 case SPIN_STYLE::UP: preferredSpins.emplace( SPIN_STYLE::BOTTOM ); break;
834 default: break;
835 }
836 }
837 }
838
839 if( preferredSpins.size() == 1 )
840 {
841 return *preferredSpins.begin();
842 }
843 else if( preferredSpins.size() == 2 )
844 {
845 if( preferredSpins.contains( SPIN_STYLE::UP ) )
846 return SPIN_STYLE::UP;
847 else if( preferredSpins.contains( SPIN_STYLE::BOTTOM ) )
848 return SPIN_STYLE::BOTTOM;
849 }
850 else if( preferredSpins.size() == 3 )
851 {
852 if( preferredSpins.contains( SPIN_STYLE::UP ) && preferredSpins.contains( SPIN_STYLE::BOTTOM ) )
853 {
854 if( preferredSpins.contains( SPIN_STYLE::LEFT ) )
855 return SPIN_STYLE::LEFT;
856 else if( preferredSpins.contains( SPIN_STYLE::RIGHT ) )
857 return SPIN_STYLE::RIGHT;
858 }
859 else if( preferredSpins.contains( SPIN_STYLE::LEFT ) && preferredSpins.contains( SPIN_STYLE::RIGHT ) )
860 {
861 if( preferredSpins.contains( SPIN_STYLE::UP ) )
862 return SPIN_STYLE::UP;
863 else if( preferredSpins.contains( SPIN_STYLE::BOTTOM ) )
864 return SPIN_STYLE::BOTTOM;
865 }
866 }
867
868 return aDefaultSpin;
869}
870
871
873{
874 const LTSPICE_SCHEMATIC::IOPIN& iopin = aAscfile.Iopins[aIndex];
875 wxString ioPinName;
876
877 for( unsigned int k = 0; k < aAscfile.Flags.size(); k++ )
878 {
879 if( ( aAscfile.Flags[k].Offset.x == iopin.Location.x ) && ( aAscfile.Flags[k].Offset.y == iopin.Location.y ) )
880 {
881 ioPinName = aAscfile.Flags[k].Value;
882 aAscfile.Flags.erase( aAscfile.Flags.begin() + k );
883 }
884 }
885
886 VECTOR2I pinLoc = ToKicadCoords( iopin.Location ) + m_originOffset;
887 SCH_HIERLABEL* sheetPin = new SCH_HIERLABEL( pinLoc, ioPinName, SCH_HIER_LABEL_T );
888 sheetPin->SetShape( getLabelShape( iopin.Polarity ) );
889 sheetPin->SetSpinStyle( autoLabelOrientation( aScreen, pinLoc, SPIN_STYLE::RIGHT ) );
890
891 sheetPin->AutoplaceFields( aScreen, AUTOPLACE_AUTO );
892 sheetPin->SetFlags( IS_NEW );
893
894 aScreen->Append( sheetPin );
895}
896
897
898void SCH_IO_LTSPICE_PARSER::AddAscLine( const LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex, SCH_SCREEN* aScreen )
899{
900 const LTSPICE_SCHEMATIC::LINE& lt_line = aAscfile.Lines[aIndex];
902
903 line->SetEndPoint( ToKicadCoords( lt_line.End ) );
904 line->SetStroke( getStroke( lt_line.LineWidth, lt_line.LineStyle ) );
905 line->Move( m_originOffset );
906
907 aScreen->Append( line );
908}
909
910
912{
913 const LTSPICE_SCHEMATIC::CIRCLE& lt_circle = aAscfile.Circles[aIndex];
915
916 VECTOR2I c = ( lt_circle.TopLeft + lt_circle.BotRight ) / 2;
917 int r = ( lt_circle.TopLeft.x - lt_circle.BotRight.x ) / 2;
918
919 circle->SetPosition( ToKicadCoords( c ) );
920 circle->SetEnd( ToKicadCoords( c ) + VECTOR2I( abs( ToKicadCoords( r ) ), 0 ) );
921 circle->SetStroke( getStroke( lt_circle.LineWidth, lt_circle.LineStyle ) );
922 circle->Move( m_originOffset );
923
924 aScreen->Append( circle );
925}
926
927
928void SCH_IO_LTSPICE_PARSER::AddAscArc( const LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex, SCH_SCREEN* aScreen )
929{
930 const LTSPICE_SCHEMATIC::ARC& lt_arc = aAscfile.Arcs[aIndex];
931 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
932
933 arc->SetCenter( ToKicadCoords( ( lt_arc.TopLeft + lt_arc.BotRight ) / 2 ) );
934 arc->SetEnd( ToKicadCoords( lt_arc.ArcEnd ) );
935 arc->SetStart( ToKicadCoords( lt_arc.ArcStart ) );
936 arc->SetStroke( getStroke( lt_arc.LineWidth, lt_arc.LineStyle ) );
937 arc->Move( m_originOffset );
938
939 aScreen->Append( arc );
940}
941
942
943void SCH_IO_LTSPICE_PARSER::AddAscRect( const LTSPICE_SCHEMATIC::LT_ASC& aAscfile, int aIndex, SCH_SCREEN* aScreen )
944{
945 const LTSPICE_SCHEMATIC::RECTANGLE& lt_rect = aAscfile.Rectangles[aIndex];
946 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE );
947
948 rectangle->SetPosition( ToKicadCoords( lt_rect.TopLeft ) );
949 rectangle->SetEnd( ToKicadCoords( lt_rect.BotRight ) );
950 rectangle->SetStroke( getStroke( lt_rect.LineWidth, lt_rect.LineStyle ) );
951 rectangle->Move( m_originOffset );
952
953 aScreen->Append( rectangle );
954}
955
956
958 const LTSPICE_SCHEMATIC::LT_SYMBOL& aLTSymbol,
959 SCH_SCREEN* aScreen )
960{
961 SCH_SHEET* sch_sheet = new SCH_SHEET( aScreen->Schematic() );
962
964
965 SCH_FIELD* instNameField = sch_sheet->GetField( SCH_IO_LTSPICE_PARSER::LT_INSTNAME_FIELD );
966 SCH_FIELD* sheetNameField = sch_sheet->GetField( FIELD_T::SHEET_NAME );
967 SCH_FIELD* fileNameSheet = sch_sheet->GetField( FIELD_T::SHEET_FILENAME );
968
969 wxString instName = get_def( aLTSymbol.SymAttributes, wxS( "INSTNAME" ), wxS( "_" ) );
970 wxString sanitizedName = aLTSymbol.Name;
971
972 ReplaceIllegalFileNameChars( sanitizedName, '_' );
973
974 wxString sheetName = sanitizedName + ':' + instName;
975
976 instNameField->SetText( instName );
977 instNameField->SetVisible( false );
978
979 sheetNameField->SetText( sheetName );
980 sheetNameField->SetVisible( false );
981
982 fileNameSheet->SetText( m_lt_schematic->GetSchematicFileName( aLTSymbol.AsyKey ) );
983 fileNameSheet->SetVisible( false );
984
985 BOX2I bboxLT;
986
987 for( const LTSPICE_SCHEMATIC::LT_PIN& pin : aLTSymbol.Pins )
988 {
989 bboxLT.Merge( RotateMirror( aLTSymbol, pin.PinLocation ) );
990 }
991
992 for( const LTSPICE_SCHEMATIC::RECTANGLE& rect : aLTSymbol.Rectangles )
993 {
994 bboxLT.Merge( RotateMirror( aLTSymbol, rect.TopLeft ) );
995 bboxLT.Merge( RotateMirror( aLTSymbol, rect.BotRight ) );
996 }
997
998 for( const LTSPICE_SCHEMATIC::CIRCLE& circle : aLTSymbol.Circles )
999 {
1000 bboxLT.Merge( RotateMirror( aLTSymbol, circle.TopLeft ) );
1001 bboxLT.Merge( RotateMirror( aLTSymbol, circle.BotRight ) );
1002 }
1003
1004 for( const LTSPICE_SCHEMATIC::ARC& arc : aLTSymbol.Arcs )
1005 {
1006 bboxLT.Merge( RotateMirror( aLTSymbol, arc.TopLeft ) );
1007 bboxLT.Merge( RotateMirror( aLTSymbol, arc.BotRight ) );
1008 }
1009
1010 for( const LTSPICE_SCHEMATIC::LINE& line : aLTSymbol.Lines )
1011 {
1012 bboxLT.Merge( RotateMirror( aLTSymbol, line.Start ) );
1013 bboxLT.Merge( RotateMirror( aLTSymbol, line.End ) );
1014 }
1015
1016 if( bboxLT.GetWidth() == 0 )
1017 bboxLT.Inflate( 16, 0 );
1018
1019 if( bboxLT.GetHeight() == 0 )
1020 bboxLT.Inflate( 0, 16 );
1021
1022 sch_sheet->SetPosition( ToKicadCoords( aLTSymbol.Offset + bboxLT.GetOrigin() ) + m_originOffset );
1023 sch_sheet->SetSize( ToKicadCoords( bboxLT.GetSize() ) );
1024 sch_sheet->SetBorderWidth( schIUScale.MilsToIU( 1 ) );
1025
1026 for( const LTSPICE_SCHEMATIC::LT_PIN& pin : aLTSymbol.Pins )
1027 {
1028 wxString name = get_def( pin.PinAttribute, wxS( "PinName" ) );
1029 VECTOR2I absPinPosLT = aLTSymbol.Offset + RotateMirror( aLTSymbol, pin.PinLocation );
1030
1031 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sch_sheet, absPinPosLT, name );
1032
1033 if( pin.PinJustification != LTSPICE_SCHEMATIC::JUSTIFICATION::NONE )
1034 sheetPin->SetSchTextSize( schIUScale.MilsToIU( 40 ) ); // Match LTspice size
1035 else
1036 sheetPin->SetSchTextSize( schIUScale.MilsToIU( 10 ) ); // Supposed to be invisible
1037
1038 sheetPin->ConstrainOnEdge( ToKicadCoords( absPinPosLT ) + m_originOffset, true );
1039 sch_sheet->AddPin( sheetPin );
1040
1041 VECTOR2I absPinPosNewLT = ToLtSpiceCoords( sheetPin->GetPosition() - m_originOffset );
1042
1043 // Reconnect wires/iopins/flags to the sheet pin
1044 for( LTSPICE_SCHEMATIC::WIRE& wire : aAscfile.Wires )
1045 {
1046 if( wire.Start == absPinPosLT )
1047 wire.Start = absPinPosNewLT;
1048 if( wire.End == absPinPosLT )
1049 wire.End = absPinPosNewLT;
1050 }
1051
1052 for( LTSPICE_SCHEMATIC::IOPIN& iopin : aAscfile.Iopins )
1053 {
1054 if( iopin.Location == absPinPosLT )
1055 iopin.Location = absPinPosNewLT;
1056 }
1057
1058 for( LTSPICE_SCHEMATIC::FLAG& flag : aAscfile.Flags )
1059 {
1060 if( flag.Offset == absPinPosLT )
1061 flag.Offset = absPinPosNewLT;
1062 }
1063 }
1064
1065 aScreen->Append( sch_sheet );
1066
1067 return sch_sheet;
1068}
1069
1070
1072{
1073 if( aLineWidth == LTSPICE_SCHEMATIC::LINEWIDTH::Normal )
1074 return schIUScale.MilsToIU( 6 );
1075 else if( aLineWidth == LTSPICE_SCHEMATIC::LINEWIDTH::Wide )
1076 return schIUScale.MilsToIU( 12 );
1077 else
1078 return schIUScale.MilsToIU( 6 );
1079}
1080
1081
1094
1095
1097 const LTSPICE_SCHEMATIC::LINESTYLE& aLineStyle )
1098{
1099 return STROKE_PARAMS( getLineWidth( aLineWidth ), getLineStyle( aLineStyle ) );
1100}
1101
1102
1104 LTSPICE_SCHEMATIC::JUSTIFICATION aJustification )
1105{
1106 switch( aJustification )
1107 {
1109 aText->SetVisible( false );
1110 break;
1111
1116 break;
1117
1122 break;
1123
1128 break;
1129
1134 break;
1135
1140 break;
1141
1142 default: break;
1143 }
1144
1145 switch( aJustification )
1146 {
1153 break;
1154
1160 aText->SetTextAngle( ANGLE_VERTICAL );
1161 break;
1162
1163 default: break;
1164 }
1165
1166 // Center, Left, Right aligns by first line in multiline text
1167 if( wxSplit( aText->GetText(), '\n', '\0' ).size() > 1 )
1168 {
1169 switch( aJustification )
1170 {
1175 aText->Offset( VECTOR2I( 0, -aText->GetTextHeight() / 2 ) );
1176 break;
1177
1182 aText->Offset( VECTOR2I( -aText->GetTextHeight() / 2, 0 ) );
1183 break;
1184
1185 default: break;
1186 }
1187 }
1188}
1189
1190
1191SCH_TEXT* SCH_IO_LTSPICE_PARSER::CreateSCH_TEXT( const VECTOR2I& aOffset, const wxString& aText, int aFontSize,
1192 LTSPICE_SCHEMATIC::JUSTIFICATION aJustification )
1193{
1194 VECTOR2I pos = ToKicadCoords( aOffset ) + m_originOffset;
1195 SCH_TEXT* textItem = new SCH_TEXT( pos, aText );
1196
1197 textItem->SetTextSize( ToKicadFontSize( aFontSize ) );
1198 textItem->SetVisible( true );
1199 textItem->SetMultilineAllowed( true );
1200
1201 setTextJustification( textItem, aJustification );
1202
1203 return textItem;
1204}
1205
1206
1208 SCH_LAYER_ID aLayer )
1209{
1210 SCH_LINE* segment = new SCH_LINE();
1211
1213 segment->SetLineStyle( LINE_STYLE::SOLID );
1214 segment->SetLayer( aLayer );
1215
1216 segment->SetStartPoint( ToKicadCoords( aAscfile.Wires[aIndex].Start ) + m_originOffset );
1217 segment->SetEndPoint( ToKicadCoords( aAscfile.Wires[aIndex].End ) + m_originOffset );
1218
1219 aScreen->Append( segment );
1220}
1221
1222
1223SCH_SYMBOL* SCH_IO_LTSPICE_PARSER::CreatePowerSymbol( const VECTOR2I& aOffset, const wxString& aValue, int aFontSize,
1224 SCH_SCREEN* aScreen,
1225 std::vector<LTSPICE_SCHEMATIC::WIRE>& aWires )
1226{
1227 LIB_SYMBOL* lib_symbol = new LIB_SYMBOL( wxS( "GND" ) );
1229
1230 shape->AddPoint( ToKicadCoords( { 16, 0 } ) );
1231 shape->AddPoint( ToKicadCoords( { -16, 0 } ) );
1232 shape->AddPoint( ToKicadCoords( { 0, 15 } ) );
1233 shape->AddPoint( ToKicadCoords( { 16, 0 } ) );
1234 shape->AddPoint( ToKicadCoords( { -16, 0 } ) );
1235 shape->AddPoint( ToKicadCoords( { 0, 15 } ) );
1236
1238
1239 lib_symbol->AddDrawItem( shape );
1240 lib_symbol->SetGlobalPower();
1241
1242 SCH_PIN* pin = new SCH_PIN( lib_symbol );
1243
1245 pin->SetPosition( ToKicadCoords( { 0, 0 } ) );
1246 pin->SetLength( 5 );
1247 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1248 lib_symbol->AddDrawItem( pin );
1249
1250 LIB_ID libId( wxS( "ltspice" ), wxS( "GND" ) );
1251 SCH_SYMBOL* sch_symbol = new SCH_SYMBOL( *lib_symbol, libId, nullptr, 1 );
1252
1253 sch_symbol->GetField( FIELD_T::REFERENCE )->SetText( wxString::Format( wxS( "#GND%03d" ), m_powerSymbolIndex++ ) );
1254 sch_symbol->GetField( FIELD_T::REFERENCE )->SetVisible( false );
1255 sch_symbol->SetValueFieldText( wxS( "0" ) );
1256 sch_symbol->GetField( FIELD_T::VALUE )->SetTextSize( ToKicadFontSize( aFontSize ) );
1257 sch_symbol->GetField( FIELD_T::VALUE )->SetVisible( false );
1258
1259 VECTOR2I pos = ToKicadCoords( aOffset ) + m_originOffset;
1260 sch_symbol->Move( pos );
1261
1262 switch( autoLabelOrientation( aScreen, pos, SPIN_STYLE::BOTTOM ) )
1263 {
1264 case SPIN_STYLE::BOTTOM: sch_symbol->SetOrientation( SYM_ORIENT_0 ); break;
1265 case SPIN_STYLE::RIGHT: sch_symbol->SetOrientation( SYM_ORIENT_90 ); break;
1266 case SPIN_STYLE::UP: sch_symbol->SetOrientation( SYM_ORIENT_180 ); break;
1267 case SPIN_STYLE::LEFT: sch_symbol->SetOrientation( SYM_ORIENT_270 ); break;
1268 default: break;
1269 }
1270
1271 return sch_symbol;
1272}
1273
1274
1275SCH_LABEL_BASE* SCH_IO_LTSPICE_PARSER::CreateSCH_LABEL( KICAD_T aType, const VECTOR2I& aOffset, const wxString& aValue,
1276 int aFontSize, SCH_SCREEN* aScreen )
1277{
1278 SCH_LABEL_BASE* label = nullptr;
1279
1280 if( aType == SCH_LABEL_T )
1281 {
1282 label = new SCH_LABEL();
1283
1284 label->SetText( aValue );
1285 label->SetTextSize( ToKicadFontSize( aFontSize ) );
1286 }
1287 else
1288 if( aType == SCH_GLOBAL_LABEL_T )
1289 {
1290 label = new SCH_GLOBALLABEL();
1291
1292 label->SetText( aValue );
1293 label->SetTextSize( ToKicadFontSize( aFontSize ) );
1294 }
1295 else if( aType == SCH_DIRECTIVE_LABEL_T )
1296 {
1297 label = new SCH_DIRECTIVE_LABEL();
1298
1300
1301 SCH_FIELD field( label, FIELD_T::USER, wxS( "DATAFLAG" ) );
1302 field.SetText( aValue );
1303 field.SetTextSize( ToKicadFontSize( aFontSize ) );
1304 field.SetVisible( true );
1305
1306 label->AddField( field );
1307 }
1308 else
1309 {
1310 UNIMPLEMENTED_FOR( wxString::Format( wxT( "Type not supported %d" ), (int)aType ) );
1311 }
1312
1313 if( label )
1314 {
1315 label->SetPosition( ToKicadCoords( aOffset ) + m_originOffset );
1316 label->SetSpinStyle( autoLabelOrientation( aScreen, label->GetPosition(), SPIN_STYLE::RIGHT ) );
1317 label->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
1318 label->SetVisible( true );
1319 }
1320
1321 return label;
1322}
1323
1324
1326{
1327 wxString symbolName = aLTSymbol.Name.Upper();
1328 wxString type = get_def( aLTSymbol.SymAttributes, wxS( "TYPE" ) ).Upper();
1329 wxString prefix = get_def( aLTSymbol.SymAttributes, wxS( "PREFIX" ) ).Upper();
1330 wxString instName = get_def( aLTSymbol.SymAttributes, wxS( "INSTNAME" ) ).Upper();
1331 wxString value = get_def( aLTSymbol.SymAttributes, wxS( "VALUE" ) );
1332 wxString value2 = get_def( aLTSymbol.SymAttributes, wxS( "VALUE2" ) );
1333
1334 if( value.IsEmpty() )
1335 {
1336 value = value2;
1337 value2 = wxEmptyString;
1338 }
1339
1340 auto addField =
1341 [&]( const wxString& aFieldName, const wxString& aFieldValue )
1342 {
1343 SCH_FIELD newField( aSymbol, FIELD_T::USER, aFieldName );
1344 newField.SetVisible( false );
1345 newField.SetText( aFieldValue );
1346 aSymbol->AddField( newField );
1347 };
1348
1349
1350 auto setupNonInferredPassive =
1351 [&]( const wxString& aDevice, const wxString& aValueKey )
1352 {
1353 addField( wxS( "Sim.Device" ), aDevice );
1354 addField( wxS( "Sim.Params" ), aValueKey + wxS( "=${VALUE}" ) );
1355 };
1356
1357 auto setupBehavioral =
1358 [&]( const wxString& aDevice, const wxString& aType )
1359 {
1360 aSymbol->SetValueFieldText( wxS( "${Sim.Params}" ) );
1361
1362 addField( wxS( "Sim.Device" ), aDevice );
1363 addField( wxS( "Sim.Type" ), aType );
1364 addField( wxS( "Sim.Params" ), value );
1365 };
1366
1367 static const std::set<wxString> prefixWithGain = { wxS( "E" ), wxS( "F" ), wxS( "G" ), wxS( "H" ) };
1368
1369 if( prefix == wxS( "R" ) )
1370 {
1371 setupNonInferredPassive( prefix, wxS( "R" ) );
1372 }
1373 else if( prefix == wxS( "C" ) )
1374 {
1375 setupNonInferredPassive( prefix, wxS( "C" ) );
1376 }
1377 else if( prefix == wxS( "L" ) )
1378 {
1379 setupNonInferredPassive( prefix, wxS( "L" ) );
1380 }
1381 else if( prefixWithGain.count( prefix ) > 0 )
1382 {
1383 setupNonInferredPassive( prefix, wxS( "gain" ) );
1384 }
1385 else if( prefix == wxS( "B" ) )
1386 {
1387 if( symbolName.StartsWith( wxS( "BV" ) ) )
1388 setupBehavioral( wxS( "V" ), wxS( "=" ) );
1389 else if( symbolName.StartsWith( wxS( "BI" ) ) )
1390 setupBehavioral( wxS( "I" ), wxS( "=" ) );
1391 }
1392 else if( prefix == wxS( "T" ) )
1393 {
1394 aSymbol->SetValueFieldText( wxS( "${Sim.Params}" ) );
1395
1396 addField( wxS( "Sim.Device" ), wxS( "TLINE" ) );
1397 addField( wxS( "Sim.Params" ), value );
1398 }
1399 else if( prefix == wxS( "V" ) || symbolName == wxS( "I" ) )
1400 {
1401 addField( wxS( "Sim.Device" ), wxS( "SPICE" ) );
1402
1403 wxString simParams;
1404 wxString pwlArgs;
1405 wxString upperValue = value.Upper();
1406
1407 if( upperValue.StartsWith( wxS( "PWL " ) ) && upperValue.Contains( wxS( "FILE=" ) ) )
1408 {
1409 // TODO: support REPEAT statements
1410
1411 // Take the arguments from the original text so the data file path keeps its case
1412 pwlArgs = value.Mid( 4 );
1413
1414 if( !value2.IsEmpty() )
1415 pwlArgs << wxS( " " ) << value2;
1416
1417 pwlArgs.Trim( true ).Trim( false );
1418
1419 std::vector<wxString> ltspiceArgs = tokenizeQuoted( pwlArgs );
1420 std::vector<wxString> ngspiceArgs;
1421 wxString fileRef;
1422
1423 for( wxString& arg : ltspiceArgs )
1424 {
1425 wxString argValue;
1426 wxString argKey = arg.BeforeFirst( '=', &argValue );
1427
1428 // Unquote the arg value
1429 if( argValue.length() >= 2 && argValue.StartsWith( wxS( "\"" ) ) && argValue.EndsWith( wxS( "\"" ) ) )
1430 argValue = argValue.Mid( 1, argValue.length() - 2 );
1431
1432 if( argKey.Upper() == wxS( "FILE" ) )
1433 {
1434 wxString fileValue = argValue;
1435
1436 if( fileValue.IsEmpty() )
1437 continue;
1438
1439 // Convert the data file to ngspice format
1440 wxFileName sourceFile( fileValue );
1441
1442 wxString sanitizedName = sourceFile.GetName();
1443 sanitizedName.MakeLower();
1444 sanitizedName.Replace( wxS( " " ), wxS( "_" ) );
1445
1446 wxFileName convertedFile = sourceFile;
1447 convertedFile.SetName( sanitizedName + wxS( "_ngspice" ) );
1448 convertedFile.SetExt( sourceFile.GetExt().Lower() );
1449
1450 if( sourceFile.FileExists() )
1451 {
1452 if( !convertPwlFileToNgspice( sourceFile, convertedFile ) )
1453 {
1454 wxLogWarning( wxS( "Failed to convert PWL data file to ngspice format: " )
1455 + sourceFile.GetFullPath() );
1456 }
1457 }
1458
1459 // Avoid \\ escape issues in Sim.Params quoted values.
1460 fileRef = convertedFile.GetFullPath();
1461 fileRef.Replace( wxS( "\\" ), wxS( "/" ) );
1462 }
1463 }
1464
1465 // Use a subcircuit instance for the PWL data file
1466 prefix = "X";
1467 value2 = "";
1468 value = wxS( "pwl_file file=\\\"" ) + fileRef + wxS( "\\\" timerelative=1" );
1469 }
1470
1471 simParams << "type=" << '"' << prefix << '"' << ' ';
1472
1473 if( value2.IsEmpty() )
1474 simParams << "model=" << '"' << "${VALUE}" << '"' << ' ';
1475 else
1476 simParams << "model=" << '"' << "${VALUE} ${VALUE2}" << '"' << ' ';
1477
1478 addField( wxS( "Sim.Params" ), simParams );
1479 }
1480 else
1481 {
1482 wxString libFile = get_def( aLTSymbol.SymAttributes, wxS( "MODELFILE" ) );
1483
1484 if( prefix == wxS( "X" ) )
1485 {
1486 // A prefix of X overrides the simulation model for other symbols (npn, etc.)
1487 type = wxS( "X" );
1488 }
1489 else if( libFile.IsEmpty() )
1490 {
1491 if( type.IsEmpty() )
1492 type = symbolName;
1493 }
1494
1495 if( !libFile.IsEmpty() )
1496 {
1497 addField( wxS( "Sim.Library" ), libFile );
1498 addField( wxS( "Sim.Name" ), symbolName );
1499 }
1500
1501 wxString spiceLine = get_def( aLTSymbol.SymAttributes, wxS( "SPICELINE" ) );
1502
1503 if( type == wxS( "X" ) )
1504 {
1505 addField( wxS( "Sim.Device" ), wxS( "SUBCKT" ) );
1506
1507 if( !spiceLine.IsEmpty() )
1508 addField( wxS( "Sim.Params" ), spiceLine );
1509 }
1510 else
1511 {
1512 addField( wxS( "Sim.Device" ), wxS( "SPICE" ) );
1513
1514 if( !spiceLine.IsEmpty() )
1515 addField( wxS( "Sim.Params" ), spiceLine );
1516 else
1517 addField( wxS( "Sim.Params" ), "model=\"" + value + "\"" );
1518 }
1519 }
1520
1521 // Set this at the end, as we may have changed the variables
1522 aSymbol->GetField( FIELD_T::REFERENCE )->SetText( instName );
1523 aSymbol->SetValueFieldText( value );
1524
1525 if( !value2.IsEmpty() )
1526 addField( wxS( "Value2" ), value2 );
1527
1528 for( const LTSPICE_SCHEMATIC::LT_WINDOW& lt_window : aLTSymbol.Windows )
1529 {
1530 SCH_FIELD* field = nullptr;
1531
1532 switch( lt_window.WindowNumber )
1533 {
1534 case -1: /* PartNum */ break;
1535 case 0: /* InstName */ field = aSymbol->GetField( FIELD_T::REFERENCE ); break;
1536 case 1: /* Type */ break;
1537 case 2: /* RefName */ break;
1538 case 3: /* Value */ field = aSymbol->GetField( FIELD_T::VALUE ); break;
1539
1540 case 5: /* QArea */ break;
1541
1542 case 8: /* Width */ break;
1543 case 9: /* Length */ break;
1544 case 10: /* Multi */ break;
1545
1546 case 16: /* Nec */ break;
1547
1548 case 38: /* SpiceModel */ field = aSymbol->GetField( wxS( "Sim.Name" ) ); break;
1549 case 39: /* SpiceLine */ field = aSymbol->GetField( wxS( "Sim.Params" ) ); break;
1550 case 40: /* SpiceLine2 */ break;
1551
1552 /*
1553 47 Def_Sub
1554
1555 50 Digital_Timing_Model
1556 51 Digital_Extracts
1557 52 Digital_IO_Model
1558 53 Digital_Line
1559 54 Digital_Primitive
1560 55 Digital_MNTYMXDLY
1561 56 Digital_IO_LEVEL
1562 57 Digital_StdCell
1563 58 Digital_File
1564
1565 105 Cell
1566 106 W/L
1567 107 PSIZE
1568 108 NSIZE
1569 109 sheets
1570 110 sh#
1571 111 Em_Scale
1572 112 Epi
1573 113 Sinker
1574 114 Multi5
1575
1576 118 AQ
1577 119 AQSUB
1578 120 ZSIZE
1579 121 ESR
1580 123 Value2
1581 124 COUPLE
1582 125 Voltage
1583 126 Area1
1584 127 Area2
1585 128 Area3
1586 129 Area4
1587 130 Multi1
1588 131 Multi2
1589 132 Multi3
1590 133 Multi4
1591 134 DArea
1592 135 DPerim
1593 136 CArea
1594 137 CPerim
1595 138 Shrink
1596 139 Gate_Resize
1597
1598 142 BP
1599 143 BN
1600 144 Sim_Level
1601
1602 146 G_Voltage
1603
1604 150 SpiceLine3
1605
1606 153 D_VOLTAGES
1607
1608 156 Version
1609 157 Comment
1610 158 XDef_Sub
1611 159 LVS_Area
1612
1613 162 User1
1614 163 User2
1615 164 User3
1616 165 User4
1617 166 User5
1618 167 Root
1619 168 Class
1620 169 Geometry
1621 170 WL_Delimiter
1622
1623 175 T1
1624 176 T2
1625
1626 184 DsgnName
1627 185 Designer
1628
1629 190 RTN
1630 191 PWR
1631 192 BW
1632
1633 201 CAPROWS
1634 202 CAPCOLS
1635 203 NF
1636 204 SLICES
1637 205 CUR
1638 206 TEMPRISE
1639 207 STRIPS
1640 208 WEM
1641 209 LEM
1642 210 BASES
1643 211 COLS
1644 212 XDef_Tub
1645 */
1646 default: break;
1647 }
1648
1649 if( field )
1650 {
1651 field->SetPosition( ToKicadCoords( lt_window.Position ) );
1652 field->SetTextSize( ToKicadFontSize( lt_window.FontSize ) );
1653
1655 field->SetVisible( false );
1656
1657 setTextJustification( field, lt_window.Justification );
1658 }
1659 }
1660}
1661
1662
1664 SCH_SHAPE* aRectangle )
1665{
1666 const LTSPICE_SCHEMATIC::RECTANGLE& lt_rect = aLTSymbol.Rectangles[aIndex];
1667
1668 aRectangle->SetPosition( ToKicadCoords( lt_rect.BotRight ) );
1669 aRectangle->SetEnd( ToKicadCoords( lt_rect.TopLeft ) );
1670 aRectangle->SetStroke( getStroke( lt_rect.LineWidth, lt_rect.LineStyle ) );
1671
1672 if( get_def( aLTSymbol.SymAttributes, wxS( "PREFIX" ) ) == wxS( "X" ) )
1674}
1675
1676
1678{
1679 const LTSPICE_SCHEMATIC::LT_PIN& lt_pin = aLTSymbol.Pins[aIndex];
1680 wxString device = aLTSymbol.Name.Lower();
1681
1682 if( aLTSymbol.Pins.size() == 2 && ( device == wxS( "res" )
1683 || device == wxS( "cap" )
1684 || device == wxS( "ind" ) ) )
1685 {
1686 // drop A/B pin names from simple LRCs as they're not terribly useful (and prevent
1687 // other pin names on the net from driving the net name).
1688 }
1689 else
1690 {
1691 aPin->SetName( get_def( lt_pin.PinAttribute, wxS( "PinName" ) ) );
1692
1694 aPin->SetNameTextSize( 0 );
1695 }
1696
1697 aPin->SetNumber( wxString::Format( wxS( "%d" ), aIndex + 1 ) );
1698
1699 // Prefer LTspice SpiceOrder for pin numbers
1700 wxString spiceOrder = get_def( lt_pin.PinAttribute, wxS( "SpiceOrder" ) );
1701 long spiceOrderNum = 0;
1702
1703 if( spiceOrder.ToLong( &spiceOrderNum ) && spiceOrderNum > 0 )
1704 aPin->SetNumber( wxString::Format( wxS( "%ld" ), spiceOrderNum ) );
1705
1708 aPin->SetPosition( ToKicadCoords( lt_pin.PinLocation ) );
1709
1710 int pinLen = std::max( schIUScale.MilsToIU( 10 ), ToKicadCoords( lt_pin.NameOffSet - 8 ) );
1711 aPin->SetLength( pinLen );
1712
1713 switch( lt_pin.PinJustification )
1714 {
1718 break;
1719
1723 break;
1724
1728 break;
1729
1733 break;
1734
1735 default:
1736 // Auto-detect based on connected lines
1737 for( const LTSPICE_SCHEMATIC::LINE& line : aLTSymbol.Lines )
1738 {
1739 BOX2I bbox;
1740 bbox.Merge( line.Start );
1741 bbox.Merge( line.End );
1742
1743 if( bbox.GetWidth() >= bbox.GetHeight() ) // Mostly horizontal
1744 {
1745 if( lt_pin.PinLocation == bbox.GetOrigin() )
1747 else if( lt_pin.PinLocation == bbox.GetEnd() )
1749 }
1750 else // Mostly vertical
1751 {
1752 if( lt_pin.PinLocation == bbox.GetOrigin() )
1754 else if( lt_pin.PinLocation == bbox.GetEnd() )
1756 }
1757 }
1758 }
1759}
1760
1761
1763{
1764 const LTSPICE_SCHEMATIC::ARC& lt_arc = aLTSymbol.Arcs[aIndex];
1765
1766 aArc->SetCenter( ToKicadCoords( ( lt_arc.TopLeft + lt_arc.BotRight ) / 2 ) );
1767 aArc->SetStart( ToKicadCoords( lt_arc.ArcEnd ) );
1768 aArc->SetEnd( ToKicadCoords( lt_arc.ArcStart ) );
1769 aArc->SetStroke( getStroke( lt_arc.LineWidth, lt_arc.LineStyle ) );
1770}
1771
1772
1774 SCH_SHAPE* aCircle )
1775{
1776 const LTSPICE_SCHEMATIC::CIRCLE& lt_circle = aLTSymbol.Circles[aIndex];
1777
1778 VECTOR2I c = ( lt_circle.TopLeft + lt_circle.BotRight ) / 2;
1779 int r = ( lt_circle.TopLeft.x - lt_circle.BotRight.x ) / 2;
1780
1781 aCircle->SetPosition( ToKicadCoords( c ) );
1782 aCircle->SetEnd( ToKicadCoords( c ) + VECTOR2I( abs( ToKicadCoords( r ) ), 0 ) );
1783 aCircle->SetStroke( getStroke( lt_circle.LineWidth, lt_circle.LineStyle ) );
1784}
1785
1786
1788{
1789 const LTSPICE_SCHEMATIC::TEXT& lt_text = aLTSymbol.Texts[aIndex];
1790
1791 aText->SetText( lt_text.Value );
1792 aText->SetPosition( ToKicadCoords( lt_text.Offset ) );
1793 aText->SetTextSize( ToKicadFontSize( lt_text.FontSize ) );
1794 aText->SetVisible( true );
1795
1796 setTextJustification( aText, lt_text.Justification );
1797}
1798
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:337
virtual void SetCenter(const VECTOR2I &aCenter)
void SetFillMode(FILL_T aFill)
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:287
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:512
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual int GetTextHeight() const
Definition eda_text.h:307
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
virtual void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:575
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:268
void SetMultilineAllowed(bool aAllow)
Definition eda_text.cpp:362
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
Define a library symbol object.
Definition lib_symbol.h:114
void SetGlobalPower()
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
POLARITY
Polarity enum represents polarity of pin.
JUSTIFICATION
Defines in what ways the PIN or TEXT can be justified.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:276
Holds all the data relating to one schematic.
Definition schematic.h:149
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:171
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
void SetSize(const VECTOR2I &aSize)
Class for a wire to bus entry.
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aBodyStyle=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
int ToLtSpiceCoords(int aCoordinate)
Method converts kicad coordinate(i.e scale) to ltspice coordinates.
void CreateKicadSymbolsAndSubsheets(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, SCH_SCREEN *aScreen, const std::vector< wxString > &aUniqueAscNames, std::map< wxString, SCH_SCREEN * > &aMapOfScreens)
Create KiCad symbol objects and subsheets from ASC data.
void setTextJustification(EDA_TEXT *aText, LTSPICE_SCHEMATIC::JUSTIFICATION aJustification)
SCH_TEXT * CreateSCH_TEXT(const VECTOR2I &aOffset, const wxString &aText, int aFontSize, LTSPICE_SCHEMATIC::JUSTIFICATION aJustification)
Create schematic text.
STROKE_PARAMS getStroke(const LTSPICE_SCHEMATIC::LINEWIDTH &aLineWidth, const LTSPICE_SCHEMATIC::LINESTYLE &aLineStyle)
void CreateSymArc(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_SHAPE *aArc)
Create a symbol arc from LTspice symbol data.
int getLineWidth(const LTSPICE_SCHEMATIC::LINEWIDTH &aLineWidth)
void AddAscLine(const LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic line from ASC data.
void CreateKicadSCH_ITEMs(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, SCH_SCREEN *aScreen)
Create schematic items from ASC data.
VECTOR2I RotateMirror(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, const VECTOR2I &aPoint)
Rotate and mirror a point according to LTspice symbol flags.
void CreateSymText(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_TEXT *aText)
Create a symbol text from LTspice symbol data.
void AddSymFields(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, SCH_SYMBOL *aSymbol)
Create and configure symbol fields from LTspice symbol data.
SCH_LABEL_BASE * CreateSCH_LABEL(KICAD_T aType, const VECTOR2I &aOffset, const wxString &aValue, int aFontSize, SCH_SCREEN *aScreen)
Create a schematic label.
void AssignSymOrientation(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, SCH_SYMBOL *aSchSymbol)
Set KiCad symbol orientation based on LTspice symbol orientation.
void AddAscIopin(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic I/O pin from ASC data.
void AddAscRect(const LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic rectangle from ASC data.
void AddAscArc(const LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic arc from ASC data.
SCH_SYMBOL * CreatePowerSymbol(const VECTOR2I &aOffset, const wxString &aValue, int aFontSize, SCH_SCREEN *aScreen, std::vector< LTSPICE_SCHEMATIC::WIRE > &aWires)
Create a power symbol for the schematic.
LINE_STYLE getLineStyle(const LTSPICE_SCHEMATIC::LINESTYLE &aLineStyle)
void CreateSymRect(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_SHAPE *aRectangle)
Create a symbol rectangle from LTspice symbol data.
void AddAscBusEntry(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic bus tap from ASC data.
LTSPICE_SCHEMATIC * m_lt_schematic
void CreateSymCircle(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_SHAPE *aCircle)
Create a symbol circle from LTspice symbol data.
void RotateMirrorItem(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, SCH_ITEM *aItem)
Rotate and mirror an item according to LTspice symbol flags.
static constexpr const wxChar * LT_INSTNAME_FIELD
int ToKicadCoords(int aCoordinate)
Method converts ltspice coordinate(i.e scale) to kicad coordinates.
void CreateSymPin(const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_PIN *aPin)
Create a symbol pin from LTspice symbol data.
void CreateSymLine(LIB_SYMBOL *aSymbol, const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, int aIndex, SCH_SHAPE *aShape)
Create a library-symbol line from LTspice symbol data.
void AddAscCircle(const LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen)
Create a schematic circle from ASC data.
void CreateItems(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, SCH_SCREEN *aScreen, const std::vector< wxString > &aUniqueAscNames, std::map< wxString, SCH_SCREEN * > &aMapOfScreens, VECTOR2I aOriginOffset)
Create KiCad items based on LTspice data.
SCH_SHEET * AddAscSymAsSubsheet(LTSPICE_SCHEMATIC::LT_ASC &aAscfile, const LTSPICE_SCHEMATIC::LT_SYMBOL &aLTSymbol, SCH_SCREEN *aScreen)
VECTOR2I ToKicadFontSize(int aLTFontSize)
void CreateSymbol(LTSPICE_SCHEMATIC::LT_SYMBOL &aLtSymbol, LIB_SYMBOL *aLibSymbol)
Create a library symbol from LTspice symbol data.
void AddAscWire(const LTSPICE_SCHEMATIC::LT_ASC &aAscfile, int aIndex, SCH_SCREEN *aScreen, SCH_LAYER_ID aLayer)
Create a schematic wire from ASC data.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:430
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:354
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:446
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:438
void AddField(const SCH_FIELD &aField)
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:179
void SetPosition(const VECTOR2I &aPosition) override
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void SetStartPoint(const VECTOR2I &aPosition)
Definition sch_line.h:137
void SetLineWidth(const int aSize)
Definition sch_line.cpp:438
void SetLineStyle(const LINE_STYLE aStyle)
Definition sch_line.cpp:409
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition sch_line.cpp:247
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_line.h:199
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:842
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:113
void SetName(const wxString &aName)
Definition sch_pin.cpp:545
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:318
void SetLength(int aLength)
Definition sch_pin.h:119
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:116
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:455
void SetNameTextSize(int aSize)
Definition sch_pin.cpp:870
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
SCHEMATIC * Schematic() const
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:89
void Move(const VECTOR2I &aOffset) override
Move the item by aMoveVector to a new position.
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:98
void AddPoint(const VECTOR2I &aPosition)
Define a sheet pin (label) used in sheets to create hierarchical schematics.
void ConstrainOnEdge(const VECTOR2I &aPos, bool aAllowEdgeSwitch)
Adjust label position to edge based on proximity to vertical or horizontal edge of the parent sheet.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetSize(const VECTOR2I &aSize)
Definition sch_sheet.h:154
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetPosition(const VECTOR2I &aPosition) override
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
void SetBorderWidth(int aWidth)
Definition sch_sheet.h:157
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add aFieldName to the list of fields.
Schematic symbol object.
Definition sch_symbol.h:75
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition sch_symbol.h:802
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
VECTOR2I GetPosition() const override
Definition sch_text.h:143
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_text.h:144
void SetSchTextSize(int aSize)
Definition sch_text.h:74
Helper class to handle Spice way of expressing values (e.g. 10.5 Meg)
Definition spice_value.h:51
wxString ToSpiceString() const
Return string value in Spice format (e.g.
double ToDouble() const
Spin style for labels of all kinds on schematics.
Definition sch_label.h:38
Simple container to manage line stroke parameters.
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:174
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:445
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:444
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
@ FILLED_WITH_BG_BODYCOLOR
Definition eda_fill.h:32
#define IS_NEW
New item, just created.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:477
@ LAYER_DEVICE
Definition layer_ids.h:494
@ LAYER_WIRE
Definition layer_ids.h:480
@ LAYER_NOTES
Definition layer_ids.h:495
@ LAYER_BUS
Definition layer_ids.h:481
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
wxString get_def(const std::map< wxString, wxString > &aMap, const char *aKey, const char *aDefval="")
Definition map_helpers.h:60
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:123
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:107
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:114
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:131
static wxString convertLtSpiceTextToNgspice(const wxString &aText)
static std::vector< wxString > tokenizeQuoted(const wxString &aText)
Parses the datastructure produced by the LTSPICE_SCHEMATIC into a KiCad schematic file.
static bool convertPwlFileToNgspice(const wxFileName &aSourceFile, const wxFileName &aDestFile)
LABEL_FLAG_SHAPE getLabelShape(LTSPICE_SCHEMATIC::POLARITY aPolarity)
SPIN_STYLE autoLabelOrientation(SCH_SCREEN *aScreen, VECTOR2I aLabelPos, SPIN_STYLE aDefaultSpin)
@ AUTOPLACE_AUTO
Definition sch_item.h:75
LABEL_FLAG_SHAPE
Label and flag shapes used with text objects.
Definition sch_label.h:97
@ L_BIDI
Definition sch_label.h:100
@ L_UNSPECIFIED
Definition sch_label.h:102
@ L_OUTPUT
Definition sch_label.h:99
@ L_INPUT
Definition sch_label.h:98
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
LINE_STYLE
Dashed line types.
The ARC is represented inside a rectangle whose opposite site are given.
The CIRCLE is represented in Ltpsice inside a rectangle whose two opposite points and line style are ...
IOPIN is special contact on symbol used for IO operations.
A struct to hold .asc file definition.
std::vector< CIRCLE > Circles
std::vector< IOPIN > Iopins
std::vector< BUSTAP > Bustap
std::vector< LT_SYMBOL > Symbols
std::vector< DATAFLAG > DataFlags
std::vector< RECTANGLE > Rectangles
std::map< wxString, wxString > PinAttribute
A struct to hold SYMBOL definition.
std::map< wxString, wxString > SymAttributes
std::vector< RECTANGLE > Rectangles
std::vector< LT_WINDOW > Windows
std::vector< CIRCLE > Circles
A 4-sided polygon with opposite equal sides, used in representing shapes.
A metallic connection, used for transfer, between two points or pin.
@ SYM_ORIENT_270
Definition symbol.h:39
@ SYM_ROTATE_CLOCKWISE
Definition symbol.h:34
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition symbol.h:35
@ SYM_MIRROR_Y
Definition symbol.h:41
@ SYM_ORIENT_180
Definition symbol.h:38
@ SYM_MIRROR_X
Definition symbol.h:40
@ SYM_ORIENT_90
Definition symbol.h:37
@ SYM_ORIENT_0
Definition symbol.h:36
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_PIN * pin
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:167
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_SHEET_PIN_T
Definition typeinfo.h:170
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
@ SCH_PIN_T
Definition typeinfo.h:149
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition util.h:161
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708