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