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