KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_altium.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) 2020 Thomas Pointhuber <[email protected]>
5 * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <memory>
26
27#include "altium_parser_sch.h"
28#include <io/io_utils.h>
33
34#include <schematic.h>
35#include <project_sch.h>
38
39#include <lib_id.h>
40#include <sch_pin.h>
41#include <sch_bitmap.h>
42#include <sch_bus_entry.h>
43#include <sch_symbol.h>
44#include <sch_junction.h>
45#include <sch_line.h>
46#include <sch_shape.h>
47#include <sch_no_connect.h>
48#include <sch_screen.h>
49#include <sch_label.h>
50#include <sch_sheet.h>
51#include <sch_sheet_pin.h>
52#include <sch_textbox.h>
53
54#include <bezier_curves.h>
55#include <compoundfilereader.h>
56#include <geometry/ellipse.h>
57#include <string_utils.h>
58#include <sch_edit_frame.h>
60#include <wx/mstream.h>
61#include <wx/log.h>
62#include <wx/zstream.h>
63#include <wx/wfstream.h>
64#include <magic_enum.hpp>
65#include "sch_io_altium.h"
66
67// Harness port object itself does not contain color information about itself
68// It seems altium is drawing harness ports using these colors
69#define HARNESS_PORT_COLOR_DEFAULT_BACKGROUND COLOR4D( 0.92941176470588238, \
70 0.94901960784313721, \
71 0.98431372549019602, 1.0 )
72
73#define HARNESS_PORT_COLOR_DEFAULT_OUTLINE COLOR4D( 0.56078431372549020, \
74 0.61960784313725492, \
75 0.78823529411764703, 1.0 )
76
77
78static const VECTOR2I GetRelativePosition( const VECTOR2I& aPosition, const SCH_SYMBOL* aSymbol )
79{
81 return t.TransformCoordinate( aPosition - aSymbol->GetPosition() );
82}
83
84
85static const VECTOR2I GetLibEditPosition( const VECTOR2I& aPosition )
86{
87 return VECTOR2I( aPosition.x, -aPosition.y );
88}
89
90
92{
93 int red = color & 0x0000FF;
94 int green = ( color & 0x00FF00 ) >> 8;
95 int blue = ( color & 0xFF0000 ) >> 16;
96
97 return COLOR4D().FromCSSRGBA( red, green, blue, 1.0 );
98}
99
100
102{
103 switch( linestyle )
104 {
109 default: return LINE_STYLE::DEFAULT;
110 }
111}
112
113
114static void SetSchShapeLine( const ASCH_BORDER_INTERFACE& elem, SCH_SHAPE* shape )
115{
117 GetColorFromInt( elem.Color ) ) );
118}
119
120static void SetSchShapeFillAndColor( const ASCH_FILL_INTERFACE& elem, SCH_SHAPE* shape )
121{
122
123 if( !elem.IsSolid )
124 {
126 }
127 else
128 {
130 shape->SetFillColor( GetColorFromInt( elem.AreaColor ) );
131 }
132}
133
134
135static void SetLibShapeLine( const ASCH_BORDER_INTERFACE& elem, SCH_SHAPE* shape,
136 ALTIUM_SCH_RECORD aType )
137{
139 COLOR4D default_color;
140 COLOR4D alt_default_color = COLOR4D( PUREBLUE ); // PUREBLUE is used for many objects, so if
141 // it is used, we will assume that it should
142 // blend with the others
143 STROKE_PARAMS stroke;
144
145 switch( aType )
146 {
147 case ALTIUM_SCH_RECORD::ARC: default_color = COLOR4D( PUREBLUE ); break;
148 case ALTIUM_SCH_RECORD::BEZIER: default_color = COLOR4D( PURERED ); break;
149 case ALTIUM_SCH_RECORD::ELLIPSE: default_color = COLOR4D( PUREBLUE ); break;
150 case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC: default_color = COLOR4D( PUREBLUE ); break;
151 case ALTIUM_SCH_RECORD::LINE: default_color = COLOR4D( PUREBLUE ); break;
152 case ALTIUM_SCH_RECORD::POLYGON: default_color = COLOR4D( PUREBLUE ); break;
153 case ALTIUM_SCH_RECORD::POLYLINE: default_color = COLOR4D( BLACK ); break;
154 case ALTIUM_SCH_RECORD::RECTANGLE: default_color = COLOR4D( 0.5, 0, 0, 1.0 ); break;
155 case ALTIUM_SCH_RECORD::ROUND_RECTANGLE: default_color = COLOR4D( PUREBLUE ); break;
156 default: default_color = COLOR4D( PUREBLUE ); break;
157 }
158
159 if( color == default_color || color == alt_default_color )
161
163}
164
166 ALTIUM_SCH_RECORD aType, int aStrokeColor )
167{
168 COLOR4D bgcolor = GetColorFromInt( elem.AreaColor );
169 COLOR4D default_bgcolor;
170
171 switch (aType)
172 {
174 default_bgcolor = GetColorFromInt( 11599871 ); // Light Yellow
175 break;
176 default:
177 default_bgcolor = GetColorFromInt( 12632256 ); // Grey
178 break;
179 }
180
181 if( elem.IsTransparent )
182 bgcolor = bgcolor.WithAlpha( 0.5 );
183
184 if( !elem.IsSolid )
185 {
187 }
188 else if( elem.AreaColor == aStrokeColor )
189 {
190 bgcolor = shape->GetStroke().GetColor();
191
193 }
194 else if( bgcolor.WithAlpha( 1.0 ) == default_bgcolor )
195 {
197 }
198 else
199 {
201 }
202
203 shape->SetFillColor( bgcolor );
204
205 if( elem.AreaColor == aStrokeColor
206 && shape->GetStroke().GetWidth() == schIUScale.MilsToIU( 1 ) )
207 {
208 STROKE_PARAMS stroke = shape->GetStroke();
209 stroke.SetWidth( -1 );
210 shape->SetStroke( stroke );
211 }
212}
213
214
216 SCH_IO( wxS( "Altium" ) )
217{
218 m_isIntLib = false;
219 m_rootSheet = nullptr;
220 m_schematic = nullptr;
223
225}
226
227
229{
230 for( auto& [libName, lib] : m_libCache )
231 {
232 for( auto& [name, symbol] : lib )
233 delete symbol;
234 }
235}
236
237
239{
240 return 0;
241}
242
243
244bool SCH_IO_ALTIUM::isBinaryFile( const wxString& aFileName )
245{
246 // Compound File Binary Format header
248}
249
250
251bool SCH_IO_ALTIUM::isASCIIFile( const wxString& aFileName )
252{
253 // ASCII file format
254 return IO_UTILS::fileStartsWithPrefix( aFileName, wxS( "|HEADER=" ), false );
255}
256
257
258bool SCH_IO_ALTIUM::checkFileHeader( const wxString& aFileName )
259{
260 return isBinaryFile( aFileName ) || isASCIIFile( aFileName );
261}
262
263
264bool SCH_IO_ALTIUM::CanReadSchematicFile( const wxString& aFileName ) const
265{
266 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
267 return false;
268
269 return checkFileHeader( aFileName );
270}
271
272
273bool SCH_IO_ALTIUM::CanReadLibrary( const wxString& aFileName ) const
274{
275 if( !SCH_IO::CanReadLibrary( aFileName ) )
276 return false;
277
278 return checkFileHeader( aFileName );
279}
280
281
283{
284 if( m_libName.IsEmpty() )
285 {
286 // Try to come up with a meaningful name
288
289 if( m_libName.IsEmpty() )
290 {
291 wxFileName fn( m_rootSheet->GetFileName() );
292 m_libName = fn.GetName();
293 }
294
295 if( m_libName.IsEmpty() )
296 m_libName = "noname";
297
298 m_libName += "-altium-import";
300 }
301
302 return m_libName;
303}
304
305
307{
308 wxFileName fn( m_schematic->Prj().GetProjectPath(), getLibName(),
310
311 return fn;
312}
313
314
315SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic,
316 SCH_SHEET* aAppendToMe,
317 const STRING_UTF8_MAP* aProperties )
318{
319 wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
320
321 wxFileName fileName( aFileName );
322 fileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
323 m_schematic = aSchematic;
324
325 // Delete on exception, if I own m_rootSheet, according to aAppendToMe
326 std::unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
327
328 if( aAppendToMe )
329 {
330 wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
331 m_rootSheet = &aSchematic->Root();
332 }
333 else
334 {
335 m_rootSheet = new SCH_SHEET( aSchematic );
336 m_rootSheet->SetFileName( fileName.GetFullPath() );
337
338 aSchematic->SetRoot( m_rootSheet );
339
340 SCH_SHEET_PATH sheetpath;
341 sheetpath.push_back( m_rootSheet );
342
343 // We'll update later if we find a pageNumber record for it.
344 sheetpath.SetPageNumber( "#" );
345 }
346
347 if( !m_rootSheet->GetScreen() )
348 {
349 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
350 screen->SetFileName( aFileName );
351 m_rootSheet->SetScreen( screen );
352 const_cast<KIID&>( m_rootSheet->m_Uuid ) = screen->GetUuid();
353 }
354
356
357 wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
358
359 m_pi.reset( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
360
363 if( !libTable->HasLibrary( getLibName() ) )
364 {
365 // Create a new empty symbol library.
366 m_pi->CreateLibrary( getLibFileName().GetFullPath() );
367 wxString libTableUri = "${KIPRJMOD}/" + getLibFileName().GetFullName();
368
369 // Add the new library to the project symbol library table.
370 libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
371 wxString( "KiCad" ) ) );
372
373 // Save project symbol library table.
374 wxFileName fn( m_schematic->Prj().GetProjectPath(),
376
377 // So output formatter goes out of scope and closes the file before reloading.
378 {
379 FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
380 libTable->Format( &formatter, 0 );
381 }
382
383 // Reload the symbol library table.
386 }
387
389
390 SCH_SCREEN* rootScreen = m_rootSheet->GetScreen();
391 wxCHECK( rootScreen, nullptr );
392
393 SCH_SHEET_INSTANCE sheetInstance;
394
395 sheetInstance.m_Path = m_sheetPath.Path();
396 sheetInstance.m_PageNumber = wxT( "#" );
397
398 rootScreen->m_sheetInstances.emplace_back( sheetInstance );
399
400 ParseAltiumSch( aFileName );
401
402 m_pi->SaveLibrary( getLibFileName().GetFullPath() );
403
404 SCH_SCREENS allSheets( m_rootSheet );
405 allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
406 allSheets.ClearEditFlags();
407
408 // Set up the default netclass wire & bus width based on imported wires & buses.
409 //
410
411 int minWireWidth = std::numeric_limits<int>::max();
412 int minBusWidth = std::numeric_limits<int>::max();
413
414 for( SCH_SCREEN* screen = allSheets.GetFirst(); screen != nullptr; screen = allSheets.GetNext() )
415 {
416 std::vector<SCH_MARKER*> markers;
417
418 for( SCH_ITEM* item : screen->Items().OfType( SCH_LINE_T ) )
419 {
420 SCH_LINE* line = static_cast<SCH_LINE*>( item );
421
422 if( line->IsWire() && line->GetLineWidth() > 0 )
423 minWireWidth = std::min( minWireWidth, line->GetLineWidth() );
424
425 if( line->IsBus() && line->GetLineWidth() > 0 )
426 minBusWidth = std::min( minBusWidth, line->GetLineWidth() );
427 }
428 }
429
430 std::shared_ptr<NET_SETTINGS>& netSettings = m_schematic->Prj().GetProjectFile().NetSettings();
431
432 if( minWireWidth < std::numeric_limits<int>::max() )
433 netSettings->m_DefaultNetClass->SetWireWidth( minWireWidth );
434
435 if( minBusWidth < std::numeric_limits<int>::max() )
436 netSettings->m_DefaultNetClass->SetBusWidth( minBusWidth );
437
438 return m_rootSheet;
439}
440
441
443{
444 return m_sheetPath.LastScreen();
445}
446
447
449{
450 return m_sheetPath.Last();
451}
452
453
454void SCH_IO_ALTIUM::ParseAltiumSch( const wxString& aFileName )
455{
456 // Load path may be different from the project path.
457 wxFileName parentFileName = aFileName;
458
459 if( isBinaryFile( aFileName ) )
460 {
461 ALTIUM_COMPOUND_FILE altiumSchFile( aFileName );
462
463 try
464 {
465 ParseStorage( altiumSchFile ); // we need this before parsing the FileHeader
466 ParseFileHeader( altiumSchFile );
467
468 // Parse "Additional" because sheet is set up during "FileHeader" parsing.
469 ParseAdditional( altiumSchFile );
470 }
471 catch( const CFB::CFBException& exception )
472 {
473 THROW_IO_ERROR( exception.what() );
474 }
475 catch( const std::exception& exc )
476 {
477 wxLogDebug( wxT( "Unhandled exception in Altium schematic parsers: %s." ), exc.what() );
478 throw;
479 }
480 }
481 else // ASCII
482 {
483 ParseASCIISchematic( aFileName );
484 }
485
486 SCH_SCREEN* currentScreen = getCurrentScreen();
487 wxCHECK( currentScreen, /* void */ );
488
489 // Descend the sheet hierarchy.
490 for( SCH_ITEM* item : currentScreen->Items().OfType( SCH_SHEET_T ) )
491 {
492 SCH_SCREEN* loadedScreen = nullptr;
493 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item );
494
495 wxCHECK2( sheet, continue );
496
497 // The assumption is that all of the Altium schematic files will be in the same
498 // path as the parent sheet path.
499 wxFileName loadAltiumFileName( parentFileName.GetPath(), sheet->GetFileName() );
500
501 if( !loadAltiumFileName.IsFileReadable() )
502 {
503 // Try case-insensitive search
504 wxArrayString files;
505 wxDir::GetAllFiles( parentFileName.GetPath(), &files, wxEmptyString,
506 wxDIR_FILES | wxDIR_HIDDEN );
507
508 for( const wxString& candidate : files )
509 {
510 wxFileName candidateFname( candidate );
511
512 if( candidateFname.GetFullName().IsSameAs( sheet->GetFileName(), false ) )
513 {
514 loadAltiumFileName = candidateFname;
515 break;
516 }
517 }
518 }
519
520 if( loadAltiumFileName.GetFullName().IsEmpty() || !loadAltiumFileName.IsFileReadable() )
521 {
522 wxString msg;
523
524 msg.Printf( _( "The file name for sheet %s is undefined, this is probably an"
525 " Altium signal harness that got converted to a sheet." ),
526 sheet->GetName() );
527 m_reporter->Report( msg );
528 sheet->SetScreen( new SCH_SCREEN( m_schematic ) );
529 continue;
530 }
531
532 m_rootSheet->SearchHierarchy( loadAltiumFileName.GetFullPath(), &loadedScreen );
533
534 if( loadedScreen )
535 {
536 sheet->SetScreen( loadedScreen );
537 // Do not need to load the sub-sheets - this has already been done.
538 }
539 else
540 {
541 sheet->SetScreen( new SCH_SCREEN( m_schematic ) );
542 SCH_SCREEN* screen = sheet->GetScreen();
543
544 if( sheet->GetName().Trim().empty() )
545 sheet->SetName( loadAltiumFileName.GetName() );
546
547 wxCHECK2( screen, continue );
548
549 m_sheetPath.push_back( sheet );
550 ParseAltiumSch( loadAltiumFileName.GetFullPath() );
551
552 // Map the loaded Altium file to the project file.
553 wxFileName projectFileName = loadAltiumFileName;
554 projectFileName.SetPath( m_schematic->Prj().GetProjectPath() );
555 projectFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
556 sheet->SetFileName( projectFileName.GetFullName() );
557 screen->SetFileName( projectFileName.GetFullPath() );
558
560 }
561 }
562}
563
564
566{
567 const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "Storage" } );
568
569 if( file == nullptr )
570 return;
571
572 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
573
574 std::map<wxString, wxString> properties = reader.ReadProperties();
575 wxString header = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
576 int weight = ALTIUM_PROPS_UTILS::ReadInt( properties, "WEIGHT", 0 );
577
578 if( weight < 0 )
579 THROW_IO_ERROR( "Storage weight is negative!" );
580
581 for( int i = 0; i < weight; i++ )
582 m_altiumStorage.emplace_back( reader );
583
584 if( reader.HasParsingError() )
585 THROW_IO_ERROR( "stream was not parsed correctly!" );
586
587 // TODO pointhi: is it possible to have multiple headers in one Storage file? Otherwise
588 // throw IO Error.
589 if( reader.GetRemainingBytes() != 0 )
590 {
591 m_reporter->Report( wxString::Format( _( "Storage file not fully parsed "
592 "(%d bytes remaining)." ),
593 reader.GetRemainingBytes() ),
595 }
596}
597
598
600{
601 wxString streamName = wxS( "Additional" );
602
603 const CFB::COMPOUND_FILE_ENTRY* file =
604 aAltiumSchFile.FindStream( { streamName.ToStdString() } );
605
606 if( file == nullptr )
607 return;
608
609 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
610
611 if( reader.GetRemainingBytes() <= 0 )
612 {
613 THROW_IO_ERROR( "Additional section does not contain any data" );
614 }
615 else
616 {
617 std::map<wxString, wxString> properties = reader.ReadProperties();
618
619 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
620 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
621
622 if( record != ALTIUM_SCH_RECORD::HEADER )
623 THROW_IO_ERROR( "Header expected" );
624 }
625
626 for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
627 {
628 std::map<wxString, wxString> properties = reader.ReadProperties();
629
630 ParseRecord( index, properties, streamName );
631 }
632
633 // Handle harness Ports
635 ParseHarnessPort( port );
636
637 if( reader.HasParsingError() )
638 THROW_IO_ERROR( "stream was not parsed correctly!" );
639
640 if( reader.GetRemainingBytes() != 0 )
641 THROW_IO_ERROR( "stream is not fully parsed" );
642
644}
645
646
648{
649 wxString streamName = wxS( "FileHeader" );
650
651 const CFB::COMPOUND_FILE_ENTRY* file =
652 aAltiumSchFile.FindStream( { streamName.ToStdString() } );
653
654 if( file == nullptr )
655 THROW_IO_ERROR( "FileHeader not found" );
656
657 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
658
659 if( reader.GetRemainingBytes() <= 0 )
660 {
661 THROW_IO_ERROR( "FileHeader does not contain any data" );
662 }
663 else
664 {
665 std::map<wxString, wxString> properties = reader.ReadProperties();
666
667 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
668
669 if( libtype.CmpNoCase( "Protel for Windows - Schematic Capture Binary File Version 5.0" ) )
670 THROW_IO_ERROR( _( "Expected Altium Schematic file version 5.0" ) );
671 }
672
673 // Prepare some local variables
674 wxCHECK( m_altiumPortsCurrentSheet.empty(), /* void */ );
675 wxCHECK( !m_currentTitleBlock, /* void */ );
676
677 m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
678
679 // index is required to resolve OWNERINDEX
680 for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
681 {
682 std::map<wxString, wxString> properties = reader.ReadProperties();
683
684 ParseRecord( index, properties, streamName );
685 }
686
687 if( reader.HasParsingError() )
688 THROW_IO_ERROR( "stream was not parsed correctly!" );
689
690 if( reader.GetRemainingBytes() != 0 )
691 THROW_IO_ERROR( "stream is not fully parsed" );
692
693 // assign LIB_SYMBOL -> COMPONENT
694 for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
695 {
696 auto libSymbolIt = m_libSymbols.find( symbol.first );
697
698 if( libSymbolIt == m_libSymbols.end() )
699 THROW_IO_ERROR( "every symbol should have a symbol attached" );
700
701 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
702 new LIB_SYMBOL( *( libSymbolIt->second ) ), m_properties.get() );
703
704 symbol.second->SetLibSymbol( libSymbolIt->second );
705 }
706
707 SCH_SCREEN* screen = getCurrentScreen();
708 wxCHECK( screen, /* void */ );
709
710 // Handle title blocks
712 m_currentTitleBlock.reset();
713
714 // Handle Ports
715 for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
716 ParsePort( port );
717
719 m_altiumComponents.clear();
720 m_altiumTemplates.clear();
722
723 m_symbols.clear();
724 m_libSymbols.clear();
725
726 // Otherwise we cannot save the imported sheet?
727 SCH_SHEET* sheet = getCurrentSheet();
728
729 wxCHECK( sheet, /* void */ );
730
731 sheet->SetModified();
732}
733
734
735void SCH_IO_ALTIUM::ParseASCIISchematic( const wxString& aFileName )
736{
737 // Read storage content first
738 {
739 ALTIUM_ASCII_PARSER storageReader( aFileName );
740
741 while( storageReader.CanRead() )
742 {
743 std::map<wxString, wxString> properties = storageReader.ReadProperties();
744
745 // Binary data
746 if( properties.find( wxS( "BINARY" ) ) != properties.end() )
747 m_altiumStorage.emplace_back( properties );
748 }
749 }
750
751 // Read other data
752 ALTIUM_ASCII_PARSER reader( aFileName );
753
754 if( !reader.CanRead() )
755 {
756 THROW_IO_ERROR( "FileHeader does not contain any data" );
757 }
758 else
759 {
760 std::map<wxString, wxString> properties = reader.ReadProperties();
761
762 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
763
764 if( libtype.CmpNoCase( "Protel for Windows - Schematic Capture Ascii File Version 5.0" ) )
765 THROW_IO_ERROR( _( "Expected Altium Schematic file version 5.0" ) );
766 }
767
768 // Prepare some local variables
769 wxCHECK( m_altiumPortsCurrentSheet.empty(), /* void */ );
770 wxCHECK( !m_currentTitleBlock, /* void */ );
771
772 m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
773
774 // index is required to resolve OWNERINDEX
775 int index = 0;
776
777 while( reader.CanRead() )
778 {
779 std::map<wxString, wxString> properties = reader.ReadProperties();
780
781 // Reset index at headers
782 if( properties.find( wxS( "HEADER" ) ) != properties.end() )
783 {
784 index = 0;
785 continue;
786 }
787
788 if( properties.find( wxS( "RECORD" ) ) != properties.end() )
789 ParseRecord( index, properties, aFileName );
790
791 index++;
792 }
793
794 if( reader.HasParsingError() )
795 THROW_IO_ERROR( "stream was not parsed correctly!" );
796
797 if( reader.CanRead() )
798 THROW_IO_ERROR( "stream is not fully parsed" );
799
800 // assign LIB_SYMBOL -> COMPONENT
801 for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
802 {
803 auto libSymbolIt = m_libSymbols.find( symbol.first );
804
805 if( libSymbolIt == m_libSymbols.end() )
806 THROW_IO_ERROR( "every symbol should have a symbol attached" );
807
808 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
809 new LIB_SYMBOL( *( libSymbolIt->second ) ), m_properties.get() );
810
811 symbol.second->SetLibSymbol( libSymbolIt->second );
812 }
813
814 SCH_SCREEN* screen = getCurrentScreen();
815 wxCHECK( screen, /* void */ );
816
817 // Handle title blocks
819 m_currentTitleBlock.reset();
820
821 // Handle harness Ports
823 ParseHarnessPort( port );
824
825 // Handle Ports
826 for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
827 ParsePort( port );
828
830 m_altiumComponents.clear();
831 m_altiumTemplates.clear();
833
834 m_symbols.clear();
835 m_libSymbols.clear();
836
837 // Otherwise we cannot save the imported sheet?
838 SCH_SHEET* sheet = getCurrentSheet();
839
840 wxCHECK( sheet, /* void */ );
841
842 sheet->SetModified();
843}
844
845
846void SCH_IO_ALTIUM::ParseRecord( int index, std::map<wxString, wxString>& properties,
847 const wxString& aSectionName )
848{
849 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", -1 );
850 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
851
852 // see: https://github.com/vadmium/python-altium/blob/master/format.md
853 switch( record )
854 {
855 // FileHeader section
856
857 case ALTIUM_SCH_RECORD::HEADER:
858 THROW_IO_ERROR( "Header already parsed" );
859
860 case ALTIUM_SCH_RECORD::COMPONENT:
861 ParseComponent( index, properties );
862 break;
863
864 case ALTIUM_SCH_RECORD::PIN:
865 ParsePin( properties );
866 break;
867
868 case ALTIUM_SCH_RECORD::IEEE_SYMBOL:
869 m_reporter->Report( _( "Record 'IEEE_SYMBOL' not handled." ), RPT_SEVERITY_INFO );
870 break;
871
872 case ALTIUM_SCH_RECORD::LABEL:
873 ParseLabel( properties );
874 break;
875
876 case ALTIUM_SCH_RECORD::BEZIER:
877 ParseBezier( properties );
878 break;
879
880 case ALTIUM_SCH_RECORD::POLYLINE:
881 ParsePolyline( properties );
882 break;
883
884 case ALTIUM_SCH_RECORD::POLYGON:
885 ParsePolygon( properties );
886 break;
887
888 case ALTIUM_SCH_RECORD::ELLIPSE:
889 ParseEllipse( properties );
890 break;
891
892 case ALTIUM_SCH_RECORD::PIECHART:
893 m_reporter->Report( _( "Record 'PIECHART' not handled." ), RPT_SEVERITY_INFO );
894 break;
895
896 case ALTIUM_SCH_RECORD::ROUND_RECTANGLE:
897 ParseRoundRectangle( properties );
898 break;
899
900 case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC:
901 case ALTIUM_SCH_RECORD::ARC:
902 ParseArc( properties );
903 break;
904
905 case ALTIUM_SCH_RECORD::LINE:
906 ParseLine( properties );
907 break;
908
909 case ALTIUM_SCH_RECORD::RECTANGLE:
910 ParseRectangle( properties );
911 break;
912
913 case ALTIUM_SCH_RECORD::SHEET_SYMBOL:
914 ParseSheetSymbol( index, properties );
915 break;
916
917 case ALTIUM_SCH_RECORD::SHEET_ENTRY:
918 ParseSheetEntry( properties );
919 break;
920
921 case ALTIUM_SCH_RECORD::POWER_PORT:
922 ParsePowerPort( properties );
923 break;
924
925 case ALTIUM_SCH_RECORD::PORT:
926 // Ports are parsed after the sheet was parsed
927 // This is required because we need all electrical connection points before placing.
928 m_altiumPortsCurrentSheet.emplace_back( properties );
929 break;
930
931 case ALTIUM_SCH_RECORD::NO_ERC:
932 ParseNoERC( properties );
933 break;
934
935 case ALTIUM_SCH_RECORD::NET_LABEL:
936 ParseNetLabel( properties );
937 break;
938
939 case ALTIUM_SCH_RECORD::BUS:
940 ParseBus( properties );
941 break;
942
943 case ALTIUM_SCH_RECORD::WIRE:
944 ParseWire( properties );
945 break;
946
947 case ALTIUM_SCH_RECORD::TEXT_FRAME:
948 ParseTextFrame( properties );
949 break;
950
951 case ALTIUM_SCH_RECORD::JUNCTION:
952 ParseJunction( properties );
953 break;
954
955 case ALTIUM_SCH_RECORD::IMAGE:
956 ParseImage( properties );
957 break;
958
959 case ALTIUM_SCH_RECORD::SHEET:
960 ParseSheet( properties );
961 break;
962
963 case ALTIUM_SCH_RECORD::SHEET_NAME:
964 ParseSheetName( properties );
965 break;
966
967 case ALTIUM_SCH_RECORD::FILE_NAME:
968 ParseFileName( properties );
969 break;
970
971 case ALTIUM_SCH_RECORD::DESIGNATOR:
972 ParseDesignator( properties );
973 break;
974
975 case ALTIUM_SCH_RECORD::BUS_ENTRY:
976 ParseBusEntry( properties );
977 break;
978
979 case ALTIUM_SCH_RECORD::TEMPLATE:
980 ParseTemplate( index, properties );
981 break;
982
983 case ALTIUM_SCH_RECORD::PARAMETER:
984 ParseParameter( properties );
985 break;
986
987 case ALTIUM_SCH_RECORD::PARAMETER_SET:
988 m_reporter->Report( _( "Parameter Set not currently supported." ), RPT_SEVERITY_ERROR );
989 break;
990
991 case ALTIUM_SCH_RECORD::IMPLEMENTATION_LIST:
992 ParseImplementationList( index, properties );
993 break;
994
995 case ALTIUM_SCH_RECORD::IMPLEMENTATION:
996 ParseImplementation( properties );
997 break;
998
999 case ALTIUM_SCH_RECORD::MAP_DEFINER_LIST:
1000 break;
1001
1002 case ALTIUM_SCH_RECORD::MAP_DEFINER:
1003 break;
1004
1005 case ALTIUM_SCH_RECORD::IMPL_PARAMS:
1006 break;
1007
1008 case ALTIUM_SCH_RECORD::NOTE:
1009 ParseNote( properties );
1010 break;
1011
1012 case ALTIUM_SCH_RECORD::COMPILE_MASK:
1013 m_reporter->Report( _( "Compile mask not currently supported." ), RPT_SEVERITY_ERROR );
1014 break;
1015
1016 case ALTIUM_SCH_RECORD::HYPERLINK:
1017 break;
1018
1019 // Additional section
1020
1021 case ALTIUM_SCH_RECORD::HARNESS_CONNECTOR:
1022 ParseHarnessConnector( index, properties );
1023 break;
1024
1025 case ALTIUM_SCH_RECORD::HARNESS_ENTRY:
1026 ParseHarnessEntry( properties );
1027 break;
1028
1029 case ALTIUM_SCH_RECORD::HARNESS_TYPE:
1030 ParseHarnessType( properties );
1031 break;
1032
1033 case ALTIUM_SCH_RECORD::SIGNAL_HARNESS:
1034 ParseSignalHarness( properties );
1035 break;
1036
1037 case ALTIUM_SCH_RECORD::BLANKET:
1038 m_reporter->Report( _( "Blanket not currently supported." ), RPT_SEVERITY_ERROR );
1039 break;
1040
1041 default:
1043 wxString::Format( _( "Unknown or unexpected record id %d found in %s." ), recordId,
1044 aSectionName ),
1046 break;
1047 }
1048
1050}
1051
1052
1054{
1055 const auto& component = m_altiumComponents.find( aElem.ownerindex );
1056 const auto& templ = m_altiumTemplates.find( aElem.ownerindex );
1057
1058 if( component != m_altiumComponents.end() )
1059 return component->second.displaymode == aElem.ownerpartdisplaymode;
1060
1061 if( templ != m_altiumTemplates.end() )
1062 return true;
1063
1064 return false;
1065}
1066
1067
1068const ASCH_STORAGE_FILE* SCH_IO_ALTIUM::GetFileFromStorage( const wxString& aFilename ) const
1069{
1070 const ASCH_STORAGE_FILE* nonExactMatch = nullptr;
1071
1072 for( const ASCH_STORAGE_FILE& file : m_altiumStorage )
1073 {
1074 if( file.filename.IsSameAs( aFilename ) )
1075 return &file;
1076
1077 if( file.filename.EndsWith( aFilename ) )
1078 nonExactMatch = &file;
1079 }
1080
1081 return nonExactMatch;
1082}
1083
1084
1085void SCH_IO_ALTIUM::ParseComponent( int aIndex, const std::map<wxString, wxString>& aProperties )
1086{
1087 SCH_SHEET* currentSheet = m_sheetPath.Last();
1088 wxCHECK( currentSheet, /* void */ );
1089
1090 wxString sheetName = currentSheet->GetName();
1091
1092 if( sheetName.IsEmpty() )
1093 sheetName = wxT( "root" );
1094
1095 ASCH_SYMBOL altiumSymbol( aProperties );
1096
1097 if( m_altiumComponents.count( aIndex ) )
1098 {
1099 const ASCH_SYMBOL& currentSymbol = m_altiumComponents.at( aIndex );
1100
1101 m_reporter->Report( wxString::Format( _( "Symbol \"%s\" in sheet \"%s\" at index %d "
1102 "replaced with symbol \"%s\"." ),
1103 currentSymbol.libreference,
1104 sheetName,
1105 aIndex,
1106 altiumSymbol.libreference ),
1108 }
1109
1110 auto pair = m_altiumComponents.insert( { aIndex, altiumSymbol } );
1111 const ASCH_SYMBOL& elem = pair.first->second;
1112
1113 // TODO: this is a hack until we correctly apply all transformations to every element
1114 wxString name = wxString::Format( "%s_%d%s_%s",
1115 sheetName,
1116 elem.orientation,
1117 elem.isMirrored ? "_mirrored" : "",
1118 elem.libreference );
1119
1120 if( elem.displaymodecount > 1 )
1121 name << '_' << elem.displaymode;
1122
1124
1125 LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString );
1126 ksymbol->SetName( name );
1127 ksymbol->SetDescription( elem.componentdescription );
1128 ksymbol->SetLibId( libId );
1129 m_libSymbols.insert( { aIndex, ksymbol } );
1130
1131 // each component has its own symbol for now
1132 SCH_SYMBOL* symbol = new SCH_SYMBOL();
1133
1134 symbol->SetPosition( elem.location + m_sheetOffset );
1135
1136 // TODO: keep it simple for now, and only set position.
1137 // component->SetOrientation( elem.orientation );
1138 symbol->SetLibId( libId );
1139 symbol->SetUnit( std::max( 0, elem.currentpartid ) );
1141
1142 SCH_SCREEN* screen = getCurrentScreen();
1143 wxCHECK( screen, /* void */ );
1144
1145 screen->Append( symbol );
1146
1147 m_symbols.insert( { aIndex, symbol } );
1148}
1149
1150
1151void SCH_IO_ALTIUM::ParseTemplate( int aIndex, const std::map<wxString, wxString>& aProperties )
1152{
1153 SCH_SHEET* currentSheet = m_sheetPath.Last();
1154 wxCHECK( currentSheet, /* void */ );
1155
1156 wxString sheetName = currentSheet->GetName();
1157
1158 if( sheetName.IsEmpty() )
1159 sheetName = wxT( "root" );
1160
1161 ASCH_TEMPLATE altiumTemplate( aProperties );
1162
1163 // Extract base name from path
1164 wxString baseName = altiumTemplate.filename.AfterLast( '\\' ).BeforeLast( '.' );
1165
1166 if( baseName.IsEmpty() )
1167 baseName = wxS( "Template" );
1168
1169 m_altiumTemplates.insert( { aIndex, altiumTemplate } );
1170 // No need to create a symbol - graphics is put on the sheet
1171}
1172
1173
1174void SCH_IO_ALTIUM::ParsePin( const std::map<wxString, wxString>& aProperties,
1175 std::vector<LIB_SYMBOL*>& aSymbol )
1176{
1177 ASCH_PIN elem( aProperties );
1178
1179 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
1180 ? nullptr
1181 : aSymbol[elem.ownerpartdisplaymode];
1182 SCH_SYMBOL* schSymbol = nullptr;
1183
1184 if( !symbol )
1185 {
1186 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1187
1188 if( libSymbolIt == m_libSymbols.end() )
1189 {
1190 // TODO: e.g. can depend on Template (RECORD=39
1191 m_reporter->Report( wxString::Format( wxT( "Pin's owner (%d) not found." ),
1192 elem.ownerindex ),
1194 return;
1195 }
1196
1197 if( !IsComponentPartVisible( elem ) )
1198 return;
1199
1200 schSymbol = m_symbols.at( libSymbolIt->first );
1201 symbol = libSymbolIt->second;
1202 }
1203
1204 SCH_PIN* pin = new SCH_PIN( symbol );
1205
1206 // Make sure that these are visible when initializing the symbol
1207 // This may be overriden by the file data but not by the pin defaults
1208 pin->SetNameTextSize( schIUScale.MilsToIU( DEFAULT_PINNAME_SIZE ) );
1209 pin->SetNumberTextSize( schIUScale.MilsToIU( DEFAULT_PINNUM_SIZE ) );
1210
1211 symbol->AddDrawItem( pin, false );
1212
1213 pin->SetUnit( std::max( 0, elem.ownerpartid ) );
1214
1215 pin->SetName( AltiumPinNamesToKiCad( elem.name ) );
1216 pin->SetNumber( elem.designator );
1217 pin->SetLength( elem.pinlength );
1218
1219 if( elem.hidden )
1220 pin->SetVisible( false );
1221
1222 if( !elem.showDesignator )
1223 pin->SetNumberTextSize( 0 );
1224
1225 if( !elem.showPinName )
1226 pin->SetNameTextSize( 0 );
1227
1228 VECTOR2I pinLocation = elem.location; // the location given is not the connection point!
1229
1230 switch( elem.orientation )
1231 {
1232 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
1233 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT );
1234 pinLocation.x += elem.pinlength;
1235 break;
1236
1237 case ASCH_RECORD_ORIENTATION::UPWARDS:
1238 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1239 pinLocation.y -= elem.pinlength;
1240 break;
1241
1242 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
1243 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT );
1244 pinLocation.x -= elem.pinlength;
1245 break;
1246
1247 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
1248 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
1249 pinLocation.y += elem.pinlength;
1250 break;
1251
1252 default:
1253 m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
1254 break;
1255 }
1256
1257 // TODO: position can be sometimes off a little bit!
1258 if( schSymbol )
1259 pin->SetPosition( GetRelativePosition( pinLocation + m_sheetOffset, schSymbol ) );
1260 else
1261 pin->SetPosition( VECTOR2I( pinLocation.x, -pinLocation.y ) );
1262
1263 switch( elem.electrical )
1264 {
1265 case ASCH_PIN_ELECTRICAL::INPUT:
1266 pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
1267 break;
1268
1269 case ASCH_PIN_ELECTRICAL::BIDI:
1270 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
1271 break;
1272
1273 case ASCH_PIN_ELECTRICAL::OUTPUT:
1274 pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
1275 break;
1276
1277 case ASCH_PIN_ELECTRICAL::OPEN_COLLECTOR:
1278 pin->SetType( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
1279 break;
1280
1281 case ASCH_PIN_ELECTRICAL::PASSIVE:
1282 pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
1283 break;
1284
1285 case ASCH_PIN_ELECTRICAL::TRISTATE:
1286 pin->SetType( ELECTRICAL_PINTYPE::PT_TRISTATE );
1287 break;
1288
1289 case ASCH_PIN_ELECTRICAL::OPEN_EMITTER:
1290 pin->SetType( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
1291 break;
1292
1293 case ASCH_PIN_ELECTRICAL::POWER:
1294 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
1295 break;
1296
1297 case ASCH_PIN_ELECTRICAL::UNKNOWN:
1298 default:
1299 pin->SetType( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
1300 m_reporter->Report( _( "Pin has unexpected electrical type." ), RPT_SEVERITY_WARNING );
1301 break;
1302 }
1303
1305 m_reporter->Report( _( "Pin has unexpected outer edge type." ), RPT_SEVERITY_WARNING );
1306
1308 m_reporter->Report( _( "Pin has unexpected inner edge type." ), RPT_SEVERITY_WARNING );
1309
1311 {
1312 switch( elem.symbolInnerEdge )
1313 {
1315 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
1316 break;
1317
1318 default:
1319 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
1320 break;
1321 }
1322 }
1324 {
1325 switch( elem.symbolInnerEdge )
1326 {
1328 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW );
1329 break;
1330
1331 default:
1332 pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW );
1333 break;
1334 }
1335 }
1337 {
1338 pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW );
1339 }
1340 else
1341 {
1342 switch( elem.symbolInnerEdge )
1343 {
1345 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
1346 break;
1347
1348 default:
1349 pin->SetShape( GRAPHIC_PINSHAPE::LINE ); // nothing to do
1350 break;
1351 }
1352 }
1353}
1354
1355
1357 ASCH_RECORD_ORIENTATION orientation )
1358{
1359 int vjustify, hjustify;
1361
1362 switch( justification )
1363 {
1364 default:
1369 vjustify = GR_TEXT_V_ALIGN_BOTTOM;
1370 break;
1371
1375 vjustify = GR_TEXT_V_ALIGN_CENTER;
1376 break;
1377
1381 vjustify = GR_TEXT_V_ALIGN_TOP;
1382 break;
1383 }
1384
1385 switch( justification )
1386 {
1387 default:
1392 hjustify = GR_TEXT_H_ALIGN_LEFT;
1393 break;
1394
1398 hjustify = GR_TEXT_H_ALIGN_CENTER;
1399 break;
1400
1404 hjustify = GR_TEXT_H_ALIGN_RIGHT;
1405 break;
1406 }
1407
1408 switch( orientation )
1409 {
1411 angle = ANGLE_HORIZONTAL;
1412 break;
1413
1415 vjustify *= -1;
1416 hjustify *= -1;
1417 angle = ANGLE_HORIZONTAL;
1418 break;
1419
1421 angle = ANGLE_VERTICAL;
1422 break;
1423
1425 vjustify *= -1;
1426 hjustify *= -1;
1427 angle = ANGLE_VERTICAL;
1428 break;
1429 }
1430
1431 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( vjustify ) );
1432 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( hjustify ) );
1433 text->SetTextAngle( angle );
1434}
1435
1436
1438{
1439 // No component assigned -> Put on sheet
1440 if( aOwnerindex == ALTIUM_COMPONENT_NONE )
1441 return true;
1442
1443 // For a template -> Put on sheet so we can resolve variables
1444 if( m_altiumTemplates.find( aOwnerindex ) != m_altiumTemplates.end() )
1445 return true;
1446
1447 return false;
1448}
1449
1450
1451void SCH_IO_ALTIUM::ParseLabel( const std::map<wxString, wxString>& aProperties,
1452 std::vector<LIB_SYMBOL*>& aSymbol, std::vector<int>& aFontSizes )
1453{
1454 ASCH_LABEL elem( aProperties );
1455
1456 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1457 {
1458 static const std::map<wxString, wxString> variableMap = {
1459 { "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
1460 { "SHEETNUMBER", "#" },
1461 { "SHEETTOTAL", "##" },
1462 { "TITLE", "TITLE" }, // 1:1 maps are sort of useless, but it makes it
1463 { "REVISION", "REVISION" }, // easier to see that the list is complete
1464 { "DATE", "ISSUE_DATE" },
1465 { "CURRENTDATE", "CURRENT_DATE" },
1466 { "COMPANYNAME", "COMPANY" },
1467 { "DOCUMENTNAME", "FILENAME" },
1468 { "DOCUMENTFULLPATHANDNAME",
1469 "FILEPATH" },
1470 { "PROJECTNAME", "PROJECTNAME" },
1471 };
1472
1473 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
1474 SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
1475
1476 SetTextPositioning( textItem, elem.justification, elem.orientation );
1477
1478 size_t fontId = static_cast<int>( elem.fontId );
1479
1480 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1481 {
1482 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1483 textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
1484
1485 // Must come after SetTextSize()
1486 textItem->SetBold( font.Bold );
1487 textItem->SetItalic( font.Italic );
1488 }
1489
1490 textItem->SetFlags(IS_NEW );
1491
1492 SCH_SCREEN* screen = getCurrentScreen();
1493 wxCHECK( screen, /* void */ );
1494
1495 screen->Append( textItem );
1496 }
1497 else
1498 {
1499 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
1500 ? nullptr
1501 : aSymbol[elem.ownerpartdisplaymode];
1502 SCH_SYMBOL* schsym = nullptr;
1503
1504 if( !symbol )
1505 {
1506 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1507
1508 if( libSymbolIt == m_libSymbols.end() )
1509 {
1510 // TODO: e.g. can depend on Template (RECORD=39
1511 m_reporter->Report( wxString::Format( wxT( "Label's owner (%d) not found." ),
1512 elem.ownerindex ),
1514 return;
1515 }
1516
1517 symbol = libSymbolIt->second;
1518 schsym = m_symbols.at( libSymbolIt->first );
1519 }
1520
1521 SCH_TEXT* textItem = new SCH_TEXT( { 0, 0 }, elem.text, LAYER_DEVICE );
1522 symbol->AddDrawItem( textItem, false );
1523
1525 if( !schsym )
1526 textItem->SetPosition( GetLibEditPosition(elem.location ) );
1527 else
1528 textItem->SetPosition( GetRelativePosition( elem.location + m_sheetOffset, schsym ) );
1529
1530 textItem->SetUnit( std::max( 0, elem.ownerpartid ) );
1531 SetTextPositioning( textItem, elem.justification, elem.orientation );
1532
1533 size_t fontId = elem.fontId;
1534
1535 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1536 {
1537 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1538 textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
1539
1540 // Must come after SetTextSize()
1541 textItem->SetBold( font.Bold );
1542 textItem->SetItalic( font.Italic );
1543 }
1544 else if( fontId > 0 && fontId <= aFontSizes.size() )
1545 {
1546 int size = aFontSizes[fontId - 1];
1547 textItem->SetTextSize( { size, size } );
1548 }
1549 }
1550}
1551
1552
1553void SCH_IO_ALTIUM::ParseTextFrame( const std::map<wxString, wxString>& aProperties,
1554 std::vector<LIB_SYMBOL*>& aSymbol,
1555 std::vector<int>& aFontSizes )
1556{
1557 ASCH_TEXT_FRAME elem( aProperties );
1558
1559 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1560 AddTextBox( &elem );
1561 else
1562 AddLibTextBox( &elem, aSymbol, aFontSizes );
1563}
1564
1565
1566void SCH_IO_ALTIUM::ParseNote( const std::map<wxString, wxString>& aProperties )
1567{
1568 ASCH_NOTE elem( aProperties );
1569 AddTextBox( static_cast<ASCH_TEXT_FRAME*>( &elem ) );
1570
1571 // TODO: need some sort of property system for storing author....
1572}
1573
1574
1576{
1577 SCH_TEXTBOX* textBox = new SCH_TEXTBOX();
1578
1579 VECTOR2I sheetTopRight = aElem->TopRight + m_sheetOffset;
1580 VECTOR2I sheetBottomLeft = aElem->BottomLeft +m_sheetOffset;
1581
1582 textBox->SetStart( sheetTopRight );
1583 textBox->SetEnd( sheetBottomLeft );
1584
1585 textBox->SetText( aElem->Text );
1586
1587 textBox->SetFillColor( GetColorFromInt( aElem->AreaColor ) );
1588
1589 if( aElem->isSolid)
1590 textBox->SetFillMode( FILL_T::FILLED_WITH_COLOR );
1591 else
1592 textBox->SetFilled( false );
1593
1594 if( aElem->ShowBorder )
1595 textBox->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::DEFAULT,
1596 GetColorFromInt( aElem->BorderColor ) ) );
1597 else
1598 textBox->SetStroke( STROKE_PARAMS( -1, LINE_STYLE::DEFAULT,
1599 GetColorFromInt( aElem->BorderColor ) ) );
1600
1601 switch( aElem->Alignment )
1602 {
1603 default:
1604 case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
1606 break;
1607 case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
1609 break;
1610 case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
1612 break;
1613 }
1614
1615 size_t fontId = static_cast<int>( aElem->FontID );
1616
1617 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1618 {
1619 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1620 textBox->SetTextSize( { font.Size / 2, font.Size / 2 } );
1621
1622 // Must come after SetTextSize()
1623 textBox->SetBold( font.Bold );
1624 textBox->SetItalic( font.Italic );
1625 //textBox->SetFont( //how to set font, we have a font name here: ( font.fontname );
1626 }
1627
1628 textBox->SetFlags( IS_NEW );
1629
1630 SCH_SCREEN* screen = getCurrentScreen();
1631 wxCHECK( screen, /* void */ );
1632
1633 screen->Append( textBox );
1634}
1635
1636
1637void SCH_IO_ALTIUM::AddLibTextBox( const ASCH_TEXT_FRAME *aElem, std::vector<LIB_SYMBOL*>& aSymbol,
1638 std::vector<int>& aFontSizes )
1639{
1640 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= aElem->ownerpartdisplaymode
1641 ? nullptr
1642 : aSymbol[aElem->ownerpartdisplaymode];
1643 SCH_SYMBOL* schsym = nullptr;
1644
1645 if( !symbol )
1646 {
1647 const auto& libSymbolIt = m_libSymbols.find( aElem->ownerindex );
1648
1649 if( libSymbolIt == m_libSymbols.end() )
1650 {
1651 // TODO: e.g. can depend on Template (RECORD=39
1653 wxString::Format( wxT( "Label's owner (%d) not found." ), aElem->ownerindex ),
1655 return;
1656 }
1657
1658 symbol = libSymbolIt->second;
1659 schsym = m_symbols.at( libSymbolIt->first );
1660 }
1661
1662 SCH_TEXTBOX* textBox = new SCH_TEXTBOX( LAYER_DEVICE );
1663
1664 textBox->SetUnit( std::max( 0, aElem->ownerpartid ) );
1665 symbol->AddDrawItem( textBox, false );
1666
1668 if( !schsym )
1669 {
1670 textBox->SetStart( GetLibEditPosition( aElem->TopRight ) );
1671 textBox->SetEnd( GetLibEditPosition( aElem->BottomLeft ) );
1672 }
1673 else
1674 {
1675 textBox->SetStart( GetRelativePosition( aElem->TopRight + m_sheetOffset, schsym ) );
1676 textBox->SetEnd( GetRelativePosition( aElem->BottomLeft + m_sheetOffset, schsym ) );
1677 }
1678
1679 textBox->SetText( aElem->Text );
1680
1681 textBox->SetFillColor( GetColorFromInt( aElem->AreaColor ) );
1682
1683 if( aElem->isSolid)
1684 textBox->SetFillMode( FILL_T::FILLED_WITH_COLOR );
1685 else
1686 textBox->SetFilled( false );
1687
1688 if( aElem->ShowBorder )
1689 textBox->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::DEFAULT,
1690 GetColorFromInt( aElem->BorderColor ) ) );
1691 else
1692 textBox->SetStroke( STROKE_PARAMS( -1 ) );
1693
1694 switch( aElem->Alignment )
1695 {
1696 default:
1697 case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
1699 break;
1700 case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
1702 break;
1703 case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
1705 break;
1706 }
1707
1708 if( aElem->FontID > 0 && aElem->FontID <= static_cast<int>( aFontSizes.size() ) )
1709 {
1710 int size = aFontSizes[aElem->FontID - 1];
1711 textBox->SetTextSize( { size, size } );
1712 }
1713}
1714
1715
1716void SCH_IO_ALTIUM::ParseBezier( const std::map<wxString, wxString>& aProperties,
1717 std::vector<LIB_SYMBOL*>& aSymbol )
1718{
1719 ASCH_BEZIER elem( aProperties );
1720
1721 if( elem.points.size() < 2 )
1722 {
1723 m_reporter->Report( wxString::Format( _( "Bezier has %d control points. At least 2 are "
1724 "expected." ),
1725 static_cast<int>( elem.points.size() ) ),
1727 return;
1728 }
1729
1730 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1731 {
1732 SCH_SCREEN* currentScreen = getCurrentScreen();
1733 wxCHECK( currentScreen, /* void */ );
1734
1735 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
1736 {
1737 if( i + 2 == elem.points.size() )
1738 {
1739 // special case: single line
1740 SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
1741 SCH_LAYER_ID::LAYER_NOTES );
1742
1743 line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
1744 line->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
1745
1746 line->SetFlags( IS_NEW );
1747
1748 currentScreen->Append( line );
1749 }
1750 else
1751 {
1752 // simulate Bezier using line segments
1753 std::vector<VECTOR2I> bezierPoints;
1754 std::vector<VECTOR2I> polyPoints;
1755
1756 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
1757 bezierPoints.push_back( elem.points.at( j ) );
1758
1759 BEZIER_POLY converter( bezierPoints );
1760 converter.GetPoly( polyPoints );
1761
1762 for( size_t k = 0; k + 1 < polyPoints.size(); k++ )
1763 {
1764 SCH_LINE* line = new SCH_LINE( polyPoints.at( k ) + m_sheetOffset,
1765 SCH_LAYER_ID::LAYER_NOTES );
1766
1767 line->SetEndPoint( polyPoints.at( k + 1 ) + m_sheetOffset );
1768 line->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
1769
1770 line->SetFlags( IS_NEW );
1771 currentScreen->Append( line );
1772 }
1773 }
1774 }
1775 }
1776 else
1777 {
1778 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
1779 ? nullptr
1780 : aSymbol[elem.ownerpartdisplaymode];
1781 SCH_SYMBOL* schsym = nullptr;
1782
1783 if( !symbol )
1784 {
1785 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1786
1787 if( libSymbolIt == m_libSymbols.end() )
1788 {
1789 // TODO: e.g. can depend on Template (RECORD=39
1790 m_reporter->Report( wxString::Format( wxT( "Bezier's owner (%d) not found." ),
1791 elem.ownerindex ),
1793 return;
1794 }
1795
1796 symbol = libSymbolIt->second;
1797 schsym = m_symbols.at( libSymbolIt->first );
1798 }
1799
1800 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
1801 return;
1802
1803 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
1804 {
1805 if( i + 2 == elem.points.size() )
1806 {
1807 // special case: single line
1808 SCH_SHAPE* line = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1809 symbol->AddDrawItem( line, false );
1810
1811 line->SetUnit( std::max( 0, elem.ownerpartid ) );
1812
1813 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
1814 {
1815 if( !schsym )
1816 line->AddPoint( GetLibEditPosition( elem.points.at( j ) ) );
1817 else
1818 line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
1819 schsym ) );
1820 }
1821
1822 line->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
1823 }
1824 else if( i + 3 == elem.points.size() )
1825 {
1826 // TODO: special case of a single line with an extra point?
1827 // I haven't a clue what this is all about, but the sample document we have in
1828 // https://gitlab.com/kicad/code/kicad/-/issues/8974 responds best by treating it
1829 // as another single line special case.
1830 SCH_SHAPE* line = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1831 symbol->AddDrawItem( line, false );
1832
1833 line->SetUnit( std::max( 0, elem.ownerpartid ) );
1834
1835 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
1836 {
1837 if( !schsym )
1838 line->AddPoint( GetLibEditPosition( elem.points.at( j ) ) );
1839 else
1840 line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
1841 schsym ) );
1842 }
1843
1844 line->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
1845 }
1846 else
1847 {
1848 // Bezier always has exactly 4 control points
1849 SCH_SHAPE* bezier = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE );
1850 symbol->AddDrawItem( bezier, false );
1851
1852 bezier->SetUnit( std::max( 0, elem.ownerpartid ) );
1853
1854 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
1855 {
1856 VECTOR2I pos;
1857
1858 if( !schsym )
1859 pos = GetLibEditPosition( elem.points.at( j ) );
1860 else
1861 pos = GetRelativePosition( elem.points.at( j ) + m_sheetOffset, schsym );
1862
1863 switch( j - i )
1864 {
1865 case 0: bezier->SetStart( pos ); break;
1866 case 1: bezier->SetBezierC1( pos ); break;
1867 case 2: bezier->SetBezierC2( pos ); break;
1868 case 3: bezier->SetEnd( pos ); break;
1869 default: break; // Can't get here but silence warnings
1870 }
1871 }
1872
1873 bezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
1874 }
1875 }
1876 }
1877}
1878
1879
1880void SCH_IO_ALTIUM::ParsePolyline( const std::map<wxString, wxString>& aProperties,
1881 std::vector<LIB_SYMBOL*>& aSymbol )
1882{
1883 ASCH_POLYLINE elem( aProperties );
1884
1885 if( elem.Points.size() < 2 )
1886 return;
1887
1888 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1889 {
1890 SCH_SCREEN* screen = getCurrentScreen();
1891 wxCHECK( screen, /* void */ );
1892
1893 for( size_t i = 1; i < elem.Points.size(); i++ )
1894 {
1895 SCH_LINE* line = new SCH_LINE;
1896
1897 line->SetStartPoint( elem.Points[i - 1] + m_sheetOffset );
1898 line->SetEndPoint( elem.Points[i] + m_sheetOffset );
1899
1901 GetColorFromInt( elem.Color ) ) );
1902
1903 line->SetFlags( IS_NEW );
1904
1905 screen->Append( line );
1906 }
1907 }
1908 else
1909 {
1910 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
1911 ? nullptr
1912 : aSymbol[elem.ownerpartdisplaymode];
1913 SCH_SYMBOL* schsym = nullptr;
1914
1915 if( !symbol )
1916 {
1917 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1918
1919 if( libSymbolIt == m_libSymbols.end() )
1920 {
1921 // TODO: e.g. can depend on Template (RECORD=39
1922 m_reporter->Report( wxString::Format( wxT( "Polyline's owner (%d) not found." ),
1923 elem.ownerindex ),
1925 return;
1926 }
1927
1928 symbol = libSymbolIt->second;
1929 schsym = m_symbols.at( libSymbolIt->first );
1930 }
1931
1932 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
1933 return;
1934
1935 SCH_SHAPE* line = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1936 symbol->AddDrawItem( line, false );
1937
1938 line->SetUnit( std::max( 0, elem.ownerpartid ) );
1939
1940 for( VECTOR2I& point : elem.Points )
1941 {
1942 if( !schsym )
1943 line->AddPoint( GetLibEditPosition( point ) );
1944 else
1945 line->AddPoint( GetRelativePosition( point + m_sheetOffset, schsym ) );
1946 }
1947
1948 SetLibShapeLine( elem, line, ALTIUM_SCH_RECORD::POLYLINE );
1949 STROKE_PARAMS stroke = line->GetStroke();
1950 stroke.SetLineStyle( GetPlotDashType( elem.LineStyle ) );
1951
1952 line->SetStroke( stroke );
1953 }
1954}
1955
1956
1957void SCH_IO_ALTIUM::ParsePolygon( const std::map<wxString, wxString>& aProperties,
1958 std::vector<LIB_SYMBOL*>& aSymbol )
1959{
1960 ASCH_POLYGON elem( aProperties );
1961
1962 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1963 {
1964 SCH_SCREEN* screen = getCurrentScreen();
1965 wxCHECK( screen, /* void */ );
1966
1967 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
1968
1969 for( VECTOR2I& point : elem.points )
1970 poly->AddPoint( point + m_sheetOffset );
1971 poly->AddPoint( elem.points.front() + m_sheetOffset );
1972
1973 SetSchShapeLine( elem, poly );
1974 SetSchShapeFillAndColor( elem, poly );
1975 poly->SetFlags( IS_NEW );
1976
1977 screen->Append( poly );
1978 }
1979 else
1980 {
1981 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
1982 ? nullptr
1983 : aSymbol[elem.ownerpartdisplaymode];
1984 SCH_SYMBOL* schsym = nullptr;
1985
1986 if( !symbol )
1987 {
1988 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1989
1990 if( libSymbolIt == m_libSymbols.end() )
1991 {
1992 // TODO: e.g. can depend on Template (RECORD=39
1993 m_reporter->Report( wxString::Format( wxT( "Polygon's owner (%d) not found." ),
1994 elem.ownerindex ),
1996 return;
1997 }
1998
1999 symbol = libSymbolIt->second;
2000 schsym = m_symbols.at( libSymbolIt->first );
2001 }
2002
2003 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2004 return;
2005
2006 SCH_SHAPE* line = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2007
2008 symbol->AddDrawItem( line, false );
2009 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2010
2011 for( VECTOR2I& point : elem.points )
2012 {
2013 if( !schsym )
2014 line->AddPoint( GetLibEditPosition( point ) );
2015 else
2016 line->AddPoint( GetRelativePosition( point + m_sheetOffset, schsym ) );
2017 }
2018
2019 if( !schsym )
2020 line->AddPoint( GetLibEditPosition( elem.points.front() ) );
2021 else
2022 line->AddPoint( GetRelativePosition( elem.points.front() + m_sheetOffset, schsym ) );
2023
2024 SetLibShapeLine( elem, line, ALTIUM_SCH_RECORD::POLYGON );
2025 SetLibShapeFillAndColor( elem, line, ALTIUM_SCH_RECORD::POLYGON, elem.Color );
2026
2027 if( line->GetFillColor() == line->GetStroke().GetColor()
2028 && line->GetFillMode() != FILL_T::NO_FILL )
2029 {
2030 STROKE_PARAMS stroke = line->GetStroke();
2031 stroke.SetWidth( -1 );
2032 line->SetStroke( stroke );
2033 }
2034 }
2035}
2036
2037
2038void SCH_IO_ALTIUM::ParseRoundRectangle( const std::map<wxString, wxString>& aProperties,
2039 std::vector<LIB_SYMBOL*>& aSymbol )
2040{
2041 ASCH_ROUND_RECTANGLE elem( aProperties );
2042
2043 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2044 {
2045 SCH_SCREEN* screen = getCurrentScreen();
2046 wxCHECK( screen, /* void */ );
2047
2048 // TODO: misses rounded edges
2049 SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2050
2051 rect->SetPosition( elem.TopRight + m_sheetOffset );
2052 rect->SetEnd( elem.BottomLeft + m_sheetOffset );
2053 SetSchShapeLine( elem, rect );
2054 SetSchShapeFillAndColor( elem, rect );
2055 rect->SetFlags( IS_NEW );
2056
2057 screen->Append( rect );
2058 }
2059 else
2060 {
2061 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2062 ? nullptr
2063 : aSymbol[elem.ownerpartdisplaymode];
2064 SCH_SYMBOL* schsym = nullptr;
2065
2066 if( !symbol )
2067 {
2068 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2069
2070 if( libSymbolIt == m_libSymbols.end() )
2071 {
2072 // TODO: e.g. can depend on Template (RECORD=39
2073 m_reporter->Report( wxString::Format( wxT( "Rounded rectangle's owner (%d) not "
2074 "found." ),
2075 elem.ownerindex ),
2077 return;
2078 }
2079
2080 symbol = libSymbolIt->second;
2081 schsym = m_symbols.at( libSymbolIt->first );
2082 }
2083
2084 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2085 return;
2086
2087 SCH_SHAPE* rect = nullptr;
2088
2089 int width = std::abs( elem.TopRight.x - elem.BottomLeft.x );
2090 int height = std::abs( elem.TopRight.y - elem.BottomLeft.y );
2091
2092 // If it is a circle, make it a circle
2093 if( std::abs( elem.CornerRadius.x ) >= width / 2
2094 && std::abs( elem.CornerRadius.y ) >= height / 2 )
2095 {
2096 rect = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2097
2098 VECTOR2I center = ( elem.TopRight + elem.BottomLeft ) / 2;
2099 int radius = std::min( width / 2, height / 2 );
2100
2101 if( !schsym )
2102 rect->SetPosition( GetLibEditPosition( center ) );
2103 else
2104 rect->SetPosition( GetRelativePosition( center + m_sheetOffset, schsym ) );
2105
2106 rect->SetEnd( VECTOR2I( rect->GetPosition().x + radius, rect->GetPosition().y ) );
2107 }
2108 else
2109 {
2110 rect = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
2111
2112 if( !schsym )
2113 {
2114 rect->SetPosition( GetLibEditPosition( elem.TopRight ) );
2115 rect->SetEnd( GetLibEditPosition( elem.BottomLeft ) );
2116 }
2117 else
2118 {
2119 rect->SetPosition( GetRelativePosition( elem.TopRight + m_sheetOffset, schsym ) );
2120 rect->SetEnd( GetRelativePosition( elem.BottomLeft + m_sheetOffset, schsym ) );
2121 }
2122
2123 rect->Normalize();
2124 }
2125
2126 SetLibShapeLine( elem, rect, ALTIUM_SCH_RECORD::ROUND_RECTANGLE );
2127 SetLibShapeFillAndColor( elem, rect, ALTIUM_SCH_RECORD::ROUND_RECTANGLE, elem.Color );
2128
2129 symbol->AddDrawItem( rect, false );
2130 rect->SetUnit( std::max( 0, elem.ownerpartid ) );
2131 }
2132}
2133
2134
2135void SCH_IO_ALTIUM::ParseArc( const std::map<wxString, wxString>& aProperties,
2136 std::vector<LIB_SYMBOL*>& aSymbol )
2137{
2138 ASCH_ARC elem( aProperties );
2139
2140 int arc_radius = elem.m_Radius;
2141
2142 // Try to approximate this ellipse by a series of beziers
2143
2144 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2145 {
2146 SCH_SCREEN* currentScreen = getCurrentScreen();
2147 wxCHECK( currentScreen, /* void */ );
2148
2149 if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
2150 {
2151 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
2152
2153 circle->SetPosition( elem.m_Center + m_sheetOffset );
2154 circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
2155 circle->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2156
2157 currentScreen->Append( circle );
2158 }
2159 else
2160 {
2161 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
2162 EDA_ANGLE includedAngle( elem.m_EndAngle - elem.m_StartAngle, DEGREES_T );
2163 EDA_ANGLE startAngle( elem.m_EndAngle, DEGREES_T );
2164 VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
2165 -KiROUND( arc_radius * startAngle.Sin() ) );
2166
2167 arc->SetCenter( elem.m_Center + m_sheetOffset );
2168 arc->SetStart( elem.m_Center + startOffset + m_sheetOffset );
2169 arc->SetArcAngleAndEnd( includedAngle.Normalize(), true );
2170
2171 arc->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2172
2173 currentScreen->Append( arc );
2174 }
2175 }
2176 else
2177 {
2178 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2179 ? nullptr
2180 : aSymbol[elem.ownerpartdisplaymode];
2181 SCH_SYMBOL* schsym = nullptr;
2182
2183 if( !symbol )
2184 {
2185 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2186
2187 if( libSymbolIt == m_libSymbols.end() )
2188 {
2189 // TODO: e.g. can depend on Template (RECORD=39
2190 m_reporter->Report( wxString::Format( wxT( "Arc's owner (%d) not found." ),
2191 elem.ownerindex ),
2193 return;
2194 }
2195
2196 symbol = libSymbolIt->second;
2197 schsym = m_symbols.at( libSymbolIt->first );
2198 }
2199
2200 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2201 return;
2202
2203 if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
2204 {
2205 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2206 symbol->AddDrawItem( circle, false );
2207
2208 circle->SetUnit( std::max( 0, elem.ownerpartid ) );
2209
2210 if( !schsym )
2211 circle->SetPosition( GetLibEditPosition( elem.m_Center ) );
2212 else
2213 circle->SetPosition( GetRelativePosition( elem.m_Center + m_sheetOffset, schsym ) );
2214
2215 circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
2216 SetLibShapeLine( elem, circle, ALTIUM_SCH_RECORD::ARC );
2217 }
2218 else
2219 {
2220 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2221 symbol->AddDrawItem( arc, false );
2222 arc->SetUnit( std::max( 0, elem.ownerpartid ) );
2223
2224 EDA_ANGLE includedAngle( elem.m_EndAngle - elem.m_StartAngle, DEGREES_T );
2225 EDA_ANGLE startAngle( elem.m_StartAngle, DEGREES_T );
2226 VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
2227 -KiROUND( arc_radius * startAngle.Sin() ) );
2228
2229 if( schsym )
2230 {
2231 arc->SetCenter( GetRelativePosition( elem.m_Center + m_sheetOffset, schsym ) );
2232 arc->SetStart( GetRelativePosition( elem.m_Center + startOffset + m_sheetOffset,
2233 schsym ) );
2234 }
2235 else
2236 {
2237 arc->SetCenter( GetLibEditPosition( elem.m_Center ) );
2238 arc->SetStart( GetLibEditPosition( elem.m_Center + startOffset + m_sheetOffset ) );
2239 }
2240
2241 arc->SetArcAngleAndEnd( includedAngle.Normalize(), true );
2242
2243 SetLibShapeLine( elem, arc, ALTIUM_SCH_RECORD::ARC );
2244 }
2245 }
2246}
2247
2248
2249void SCH_IO_ALTIUM::ParseEllipticalArc( const std::map<wxString, wxString>& aProperties,
2250 std::vector<LIB_SYMBOL*>& aSymbol )
2251{
2252 ASCH_ARC elem( aProperties );
2253
2254 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2255 {
2256 SCH_SCREEN* currentScreen = getCurrentScreen();
2257 wxCHECK( currentScreen, /* void */ );
2258
2259 ELLIPSE<int> ellipse( elem.m_Center + m_sheetOffset, elem.m_Radius,
2262 EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
2263 std::vector<BEZIER<int>> beziers;
2264
2265 TransformEllipseToBeziers( ellipse, beziers );
2266
2267 for( const BEZIER<int>& bezier : beziers )
2268 {
2269 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER );
2270 schbezier->SetStart( bezier.Start );
2271 schbezier->SetBezierC1( bezier.C1 );
2272 schbezier->SetBezierC2( bezier.C2 );
2273 schbezier->SetEnd( bezier.End );
2274 schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2276
2277 currentScreen->Append( schbezier );
2278 }
2279 }
2280 else
2281 {
2282 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2283 ? nullptr
2284 : aSymbol[elem.ownerpartdisplaymode];
2285 SCH_SYMBOL* schsym = nullptr;
2286
2287 if( !symbol )
2288 {
2289 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2290
2291 if( libSymbolIt == m_libSymbols.end() )
2292 {
2293 // TODO: e.g. can depend on Template (RECORD=39
2294 m_reporter->Report( wxString::Format( wxT( "Elliptical Arc's owner (%d) not found." ),
2295 elem.ownerindex ),
2297 return;
2298 }
2299
2300 symbol = libSymbolIt->second;
2301 schsym = m_symbols.at( libSymbolIt->first );
2302 }
2303
2304 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2305 return;
2306
2307 ELLIPSE<int> ellipse( elem.m_Center, elem.m_Radius,
2310 EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
2311 std::vector<BEZIER<int>> beziers;
2312
2313 TransformEllipseToBeziers( ellipse, beziers );
2314
2315 for( const BEZIER<int>& bezier : beziers )
2316 {
2317 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE );
2318 symbol->AddDrawItem( schbezier, false );
2319
2320 schbezier->SetUnit( std::max( 0, elem.ownerpartid ) );
2321
2322 if( schsym )
2323 {
2324 schbezier->SetStart( GetRelativePosition( bezier.Start + m_sheetOffset, schsym ) );
2325 schbezier->SetBezierC1( GetRelativePosition( bezier.C1 + m_sheetOffset, schsym ) );
2326 schbezier->SetBezierC2( GetRelativePosition( bezier.C2 + m_sheetOffset, schsym ) );
2327 schbezier->SetEnd( GetRelativePosition( bezier.End + m_sheetOffset, schsym ) );
2328 }
2329 else
2330 {
2331 schbezier->SetStart( GetLibEditPosition( bezier.Start ) );
2332 schbezier->SetBezierC1( GetLibEditPosition( bezier.C1 ) );
2333 schbezier->SetBezierC2( GetLibEditPosition( bezier.C2 ) );
2334 schbezier->SetEnd( GetLibEditPosition( bezier.End ) );
2335 }
2336
2337 SetLibShapeLine( elem, schbezier, ALTIUM_SCH_RECORD::ELLIPTICAL_ARC );
2339 }
2340 }
2341}
2342
2343
2344void SCH_IO_ALTIUM::ParseEllipse( const std::map<wxString, wxString>& aProperties,
2345 std::vector<LIB_SYMBOL*>& aSymbol )
2346{
2347 ASCH_ELLIPSE elem( aProperties );
2348
2349 if( elem.Radius == elem.SecondaryRadius )
2350 {
2351 ParseCircle( aProperties, aSymbol );
2352 return;
2353 }
2354
2355 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2356 {
2357 SCH_SCREEN* screen = getCurrentScreen();
2358 wxCHECK( screen, /* void */ );
2359
2360 COLOR4D fillColor = GetColorFromInt( elem.AreaColor );
2361
2362 if( elem.IsTransparent )
2363 fillColor = fillColor.WithAlpha( 0.5 );
2364
2365 FILL_T fillMode = elem.IsSolid ? FILL_T::FILLED_WITH_COLOR : FILL_T::NO_FILL;
2366
2367 ELLIPSE<int> ellipse( elem.Center + m_sheetOffset, elem.Radius,
2368 KiROUND( elem.SecondaryRadius ), ANGLE_0 );
2369
2370 std::vector<BEZIER<int>> beziers;
2371 std::vector<VECTOR2I> polyPoints;
2372
2373 TransformEllipseToBeziers( ellipse, beziers );
2374
2375 for( const BEZIER<int>& bezier : beziers )
2376 {
2377 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER );
2378 schbezier->SetStart( bezier.Start );
2379 schbezier->SetBezierC1( bezier.C1 );
2380 schbezier->SetBezierC2( bezier.C2 );
2381 schbezier->SetEnd( bezier.End );
2382 schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2383 schbezier->SetFillColor( fillColor );
2384 schbezier->SetFillMode( fillMode );
2385
2386 schbezier->RebuildBezierToSegmentsPointsList( schbezier->GetWidth() / 2 );
2387 screen->Append( schbezier );
2388
2389 polyPoints.push_back( bezier.Start );
2390 }
2391
2392 if( fillMode != FILL_T::NO_FILL )
2393 {
2394 SCH_SHAPE* schpoly = new SCH_SHAPE( SHAPE_T::POLY );
2395 schpoly->SetFillColor( fillColor );
2396 schpoly->SetFillMode( fillMode );
2397 schpoly->SetWidth( -1 );
2398
2399 for( const VECTOR2I& point : polyPoints )
2400 schpoly->AddPoint( point );
2401
2402 schpoly->AddPoint( polyPoints[0] );
2403
2404 screen->Append( schpoly );
2405 }
2406 }
2407 else
2408 {
2409 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2410 ? nullptr
2411 : aSymbol[elem.ownerpartdisplaymode];
2412 SCH_SYMBOL* schsym = nullptr;
2413
2414 if( !symbol )
2415 {
2416 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2417
2418 if( libSymbolIt == m_libSymbols.end() )
2419 {
2420 // TODO: e.g. can depend on Template (RECORD=39
2421 m_reporter->Report( wxString::Format( wxT( "Ellipse's owner (%d) not found." ),
2422 elem.ownerindex ),
2424 return;
2425 }
2426
2427 symbol = libSymbolIt->second;
2428 schsym = m_symbols.at( libSymbolIt->first );
2429 }
2430
2431 ELLIPSE<int> ellipse( elem.Center, elem.Radius, KiROUND( elem.SecondaryRadius ),
2432 ANGLE_0 );
2433
2434 std::vector<BEZIER<int>> beziers;
2435 std::vector<VECTOR2I> polyPoints;
2436
2437 TransformEllipseToBeziers( ellipse, beziers );
2438
2439 for( const BEZIER<int>& bezier : beziers )
2440 {
2441 SCH_SHAPE* libbezier = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE );
2442 symbol->AddDrawItem( libbezier, false );
2443 libbezier->SetUnit( std::max( 0, elem.ownerpartid ) );
2444
2445 if( !schsym )
2446 {
2447 libbezier->SetStart( GetLibEditPosition( bezier.Start ) );
2448 libbezier->SetBezierC1( GetLibEditPosition( bezier.C1 ) );
2449 libbezier->SetBezierC2( GetLibEditPosition( bezier.C2 ) );
2450 libbezier->SetEnd( GetLibEditPosition( bezier.End ) );
2451 }
2452 else
2453 {
2454 libbezier->SetStart( GetRelativePosition( bezier.Start + m_sheetOffset, schsym ) );
2455 libbezier->SetBezierC1( GetRelativePosition( bezier.C1 + m_sheetOffset, schsym ) );
2456 libbezier->SetBezierC2( GetRelativePosition( bezier.C2 + m_sheetOffset, schsym ) );
2457 libbezier->SetEnd( GetRelativePosition( bezier.End + m_sheetOffset, schsym ) );
2458 }
2459
2460 SetLibShapeLine( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE );
2461 SetLibShapeFillAndColor( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE, elem.Color );
2462 libbezier->RebuildBezierToSegmentsPointsList( libbezier->GetWidth() / 2 );
2463
2464 polyPoints.push_back( libbezier->GetStart() );
2465 }
2466
2467 // A series of beziers won't fill the center, so if this is meant to be fully filled,
2468 // Add a polygon to fill the center
2469 if( elem.IsSolid )
2470 {
2471 SCH_SHAPE* libline = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2472 symbol->AddDrawItem( libline, false );
2473 libline->SetUnit( std::max( 0, elem.ownerpartid ) );
2474
2475 for( const VECTOR2I& point : polyPoints )
2476 libline->AddPoint( point );
2477
2478 libline->AddPoint( polyPoints[0] );
2479
2480 libline->SetWidth( -1 );
2481 SetLibShapeFillAndColor( elem, libline, ALTIUM_SCH_RECORD::ELLIPSE, elem.Color );
2482 }
2483 }
2484}
2485
2486
2487void SCH_IO_ALTIUM::ParseCircle( const std::map<wxString, wxString>& aProperties,
2488 std::vector<LIB_SYMBOL*>& aSymbol )
2489{
2490 ASCH_ELLIPSE elem( aProperties );
2491
2492 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2493 {
2494 SCH_SCREEN* screen = getCurrentScreen();
2495 wxCHECK( screen, /* void */ );
2496
2497 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
2498
2499 circle->SetPosition( elem.Center + m_sheetOffset );
2500 circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
2501 circle->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2502
2503 circle->SetFillColor( GetColorFromInt( elem.AreaColor ) );
2504
2505 if( elem.IsSolid )
2506 circle->SetFillMode( FILL_T::FILLED_WITH_COLOR );
2507 else
2508 circle->SetFilled( false );
2509
2510 screen->Append( circle );
2511 }
2512 else
2513 {
2514 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2515 ? nullptr
2516 : aSymbol[elem.ownerpartdisplaymode];
2517 SCH_SYMBOL* schsym = nullptr;
2518
2519 if( !symbol )
2520 {
2521 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2522
2523 if( libSymbolIt == m_libSymbols.end() )
2524 {
2525 // TODO: e.g. can depend on Template (RECORD=39
2526 m_reporter->Report( wxString::Format( wxT( "Ellipse's owner (%d) not found." ),
2527 elem.ownerindex ),
2529 return;
2530 }
2531
2532 symbol = libSymbolIt->second;
2533 schsym = m_symbols.at( libSymbolIt->first );
2534 }
2535
2536 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2537 symbol->AddDrawItem( circle, false );
2538
2539 circle->SetUnit( std::max( 0, elem.ownerpartid ) );
2540
2541 if( !schsym )
2542 circle->SetPosition( GetLibEditPosition( elem.Center ) );
2543 else
2544 circle->SetPosition( GetRelativePosition( elem.Center + m_sheetOffset, schsym ) );
2545
2546 circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
2547
2548 SetLibShapeLine( elem, circle, ALTIUM_SCH_RECORD::ELLIPSE );
2549 SetLibShapeFillAndColor( elem, circle, ALTIUM_SCH_RECORD::ELLIPSE, elem.Color );
2550 }
2551}
2552
2553
2554void SCH_IO_ALTIUM::ParseLine( const std::map<wxString, wxString>& aProperties,
2555 std::vector<LIB_SYMBOL*>& aSymbol )
2556{
2557 ASCH_LINE elem( aProperties );
2558
2559 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2560 {
2561
2562 SCH_SCREEN* screen = getCurrentScreen();
2563 wxCHECK( screen, /* void */ );
2564
2565 // close polygon
2566 SCH_LINE* line = new SCH_LINE( elem.point1 + m_sheetOffset, SCH_LAYER_ID::LAYER_NOTES );
2567 line->SetEndPoint( elem.point2 + m_sheetOffset );
2569 GetColorFromInt( elem.Color ) ) );
2570
2571 line->SetFlags( IS_NEW );
2572 screen->Append( line );
2573 }
2574 else
2575 {
2576 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2577 ? nullptr
2578 : aSymbol[elem.ownerpartdisplaymode];
2579 SCH_SYMBOL* schsym = nullptr;
2580
2581 if( !symbol )
2582 {
2583 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2584
2585 if( libSymbolIt == m_libSymbols.end() )
2586 {
2587 // TODO: e.g. can depend on Template (RECORD=39
2588 m_reporter->Report( wxString::Format( wxT( "Line's owner (%d) not found." ),
2589 elem.ownerindex ),
2591 return;
2592 }
2593
2594 symbol = libSymbolIt->second;
2595 schsym = m_symbols.at( libSymbolIt->first );
2596 }
2597
2598 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2599 return;
2600
2601 SCH_SHAPE* line = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2602 symbol->AddDrawItem( line, false );
2603
2604 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2605
2606 if( !schsym )
2607 {
2608 line->AddPoint( GetLibEditPosition( elem.point1 ) );
2609 line->AddPoint( GetLibEditPosition( elem.point2 ) );
2610 }
2611 else
2612 {
2613 line->AddPoint( GetRelativePosition( elem.point1 + m_sheetOffset, schsym ) );
2614 line->AddPoint( GetRelativePosition( elem.point2 + m_sheetOffset, schsym ) );
2615 }
2616
2617 SetLibShapeLine( elem, line, ALTIUM_SCH_RECORD::LINE );
2618 line->SetLineStyle( GetPlotDashType( elem.LineStyle ) );
2619 }
2620}
2621
2622
2623void SCH_IO_ALTIUM::ParseSignalHarness( const std::map<wxString, wxString>& aProperties )
2624{
2625 ASCH_SIGNAL_HARNESS elem( aProperties );
2626
2627 if( ShouldPutItemOnSheet( elem.ownerindex ) )
2628 {
2629 SCH_SCREEN* screen = getCurrentScreen();
2630 wxCHECK( screen, /* void */ );
2631
2632 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
2633
2634 for( VECTOR2I& point : elem.Points )
2635 poly->AddPoint( point + m_sheetOffset );
2636
2637 poly->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID,
2638 GetColorFromInt( elem.Color ) ) );
2639 poly->SetFlags( IS_NEW );
2640
2641 screen->Append( poly );
2642 }
2643 else
2644 {
2645 // No clue if this situation can ever exist
2646 m_reporter->Report( wxT( "Signal harness, belonging to the part is not currently "
2647 "supported." ), RPT_SEVERITY_DEBUG );
2648 }
2649}
2650
2651
2652void SCH_IO_ALTIUM::ParseHarnessConnector( int aIndex, const std::map<wxString,
2653 wxString>& aProperties )
2654{
2655 ASCH_HARNESS_CONNECTOR elem( aProperties );
2656
2657 if( ShouldPutItemOnSheet( elem.ownerindex ) )
2658 {
2659 SCH_SCREEN* currentScreen = getCurrentScreen();
2660 wxCHECK( currentScreen, /* void */ );
2661
2663 elem.Size );
2664
2665 sheet->SetScreen( new SCH_SCREEN( m_schematic ) );
2667 sheet->SetBorderColor( GetColorFromInt( elem.Color ) );
2668
2669 currentScreen->Append( sheet );
2670
2671 SCH_SHEET_PATH sheetpath = m_sheetPath;
2672 sheetpath.push_back( sheet );
2673
2674 sheetpath.SetPageNumber( "Harness #" );
2675
2677 m_sheets.insert( { m_harnessEntryParent, sheet } );
2678 }
2679 else
2680 {
2681 // I have no clue if this situation can ever exist
2682 m_reporter->Report( wxT( "Harness connector, belonging to the part is not currently "
2683 "supported." ),
2685 }
2686}
2687
2688
2689void SCH_IO_ALTIUM::ParseHarnessEntry( const std::map<wxString, wxString>& aProperties )
2690{
2691 ASCH_HARNESS_ENTRY elem( aProperties );
2692
2693 const auto& sheetIt = m_sheets.find( m_harnessEntryParent );
2694
2695 if( sheetIt == m_sheets.end() )
2696 {
2697 m_reporter->Report( wxString::Format( wxT( "Harness entry's parent (%d) not found." ),
2700 return;
2701 }
2702
2703 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
2704 sheetIt->second->AddPin( sheetPin );
2705
2706 sheetPin->SetText( elem.Name );
2707 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
2708
2709 VECTOR2I pos = sheetIt->second->GetPosition();
2710 VECTOR2I size = sheetIt->second->GetSize();
2711
2712 switch( elem.Side )
2713 {
2714 default:
2715 case ASCH_SHEET_ENTRY_SIDE::LEFT:
2716 sheetPin->SetPosition( { pos.x, pos.y + elem.DistanceFromTop } );
2717 sheetPin->SetSpinStyle( SPIN_STYLE::LEFT );
2718 sheetPin->SetSide( SHEET_SIDE::LEFT );
2719 break;
2720 case ASCH_SHEET_ENTRY_SIDE::RIGHT:
2721 sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.DistanceFromTop } );
2722 sheetPin->SetSpinStyle( SPIN_STYLE::RIGHT );
2723 sheetPin->SetSide( SHEET_SIDE::RIGHT );
2724 break;
2725 case ASCH_SHEET_ENTRY_SIDE::TOP:
2726 sheetPin->SetPosition( { pos.x + elem.DistanceFromTop, pos.y } );
2727 sheetPin->SetSpinStyle( SPIN_STYLE::UP );
2728 sheetPin->SetSide( SHEET_SIDE::TOP );
2729 break;
2730 case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
2731 sheetPin->SetPosition( { pos.x + elem.DistanceFromTop, pos.y + size.y } );
2732 sheetPin->SetSpinStyle( SPIN_STYLE::BOTTOM );
2733 sheetPin->SetSide( SHEET_SIDE::BOTTOM );
2734 break;
2735 }
2736}
2737
2738
2739void SCH_IO_ALTIUM::ParseHarnessType( const std::map<wxString, wxString>& aProperties )
2740{
2741 ASCH_HARNESS_TYPE elem( aProperties );
2742
2743 const auto& sheetIt = m_sheets.find( m_harnessEntryParent );
2744
2745 if( sheetIt == m_sheets.end() )
2746 {
2747 m_reporter->Report( wxString::Format( wxT( "Harness type's parent (%d) not found." ),
2750 return;
2751 }
2752
2753 SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
2754
2755 sheetNameField.SetPosition( elem.Location + m_sheetOffset );
2756 sheetNameField.SetText( elem.Text );
2757
2758 // Always set as visible so user is aware about ( !elem.isHidden );
2759 sheetNameField.SetVisible( true );
2760 SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT,
2761 ASCH_RECORD_ORIENTATION::RIGHTWARDS );
2762 sheetNameField.SetTextColor( GetColorFromInt( elem.Color ) );
2763
2764 SCH_FIELD& sheetFileName = sheetIt->second->GetFields()[SHEETFILENAME];
2765 sheetFileName.SetText( elem.Text + wxT( "." ) + FILEEXT::KiCadSchematicFileExtension );
2766
2767 wxFileName fn( m_schematic->Prj().GetProjectPath(), elem.Text,
2769 wxString fullPath = fn.GetFullPath();
2770
2771 fullPath.Replace( wxT( "\\" ), wxT( "/" ) );
2772
2773 SCH_SCREEN* screen = sheetIt->second->GetScreen();
2774
2775 wxCHECK( screen, /* void */ );
2776 screen->SetFileName( fullPath );
2777
2778 m_reporter->Report( wxString::Format( _( "Altium's harness connector (%s) was imported as a "
2779 "hierarchical sheet. Please review the imported "
2780 "schematic." ),
2781 elem.Text ),
2783}
2784
2785
2786void SCH_IO_ALTIUM::ParseRectangle( const std::map<wxString, wxString>& aProperties,
2787 std::vector<LIB_SYMBOL*>& aSymbol )
2788{
2789 ASCH_RECTANGLE elem( aProperties );
2790
2791 VECTOR2I sheetTopRight = elem.TopRight + m_sheetOffset;
2792 VECTOR2I sheetBottomLeft = elem.BottomLeft + m_sheetOffset;
2793
2794 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2795 {
2796 SCH_SCREEN* screen = getCurrentScreen();
2797 wxCHECK( screen, /* void */ );
2798
2799 SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2800
2801 rect->SetPosition( sheetTopRight );
2802 rect->SetEnd( sheetBottomLeft );
2803 SetSchShapeLine( elem, rect );
2804 SetSchShapeFillAndColor( elem, rect );
2805 rect->SetFlags( IS_NEW );
2806
2807 screen->Append( rect );
2808 }
2809 else
2810 {
2811 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= elem.ownerpartdisplaymode
2812 ? nullptr
2813 : aSymbol[elem.ownerpartdisplaymode];
2814 SCH_SYMBOL* schsym = nullptr;
2815
2816 if( !symbol )
2817 {
2818 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2819
2820 if( libSymbolIt == m_libSymbols.end() )
2821 {
2822 // TODO: e.g. can depend on Template (RECORD=39
2823 m_reporter->Report( wxString::Format( wxT( "Rectangle's owner (%d) not found." ),
2824 elem.ownerindex ),
2826 return;
2827 }
2828
2829 symbol = libSymbolIt->second;
2830 schsym = m_symbols.at( libSymbolIt->first );
2831 }
2832
2833 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2834 return;
2835
2836 SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
2837 symbol->AddDrawItem( rect, false );
2838
2839 rect->SetUnit( std::max( 0, elem.ownerpartid ) );
2840
2841 if( !schsym )
2842 {
2843 rect->SetPosition( GetLibEditPosition( sheetTopRight ) );
2844 rect->SetEnd( GetLibEditPosition( sheetBottomLeft ) );
2845 }
2846 else
2847 {
2848 rect->SetPosition( GetRelativePosition( sheetTopRight, schsym ) );
2849 rect->SetEnd( GetRelativePosition( sheetBottomLeft, schsym ) );
2850 }
2851
2852 SetLibShapeLine( elem, rect, ALTIUM_SCH_RECORD::RECTANGLE );
2853 SetLibShapeFillAndColor( elem, rect, ALTIUM_SCH_RECORD::RECTANGLE, elem.Color );
2854 }
2855}
2856
2857
2859 const std::map<wxString, wxString>& aProperties )
2860{
2861 ASCH_SHEET_SYMBOL elem( aProperties );
2862
2864 elem.size );
2865
2866 sheet->SetBorderColor( GetColorFromInt( elem.color ) );
2867
2868 if( elem.isSolid )
2870
2871 sheet->SetFlags( IS_NEW );
2872
2873 SCH_SCREEN* currentScreen = getCurrentScreen();
2874 wxCHECK( currentScreen, /* void */ );
2875 currentScreen->Append( sheet );
2876
2877 SCH_SHEET_PATH sheetpath = m_sheetPath;
2878 sheetpath.push_back( sheet );
2879
2880 // We'll update later if we find a pageNumber record for it.
2881 sheetpath.SetPageNumber( "#" );
2882
2883 SCH_SCREEN* rootScreen = m_rootSheet->GetScreen();
2884 wxCHECK( rootScreen, /* void */ );
2885
2886 SCH_SHEET_INSTANCE sheetInstance;
2887
2888 sheetInstance.m_Path = sheetpath.Path();
2889 sheetInstance.m_PageNumber = wxT( "#" );
2890
2891 rootScreen->m_sheetInstances.emplace_back( sheetInstance );
2892 m_sheets.insert( { aIndex, sheet } );
2893}
2894
2895
2896void SCH_IO_ALTIUM::ParseSheetEntry( const std::map<wxString, wxString>& aProperties )
2897{
2898 ASCH_SHEET_ENTRY elem( aProperties );
2899
2900 const auto& sheetIt = m_sheets.find( elem.ownerindex );
2901
2902 if( sheetIt == m_sheets.end() )
2903 {
2904 m_reporter->Report( wxString::Format( wxT( "Sheet entry's owner (%d) not found." ),
2905 elem.ownerindex ),
2907 return;
2908 }
2909
2910 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
2911 sheetIt->second->AddPin( sheetPin );
2912
2913 sheetPin->SetText( elem.name );
2914 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
2915 //sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
2916 //sheetPin->SetPosition( getKiCadPoint( term.Position ) );
2917
2918 VECTOR2I pos = sheetIt->second->GetPosition();
2919 VECTOR2I size = sheetIt->second->GetSize();
2920
2921 switch( elem.side )
2922 {
2923 default:
2924 case ASCH_SHEET_ENTRY_SIDE::LEFT:
2925 sheetPin->SetPosition( { pos.x, pos.y + elem.distanceFromTop } );
2926 sheetPin->SetSpinStyle( SPIN_STYLE::LEFT );
2927 sheetPin->SetSide( SHEET_SIDE::LEFT );
2928 break;
2929
2930 case ASCH_SHEET_ENTRY_SIDE::RIGHT:
2931 sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.distanceFromTop } );
2932 sheetPin->SetSpinStyle( SPIN_STYLE::RIGHT );
2933 sheetPin->SetSide( SHEET_SIDE::RIGHT );
2934 break;
2935
2936 case ASCH_SHEET_ENTRY_SIDE::TOP:
2937 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y } );
2938 sheetPin->SetSpinStyle( SPIN_STYLE::UP );
2939 sheetPin->SetSide( SHEET_SIDE::TOP );
2940 break;
2941
2942 case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
2943 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y + size.y } );
2944 sheetPin->SetSpinStyle( SPIN_STYLE::BOTTOM );
2945 sheetPin->SetSide( SHEET_SIDE::BOTTOM );
2946 break;
2947 }
2948
2949 switch( elem.iotype )
2950 {
2951 default:
2952 case ASCH_PORT_IOTYPE::UNSPECIFIED:
2953 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
2954 break;
2955
2956 case ASCH_PORT_IOTYPE::OUTPUT:
2957 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
2958 break;
2959
2960 case ASCH_PORT_IOTYPE::INPUT:
2961 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
2962 break;
2963
2964 case ASCH_PORT_IOTYPE::BIDI:
2965 sheetPin->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
2966 break;
2967 }
2968}
2969
2970
2972 REPORTER* aReporter )
2973{
2975 {
2977 aKsymbol->AddDrawItem( line1, false );
2979 line1->AddPoint( { 0, 0 } );
2980 line1->AddPoint( { 0, schIUScale.MilsToIU( -50 ) } );
2981
2982 if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE )
2983 {
2985 aKsymbol->AddDrawItem( circle, false );
2987 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -75 ) } );
2988 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 25 ), 0 ) );
2989 }
2990 else
2991 {
2993 aKsymbol->AddDrawItem( line2, false );
2995 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
2996 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
2997 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
2998 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
2999 }
3000
3001 return { 0, schIUScale.MilsToIU( 150 ) };
3002 }
3003 else if( aStyle == ASCH_POWER_PORT_STYLE::WAVE )
3004 {
3006 aKsymbol->AddDrawItem( line, false );
3008 line->AddPoint( { 0, 0 } );
3009 line->AddPoint( { 0, schIUScale.MilsToIU( -72 ) } );
3010
3012 aKsymbol->AddDrawItem( bezier, false );
3014 bezier->SetStart( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
3015 bezier->SetBezierC1( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
3016 bezier->SetBezierC2( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
3017 bezier->SetEnd( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
3018
3019 return { 0, schIUScale.MilsToIU( 150 ) };
3020 }
3021 else if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND
3023 || aStyle == ASCH_POWER_PORT_STYLE::EARTH
3025 {
3027 aKsymbol->AddDrawItem( line1, false );
3029 line1->AddPoint( { 0, 0 } );
3030 line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
3031
3033 {
3035 aKsymbol->AddDrawItem( line2, false );
3037 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
3038 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
3039
3041 aKsymbol->AddDrawItem( line3, false );
3043 line3->AddPoint( { schIUScale.MilsToIU( -70 ), schIUScale.MilsToIU( -130 ) } );
3044 line3->AddPoint( { schIUScale.MilsToIU( 70 ), schIUScale.MilsToIU( -130 ) } );
3045
3047 aKsymbol->AddDrawItem( line4, false );
3049 line4->AddPoint( { schIUScale.MilsToIU( -40 ), schIUScale.MilsToIU( -160 ) } );
3050 line4->AddPoint( { schIUScale.MilsToIU( 40 ), schIUScale.MilsToIU( -160 ) } );
3051
3053 aKsymbol->AddDrawItem( line5, false );
3055 line5->AddPoint( { schIUScale.MilsToIU( -10 ), schIUScale.MilsToIU( -190 ) } );
3056 line5->AddPoint( { schIUScale.MilsToIU( 10 ), schIUScale.MilsToIU( -190 ) } );
3057 }
3058 else if( aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND )
3059 {
3061 aKsymbol->AddDrawItem( line2, false );
3063 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
3064 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
3065 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -200 ) } );
3066 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
3067 }
3068 else if( aStyle == ASCH_POWER_PORT_STYLE::EARTH )
3069 {
3071 aKsymbol->AddDrawItem( line2, false );
3073 line2->AddPoint( { schIUScale.MilsToIU( -150 ), schIUScale.MilsToIU( -200 ) } );
3074 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -100 ) } );
3075 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -100 ) } );
3076 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -200 ) } );
3077
3079 aKsymbol->AddDrawItem( line3, false );
3081 line3->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
3082 line3->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -200 ) } );
3083 }
3084 else // ASCH_POWER_PORT_STYLE::GOST_ARROW
3085 {
3087 aKsymbol->AddDrawItem( line2, false );
3089 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( -50 ) } );
3090 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -100 ) } );
3091 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( -50 ) } );
3092
3093 return { 0, schIUScale.MilsToIU( 150 ) }; // special case
3094 }
3095
3096 return { 0, schIUScale.MilsToIU( 250 ) };
3097 }
3100 {
3102 aKsymbol->AddDrawItem( line1, false );
3104 line1->AddPoint( { 0, 0 } );
3105 line1->AddPoint( { 0, schIUScale.MilsToIU( -160 ) } );
3106
3108 aKsymbol->AddDrawItem( line2, false );
3110 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -160 ) } );
3111 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -160 ) } );
3112
3114 aKsymbol->AddDrawItem( line3, false );
3116 line3->AddPoint( { schIUScale.MilsToIU( -60 ), schIUScale.MilsToIU( -200 ) } );
3117 line3->AddPoint( { schIUScale.MilsToIU( 60 ), schIUScale.MilsToIU( -200 ) } );
3118
3120 aKsymbol->AddDrawItem( line4, false );
3122 line4->AddPoint( { schIUScale.MilsToIU( -20 ), schIUScale.MilsToIU( -240 ) } );
3123 line4->AddPoint( { schIUScale.MilsToIU( 20 ), schIUScale.MilsToIU( -240 ) } );
3124
3126 return { 0, schIUScale.MilsToIU( 300 ) };
3127
3129 aKsymbol->AddDrawItem( circle, false );
3131 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( -160 ) } );
3132 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 120 ), 0 ) );
3133
3134 return { 0, schIUScale.MilsToIU( 350 ) };
3135 }
3136 else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_BAR )
3137 {
3139 aKsymbol->AddDrawItem( line1, false );
3141 line1->AddPoint( { 0, 0 } );
3142 line1->AddPoint( { 0, schIUScale.MilsToIU( -200 ) } );
3143
3145 aKsymbol->AddDrawItem( line2, false );
3147 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( -200 ) } );
3148 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( -200 ) } );
3149
3150 return { 0, schIUScale.MilsToIU( 250 ) };
3151 }
3152 else
3153 {
3154 if( aStyle != ASCH_POWER_PORT_STYLE::BAR )
3155 {
3156 aReporter->Report( _( "Power Port with unknown style imported as 'Bar' type." ),
3158 }
3159
3161 aKsymbol->AddDrawItem( line1, false );
3163 line1->AddPoint( { 0, 0 } );
3164 line1->AddPoint( { 0, schIUScale.MilsToIU( -100 ) } );
3165
3167 aKsymbol->AddDrawItem( line2, false );
3169 line2->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( -100 ) } );
3170 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( -100 ) } );
3171
3172 return { 0, schIUScale.MilsToIU( 150 ) };
3173 }
3174}
3175
3176
3177void SCH_IO_ALTIUM::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
3178{
3179 ASCH_POWER_PORT elem( aProperties );
3180
3181 wxString symName( elem.text );
3182 std::string styleName( magic_enum::enum_name<ASCH_POWER_PORT_STYLE>( elem.style ) );
3183
3184 if( !styleName.empty() )
3185 symName << '_' << styleName;
3186
3187 LIB_ID libId = AltiumToKiCadLibID( getLibName(), symName );
3188 LIB_SYMBOL* libSymbol = nullptr;
3189
3190 const auto& powerSymbolIt = m_powerSymbols.find( symName );
3191
3192 if( powerSymbolIt != m_powerSymbols.end() )
3193 {
3194 libSymbol = powerSymbolIt->second; // cache hit
3195 }
3196 else if( LIB_SYMBOL* alreadyLoaded =
3197 m_pi->LoadSymbol( getLibFileName().GetFullPath(), elem.text, m_properties.get() ) )
3198 {
3199 libSymbol = alreadyLoaded;
3200 }
3201 else
3202 {
3203 libSymbol = new LIB_SYMBOL( wxEmptyString );
3204 libSymbol->SetPower();
3205 libSymbol->SetName( elem.text );
3206 libSymbol->GetReferenceField().SetText( "#PWR" );
3207 libSymbol->GetValueField().SetText( elem.text );
3208 libSymbol->GetValueField().SetVisible( true );
3209 libSymbol->SetDescription( wxString::Format( _( "Power symbol creates a global "
3210 "label with name '%s'" ), elem.text ) );
3211 libSymbol->SetKeyWords( "power-flag" );
3212 libSymbol->SetLibId( libId );
3213
3214 // generate graphic
3215 SCH_PIN* pin = new SCH_PIN( libSymbol );
3216 libSymbol->AddDrawItem( pin, false );
3217
3218 pin->SetName( elem.text );
3219 pin->SetPosition( { 0, 0 } );
3220 pin->SetLength( 0 );
3221 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
3222 pin->SetVisible( false );
3223
3224 VECTOR2I valueFieldPos = HelperGeneratePowerPortGraphics( libSymbol, elem.style,
3225 m_reporter );
3226
3227 libSymbol->GetValueField().SetPosition( valueFieldPos );
3228
3229 // this has to be done after parsing the LIB_SYMBOL!
3230 m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
3231 m_powerSymbols.insert( { symName, libSymbol } );
3232 }
3233
3234 SCH_SCREEN* screen = getCurrentScreen();
3235 wxCHECK( screen, /* void */ );
3236
3237 // each symbol has its own powerSymbolIt for now
3238 SCH_SYMBOL* symbol = new SCH_SYMBOL();
3239 symbol->SetRef( &m_sheetPath, "#PWR?" );
3240 symbol->SetValueFieldText( elem.text );
3241 symbol->SetLibId( libId );
3242 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
3243
3244 SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
3245 valueField->SetVisible( elem.showNetName );
3246
3247 // TODO: Why do I need to set this a second time?
3248 valueField->SetPosition( libSymbol->GetValueField().GetPosition() );
3249
3250 symbol->SetPosition( elem.location + m_sheetOffset );
3251
3252 switch( elem.orientation )
3253 {
3254 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
3255 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_90 );
3256 valueField->SetTextAngle( ANGLE_VERTICAL );
3258 break;
3259
3260 case ASCH_RECORD_ORIENTATION::UPWARDS:
3261 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_180 );
3262 valueField->SetTextAngle( ANGLE_HORIZONTAL );
3264 break;
3265
3266 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
3267 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_270 );
3268 valueField->SetTextAngle( ANGLE_VERTICAL );
3270 break;
3271
3272 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
3273 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_0 );
3274 valueField->SetTextAngle( ANGLE_HORIZONTAL );
3276 break;
3277
3278 default:
3279 m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
3280 break;
3281 }
3282
3283 screen->Append( symbol );
3284}
3285
3286
3288{
3289 SCH_TEXTBOX* textBox = new SCH_TEXTBOX();
3290
3291 textBox->SetText( aElem.Name );
3292 textBox->SetTextColor( GetColorFromInt( aElem.TextColor ) );
3293
3294 int height = aElem.Height;
3295 if( height <= 0 )
3296 height = schIUScale.MilsToIU( 100 ); // chose default 50 grid
3297
3298 textBox->SetStartX( ( aElem.Location + m_sheetOffset ).x );
3299 textBox->SetStartY( ( aElem.Location + m_sheetOffset ).y - ( height / 2 ) );
3300 textBox->SetEndX( ( aElem.Location + m_sheetOffset ).x + ( aElem.Width ) );
3301 textBox->SetEndY( ( aElem.Location + m_sheetOffset ).y + ( height / 2 ) );
3302
3304 textBox->SetFillMode( FILL_T::FILLED_WITH_COLOR );
3305
3306 textBox->SetStroke( STROKE_PARAMS( 2, LINE_STYLE::DEFAULT,
3308
3309 switch( aElem.Alignment )
3310 {
3311 default:
3312 case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
3314 break;
3315
3316 case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
3318 break;
3319
3320 case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
3322 break;
3323 }
3324
3325 size_t fontId = static_cast<int>( aElem.FontID );
3326
3327 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
3328 {
3329 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
3330 textBox->SetTextSize( { font.Size / 2, font.Size / 2 } );
3331
3332 // Must come after SetTextSize()
3333 textBox->SetBold( font.Bold );
3334 textBox->SetItalic( font.Italic );
3335 //textBox->SetFont( //how to set font, we have a font name here: ( font.fontname );
3336 }
3337
3338 textBox->SetFlags( IS_NEW );
3339
3340 SCH_SCREEN* screen = getCurrentScreen();
3341 wxCHECK( screen, /* void */ );
3342
3343 screen->Append( textBox );
3344
3345 m_reporter->Report( wxString::Format( _( "Altium's harness port (%s) was imported as "
3346 "a text box. Please review the imported "
3347 "schematic." ),
3348 aElem.Name ),
3350}
3351
3352
3354{
3355 if( !aElem.HarnessType.IsEmpty() )
3356 {
3357 // Parse harness ports after "Additional" compound section is parsed
3358 m_altiumHarnessPortsCurrentSheet.emplace_back( aElem );
3359 return;
3360 }
3361
3362 VECTOR2I start = aElem.Location + m_sheetOffset;
3363 VECTOR2I end = start;
3364
3365 switch( aElem.Style )
3366 {
3367 default:
3368 case ASCH_PORT_STYLE::NONE_HORIZONTAL:
3369 case ASCH_PORT_STYLE::LEFT:
3370 case ASCH_PORT_STYLE::RIGHT:
3371 case ASCH_PORT_STYLE::LEFT_RIGHT:
3372 end.x += aElem.Width;
3373 break;
3374
3375 case ASCH_PORT_STYLE::NONE_VERTICAL:
3376 case ASCH_PORT_STYLE::TOP:
3377 case ASCH_PORT_STYLE::BOTTOM:
3378 case ASCH_PORT_STYLE::TOP_BOTTOM:
3379 end.y -= aElem.Width;
3380 break;
3381 }
3382
3383 // Check which connection points exists in the schematic
3384 SCH_SCREEN* screen = getCurrentScreen();
3385 wxCHECK( screen, /* void */ );
3386
3387 bool startIsWireTerminal = screen->IsTerminalPoint( start, LAYER_WIRE );
3388 bool startIsBusTerminal = screen->IsTerminalPoint( start, LAYER_BUS );
3389
3390 bool endIsWireTerminal = screen->IsTerminalPoint( end, LAYER_WIRE );
3391 bool endIsBusTerminal = screen->IsTerminalPoint( end, LAYER_BUS );
3392
3393 // check if any of the points is a terminal point
3394 // TODO: there seems a problem to detect approximated connections towards component pins?
3395 bool connectionFound = startIsWireTerminal
3396 || startIsBusTerminal
3397 || endIsWireTerminal
3398 || endIsBusTerminal;
3399
3400 if( !connectionFound )
3401 {
3402 m_reporter->Report( wxString::Format( _( "Port %s has no connections." ), aElem.Name ),
3404 }
3405
3406 // Select label position. In case both match, we will add a line later.
3407 VECTOR2I position = ( startIsWireTerminal || startIsBusTerminal ) ? start : end;
3408 SCH_LABEL_BASE* label;
3409
3410 // TODO: detect correct label type depending on sheet settings, etc.
3411#if 1 // Set to 1 to use SCH_HIERLABEL label, 0 to use SCH_GLOBALLABEL
3412 {
3413 label = new SCH_HIERLABEL( position, aElem.Name );
3414 }
3415#else
3416 label = new SCH_GLOBALLABEL( position, aElem.Name );
3417#endif
3418
3419 switch( aElem.IOtype )
3420 {
3421 default:
3422 case ASCH_PORT_IOTYPE::UNSPECIFIED: label->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED ); break;
3423 case ASCH_PORT_IOTYPE::OUTPUT: label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT ); break;
3424 case ASCH_PORT_IOTYPE::INPUT: label->SetShape( LABEL_FLAG_SHAPE::L_INPUT ); break;
3425 case ASCH_PORT_IOTYPE::BIDI: label->SetShape( LABEL_FLAG_SHAPE::L_BIDI ); break;
3426 }
3427
3428 switch( aElem.Style )
3429 {
3430 default:
3431 case ASCH_PORT_STYLE::NONE_HORIZONTAL:
3432 case ASCH_PORT_STYLE::LEFT:
3433 case ASCH_PORT_STYLE::RIGHT:
3434 case ASCH_PORT_STYLE::LEFT_RIGHT:
3435 if( ( startIsWireTerminal || startIsBusTerminal ) )
3437 else
3439
3440 break;
3441
3442 case ASCH_PORT_STYLE::NONE_VERTICAL:
3443 case ASCH_PORT_STYLE::TOP:
3444 case ASCH_PORT_STYLE::BOTTOM:
3445 case ASCH_PORT_STYLE::TOP_BOTTOM:
3446 if( ( startIsWireTerminal || startIsBusTerminal ) )
3447 label->SetSpinStyle( SPIN_STYLE::UP );
3448 else
3450
3451 break;
3452 }
3453
3454 label->AutoplaceFields( screen, false );
3455
3456 // Default "Sheet References" field should be hidden, at least for now
3457 if( label->GetFields().size() > 0 )
3458 label->GetFields()[0].SetVisible( false );
3459
3460 label->SetFlags( IS_NEW );
3461
3462 screen->Append( label );
3463
3464 // This is a hack, for the case both connection points are valid: add a small wire
3465 if( ( startIsWireTerminal && endIsWireTerminal ) )
3466 {
3467 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_WIRE );
3468 wire->SetEndPoint( end );
3469 wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
3470 wire->SetFlags( IS_NEW );
3471 screen->Append( wire );
3472 }
3473 else if( startIsBusTerminal && endIsBusTerminal )
3474 {
3475 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_BUS );
3476 wire->SetEndPoint( end );
3477 wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
3478 wire->SetFlags( IS_NEW );
3479 screen->Append( wire );
3480 }
3481}
3482
3483
3484void SCH_IO_ALTIUM::ParseNoERC( const std::map<wxString, wxString>& aProperties )
3485{
3486 ASCH_NO_ERC elem( aProperties );
3487
3488 SCH_SCREEN* screen = getCurrentScreen();
3489 wxCHECK( screen, /* void */ );
3490
3491 if( elem.isActive )
3492 {
3493 SCH_NO_CONNECT* noConnect = new SCH_NO_CONNECT( elem.location + m_sheetOffset );
3494
3495 noConnect->SetFlags( IS_NEW );
3496 screen->Append( noConnect );
3497 }
3498}
3499
3500
3501void SCH_IO_ALTIUM::ParseNetLabel( const std::map<wxString, wxString>& aProperties )
3502{
3503 ASCH_NET_LABEL elem( aProperties );
3504
3505 SCH_LABEL* label = new SCH_LABEL( elem.location + m_sheetOffset, elem.text );
3506
3507 SCH_SCREEN* screen = getCurrentScreen();
3508 wxCHECK( screen, /* void */ );
3509
3510 SetTextPositioning( label, elem.justification, elem.orientation );
3511
3512 label->SetFlags( IS_NEW );
3513 screen->Append( label );
3514}
3515
3516
3517void SCH_IO_ALTIUM::ParseBus( const std::map<wxString, wxString>& aProperties )
3518{
3519 ASCH_BUS elem( aProperties );
3520
3521 SCH_SCREEN* screen = getCurrentScreen();
3522 wxCHECK( screen, /* void */ );
3523
3524 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
3525 {
3526 SCH_LINE* bus = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
3527 SCH_LAYER_ID::LAYER_BUS );
3528 bus->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
3529 bus->SetLineWidth( elem.lineWidth );
3530
3531 bus->SetFlags( IS_NEW );
3532 screen->Append( bus );
3533 }
3534}
3535
3536
3537void SCH_IO_ALTIUM::ParseWire( const std::map<wxString, wxString>& aProperties )
3538{
3539 ASCH_WIRE elem( aProperties );
3540
3541 SCH_SCREEN* screen = getCurrentScreen();
3542 wxCHECK( screen, /* void */ );
3543
3544 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
3545 {
3546 SCH_LINE* wire = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
3547 SCH_LAYER_ID::LAYER_WIRE );
3548 wire->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
3549 // wire->SetLineWidth( elem.lineWidth );
3550
3551 wire->SetFlags( IS_NEW );
3552 screen->Append( wire );
3553 }
3554}
3555
3556
3557void SCH_IO_ALTIUM::ParseJunction( const std::map<wxString, wxString>& aProperties )
3558{
3559 SCH_SCREEN* screen = getCurrentScreen();
3560 wxCHECK( screen, /* void */ );
3561
3562 ASCH_JUNCTION elem( aProperties );
3563
3564 SCH_JUNCTION* junction = new SCH_JUNCTION( elem.location + m_sheetOffset );
3565
3566 junction->SetFlags( IS_NEW );
3567 screen->Append( junction );
3568}
3569
3570
3571void SCH_IO_ALTIUM::ParseImage( const std::map<wxString, wxString>& aProperties )
3572{
3573 ASCH_IMAGE elem( aProperties );
3574
3575 const auto& component = m_altiumComponents.find( elem.ownerindex );
3576
3577 //Hide the image if it is owned by a component but the part id do not match
3578 if( component != m_altiumComponents.end()
3579 && component->second.currentpartid != elem.ownerpartid )
3580 return;
3581
3582 VECTOR2I center = ( elem.location + elem.corner ) / 2 + m_sheetOffset;
3583 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
3584
3585 SCH_SCREEN* screen = getCurrentScreen();
3586 wxCHECK( screen, /* void */ );
3587
3588 if( elem.embedimage )
3589 {
3590 const ASCH_STORAGE_FILE* storageFile = GetFileFromStorage( elem.filename );
3591
3592 if( !storageFile )
3593 {
3594 wxString msg = wxString::Format( _( "Embedded file %s not found in storage." ),
3595 elem.filename );
3597 return;
3598 }
3599
3600 wxString storagePath = wxFileName::CreateTempFileName( "kicad_import_" );
3601
3602 // As wxZlibInputStream is not seekable, we need to write a temporary file
3603 wxMemoryInputStream fileStream( storageFile->data.data(), storageFile->data.size() );
3604 wxZlibInputStream zlibInputStream( fileStream );
3605 wxFFileOutputStream outputStream( storagePath );
3606 outputStream.Write( zlibInputStream );
3607 outputStream.Close();
3608
3609 if( !bitmap->ReadImageFile( storagePath ) )
3610 {
3611 m_reporter->Report( wxString::Format( _( "Error reading image %s." ), storagePath ),
3613 return;
3614 }
3615
3616 // Remove temporary file
3617 wxRemoveFile( storagePath );
3618 }
3619 else
3620 {
3621 if( !wxFileExists( elem.filename ) )
3622 {
3623 m_reporter->Report( wxString::Format( _( "File not found %s." ), elem.filename ),
3625 return;
3626 }
3627
3628 if( !bitmap->ReadImageFile( elem.filename ) )
3629 {
3630 m_reporter->Report( wxString::Format( _( "Error reading image %s." ), elem.filename ),
3632 return;
3633 }
3634 }
3635
3636 // we only support one scale, thus we need to select one in case it does not keep aspect ratio
3637 VECTOR2I currentImageSize = bitmap->GetSize();
3638 VECTOR2I expectedImageSize = elem.location - elem.corner;
3639 double scaleX = std::abs( static_cast<double>( expectedImageSize.x ) / currentImageSize.x );
3640 double scaleY = std::abs( static_cast<double>( expectedImageSize.y ) / currentImageSize.y );
3641 bitmap->SetImageScale( std::min( scaleX, scaleY ) );
3642
3643 bitmap->SetFlags( IS_NEW );
3644 screen->Append( bitmap.release() );
3645}
3646
3647
3648void SCH_IO_ALTIUM::ParseSheet( const std::map<wxString, wxString>& aProperties )
3649{
3650 m_altiumSheet = std::make_unique<ASCH_SHEET>( aProperties );
3651
3652 SCH_SCREEN* screen = getCurrentScreen();
3653 wxCHECK( screen, /* void */ );
3654
3655 PAGE_INFO pageInfo;
3656
3657 bool isPortrait = m_altiumSheet->sheetOrientation == ASCH_SHEET_WORKSPACEORIENTATION::PORTRAIT;
3658
3659 if( m_altiumSheet->useCustomSheet )
3660 {
3663 pageInfo.SetType( PAGE_INFO::Custom, isPortrait );
3664 }
3665 else
3666 {
3667 switch( m_altiumSheet->sheetSize )
3668 {
3669 default:
3670 case ASCH_SHEET_SIZE::A4: pageInfo.SetType( "A4", isPortrait ); break;
3671 case ASCH_SHEET_SIZE::A3: pageInfo.SetType( "A3", isPortrait ); break;
3672 case ASCH_SHEET_SIZE::A2: pageInfo.SetType( "A2", isPortrait ); break;
3673 case ASCH_SHEET_SIZE::A1: pageInfo.SetType( "A1", isPortrait ); break;
3674 case ASCH_SHEET_SIZE::A0: pageInfo.SetType( "A0", isPortrait ); break;
3675 case ASCH_SHEET_SIZE::A: pageInfo.SetType( "A", isPortrait ); break;
3676 case ASCH_SHEET_SIZE::B: pageInfo.SetType( "B", isPortrait ); break;
3677 case ASCH_SHEET_SIZE::C: pageInfo.SetType( "C", isPortrait ); break;
3678 case ASCH_SHEET_SIZE::D: pageInfo.SetType( "D", isPortrait ); break;
3679 case ASCH_SHEET_SIZE::E: pageInfo.SetType( "E", isPortrait ); break;
3680 case ASCH_SHEET_SIZE::LETTER: pageInfo.SetType( "USLetter", isPortrait ); break;
3681 case ASCH_SHEET_SIZE::LEGAL: pageInfo.SetType( "USLegal", isPortrait ); break;
3682 case ASCH_SHEET_SIZE::TABLOID: pageInfo.SetType( "A3", isPortrait ); break;
3683 case ASCH_SHEET_SIZE::ORCAD_A: pageInfo.SetType( "A", isPortrait ); break;
3684 case ASCH_SHEET_SIZE::ORCAD_B: pageInfo.SetType( "B", isPortrait ); break;
3685 case ASCH_SHEET_SIZE::ORCAD_C: pageInfo.SetType( "C", isPortrait ); break;
3686 case ASCH_SHEET_SIZE::ORCAD_D: pageInfo.SetType( "D", isPortrait ); break;
3687 case ASCH_SHEET_SIZE::ORCAD_E: pageInfo.SetType( "E", isPortrait ); break;
3688 }
3689 }
3690
3691 screen->SetPageSettings( pageInfo );
3692
3693 m_sheetOffset = { 0, pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) };
3694}
3695
3696
3697void SCH_IO_ALTIUM::ParseSheetName( const std::map<wxString, wxString>& aProperties )
3698{
3699 ASCH_SHEET_NAME elem( aProperties );
3700
3701 const auto& sheetIt = m_sheets.find( elem.ownerindex );
3702
3703 if( sheetIt == m_sheets.end() )
3704 {
3705 m_reporter->Report( wxString::Format( wxT( "Sheetname's owner (%d) not found." ),
3706 elem.ownerindex ),
3708 return;
3709 }
3710
3711 SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
3712
3713 sheetNameField.SetPosition( elem.location + m_sheetOffset );
3714 sheetNameField.SetText( elem.text );
3715 sheetNameField.SetVisible( !elem.isHidden );
3716 SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
3717}
3718
3719
3720void SCH_IO_ALTIUM::ParseFileName( const std::map<wxString, wxString>& aProperties )
3721{
3722 ASCH_FILE_NAME elem( aProperties );
3723
3724 const auto& sheetIt = m_sheets.find( elem.ownerindex );
3725
3726 if( sheetIt == m_sheets.end() )
3727 {
3728 m_reporter->Report( wxString::Format( wxT( "Filename's owner (%d) not found." ),
3729 elem.ownerindex ),
3731 return;
3732 }
3733
3734 SCH_FIELD& filenameField = sheetIt->second->GetFields()[SHEETFILENAME];
3735
3736 filenameField.SetPosition( elem.location + m_sheetOffset );
3737
3738 // Keep the filename of the Altium file until after the file is actually loaded.
3739 filenameField.SetText( elem.text );
3740 filenameField.SetVisible( !elem.isHidden );
3741 SetTextPositioning( &filenameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
3742}
3743
3744
3745void SCH_IO_ALTIUM::ParseDesignator( const std::map<wxString, wxString>& aProperties )
3746{
3747 ASCH_DESIGNATOR elem( aProperties );
3748
3749 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
3750
3751 if( libSymbolIt == m_libSymbols.end() )
3752 {
3753 // TODO: e.g. can depend on Template (RECORD=39
3754 m_reporter->Report( wxString::Format( wxT( "Designator's owner (%d) not found." ),
3755 elem.ownerindex ),
3757 return;
3758 }
3759
3760 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
3761 SCH_SHEET_PATH sheetpath;
3762
3763 SCH_SCREEN* screen = getCurrentScreen();
3764 wxCHECK( screen, /* void */ );
3765
3766 // Graphics symbols have no reference. '#GRAPHIC' allows them to not have footprint associated.
3767 // Note: not all unnamed imported symbols are necessarily graphics.
3768 bool emptyRef = elem.text.IsEmpty();
3769 symbol->SetRef( &m_sheetPath, emptyRef ? wxString( wxS( "#GRAPHIC" ) ) : elem.text );
3770
3771 // I am not sure value and ref should be invisible just because emptyRef is true
3772 // I have examples with this criteria fully incorrect.
3773 bool visible = !emptyRef;
3774
3775 symbol->GetField( VALUE_FIELD )->SetVisible( visible );
3776 symbol->GetField( REFERENCE_FIELD )->SetVisible( visible );
3777
3778 SCH_FIELD* field = symbol->GetField( REFERENCE_FIELD );
3779 field->SetPosition( elem.location + m_sheetOffset );
3780 SetTextPositioning( field, elem.justification, elem.orientation );
3781}
3782
3783
3784void SCH_IO_ALTIUM::ParseLibDesignator( const std::map<wxString, wxString>& aProperties,
3785 std::vector<LIB_SYMBOL*>& aSymbol,
3786 std::vector<int>& aFontSizes )
3787{
3788 ASCH_DESIGNATOR elem( aProperties );
3789
3790 // Designators are shared by everyone
3791 for( LIB_SYMBOL* symbol : aSymbol )
3792 {
3793 bool emptyRef = elem.text.IsEmpty();
3794 SCH_FIELD& refField = symbol->GetReferenceField();
3795
3796 if( emptyRef )
3797 refField.SetText( wxT( "X" ) );
3798 else
3799 refField.SetText( elem.text.BeforeLast( '?' ) ); // remove the '?' at the end for KiCad-style
3800
3801 refField.SetPosition( GetLibEditPosition( elem.location ) );
3802
3803 if( elem.fontId > 0 && elem.fontId <= static_cast<int>( aFontSizes.size() ) )
3804 {
3805 int size = aFontSizes[elem.fontId - 1];
3806 refField.SetTextSize( { size, size } );
3807 }
3808 }
3809}
3810
3811
3812void SCH_IO_ALTIUM::ParseBusEntry( const std::map<wxString, wxString>& aProperties )
3813{
3814 ASCH_BUS_ENTRY elem( aProperties );
3815
3816 SCH_SCREEN* screen = getCurrentScreen();
3817 wxCHECK( screen, /* void */ );
3818
3819 SCH_BUS_WIRE_ENTRY* busWireEntry = new SCH_BUS_WIRE_ENTRY( elem.location + m_sheetOffset );
3820
3821 VECTOR2I vector = elem.corner - elem.location;
3822 busWireEntry->SetSize( { vector.x, vector.y } );
3823
3824 busWireEntry->SetFlags( IS_NEW );
3825 screen->Append( busWireEntry );
3826}
3827
3828
3829void SCH_IO_ALTIUM::ParseParameter( const std::map<wxString, wxString>& aProperties )
3830{
3831 ASCH_PARAMETER elem( aProperties );
3832
3833 // TODO: fill in replacements from variant, sheet and project
3834 static const std::map<wxString, wxString> variableMap = {
3835 { "COMMENT", "VALUE" },
3836 { "VALUE", "ALTIUM_VALUE" },
3837 };
3838
3839 if( elem.ownerindex <= 0 )
3840 {
3841 // This is some sheet parameter
3842 if( elem.text == "*" )
3843 return; // indicates parameter not set?
3844
3845 wxString paramName = elem.name.Upper();
3846
3847 if( paramName == "SHEETNUMBER" )
3848 {
3850 }
3851 else if( paramName == "TITLE" )
3852 {
3853 m_currentTitleBlock->SetTitle( elem.text );
3854 }
3855 else if( paramName == "REVISION" )
3856 {
3857 m_currentTitleBlock->SetRevision( elem.text );
3858 }
3859 else if( paramName == "DATE" )
3860 {
3861 m_currentTitleBlock->SetDate( elem.text );
3862 }
3863 else if( paramName == "COMPANYNAME" )
3864 {
3865 m_currentTitleBlock->SetCompany( elem.text );
3866 }
3867 else
3868 {
3869 m_schematic->Prj().GetTextVars()[ paramName ] = elem.text;
3870 }
3871 }
3872 else
3873 {
3874 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
3875
3876 if( libSymbolIt == m_libSymbols.end() )
3877 {
3878 // TODO: e.g. can depend on Template (RECORD=39
3879 return;
3880 }
3881
3882 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
3883 SCH_FIELD* field = nullptr;
3884 wxString upperName = elem.name.Upper();
3885
3886 if( upperName == "COMMENT" )
3887 {
3888 field = symbol->GetField( VALUE_FIELD );
3889 }
3890 else
3891 {
3892 int fieldIdx = 0;
3893 wxString fieldName = elem.name.Upper();
3894
3895 fieldIdx = symbol->GetFieldCount();
3896
3897 if( fieldName.IsEmpty() )
3898 {
3899 int disambiguate = 1;
3900
3901 while( 1 )
3902 {
3903 fieldName = wxString::Format( "ALTIUM_UNNAMED_%d", disambiguate++ );
3904
3905 if( !symbol->FindField( fieldName ) )
3906 break;
3907
3908 }
3909 }
3910 else if( fieldName == "VALUE" )
3911 {
3912 fieldName = "ALTIUM_VALUE";
3913 }
3914
3915 field = symbol->AddField( SCH_FIELD( VECTOR2I(), fieldIdx, symbol, fieldName ) );
3916 }
3917
3918 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
3919 field->SetText( kicadText );
3920 field->SetPosition( elem.location + m_sheetOffset );
3921 field->SetVisible( !elem.isHidden );
3922 SetTextPositioning( field, elem.justification, elem.orientation );
3923 }
3924}
3925
3926
3927void SCH_IO_ALTIUM::ParseLibParameter( const std::map<wxString, wxString>& aProperties,
3928 std::vector<LIB_SYMBOL*>& aSymbol,
3929 std::vector<int>& aFontSizes )
3930{
3931 ASCH_PARAMETER elem( aProperties );
3932
3933 // Part ID 1 is the current library part.
3934 // Part ID ALTIUM_COMPONENT_NONE(-1) means all parts
3935 // If a parameter is assigned to a specific element such as a pin,
3936 // we will need to handle it here.
3937 // TODO: Handle HIDDENNETNAME property (others?)
3938 if( elem.ownerpartid != 1 && elem.ownerpartid != ALTIUM_COMPONENT_NONE )
3939 return;
3940
3941 // If ownerindex is populated, this is parameter belongs to a subelement (e.g. pin).
3942 // Ignore for now.
3943 // TODO: Update this when KiCad supports parameters for any object
3944 if( elem.ownerindex != ALTIUM_COMPONENT_NONE )
3945 return;
3946
3947 // TODO: fill in replacements from variant, sheet and project
3948 // N.B. We do not keep the Altium "VALUE" variable here because
3949 // we don't have a way to assign variables to specific symbols
3950 std::map<wxString, wxString> variableMap = {
3951 { "COMMENT", "VALUE" },
3952 };
3953
3954 for( LIB_SYMBOL* libSymbol : aSymbol )
3955 {
3956 SCH_FIELD* field = nullptr;
3957 wxString upperName = elem.name.Upper();
3958
3959 if( upperName == "COMMENT" )
3960 {
3961 field = &libSymbol->GetValueField();
3962 }
3963 else
3964 {
3965 int fieldIdx = libSymbol->GetFieldCount();
3966 wxString fieldNameStem = elem.name;
3967 wxString fieldName = fieldNameStem;
3968 int disambiguate = 1;
3969
3970 if( fieldName.IsEmpty() )
3971 {
3972 fieldNameStem = "ALTIUM_UNNAMED";
3973 fieldName = "ALTIUM_UNNAMED_1";
3974 disambiguate = 2;
3975 }
3976 else if( upperName == "VALUE" )
3977 {
3978 fieldNameStem = "ALTIUM_VALUE";
3979 fieldName = "ALTIUM_VALUE";
3980 }
3981
3982 // Avoid adding duplicate fields
3983 while( libSymbol->FindField( fieldName ) )
3984 fieldName = wxString::Format( "%s_%d", fieldNameStem, disambiguate++ );
3985
3986 SCH_FIELD* new_field = new SCH_FIELD( libSymbol, fieldIdx, fieldName );
3987 libSymbol->AddField( new_field );
3988 field = new_field;
3989 }
3990
3991 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
3992 field->SetText( kicadText );
3993
3994
3995 field->SetTextPos( GetLibEditPosition( elem.location ) );
3996 SetTextPositioning( field, elem.justification, elem.orientation );
3997 field->SetVisible( !elem.isHidden );
3998 SetTextPositioning( field, elem.justification, elem.orientation );
3999
4000 if( elem.fontId > 0 && elem.fontId <= static_cast<int>( aFontSizes.size() ) )
4001 {
4002 int size = aFontSizes[elem.fontId - 1];
4003 field->SetTextSize( { size, size } );
4004 }
4005 }
4006}
4007
4008
4010 const std::map<wxString, wxString>& aProperties )
4011{
4012 ASCH_IMPLEMENTATION_LIST elem( aProperties );
4013
4014 m_altiumImplementationList.emplace( aIndex, elem.ownerindex );
4015}
4016
4017
4018void SCH_IO_ALTIUM::ParseImplementation( const std::map<wxString, wxString>& aProperties,
4019 std::vector<LIB_SYMBOL*>& aSymbol )
4020{
4021 ASCH_IMPLEMENTATION elem( aProperties );
4022
4023 if( elem.type != wxS( "PCBLIB" ) )
4024 return;
4025
4026 // For schematic files, we need to check if the model is current.
4027 if( aSymbol.size() == 0 && !elem.isCurrent )
4028 return;
4029
4030 // For IntLibs we want to use the same lib name for footprints
4031 wxString libName = m_isIntLib ? m_libName : elem.libname;
4032
4033 wxArrayString fpFilters;
4034 fpFilters.Add( wxString::Format( wxS( "*%s*" ), elem.name ) );
4035
4036 // Parse the footprint fields for the library symbol
4037 if( !aSymbol.empty() )
4038 {
4039 for( LIB_SYMBOL* symbol : aSymbol )
4040 {
4041 LIB_ID fpLibId = AltiumToKiCadLibID( libName, elem.name );
4042
4043 symbol->SetFPFilters( fpFilters );
4044 SCH_FIELD& footprintField = symbol->GetFootprintField();
4045 footprintField.SetText( fpLibId.Format() );
4046 }
4047
4048 return;
4049 }
4050
4051 const auto& implementationOwnerIt = m_altiumImplementationList.find( elem.ownerindex );
4052
4053 if( implementationOwnerIt == m_altiumImplementationList.end() )
4054 {
4055 m_reporter->Report( wxString::Format( wxT( "Implementation's owner (%d) not found." ),
4056 elem.ownerindex ),
4058 return;
4059 }
4060
4061 const auto& libSymbolIt = m_libSymbols.find( implementationOwnerIt->second );
4062
4063 if( libSymbolIt == m_libSymbols.end() )
4064 {
4065 m_reporter->Report( wxString::Format( wxT( "Footprint's owner (%d) not found." ),
4066 implementationOwnerIt->second ),
4068 return;
4069 }
4070
4071 LIB_ID fpLibId = AltiumToKiCadLibID( libName, elem.name );
4072
4073 libSymbolIt->second->SetFPFilters( fpFilters ); // TODO: not ideal as we overwrite it
4074
4075 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
4076
4077 symbol->SetFootprintFieldText( fpLibId.Format() );
4078}
4079
4080
4081
4082std::vector<LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibComponent( const std::map<wxString,
4083 wxString>& aProperties )
4084{
4085 ASCH_SYMBOL elem( aProperties );
4086
4087 std::vector<LIB_SYMBOL*> symbols;
4088
4089 symbols.reserve( elem.displaymodecount );
4090
4091 for( int i = 0; i < elem.displaymodecount; i++ )
4092 {
4093 LIB_SYMBOL* symbol = new LIB_SYMBOL( wxEmptyString );
4094
4095 if( elem.displaymodecount > 1 )
4096 symbol->SetName( wxString::Format( "%s (Altium Display %d)", elem.libreference,
4097 i + 1 ) );
4098 else
4099 symbol->SetName( elem.libreference );
4100
4101 LIB_ID libId = AltiumToKiCadLibID( getLibName(), symbol->GetName() );
4102 symbol->SetDescription( elem.componentdescription );
4103 symbol->SetLibId( libId );
4104 symbol->SetUnitCount( elem.partcount - 1 );
4105 symbols.push_back( symbol );
4106 }
4107
4108 return symbols;
4109}
4110
4111
4112std::map<wxString,LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibFile( const ALTIUM_COMPOUND_FILE& aAltiumLibFile )
4113{
4114 std::map<wxString,LIB_SYMBOL*> ret;
4115 std::vector<int> fontSizes;
4116
4117 ParseLibHeader( aAltiumLibFile, fontSizes );
4118
4119 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> syms = aAltiumLibFile.GetLibSymbols( nullptr );
4120
4121 for( auto& [name, entry] : syms )
4122 {
4123 ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry );
4124 std::vector<LIB_SYMBOL*> symbols;
4125
4126 if( reader.GetRemainingBytes() <= 0 )
4127 {
4128 THROW_IO_ERROR( "LibSymbol does not contain any data" );
4129 }
4130
4131 {
4132 std::map<wxString, wxString> properties = reader.ReadProperties();
4133 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
4134 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
4135
4136 if( record != ALTIUM_SCH_RECORD::COMPONENT )
4137 THROW_IO_ERROR( "LibSymbol does not start with COMPONENT record" );
4138
4139 symbols = ParseLibComponent( properties );
4140 }
4141
4142 auto handleBinaryDataLambda =
4143 []( const std::string& binaryData ) -> std::map<wxString, wxString>
4144 {
4145
4146 std::map<wxString, wxString> result;
4147
4148 ALTIUM_BINARY_READER binreader( binaryData );
4149
4150 int32_t recordId = binreader.ReadInt32();
4151
4152 if( recordId != static_cast<int32_t>( ALTIUM_SCH_RECORD::PIN ) )
4153 THROW_IO_ERROR( "Binary record missing PIN record" );
4154
4155 result["RECORD"] = wxString::Format( "%d", recordId );
4156 binreader.ReadByte(); // unknown
4157 result["OWNERPARTID"] = wxString::Format( "%d", binreader.ReadInt16() );
4158 result["OWNERPARTDISPLAYMODE"] = wxString::Format( "%d", binreader.ReadByte() );
4159 result["SYMBOL_INNEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
4160 result["SYMBOL_OUTEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
4161 result["SYMBOL_INNER"] = wxString::Format( "%d", binreader.ReadByte() );
4162 result["SYMBOL_OUTER"] = wxString::Format( "%d", binreader.ReadByte() );
4163 result["TEXT"] = binreader.ReadPascalString();
4164 binreader.ReadByte(); // unknown
4165 result["ELECTRICAL"] = wxString::Format( "%d", binreader.ReadByte() );
4166 result["PINCONGLOMERATE"] = wxString::Format( "%d", binreader.ReadByte() );
4167 result["PINLENGTH"] = wxString::Format( "%d", binreader.ReadInt16() );
4168 result["LOCATION.X"] = wxString::Format( "%d", binreader.ReadInt16() );
4169 result["LOCATION.Y"] = wxString::Format( "%d", binreader.ReadInt16() );
4170 result["COLOR"] = wxString::Format( "%d", binreader.ReadInt32() );
4171 result["NAME"] = binreader.ReadPascalString();
4172 result["DESIGNATOR"] = binreader.ReadPascalString();
4173 result["SWAPIDGROUP"] = binreader.ReadPascalString();
4174
4175
4176 std::string partSeq = binreader.ReadPascalString(); // This is 'part|&|seq'
4177 std::vector<std::string> partSeqSplit = split( partSeq, "|" );
4178
4179 if( partSeqSplit.size() == 3 )
4180 {
4181 result["PART"] = partSeqSplit[0];
4182 result["SEQ"] = partSeqSplit[2];
4183 }
4184
4185 // Mark the pin as belonging to a library symbol, so we can adjust the coordinates
4186 // as needed for KiCad's symbol editor
4187 result["ISKICADLIBPIN"] = wxString( "T" );
4188 return result;
4189 };
4190
4191 while( reader.GetRemainingBytes() > 0 )
4192 {
4193 std::map<wxString, wxString> properties = reader.ReadProperties( handleBinaryDataLambda );
4194
4195 if( properties.empty() )
4196 continue;
4197
4198 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
4199 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
4200
4201 switch( record )
4202 {
4203 case ALTIUM_SCH_RECORD::PIN: ParsePin( properties, symbols ); break;
4204
4205 case ALTIUM_SCH_RECORD::LABEL: ParseLabel( properties, symbols, fontSizes ); break;
4206
4207 case ALTIUM_SCH_RECORD::BEZIER: ParseBezier( properties, symbols ); break;
4208
4209 case ALTIUM_SCH_RECORD::POLYLINE: ParsePolyline( properties, symbols ); break;
4210
4211 case ALTIUM_SCH_RECORD::POLYGON: ParsePolygon( properties, symbols ); break;
4212
4213 case ALTIUM_SCH_RECORD::ELLIPSE: ParseEllipse( properties, symbols ); break;
4214
4215 case ALTIUM_SCH_RECORD::ROUND_RECTANGLE: ParseRoundRectangle( properties, symbols ); break;
4216
4217 case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC: ParseEllipticalArc( properties, symbols ); break;
4218
4219 case ALTIUM_SCH_RECORD::ARC: ParseArc( properties, symbols ); break;
4220
4221 case ALTIUM_SCH_RECORD::LINE: ParseLine( properties, symbols ); break;
4222
4223 case ALTIUM_SCH_RECORD::RECTANGLE: ParseRectangle( properties, symbols ); break;
4224
4225 case ALTIUM_SCH_RECORD::DESIGNATOR: ParseLibDesignator( properties, symbols, fontSizes ); break;
4226
4227 case ALTIUM_SCH_RECORD::PARAMETER: ParseLibParameter( properties, symbols, fontSizes ); break;
4228
4229 case ALTIUM_SCH_RECORD::TEXT_FRAME: ParseTextFrame( properties, symbols, fontSizes ); break;
4230
4231 // Nothing for now. TODO: Figure out how implementation lists are generted in libs
4232 case ALTIUM_SCH_RECORD::IMPLEMENTATION_LIST: break;
4233
4234 case ALTIUM_SCH_RECORD::IMPLEMENTATION: ParseImplementation( properties, symbols ); break;
4235
4236 case ALTIUM_SCH_RECORD::IMPL_PARAMS: break;
4237
4238 case ALTIUM_SCH_RECORD::MAP_DEFINER_LIST: break;
4239 case ALTIUM_SCH_RECORD::MAP_DEFINER: break;
4240
4241 // TODO: add support for these. They are just drawn symbols, so we can probably hardcode
4242 case ALTIUM_SCH_RECORD::IEEE_SYMBOL: break;
4243
4244 // TODO: Hanlde images once libedit supports them
4245 case ALTIUM_SCH_RECORD::IMAGE: break;
4246
4247 default:
4248 m_reporter->Report( wxString::Format( _( "Unknown or unexpected record id %d found "
4249 "in %s." ),
4250 recordId, symbols[0]->GetName() ),
4252 break;
4253 }
4254 }
4255
4256 if( reader.HasParsingError() )
4257 THROW_IO_ERROR( "stream was not parsed correctly!" );
4258
4259 if( reader.GetRemainingBytes() != 0 )
4260 THROW_IO_ERROR( "stream is not fully parsed" );
4261
4262 for( size_t ii = 0; ii < symbols.size(); ii++ )
4263 {
4264 LIB_SYMBOL* symbol = symbols[ii];
4265 symbol->FixupDrawItems();
4266
4267 SCH_FIELD& valField = symbol->GetValueField();
4268
4269 if( valField.GetText().IsEmpty() )
4270 valField.SetText( name );
4271
4272 if( symbols.size() == 1 )
4273 ret[name] = symbol;
4274 else
4275 ret[wxString::Format( "%s (Altium Display %zd)", name, ii + 1 )] = symbol;
4276 }
4277 }
4278
4279 return ret;
4280}
4281
4282
4283long long SCH_IO_ALTIUM::getLibraryTimestamp( const wxString& aLibraryPath ) const
4284{
4285 wxFileName fn( aLibraryPath );
4286
4287 if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
4288 return fn.GetModificationTime().GetValue().GetValue();
4289 else
4290 return wxDateTime( 0.0 ).GetValue().GetValue();
4291}
4292
4293
4294void SCH_IO_ALTIUM::ensureLoadedLibrary( const wxString& aLibraryPath,
4295 const STRING_UTF8_MAP* aProperties )
4296{
4297 if( m_libCache.count( aLibraryPath ) )
4298 {
4299 wxCHECK( m_timestamps.count( aLibraryPath ), /*void*/ );
4300
4301 if( m_timestamps.at( aLibraryPath ) == getLibraryTimestamp( aLibraryPath ) )
4302 return;
4303 }
4304
4305 std::vector<std::unique_ptr<ALTIUM_COMPOUND_FILE>> compoundFiles;
4306
4307 wxFileName fileName( aLibraryPath );
4308 m_libName = fileName.GetName();
4309
4310 try
4311 {
4312 if( aLibraryPath.Lower().EndsWith( wxS( ".schlib" ) ) )
4313 {
4314 m_isIntLib = false;
4315
4316 compoundFiles.push_back( std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath ) );
4317 }
4318 else if( aLibraryPath.Lower().EndsWith( wxS( ".intlib" ) ) )
4319 {
4320 m_isIntLib = true;
4321
4322 std::unique_ptr<ALTIUM_COMPOUND_FILE> intCom =
4323 std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath );
4324
4325 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> schLibFiles =
4326 intCom->EnumDir( L"SchLib" );
4327
4328 for( const auto& [schLibName, cfe] : schLibFiles )
4329 compoundFiles.push_back( intCom->DecodeIntLibStream( *cfe ) );
4330 }
4331
4332 std::map<wxString, LIB_SYMBOL*>& cacheMapRef = m_libCache[aLibraryPath];
4333
4334 for( auto& altiumSchFilePtr : compoundFiles )
4335 {
4336 std::map<wxString, LIB_SYMBOL*> parsed = ParseLibFile( *altiumSchFilePtr );
4337 cacheMapRef.insert( parsed.begin(), parsed.end() );
4338 }
4339
4340 m_timestamps[aLibraryPath] = getLibraryTimestamp( aLibraryPath );
4341 }
4342 catch( const CFB::CFBException& exception )
4343 {
4344 THROW_IO_ERROR( exception.what() );
4345 }
4346 catch( const std::exception& exc )
4347 {
4348 wxFAIL_MSG( wxString::Format( wxT( "Unhandled exception in Altium schematic parsers: %s." ),
4349 exc.what() ) );
4350 throw;
4351 }
4352}
4353
4354
4356 std::vector<int>& aFontSizes )
4357{
4358 const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "FileHeader" } );
4359
4360 if( file == nullptr )
4361 THROW_IO_ERROR( "FileHeader not found" );
4362
4363 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
4364
4365 if( reader.GetRemainingBytes() <= 0 )
4366 {
4367 THROW_IO_ERROR( "FileHeader does not contain any data" );
4368 }
4369
4370 std::map<wxString, wxString> properties = reader.ReadProperties();
4371
4372 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
4373
4374 if( libtype.CmpNoCase( "Protel for Windows - Schematic Library Editor Binary File Version 5.0" ) )
4375 THROW_IO_ERROR( _( "Expected Altium Schematic Library file version 5.0" ) );
4376
4377 for( auto& [key, value] : properties )
4378 {
4379 wxString upperKey = key.Upper();
4380 wxString remaining;
4381
4382 if( upperKey.StartsWith( "SIZE", &remaining ) )
4383 {
4384 if( !remaining.empty() )
4385 {
4386 int ind = wxAtoi( remaining );
4387
4388 if( static_cast<int>( aFontSizes.size() ) < ind )
4389 aFontSizes.resize( ind );
4390
4391 // Altium stores in pt. 1 pt = 1/72 inch. 1 mil = 1/1000 inch.
4392 int scaled = schIUScale.MilsToIU( wxAtoi( value ) * 72.0 / 10.0 );
4393 aFontSizes[ind - 1] = scaled;
4394 }
4395 }
4396 }
4397
4398}
4399
4400
4401void SCH_IO_ALTIUM::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
4402 const wxString& aLibraryPath,
4403 const STRING_UTF8_MAP* aProperties )
4404{
4405 ensureLoadedLibrary( aLibraryPath, aProperties );
4406
4407 auto it = m_libCache.find( aLibraryPath );
4408
4409 if( it != m_libCache.end() )
4410 {
4411 for( auto& [libnameStr, libSymbol] : it->second )
4412 aSymbolNameList.Add( libnameStr );
4413 }
4414
4415}
4416
4417
4418void SCH_IO_ALTIUM::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
4419 const wxString& aLibraryPath,
4420 const STRING_UTF8_MAP* aProperties )
4421{
4422 ensureLoadedLibrary( aLibraryPath, aProperties );
4423
4424 auto it = m_libCache.find( aLibraryPath );
4425
4426 if( it != m_libCache.end() )
4427 {
4428 for( auto& [libnameStr, libSymbol] : it->second )
4429 aSymbolList.push_back( libSymbol );
4430 }
4431}
4432
4433LIB_SYMBOL* SCH_IO_ALTIUM::LoadSymbol( const wxString& aLibraryPath,
4434 const wxString& aAliasName,
4435 const STRING_UTF8_MAP* aProperties )
4436{
4437 ensureLoadedLibrary( aLibraryPath, aProperties );
4438
4439 auto it = m_libCache.find( aLibraryPath );
4440
4441 if( it != m_libCache.end() )
4442 {
4443 auto it2 = it->second.find( aAliasName );
4444
4445 if( it2 != it->second.end() )
4446 return it2->second;
4447 }
4448
4449 return nullptr;
4450}
int color
Definition: DXF_plotter.cpp:58
const char * name
Definition: DXF_plotter.cpp:57
ALTIUM_SCH_RECORD
ASCH_RECORD_ORIENTATION
const int ALTIUM_COMPONENT_NONE
ASCH_LABEL_JUSTIFICATION
ASCH_POLYLINE_LINESTYLE
ASCH_POWER_PORT_STYLE
wxString AltiumSchSpecialStringsToKiCadVariables(const wxString &aString, const std::map< wxString, wxString > &aOverrides)
wxString AltiumPinNamesToKiCad(wxString &aString)
LIB_ID AltiumToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
void TransformEllipseToBeziers(const ELLIPSE< T > &aEllipse, std::vector< BEZIER< T > > &aBeziers)
Transforms an ellipse or elliptical arc into a set of quadratic Bezier curves that approximate it.
std::map< wxString, wxString > ReadProperties()
size_t GetRemainingBytes() const
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
std::map< wxString, const CFB::COMPOUND_FILE_ENTRY * > GetLibSymbols(const CFB::COMPOUND_FILE_ENTRY *aStart) const
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMinSegLen=0, int aMaxSegCount=32)
Convert a Bezier curve to a polygon.
Generic cubic Bezier representation.
Definition: bezier_curves.h:78
EDA_ANGLE Normalize()
Definition: eda_angle.h:255
double Sin() const
Definition: eda_angle.h:212
double Cos() const
Definition: eda_angle.h:227
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
void SetModified()
Definition: eda_item.cpp:64
const KIID m_Uuid
Definition: eda_item.h:485
void SetStartX(int x)
Definition: eda_shape.h:141
void SetBezierC2(const VECTOR2I &aPt)
Definition: eda_shape.h:188
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:543
FILL_T GetFillMode() const
Definition: eda_shape.h:102
void SetEndY(int aY)
Definition: eda_shape.h:160
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
Definition: eda_shape.cpp:478
void SetLineStyle(const LINE_STYLE aStyle)
Definition: eda_shape.cpp:1786
void SetStartY(int y)
Definition: eda_shape.h:135
void SetFilled(bool aFlag)
Definition: eda_shape.h:96
void SetFillColor(const COLOR4D &aColor)
Definition: eda_shape.h:107
void SetEndX(int aX)
Definition: eda_shape.h:166
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:129
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:125
COLOR4D GetFillColor() const
Definition: eda_shape.h:106
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:154
void SetBezierC1(const VECTOR2I &aPt)
Definition: eda_shape.h:185
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:689
virtual int GetWidth() const
Definition: eda_shape.h:110
void SetWidth(int aWidth)
Definition: eda_shape.h:109
void SetFillMode(FILL_T aFill)
Definition: eda_shape.h:101
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
void SetTextColor(const COLOR4D &aColor)
Definition: eda_text.h:230
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:374
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:419
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:245
void SetBold(bool aBold)
Definition: eda_text.cpp:221
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:183
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:205
void SetItalic(bool aItalic)
Definition: eda_text.cpp:213
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:268
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
This class was created to handle importing ellipses from other file formats that support them nativel...
Definition: ellipse.h:34
Used for text file output.
Definition: richio.h:475
const wxString & GetName() const
Return a brief hard coded name for this IO interface.
Definition: io_base.h:71
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition: io_base.h:210
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition: io_base.cpp:67
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:398
COLOR4D & FromCSSRGBA(int aRed, int aGreen, int aBlue, double aAlpha=1.0)
Initialize the color from a RGBA value with 0-255 red/green/blue and 0-1 alpha.
Definition: color4d.cpp:577
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
UTF8 Format() const
Definition: lib_id.cpp:118
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
Define a library symbol object.
Definition: lib_symbol.h:77
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per symbol count.
SCH_FIELD & GetValueField() const
Return reference to the value field.
void FixupDrawItems()
This function finds the filled draw items that are covering up smaller draw items and replaces their ...
Definition: lib_symbol.cpp:902
void SetPower()
Definition: lib_symbol.cpp:679
wxString GetName() const override
Definition: lib_symbol.h:136
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
Definition: lib_symbol.h:151
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:168
SCH_FIELD & GetReferenceField() const
Return reference to the reference designator field.
void SetLibId(const LIB_ID &aLibId)
Definition: lib_symbol.h:143
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:969
virtual void SetName(const wxString &aName)
Definition: lib_symbol.cpp:563
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
int GetHeightIU(double aIUScale) const
Gets the page height in IU.
Definition: page_info.h:162
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
Definition: page_info.cpp:235
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:82
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
Definition: page_info.cpp:241
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
Definition: page_info.cpp:122
std::shared_ptr< NET_SETTINGS > & NetSettings()
Definition: project_file.h:101
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:147
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:166
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:309
virtual std::map< wxString, wxString > & GetTextVars() const
Definition: project.cpp:84
@ ELEM_SYMBOL_LIB_TABLE
Definition: project.h:228
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Holds all the data relating to one schematic.
Definition: schematic.h:75
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:184
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:121
SCH_SHEET & Root() const
Definition: schematic.h:105
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:90
void SetSize(const VECTOR2I &aSize)
Definition: sch_bus_entry.h:74
Class for a wire to bus entry.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1407
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1387
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1138
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:2084
void ParseFileHeader(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
void ParseSignalHarness(const std::map< wxString, wxString > &aProperties)
std::map< int, ASCH_TEMPLATE > m_altiumTemplates
std::map< int, ASCH_SYMBOL > m_altiumComponents
void ParsePort(const ASCH_PORT &aElem)
bool IsComponentPartVisible(const ASCH_OWNER_INTERFACE &aElem) const
void ParseNote(const std::map< wxString, wxString > &aProperties)
void ParseAltiumSch(const wxString &aFileName)
std::vector< ASCH_PORT > m_altiumPortsCurrentSheet
void ParseSheetName(const std::map< wxString, wxString > &aProperties)
void ParseBusEntry(const std::map< wxString, wxString > &aProperties)
SCH_SHEET * getCurrentSheet()
void ParseStorage(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
std::map< wxString, LIB_SYMBOL * > m_powerSymbols
void ParseBus(const std::map< wxString, wxString > &aProperties)
void ParseFileName(const std::map< wxString, wxString > &aProperties)
static bool isASCIIFile(const wxString &aFileName)
wxString m_libName
std::map< int, SCH_SHEET * > m_sheets
void ParseLibHeader(const ALTIUM_COMPOUND_FILE &aAltiumSchFile, std::vector< int > &aFontSizes)
void ParseHarnessPort(const ASCH_PORT &aElem)
void ParseRoundRectangle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
int GetModifyHash() const override
Return the modification hash from the library cache.
void ParseLibDesignator(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
std::map< int, int > m_altiumImplementationList
int m_harnessEntryParent
void ParseTextFrame(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
void ParsePolygon(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
VECTOR2I m_sheetOffset
void ParseRecord(int index, std::map< wxString, wxString > &properties, const wxString &aSectionName)
std::vector< ASCH_PORT > m_altiumHarnessPortsCurrentSheet
std::unique_ptr< STRING_UTF8_MAP > m_properties
void ParseDesignator(const std::map< wxString, wxString > &aProperties)
int m_harnessOwnerIndexOffset
std::map< wxString, LIB_SYMBOL * > ParseLibFile(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
static bool checkFileHeader(const wxString &aFileName)
long long getLibraryTimestamp(const wxString &aLibraryPath) const
std::map< wxString, std::map< wxString, LIB_SYMBOL * > > m_libCache
void ParseSheetEntry(const std::map< wxString, wxString > &aProperties)
IO_RELEASER< SCH_IO > m_pi
SCH_SHEET * m_rootSheet
static bool isBinaryFile(const wxString &aFileName)
void ParseHarnessType(const std::map< wxString, wxString > &aProperties)
void ParseJunction(const std::map< wxString, wxString > &aProperties)
SCHEMATIC * m_schematic
void ParseLibParameter(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
void ParseASCIISchematic(const wxString &aFileName)
void ParsePolyline(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::unique_ptr< ASCH_SHEET > m_altiumSheet
void ParseComponent(int aIndex, const std::map< wxString, wxString > &aProperties)
std::unique_ptr< TITLE_BLOCK > m_currentTitleBlock
void ParseImage(const std::map< wxString, wxString > &aProperties)
void ParseArc(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseNetLabel(const std::map< wxString, wxString > &aProperties)
void ParseNoERC(const std::map< wxString, wxString > &aProperties)
void ParseImplementationList(int aIndex, const std::map< wxString, wxString > &aProperties)
std::vector< LIB_SYMBOL * > ParseLibComponent(const std::map< wxString, wxString > &aProperties)
void ParseSheet(const std::map< wxString, wxString > &aProperties)
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void ParseParameter(const std::map< wxString, wxString > &aProperties)
bool ShouldPutItemOnSheet(int aOwnerindex)
void AddLibTextBox(const ASCH_TEXT_FRAME *aElem, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_IO can read the specified schematic file.
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const STRING_UTF8_MAP *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
void ParseEllipticalArc(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseEllipse(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseWire(const std::map< wxString, wxString > &aProperties)
void ParseHarnessEntry(const std::map< wxString, wxString > &aProperties)
void ParseImplementation(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseTemplate(int aIndex, const std::map< wxString, wxString > &aProperties)
void ParseAdditional(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
void ensureLoadedLibrary(const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties)
void AddTextBox(const ASCH_TEXT_FRAME *aElem)
void ParsePowerPort(const std::map< wxString, wxString > &aProperties)
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
const ASCH_STORAGE_FILE * GetFileFromStorage(const wxString &aFilename) const
void ParseRectangle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
wxString getLibName()
std::vector< ASCH_STORAGE_FILE > m_altiumStorage
SCH_SHEET_PATH m_sheetPath
void ParseLabel(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
void ParseBezier(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseLine(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseCircle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::map< int, SCH_SYMBOL * > m_symbols
void ParseSheetSymbol(int aIndex, const std::map< wxString, wxString > &aProperties)
std::map< wxString, long long > m_timestamps
wxFileName getLibFileName()
SCH_SCREEN * getCurrentScreen()
void ParsePin(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::map< int, LIB_SYMBOL * > m_libSymbols
void ParseHarnessConnector(int aIndex, const std::map< wxString, wxString > &aProperties)
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io.h:57
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition: sch_io.cpp:46
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:174
virtual void SetUnit(int aUnit)
Definition: sch_item.h:236
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:173
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_label.cpp:639
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:196
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:338
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:136
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:1011
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:321
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:1017
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_line.h:176
int GetLineWidth() const
Definition: sch_line.h:172
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:141
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:704
SCH_SCREEN * GetNext()
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
SCH_SCREEN * GetFirst()
void ClearEditFlags()
std::vector< SCH_SHEET_INSTANCE > m_sheetInstances
Definition: sch_screen.h:682
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: sch_screen.h:157
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:150
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:132
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
const KIID & GetUuid() const
Definition: sch_screen.h:525
bool IsTerminalPoint(const VECTOR2I &aPosition, int aLayer) const
Test if aPosition is a connection point on aLayer.
Definition: sch_screen.cpp:815
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:115
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:71
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
void Normalize()
Definition: sch_shape.cpp:75
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:642
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:55
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_SCREEN * LastScreen()
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
void SetPosition(const VECTOR2I &aPosition) override
void SetSide(SHEET_SIDE aEdge)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:119
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:312
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:306
wxString GetName() const
Definition: sch_sheet.h:107
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:728
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:122
void SetName(const wxString &aName)
Definition: sch_sheet.h:108
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:162
Schematic symbol object.
Definition: sch_symbol.h:108
void SetLibId(const LIB_ID &aName)
Definition: sch_symbol.cpp:259
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_symbol.h:783
int GetFieldCount() const
Return the number of fields in this symbol.
Definition: sch_symbol.h:571
void SetValueFieldText(const wxString &aValue)
Definition: sch_symbol.cpp:888
SCH_FIELD * FindField(const wxString &aFieldName, bool aIncludeDefaultFields=true, bool aCaseInsensitive=false)
Search for a SCH_FIELD with aFieldName.
Definition: sch_symbol.cpp:993
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:910
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Definition: sch_symbol.cpp:750
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
void SetFootprintFieldText(const wxString &aFootprint)
Definition: sch_symbol.cpp:904
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:782
TRANSFORM & GetTransform()
Definition: sch_symbol.h:285
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
Definition: sch_symbol.cpp:973
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
Definition: sch_symbol.cpp:274
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:142
A name/value tuple with unique names and optional values.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
int GetWidth() const
Definition: stroke_params.h:91
void SetLineStyle(LINE_STYLE aLineStyle)
Definition: stroke_params.h:95
void SetWidth(int aWidth)
Definition: stroke_params.h:92
KIGFX::COLOR4D GetColor() const
Definition: stroke_params.h:97
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
static const wxString & GetSymbolLibTableFileName()
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indentation level of aIndentLevel.
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:46
TRANSFORM InverseTransform() const
Calculate the Inverse mirror/rotation transform.
Definition: transform.cpp:59
VECTOR2I TransformCoordinate(const VECTOR2I &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:44
wxString wx_str() const
Definition: utf8.cpp:45
static REPORTER & GetInstance()
Definition: reporter.cpp:203
@ PURERED
Definition: color4d.h:71
@ PUREBLUE
Definition: color4d.h:68
@ BLACK
Definition: color4d.h:44
#define DEFAULT_PINNUM_SIZE
The default pin name size when creating pins(can be changed in preference menu)
#define DEFAULT_PINNAME_SIZE
The default selection highlight thickness (can be changed in preference menu)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:432
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
#define IS_NEW
New item, just created.
FILL_T
Definition: eda_shape.h:55
@ FILLED_WITH_COLOR
@ FILLED_WITH_BG_BODYCOLOR
@ FILLED_SHAPE
static const std::string KiCadSchematicFileExtension
static const std::string KiCadSymbolLibFileExtension
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
@ LAYER_DEVICE
Definition: layer_ids.h:370
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_BUS
Definition: layer_ids.h:357
static const std::vector< uint8_t > COMPOUND_FILE_HEADER
Definition: io_utils.h:35
bool fileStartsWithBinaryHeader(const wxString &aFilePath, const std::vector< uint8_t > &aHeader)
Check if a file starts with a defined binary header.
Definition: io_utils.cpp:57
bool fileStartsWithPrefix(const wxString &aFilePath, const wxString &aPrefix, bool aIgnoreWhitespace)
Check if a file starts with a defined string.
Definition: io_utils.cpp:32
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_DEBUG
@ RPT_SEVERITY_INFO
static COLOR4D GetColorFromInt(int color)
#define HARNESS_PORT_COLOR_DEFAULT_OUTLINE
static void SetLibShapeFillAndColor(const ASCH_FILL_INTERFACE &elem, SCH_SHAPE *shape, ALTIUM_SCH_RECORD aType, int aStrokeColor)
VECTOR2I HelperGeneratePowerPortGraphics(LIB_SYMBOL *aKsymbol, ASCH_POWER_PORT_STYLE aStyle, REPORTER *aReporter)
static void SetSchShapeLine(const ASCH_BORDER_INTERFACE &elem, SCH_SHAPE *shape)
static const VECTOR2I GetRelativePosition(const VECTOR2I &aPosition, const SCH_SYMBOL *aSymbol)
static void SetLibShapeLine(const ASCH_BORDER_INTERFACE &elem, SCH_SHAPE *shape, ALTIUM_SCH_RECORD aType)
static LINE_STYLE GetPlotDashType(const ASCH_POLYLINE_LINESTYLE linestyle)
static const VECTOR2I GetLibEditPosition(const VECTOR2I &aPosition)
#define HARNESS_PORT_COLOR_DEFAULT_BACKGROUND
static void SetSchShapeFillAndColor(const ASCH_FILL_INTERFACE &elem, SCH_SHAPE *shape)
void SetTextPositioning(EDA_TEXT *text, ASCH_LABEL_JUSTIFICATION justification, ASCH_RECORD_ORIENTATION orientation)
@ SHEETNAME
Definition: sch_sheet.h:45
@ SHEETFILENAME
Definition: sch_sheet.h:46
static std::vector< std::string > split(const std::string &aStr, const std::string &aDelim)
Split the input string into a vector of output strings.
Definition: string_utils.h:310
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:48
double m_StartAngle
VECTOR2I m_Center
double m_EndAngle
std::vector< VECTOR2I > points
VECTOR2I corner
VECTOR2I location
std::vector< VECTOR2I > points
ASCH_LABEL_JUSTIFICATION justification
ASCH_RECORD_ORIENTATION orientation
ASCH_RECORD_ORIENTATION orientation
int DistanceFromTop
ASCH_SHEET_ENTRY_SIDE Side
wxString Name
VECTOR2I location
wxString filename
ASCH_RECORD_ORIENTATION orientation
VECTOR2I location
ASCH_LABEL_JUSTIFICATION justification
VECTOR2I point1
VECTOR2I point2
ASCH_POLYLINE_LINESTYLE LineStyle
ASCH_LABEL_JUSTIFICATION justification
ASCH_RECORD_ORIENTATION orientation
ASCH_RECORD_ORIENTATION orientation
ASCH_LABEL_JUSTIFICATION justification
VECTOR2I location
ASCH_PIN_SYMBOL::PTYPE symbolOuterEdge
wxString name
wxString designator
ASCH_PIN_ELECTRICAL electrical
ASCH_PIN_SYMBOL::PTYPE symbolInnerEdge
ASCH_RECORD_ORIENTATION orientation
std::vector< VECTOR2I > points
ASCH_POLYLINE_LINESTYLE LineStyle
std::vector< VECTOR2I > Points
VECTOR2I Location
ASCH_TEXT_FRAME_ALIGNMENT Alignment
ASCH_PORT_IOTYPE IOtype
wxString HarnessType
ASCH_PORT_STYLE Style
ASCH_POWER_PORT_STYLE style
ASCH_RECORD_ORIENTATION orientation
wxString name
int distanceFromTop
ASCH_SHEET_ENTRY_SIDE side
ASCH_PORT_IOTYPE iotype
ASCH_RECORD_ORIENTATION orientation
std::vector< VECTOR2I > Points
std::vector< char > data
wxString componentdescription
wxString libreference
ASCH_TEXT_FRAME_ALIGNMENT Alignment
std::vector< VECTOR2I > points
constexpr int IUToMils(int iu) const
Definition: base_units.h:99
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
A simple container for sheet instance information.
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SHEET_T
Definition: typeinfo.h:174
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.