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