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