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