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