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