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