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