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