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>();
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
890 wxFileName projectFileName = loadAltiumFileName;
891 projectFileName.SetPath( m_schematic->Project().GetProjectPath() );
892 projectFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
893 sheet->SetFileName( projectFileName.GetFullName() );
894 // Do not need to load the sub-sheets - this has already been done.
895 }
896 else
897 {
898 sheet->SetScreen( new SCH_SCREEN( m_schematic ) );
899 SCH_SCREEN* screen = sheet->GetScreen();
900
901 if( sheet->GetName().Trim().empty() )
902 sheet->SetName( loadAltiumFileName.GetName() );
903
904 wxCHECK2( screen, continue );
905
906 m_sheetPath.push_back( sheet );
907 m_sheets.clear();
908 ParseAltiumSch( loadAltiumFileName.GetFullPath() );
909
910 // Map the loaded Altium file to the project file.
911 wxFileName projectFileName = loadAltiumFileName;
912 projectFileName.SetPath( m_schematic->Project().GetProjectPath() );
913 projectFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
914 sheet->SetFileName( projectFileName.GetFullName() );
915 screen->SetFileName( projectFileName.GetFullPath() );
916
917 m_sheetPath.pop_back();
918 }
919 }
920}
921
922
924{
925 const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "Storage" } );
926
927 if( file == nullptr )
928 return;
929
930 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
931
932 std::map<wxString, wxString> properties = reader.ReadProperties();
933 ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
934 int weight = ALTIUM_PROPS_UTILS::ReadInt( properties, "WEIGHT", 0 );
935
936 if( weight < 0 )
937 THROW_IO_ERROR( "Storage weight is negative!" );
938
939 for( int i = 0; i < weight; i++ )
940 m_altiumStorage.emplace_back( reader );
941
942 if( reader.HasParsingError() )
943 THROW_IO_ERROR( "stream was not parsed correctly!" );
944
945 // TODO pointhi: is it possible to have multiple headers in one Storage file? Otherwise
946 // throw IO Error.
947 if( reader.GetRemainingBytes() != 0 )
948 {
949 m_errorMessages.emplace( wxString::Format( _( "Storage file not fully parsed (%d bytes remaining)." ),
950 reader.GetRemainingBytes() ),
952 }
953}
954
955
957{
958 wxString streamName = wxS( "Additional" );
959
960 const CFB::COMPOUND_FILE_ENTRY* file =
961 aAltiumSchFile.FindStream( { streamName.ToStdString() } );
962
963 if( file == nullptr )
964 return;
965
966 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
967
968 if( reader.GetRemainingBytes() <= 0 )
969 {
970 THROW_IO_ERROR( "Additional section does not contain any data" );
971 }
972 else
973 {
974 std::map<wxString, wxString> properties = reader.ReadProperties();
975
976 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
977 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
978
979 if( record != ALTIUM_SCH_RECORD::HEADER )
980 THROW_IO_ERROR( "Header expected" );
981 }
982
983 for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
984 {
985 std::map<wxString, wxString> properties = reader.ReadProperties();
986
987 ParseRecord( index, properties, streamName );
988 }
989
990 // Handle harness Ports
992 ParseHarnessPort( port );
993
995
996 if( reader.HasParsingError() )
997 THROW_IO_ERROR( "stream was not parsed correctly!" );
998
999 if( reader.GetRemainingBytes() != 0 )
1000 THROW_IO_ERROR( "stream is not fully parsed" );
1001
1002 m_altiumHarnesses.clear();
1004}
1005
1006
1008{
1009 wxString streamName = wxS( "FileHeader" );
1010
1011 const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { streamName.ToStdString() } );
1012
1013 if( file == nullptr )
1014 THROW_IO_ERROR( "FileHeader not found" );
1015
1016 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
1017
1018 if( reader.GetRemainingBytes() <= 0 )
1019 {
1020 THROW_IO_ERROR( "FileHeader does not contain any data" );
1021 }
1022 else
1023 {
1024 std::map<wxString, wxString> properties = reader.ReadProperties();
1025
1026 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
1027
1028 if( libtype.CmpNoCase( "Protel for Windows - Schematic Capture Binary File Version 5.0" ) )
1029 THROW_IO_ERROR( _( "Expected Altium Schematic file version 5.0" ) );
1030 }
1031
1032 // Prepare some local variables
1033 wxCHECK( m_altiumPortsCurrentSheet.empty(), /* void */ );
1034 wxCHECK( !m_currentTitleBlock, /* void */ );
1035
1036 m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
1037
1038 // index is required to resolve OWNERINDEX
1039 for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
1040 {
1041 std::map<wxString, wxString> properties = reader.ReadProperties();
1042
1043 ParseRecord( index, properties, streamName );
1044 }
1045
1046 if( reader.HasParsingError() )
1047 THROW_IO_ERROR( "stream was not parsed correctly!" );
1048
1049 if( reader.GetRemainingBytes() != 0 )
1050 THROW_IO_ERROR( "stream is not fully parsed" );
1051
1052 // assign LIB_SYMBOL -> COMPONENT
1053 for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
1054 {
1055 auto libSymbolIt = m_libSymbols.find( symbol.first );
1056
1057 if( libSymbolIt == m_libSymbols.end() )
1058 THROW_IO_ERROR( "every symbol should have a symbol attached" );
1059
1060 fixupSymbolPinNameNumbers( symbol.second );
1061 fixupSymbolPinNameNumbers( libSymbolIt->second );
1062
1063 symbol.second->SetLibSymbol( libSymbolIt->second );
1064 }
1065
1066 SCH_SCREEN* screen = getCurrentScreen();
1067 wxCHECK( screen, /* void */ );
1068
1069 // Handle title blocks
1071 m_currentTitleBlock.reset();
1072
1073 // Handle Ports
1074 for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
1075 ParsePort( port );
1076
1078 m_altiumComponents.clear();
1079 m_altiumTemplates.clear();
1081
1082 m_symbols.clear();
1083 m_libSymbols.clear();
1084
1085 // Otherwise we cannot save the imported sheet?
1086 SCH_SHEET* sheet = getCurrentSheet();
1087
1088 wxCHECK( sheet, /* void */ );
1089
1090 sheet->SetModified();
1091}
1092
1093
1094void SCH_IO_ALTIUM::ParseASCIISchematic( const wxString& aFileName )
1095{
1096 // Read storage content first
1097 {
1098 ALTIUM_ASCII_PARSER storageReader( aFileName );
1099
1100 while( storageReader.CanRead() )
1101 {
1102 std::map<wxString, wxString> properties = storageReader.ReadProperties();
1103
1104 // Binary data
1105 if( properties.find( wxS( "BINARY" ) ) != properties.end() )
1106 m_altiumStorage.emplace_back( properties );
1107 }
1108 }
1109
1110 // Read other data
1111 ALTIUM_ASCII_PARSER reader( aFileName );
1112
1113 if( !reader.CanRead() )
1114 {
1115 THROW_IO_ERROR( "FileHeader does not contain any data" );
1116 }
1117 else
1118 {
1119 std::map<wxString, wxString> properties = reader.ReadProperties();
1120
1121 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
1122
1123 if( libtype.CmpNoCase( "Protel for Windows - Schematic Capture Ascii File Version 5.0" ) )
1124 THROW_IO_ERROR( _( "Expected Altium Schematic file version 5.0" ) );
1125 }
1126
1127 // Prepare some local variables
1128 wxCHECK( m_altiumPortsCurrentSheet.empty(), /* void */ );
1129 wxCHECK( !m_currentTitleBlock, /* void */ );
1130
1131 m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
1132
1133 // index is required to resolve OWNERINDEX
1134 int index = 0;
1135
1136 while( reader.CanRead() )
1137 {
1138 std::map<wxString, wxString> properties = reader.ReadProperties();
1139
1140 // Reset index at headers
1141 if( properties.find( wxS( "HEADER" ) ) != properties.end() )
1142 {
1143 index = 0;
1144 continue;
1145 }
1146
1147 if( properties.find( wxS( "RECORD" ) ) != properties.end() )
1148 ParseRecord( index, properties, aFileName );
1149
1150 index++;
1151 }
1152
1153 if( reader.HasParsingError() )
1154 THROW_IO_ERROR( "stream was not parsed correctly!" );
1155
1156 if( reader.CanRead() )
1157 THROW_IO_ERROR( "stream is not fully parsed" );
1158
1159 // assign LIB_SYMBOL -> COMPONENT
1160 for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
1161 {
1162 auto libSymbolIt = m_libSymbols.find( symbol.first );
1163
1164 if( libSymbolIt == m_libSymbols.end() )
1165 THROW_IO_ERROR( "every symbol should have a symbol attached" );
1166
1167 fixupSymbolPinNameNumbers( symbol.second );
1168 fixupSymbolPinNameNumbers( libSymbolIt->second );
1169
1170 symbol.second->SetLibSymbol( libSymbolIt->second );
1171 }
1172
1173 SCH_SCREEN* screen = getCurrentScreen();
1174 wxCHECK( screen, /* void */ );
1175
1176 // Handle title blocks
1178 m_currentTitleBlock.reset();
1179
1180 // Handle harness Ports
1181 for( const ASCH_PORT& port : m_altiumHarnessPortsCurrentSheet )
1182 ParseHarnessPort( port );
1183
1184 // Handle Ports
1185 for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
1186 ParsePort( port );
1187
1188 // Add the aliases used for harnesses
1189 CreateAliases();
1190
1191 m_altiumHarnesses.clear();
1193 m_altiumComponents.clear();
1194 m_altiumTemplates.clear();
1196
1197 m_symbols.clear();
1198 m_libSymbols.clear();
1199
1200 // Otherwise we cannot save the imported sheet?
1201 SCH_SHEET* sheet = getCurrentSheet();
1202
1203 wxCHECK( sheet, /* void */ );
1204
1205 sheet->SetModified();
1206}
1207
1208
1209void SCH_IO_ALTIUM::ParseRecord( int index, std::map<wxString, wxString>& properties,
1210 const wxString& aSectionName )
1211{
1212 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", -1 );
1213 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
1214
1215 // see: https://github.com/vadmium/python-altium/blob/master/format.md
1216 switch( record )
1217 {
1218 // FileHeader section
1219
1221 THROW_IO_ERROR( "Header already parsed" );
1222
1224 ParseComponent( index, properties );
1225 break;
1226
1228 ParsePin( properties );
1229 break;
1230
1232 m_errorMessages.emplace( _( "Record 'IEEE_SYMBOL' not handled." ), RPT_SEVERITY_INFO );
1233 break;
1234
1236 ParseLabel( properties );
1237 break;
1238
1240 ParseBezier( properties );
1241 break;
1242
1244 ParsePolyline( properties );
1245 break;
1246
1248 ParsePolygon( properties );
1249 break;
1250
1252 ParseEllipse( properties );
1253 break;
1254
1256 ParsePieChart( properties );
1257 break;
1258
1260 ParseRoundRectangle( properties );
1261 break;
1262
1265 ParseArc( properties );
1266 break;
1267
1269 ParseLine( properties );
1270 break;
1271
1273 ParseRectangle( properties );
1274 break;
1275
1277 ParseSheetSymbol( index, properties );
1278 break;
1279
1281 ParseSheetEntry( properties );
1282 break;
1283
1285 ParsePowerPort( properties );
1286 break;
1287
1289 // Ports are parsed after the sheet was parsed
1290 // This is required because we need all electrical connection points before placing.
1291 m_altiumPortsCurrentSheet.emplace_back( properties );
1292 break;
1293
1295 ParseNoERC( properties );
1296 break;
1297
1299 ParseNetLabel( properties );
1300 break;
1301
1303 ParseBus( properties );
1304 break;
1305
1307 ParseWire( properties );
1308 break;
1309
1311 ParseTextFrame( properties );
1312 break;
1313
1315 ParseJunction( properties );
1316 break;
1317
1319 ParseImage( properties );
1320 break;
1321
1323 ParseSheet( properties );
1324 break;
1325
1327 ParseSheetName( properties );
1328 break;
1329
1331 ParseFileName( properties );
1332 break;
1333
1335 ParseDesignator( properties );
1336 break;
1337
1339 ParseBusEntry( properties );
1340 break;
1341
1343 ParseTemplate( index, properties );
1344 break;
1345
1347 ParseParameter( properties );
1348 break;
1349
1351 m_errorMessages.emplace( _( "Parameter Set not currently supported." ), RPT_SEVERITY_ERROR );
1352 break;
1353
1355 ParseImplementationList( index, properties );
1356 break;
1357
1359 ParseImplementation( properties );
1360 break;
1361
1363 break;
1364
1366 break;
1367
1369 break;
1370
1372 ParseNote( properties );
1373 break;
1374
1376 m_errorMessages.emplace( _( "Compile mask not currently supported." ), RPT_SEVERITY_ERROR );
1377 break;
1378
1380 break;
1381
1382 // Additional section
1383
1385 ParseHarnessConnector( index, properties );
1386 break;
1387
1389 ParseHarnessEntry( properties );
1390 break;
1391
1393 ParseHarnessType( properties );
1394 break;
1395
1397 ParseSignalHarness( properties );
1398 break;
1399
1401 m_errorMessages.emplace( _( "Blanket not currently supported." ), RPT_SEVERITY_ERROR );
1402 break;
1403
1404 default:
1405 m_errorMessages.emplace(
1406 wxString::Format( _( "Unknown or unexpected record id %d found in %s." ), recordId,
1407 aSectionName ),
1409 break;
1410 }
1411
1413}
1414
1415
1417{
1418 const auto& component = m_altiumComponents.find( aElem.ownerindex );
1419 const auto& templ = m_altiumTemplates.find( aElem.ownerindex );
1420
1421 if( component != m_altiumComponents.end() )
1422 return component->second.displaymode == aElem.ownerpartdisplaymode;
1423
1424 if( templ != m_altiumTemplates.end() )
1425 return true;
1426
1427 return false;
1428}
1429
1430
1431const ASCH_STORAGE_FILE* SCH_IO_ALTIUM::GetFileFromStorage( const wxString& aFilename ) const
1432{
1433 const ASCH_STORAGE_FILE* nonExactMatch = nullptr;
1434
1435 for( const ASCH_STORAGE_FILE& file : m_altiumStorage )
1436 {
1437 if( file.filename.IsSameAs( aFilename ) )
1438 return &file;
1439
1440 if( file.filename.EndsWith( aFilename ) )
1441 nonExactMatch = &file;
1442 }
1443
1444 return nonExactMatch;
1445}
1446
1447
1448void SCH_IO_ALTIUM::ParseComponent( int aIndex, const std::map<wxString, wxString>& aProperties )
1449{
1450 SCH_SHEET* currentSheet = m_sheetPath.Last();
1451 wxCHECK( currentSheet, /* void */ );
1452
1453 wxString sheetName = currentSheet->GetName();
1454
1455 if( sheetName.IsEmpty() )
1456 sheetName = wxT( "root" );
1457
1458 ASCH_SYMBOL altiumSymbol( aProperties );
1459
1460 if( m_altiumComponents.count( aIndex ) )
1461 {
1462 const ASCH_SYMBOL& currentSymbol = m_altiumComponents.at( aIndex );
1463
1464 m_errorMessages.emplace( wxString::Format( _( "Symbol '%s' in sheet '%s' at index %d "
1465 "replaced with symbol \"%s\"." ),
1466 currentSymbol.libreference,
1467 sheetName,
1468 aIndex,
1469 altiumSymbol.libreference ),
1471 }
1472
1473 auto pair = m_altiumComponents.insert( { aIndex, altiumSymbol } );
1474 const ASCH_SYMBOL& elem = pair.first->second;
1475
1476 // TODO: this is a hack until we correctly apply all transformations to every element
1477 wxString name = wxString::Format( "%s_%d%s_%s_%s",
1478 sheetName,
1479 elem.orientation,
1480 elem.isMirrored ? "_mirrored" : "",
1481 elem.libreference,
1482 elem.sourcelibraryname );
1483
1484 if( elem.displaymodecount > 1 )
1485 name << '_' << elem.displaymode;
1486
1488
1489 LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString );
1490 ksymbol->SetName( name );
1491 ksymbol->SetDescription( elem.componentdescription );
1492 ksymbol->SetLibId( libId );
1493 ksymbol->SetUnitCount( elem.partcount - 1, true );
1494 m_libSymbols.insert( { aIndex, ksymbol } );
1495
1496 // each component has its own symbol for now
1497 SCH_SYMBOL* symbol = new SCH_SYMBOL();
1498
1499 symbol->SetPosition( elem.location + m_sheetOffset );
1500
1501 for( SCH_FIELD& field : symbol->GetFields() )
1502 field.SetVisible( false );
1503
1504 // TODO: keep it simple for now, and only set position.
1505 // component->SetOrientation( elem.orientation );
1506
1507 // If Altium has defined a library from which we have the part,
1508 // use this as the designated source library.
1509 if( !elem.sourcelibraryname.IsEmpty() )
1510 {
1511 wxFileName fn( elem.sourcelibraryname );
1512 libId.SetLibNickname( fn.GetName() );
1513 }
1514
1515 symbol->SetLibId( libId );
1516
1517 if( ksymbol->GetUnitCount() > 1 )
1518 symbol->SetUnit( std::max( 1, elem.currentpartid ) );
1519 else
1520 symbol->SetUnit( 1 );
1521
1523
1524 SCH_SCREEN* screen = getCurrentScreen();
1525 wxCHECK( screen, /* void */ );
1526
1527 screen->Append( symbol );
1528
1529 m_symbols.insert( { aIndex, symbol } );
1530}
1531
1532
1533void SCH_IO_ALTIUM::ParseTemplate( int aIndex, const std::map<wxString, wxString>& aProperties )
1534{
1535 SCH_SHEET* currentSheet = m_sheetPath.Last();
1536 wxCHECK( currentSheet, /* void */ );
1537
1538 wxString sheetName = currentSheet->GetName();
1539
1540 if( sheetName.IsEmpty() )
1541 sheetName = wxT( "root" );
1542
1543 ASCH_TEMPLATE altiumTemplate( aProperties );
1544
1545 // Extract base name from path
1546 wxString baseName = altiumTemplate.filename.AfterLast( '\\' ).BeforeLast( '.' );
1547
1548 if( baseName.IsEmpty() )
1549 baseName = wxS( "Template" );
1550
1551 m_altiumTemplates.insert( { aIndex, altiumTemplate } );
1552 // No need to create a symbol - graphics is put on the sheet
1553}
1554
1555
1556void SCH_IO_ALTIUM::ParsePin( const std::map<wxString, wxString>& aProperties,
1557 std::vector<LIB_SYMBOL*>& aSymbol )
1558{
1559 ASCH_PIN elem( aProperties );
1560
1561 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
1562 : aSymbol[elem.ownerpartdisplaymode];
1563 SCH_SYMBOL* schSymbol = nullptr;
1564
1565 if( !symbol )
1566 {
1567 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1568
1569 if( libSymbolIt == m_libSymbols.end() )
1570 {
1571 // TODO: e.g. can depend on Template (RECORD=39
1572 m_errorMessages.emplace( wxString::Format( wxT( "Pin's owner (%d) not found." ),
1573 elem.ownerindex ),
1575 return;
1576 }
1577
1578 if( !IsComponentPartVisible( elem ) )
1579 return;
1580
1581 schSymbol = m_symbols.at( libSymbolIt->first );
1582 symbol = libSymbolIt->second;
1583 }
1584
1585 SCH_PIN* pin = new SCH_PIN( symbol );
1586
1587 // Make sure that these are visible when initializing the symbol
1588 // This may be overriden by the file data but not by the pin defaults
1589 pin->SetNameTextSize( schIUScale.MilsToIU( DEFAULT_PINNAME_SIZE ) );
1590 pin->SetNumberTextSize( schIUScale.MilsToIU( DEFAULT_PINNUM_SIZE ) );
1591
1592 symbol->AddDrawItem( pin, false );
1593
1594 pin->SetUnit( std::max( 0, elem.ownerpartid ) );
1595
1596 pin->SetName( AltiumPinNamesToKiCad( elem.name ) );
1597 pin->SetNumber( elem.designator );
1598 pin->SetLength( elem.pinlength );
1599
1600 if( elem.hidden )
1601 pin->SetVisible( false );
1602
1603 if( !elem.showDesignator )
1604 pin->SetNumberTextSize( 0 );
1605
1606 if( !elem.showPinName )
1607 pin->SetNameTextSize( 0 );
1608
1609 VECTOR2I pinLocation = elem.location; // the location given is not the connection point!
1610
1611 switch( elem.orientation )
1612 {
1614 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT );
1615 pinLocation.x += elem.pinlength;
1616 break;
1617
1619 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1620 pinLocation.y -= elem.pinlength;
1621 break;
1622
1624 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT );
1625 pinLocation.x -= elem.pinlength;
1626 break;
1627
1629 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
1630 pinLocation.y += elem.pinlength;
1631 break;
1632
1633 default:
1634 m_errorMessages.emplace( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
1635 break;
1636 }
1637
1638 // TODO: position can be sometimes off a little bit!
1639
1640 if( schSymbol )
1641 pinLocation = GetRelativePosition( pinLocation + m_sheetOffset, schSymbol );
1642
1643 pin->SetPosition( pinLocation );
1644
1645 switch( elem.electrical )
1646 {
1649 break;
1650
1652 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
1653 break;
1654
1657 break;
1658
1661 break;
1662
1665 break;
1666
1669 break;
1670
1673 break;
1674
1677 break;
1678
1680 default:
1682 m_errorMessages.emplace( _( "Pin has unexpected electrical type." ), RPT_SEVERITY_WARNING );
1683 break;
1684 }
1685
1687 m_errorMessages.emplace( _( "Pin has unexpected outer edge type." ), RPT_SEVERITY_WARNING );
1688
1690 m_errorMessages.emplace( _( "Pin has unexpected inner edge type." ), RPT_SEVERITY_WARNING );
1691
1693 {
1694 switch( elem.symbolInnerEdge )
1695 {
1698 break;
1699
1700 default:
1701 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
1702 break;
1703 }
1704 }
1706 {
1707 switch( elem.symbolInnerEdge )
1708 {
1710 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW );
1711 break;
1712
1713 default:
1714 pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW );
1715 break;
1716 }
1717 }
1719 {
1720 pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW );
1721 }
1722 else
1723 {
1724 switch( elem.symbolInnerEdge )
1725 {
1727 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
1728 break;
1729
1730 default:
1731 pin->SetShape( GRAPHIC_PINSHAPE::LINE ); // nothing to do
1732 break;
1733 }
1734 }
1735}
1736
1737
1739 ASCH_RECORD_ORIENTATION orientation )
1740{
1741 int vjustify, hjustify;
1743
1744 switch( justification )
1745 {
1746 default:
1751 vjustify = GR_TEXT_V_ALIGN_BOTTOM;
1752 break;
1753
1757 vjustify = GR_TEXT_V_ALIGN_CENTER;
1758 break;
1759
1763 vjustify = GR_TEXT_V_ALIGN_TOP;
1764 break;
1765 }
1766
1767 switch( justification )
1768 {
1769 default:
1774 hjustify = GR_TEXT_H_ALIGN_LEFT;
1775 break;
1776
1780 hjustify = GR_TEXT_H_ALIGN_CENTER;
1781 break;
1782
1786 hjustify = GR_TEXT_H_ALIGN_RIGHT;
1787 break;
1788 }
1789
1790 switch( orientation )
1791 {
1793 angle = ANGLE_HORIZONTAL;
1794 break;
1795
1797 hjustify *= -1;
1798 angle = ANGLE_HORIZONTAL;
1799 break;
1800
1802 angle = ANGLE_VERTICAL;
1803 break;
1804
1806 hjustify *= -1;
1807 angle = ANGLE_VERTICAL;
1808 break;
1809 }
1810
1811 text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( vjustify ) );
1812 text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( hjustify ) );
1813 text->SetTextAngle( angle );
1814}
1815
1816
1818{
1819 // No component assigned -> Put on sheet
1820 if( aOwnerindex == ALTIUM_COMPONENT_NONE )
1821 return true;
1822
1823 // For a template -> Put on sheet so we can resolve variables
1824 if( m_altiumTemplates.find( aOwnerindex ) != m_altiumTemplates.end() )
1825 return true;
1826
1827 return false;
1828}
1829
1830
1831void SCH_IO_ALTIUM::ParseLabel( const std::map<wxString, wxString>& aProperties,
1832 std::vector<LIB_SYMBOL*>& aSymbol, std::vector<int>& aFontSizes )
1833{
1834 ASCH_LABEL elem( aProperties );
1835
1836 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1837 {
1838 static const std::map<wxString, wxString> variableMap = {
1839 { "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
1840 { "SHEETNUMBER", "#" },
1841 { "SHEETTOTAL", "##" },
1842 { "TITLE", "TITLE" }, // including 1:1 maps makes it easier
1843 { "REVISION", "REVISION" }, // to see that the list is complete
1844 { "DATE", "ISSUE_DATE" },
1845 { "CURRENTDATE", "CURRENT_DATE" },
1846 { "COMPANYNAME", "COMPANY" },
1847 { "DOCUMENTNAME", "FILENAME" },
1848 { "DOCUMENTFULLPATHANDNAME", "FILEPATH" },
1849 { "PROJECTNAME", "PROJECTNAME" },
1850 };
1851
1852 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
1853 SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
1854
1855 SetTextPositioning( textItem, elem.justification, elem.orientation );
1856
1857 size_t fontId = static_cast<int>( elem.fontId );
1858
1859 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1860 {
1861 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1862 textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
1863
1864 // Must come after SetTextSize()
1865 textItem->SetBold( font.Bold );
1866 textItem->SetItalic( font.Italic );
1867 }
1868
1869 textItem->SetFlags( IS_NEW );
1870
1871 SCH_SCREEN* screen = getCurrentScreen();
1872 wxCHECK( screen, /* void */ );
1873
1874 screen->Append( textItem );
1875 }
1876 else
1877 {
1878 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
1879 : aSymbol[elem.ownerpartdisplaymode];
1880 SCH_SYMBOL* schsym = nullptr;
1881
1882 if( !symbol )
1883 {
1884 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1885
1886 if( libSymbolIt == m_libSymbols.end() )
1887 {
1888 // TODO: e.g. can depend on Template (RECORD=39
1889 m_errorMessages.emplace( wxString::Format( wxT( "Label's owner (%d) not found." ), elem.ownerindex ),
1891 return;
1892 }
1893
1894 symbol = libSymbolIt->second;
1895 schsym = m_symbols.at( libSymbolIt->first );
1896 }
1897
1898 VECTOR2I pos = elem.location;
1899 SCH_TEXT* textItem = new SCH_TEXT( { 0, 0 }, elem.text, LAYER_DEVICE );
1900 symbol->AddDrawItem( textItem, false );
1901
1903 if( schsym )
1904 pos = GetRelativePosition( elem.location + m_sheetOffset, schsym );
1905
1906 textItem->SetPosition( pos );
1907 textItem->SetUnit( std::max( 0, elem.ownerpartid ) );
1908 SetTextPositioning( textItem, elem.justification, elem.orientation );
1909
1910 size_t fontId = elem.fontId;
1911
1912 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1913 {
1914 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1915 textItem->SetTextSize( { font.Size / 2, font.Size / 2 } );
1916
1917 // Must come after SetTextSize()
1918 textItem->SetBold( font.Bold );
1919 textItem->SetItalic( font.Italic );
1920 }
1921 else if( fontId > 0 && fontId <= aFontSizes.size() )
1922 {
1923 int size = aFontSizes[fontId - 1];
1924 textItem->SetTextSize( { size, size } );
1925 }
1926 }
1927}
1928
1929
1930void SCH_IO_ALTIUM::ParseTextFrame( const std::map<wxString, wxString>& aProperties,
1931 std::vector<LIB_SYMBOL*>& aSymbol,
1932 std::vector<int>& aFontSizes )
1933{
1934 ASCH_TEXT_FRAME elem( aProperties );
1935
1936 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
1937 AddTextBox( &elem );
1938 else
1939 AddLibTextBox( &elem, aSymbol, aFontSizes );
1940}
1941
1942
1943void SCH_IO_ALTIUM::ParseNote( const std::map<wxString, wxString>& aProperties )
1944{
1945 ASCH_NOTE elem( aProperties );
1946 AddTextBox( static_cast<ASCH_TEXT_FRAME*>( &elem ) );
1947
1948 // TODO: need some sort of property system for storing author....
1949}
1950
1951
1953{
1954 SCH_TEXTBOX* textBox = new SCH_TEXTBOX();
1955
1956 VECTOR2I sheetTopRight = aElem->TopRight + m_sheetOffset;
1957 VECTOR2I sheetBottomLeft = aElem->BottomLeft +m_sheetOffset;
1958
1959 textBox->SetStart( sheetTopRight );
1960 textBox->SetEnd( sheetBottomLeft );
1961
1962 textBox->SetText( aElem->Text );
1963
1964 textBox->SetFillColor( GetColorFromInt( aElem->AreaColor ) );
1965
1966 if( aElem->isSolid)
1968 else
1969 textBox->SetFilled( false );
1970
1971 if( aElem->ShowBorder )
1973 else
1975
1976 switch( aElem->Alignment )
1977 {
1978 default:
1981 break;
1984 break;
1987 break;
1988 }
1989
1990 size_t fontId = static_cast<int>( aElem->FontID );
1991
1992 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
1993 {
1994 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
1995 textBox->SetTextSize( { font.Size / 2, font.Size / 2 } );
1996
1997 // Must come after SetTextSize()
1998 textBox->SetBold( font.Bold );
1999 textBox->SetItalic( font.Italic );
2000 //textBox->SetFont( //how to set font, we have a font name here: ( font.fontname );
2001 }
2002
2003 textBox->SetFlags( IS_NEW );
2004
2005 SCH_SCREEN* screen = getCurrentScreen();
2006 wxCHECK( screen, /* void */ );
2007
2008 screen->Append( textBox );
2009}
2010
2011
2012void SCH_IO_ALTIUM::AddLibTextBox( const ASCH_TEXT_FRAME *aElem, std::vector<LIB_SYMBOL*>& aSymbol,
2013 std::vector<int>& aFontSizes )
2014{
2015 LIB_SYMBOL* symbol = static_cast<int>( aSymbol.size() ) <= aElem->ownerpartdisplaymode
2016 ? nullptr
2017 : aSymbol[aElem->ownerpartdisplaymode];
2018 SCH_SYMBOL* schsym = nullptr;
2019
2020 if( !symbol )
2021 {
2022 const auto& libSymbolIt = m_libSymbols.find( aElem->ownerindex );
2023
2024 if( libSymbolIt == m_libSymbols.end() )
2025 {
2026 // TODO: e.g. can depend on Template (RECORD=39
2027 m_errorMessages.emplace( wxString::Format( wxT( "Label's owner (%d) not found." ), aElem->ownerindex ),
2029 return;
2030 }
2031
2032 symbol = libSymbolIt->second;
2033 schsym = m_symbols.at( libSymbolIt->first );
2034 }
2035
2036 SCH_TEXTBOX* textBox = new SCH_TEXTBOX( LAYER_DEVICE );
2037
2038 textBox->SetUnit( std::max( 0, aElem->ownerpartid ) );
2039 symbol->AddDrawItem( textBox, false );
2040
2042 if( !schsym )
2043 {
2044 textBox->SetStart( aElem->TopRight );
2045 textBox->SetEnd( aElem->BottomLeft );
2046 }
2047 else
2048 {
2049 textBox->SetStart( GetRelativePosition( aElem->TopRight + m_sheetOffset, schsym ) );
2050 textBox->SetEnd( GetRelativePosition( aElem->BottomLeft + m_sheetOffset, schsym ) );
2051 }
2052
2053 textBox->SetText( aElem->Text );
2054
2055 textBox->SetFillColor( GetColorFromInt( aElem->AreaColor ) );
2056
2057 if( aElem->isSolid)
2059 else
2060 textBox->SetFilled( false );
2061
2062 if( aElem->ShowBorder )
2064 else
2065 textBox->SetStroke( STROKE_PARAMS( -1 ) );
2066
2067 switch( aElem->Alignment )
2068 {
2069 default:
2072 break;
2075 break;
2078 break;
2079 }
2080
2081 if( aElem->FontID > 0 && aElem->FontID <= static_cast<int>( aFontSizes.size() ) )
2082 {
2083 int size = aFontSizes[aElem->FontID - 1];
2084 textBox->SetTextSize( { size, size } );
2085 }
2086}
2087
2088
2089void SCH_IO_ALTIUM::ParseBezier( const std::map<wxString, wxString>& aProperties,
2090 std::vector<LIB_SYMBOL*>& aSymbol )
2091{
2092 ASCH_BEZIER elem( aProperties );
2093
2094 if( elem.points.size() < 2 )
2095 {
2096 m_errorMessages.emplace( wxString::Format( _( "Bezier has %d control points. At least 2 are expected." ),
2097 static_cast<int>( elem.points.size() ) ),
2099 return;
2100 }
2101
2102 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2103 {
2104 SCH_SCREEN* currentScreen = getCurrentScreen();
2105 wxCHECK( currentScreen, /* void */ );
2106
2107 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
2108 {
2109 if( i + 2 == elem.points.size() )
2110 {
2111 // special case: single line
2112 SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
2114
2115 line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
2117
2118 line->SetFlags( IS_NEW );
2119
2120 currentScreen->Append( line );
2121 }
2122 else
2123 {
2124 // simulate Bezier using line segments
2125 std::vector<VECTOR2I> bezierPoints;
2126 std::vector<VECTOR2I> polyPoints;
2127
2128 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
2129 bezierPoints.push_back( elem.points.at( j ) );
2130
2131 BEZIER_POLY converter( bezierPoints );
2132 converter.GetPoly( polyPoints );
2133
2134 for( size_t k = 0; k + 1 < polyPoints.size(); k++ )
2135 {
2136 SCH_LINE* line = new SCH_LINE( polyPoints.at( k ) + m_sheetOffset,
2138
2139 line->SetEndPoint( polyPoints.at( k + 1 ) + m_sheetOffset );
2141
2142 line->SetFlags( IS_NEW );
2143 currentScreen->Append( line );
2144 }
2145 }
2146 }
2147 }
2148 else
2149 {
2150 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2151 : aSymbol[elem.ownerpartdisplaymode];
2152 SCH_SYMBOL* schsym = nullptr;
2153
2154 if( !symbol )
2155 {
2156 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2157
2158 if( libSymbolIt == m_libSymbols.end() )
2159 {
2160 // TODO: e.g. can depend on Template (RECORD=39
2161 m_errorMessages.emplace( wxString::Format( wxT( "Bezier's owner (%d) not found." ),
2162 elem.ownerindex ),
2164 return;
2165 }
2166
2167 symbol = libSymbolIt->second;
2168 schsym = m_symbols.at( libSymbolIt->first );
2169 }
2170
2171 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2172 return;
2173
2174 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
2175 {
2176 if( i + 2 == elem.points.size() )
2177 {
2178 // special case: single line
2180 symbol->AddDrawItem( line, false );
2181
2182 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2183
2184 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
2185 {
2186 VECTOR2I pos = elem.points.at( j );
2187
2188 if( schsym )
2189 pos = GetRelativePosition( pos + m_sheetOffset, schsym );
2190
2191 line->AddPoint( pos );
2192 }
2193
2195 }
2196 else if( i + 3 == elem.points.size() )
2197 {
2198 // TODO: special case of a single line with an extra point?
2199 // I haven't a clue what this is all about, but the sample document we have in
2200 // https://gitlab.com/kicad/code/kicad/-/issues/8974 responds best by treating it
2201 // as another single line special case.
2203 symbol->AddDrawItem( line, false );
2204
2205 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2206
2207 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
2208 {
2209 VECTOR2I pos = elem.points.at( j );
2210
2211 if( schsym )
2212 pos = GetRelativePosition( pos + m_sheetOffset, schsym );
2213
2214 line->AddPoint( pos );
2215 }
2216
2218 }
2219 else
2220 {
2221 // Bezier always has exactly 4 control points
2223 symbol->AddDrawItem( bezier, false );
2224
2225 bezier->SetUnit( std::max( 0, elem.ownerpartid ) );
2226
2227 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
2228 {
2229 VECTOR2I pos = elem.points.at( j );
2230
2231 if( schsym )
2232 pos = GetRelativePosition( pos + m_sheetOffset, schsym );
2233
2234 switch( j - i )
2235 {
2236 case 0: bezier->SetStart( pos ); break;
2237 case 1: bezier->SetBezierC1( pos ); break;
2238 case 2: bezier->SetBezierC2( pos ); break;
2239 case 3: bezier->SetEnd( pos ); break;
2240 default: break; // Can't get here but silence warnings
2241 }
2242 }
2243
2246 }
2247 }
2248 }
2249}
2250
2251
2252void SCH_IO_ALTIUM::ParsePolyline( const std::map<wxString, wxString>& aProperties,
2253 std::vector<LIB_SYMBOL*>& aSymbol )
2254{
2255 ASCH_POLYLINE elem( aProperties );
2256
2257 if( elem.Points.size() < 2 )
2258 return;
2259
2260 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2261 {
2262 SCH_SCREEN* screen = getCurrentScreen();
2263 wxCHECK( screen, /* void */ );
2264
2265 for( size_t i = 1; i < elem.Points.size(); i++ )
2266 {
2267 SCH_LINE* line = new SCH_LINE;
2268
2269 line->SetStartPoint( elem.Points[i - 1] + m_sheetOffset );
2270 line->SetEndPoint( elem.Points[i] + m_sheetOffset );
2271
2273 GetColorFromInt( elem.Color ) ) );
2274
2275 line->SetFlags( IS_NEW );
2276
2277 screen->Append( line );
2278 }
2279 }
2280 else
2281 {
2282 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2283 : aSymbol[elem.ownerpartdisplaymode];
2284 SCH_SYMBOL* schsym = nullptr;
2285
2286 if( !symbol )
2287 {
2288 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2289
2290 if( libSymbolIt == m_libSymbols.end() )
2291 {
2292 // TODO: e.g. can depend on Template (RECORD=39
2293 m_errorMessages.emplace( wxString::Format( wxT( "Polyline's owner (%d) not found." ),
2294 elem.ownerindex ),
2296 return;
2297 }
2298
2299 symbol = libSymbolIt->second;
2300 schsym = m_symbols.at( libSymbolIt->first );
2301 }
2302
2303 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2304 return;
2305
2307 symbol->AddDrawItem( line, false );
2308
2309 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2310
2311 for( VECTOR2I point : elem.Points )
2312 {
2313 if( schsym )
2314 point = GetRelativePosition( point + m_sheetOffset, schsym );
2315
2316 line->AddPoint( point );
2317 }
2318
2320 STROKE_PARAMS stroke = line->GetStroke();
2321 stroke.SetLineStyle( GetPlotDashType( elem.LineStyle ) );
2322
2323 line->SetStroke( stroke );
2324 }
2325}
2326
2327
2328void SCH_IO_ALTIUM::ParsePolygon( const std::map<wxString, wxString>& aProperties,
2329 std::vector<LIB_SYMBOL*>& aSymbol )
2330{
2331 ASCH_POLYGON elem( aProperties );
2332
2333 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2334 {
2335 SCH_SCREEN* screen = getCurrentScreen();
2336 wxCHECK( screen, /* void */ );
2337
2338 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
2339
2340 for( VECTOR2I& point : elem.points )
2341 poly->AddPoint( point + m_sheetOffset );
2342 poly->AddPoint( elem.points.front() + m_sheetOffset );
2343
2344 SetSchShapeLine( elem, poly );
2345 SetSchShapeFillAndColor( elem, poly );
2346 poly->SetFlags( IS_NEW );
2347
2348 screen->Append( poly );
2349 }
2350 else
2351 {
2352 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2353 : aSymbol[elem.ownerpartdisplaymode];
2354 SCH_SYMBOL* schsym = nullptr;
2355
2356 if( !symbol )
2357 {
2358 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2359
2360 if( libSymbolIt == m_libSymbols.end() )
2361 {
2362 // TODO: e.g. can depend on Template (RECORD=39
2363 m_errorMessages.emplace( wxString::Format( wxT( "Polygon's owner (%d) not found." ),
2364 elem.ownerindex ),
2366 return;
2367 }
2368
2369 symbol = libSymbolIt->second;
2370 schsym = m_symbols.at( libSymbolIt->first );
2371 }
2372
2373 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2374 return;
2375
2377
2378 symbol->AddDrawItem( line, false );
2379 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2380
2381 for( VECTOR2I point : elem.points )
2382 {
2383 if( schsym )
2384 point = GetRelativePosition( point + m_sheetOffset, schsym );
2385
2386 line->AddPoint( point );
2387 }
2388
2389 VECTOR2I point = elem.points.front();
2390
2391 if( schsym )
2392 point = GetRelativePosition( elem.points.front() + m_sheetOffset, schsym );
2393
2394 line->AddPoint( point );
2395
2398
2399 if( line->GetFillColor() == line->GetStroke().GetColor()
2400 && line->GetFillMode() != FILL_T::NO_FILL )
2401 {
2402 STROKE_PARAMS stroke = line->GetStroke();
2403 stroke.SetWidth( -1 );
2404 line->SetStroke( stroke );
2405 }
2406 }
2407}
2408
2409
2410void SCH_IO_ALTIUM::ParseRoundRectangle( const std::map<wxString, wxString>& aProperties,
2411 std::vector<LIB_SYMBOL*>& aSymbol )
2412{
2413 ASCH_ROUND_RECTANGLE elem( aProperties );
2414
2415 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2416 {
2417 SCH_SCREEN* screen = getCurrentScreen();
2418 wxCHECK( screen, /* void */ );
2419
2420 // TODO: misses rounded edges
2421 SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2422
2423 rect->SetPosition( elem.TopRight + m_sheetOffset );
2424 rect->SetEnd( elem.BottomLeft + m_sheetOffset );
2425 SetSchShapeLine( elem, rect );
2426 SetSchShapeFillAndColor( elem, rect );
2427 rect->SetFlags( IS_NEW );
2428
2429 screen->Append( rect );
2430 }
2431 else
2432 {
2433 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2434 : aSymbol[elem.ownerpartdisplaymode];
2435 SCH_SYMBOL* schsym = nullptr;
2436
2437 if( !symbol )
2438 {
2439 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2440
2441 if( libSymbolIt == m_libSymbols.end() )
2442 {
2443 // TODO: e.g. can depend on Template (RECORD=39
2444 m_errorMessages.emplace( wxString::Format( wxT( "Rounded rectangle's owner (%d) not found." ),
2445 elem.ownerindex ),
2447 return;
2448 }
2449
2450 symbol = libSymbolIt->second;
2451 schsym = m_symbols.at( libSymbolIt->first );
2452 }
2453
2454 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2455 return;
2456
2457 SCH_SHAPE* rect = nullptr;
2458
2459 int width = std::abs( elem.TopRight.x - elem.BottomLeft.x );
2460 int height = std::abs( elem.TopRight.y - elem.BottomLeft.y );
2461
2462 // If it is a circle, make it a circle
2463 if( std::abs( elem.CornerRadius.x ) >= width / 2
2464 && std::abs( elem.CornerRadius.y ) >= height / 2 )
2465 {
2466 rect = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2467
2468 VECTOR2I center = ( elem.TopRight + elem.BottomLeft ) / 2;
2469 int radius = std::min( width / 2, height / 2 );
2470
2471 if( schsym )
2473
2474 rect->SetPosition( center );
2475 rect->SetEnd( VECTOR2I( rect->GetPosition().x + radius, rect->GetPosition().y ) );
2476 }
2477 else
2478 {
2480
2481 if( !schsym )
2482 {
2483 rect->SetPosition( elem.TopRight );
2484 rect->SetEnd( elem.BottomLeft );
2485 }
2486 else
2487 {
2488 rect->SetPosition( GetRelativePosition( elem.TopRight + m_sheetOffset, schsym ) );
2489 rect->SetEnd( GetRelativePosition( elem.BottomLeft + m_sheetOffset, schsym ) );
2490 }
2491
2492 rect->Normalize();
2493 }
2494
2497
2498 symbol->AddDrawItem( rect, false );
2499 rect->SetUnit( std::max( 0, elem.ownerpartid ) );
2500 }
2501}
2502
2503
2504void SCH_IO_ALTIUM::ParseArc( const std::map<wxString, wxString>& aProperties,
2505 std::vector<LIB_SYMBOL*>& aSymbol )
2506{
2507 ASCH_ARC elem( aProperties );
2508
2509 int arc_radius = elem.m_Radius;
2510 VECTOR2I center = elem.m_Center;
2511 EDA_ANGLE startAngle( elem.m_EndAngle, DEGREES_T );
2512 EDA_ANGLE endAngle( elem.m_StartAngle, DEGREES_T );
2513 VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
2514 -KiROUND( arc_radius * startAngle.Sin() ) );
2515 VECTOR2I endOffset( KiROUND( arc_radius * endAngle.Cos() ),
2516 -KiROUND( arc_radius * endAngle.Sin() ) );
2517
2518 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2519 {
2520 SCH_SCREEN* currentScreen = getCurrentScreen();
2521 wxCHECK( currentScreen, /* void */ );
2522
2523 if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
2524 {
2526
2527 circle->SetPosition( elem.m_Center + m_sheetOffset );
2528 circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
2529
2530 SetSchShapeLine( elem, circle );
2532
2533 currentScreen->Append( circle );
2534 }
2535 else
2536 {
2537 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
2538
2539 arc->SetCenter( elem.m_Center + m_sheetOffset );
2540 arc->SetStart( elem.m_Center + startOffset + m_sheetOffset );
2541 arc->SetEnd( elem.m_Center + endOffset + m_sheetOffset );
2542
2543 SetSchShapeLine( elem, arc );
2544 SetSchShapeFillAndColor( elem, arc );
2545
2546 currentScreen->Append( arc );
2547 }
2548 }
2549 else
2550 {
2551 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2552 : aSymbol[elem.ownerpartdisplaymode];
2553 SCH_SYMBOL* schsym = nullptr;
2554
2555 if( !symbol )
2556 {
2557 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2558
2559 if( libSymbolIt == m_libSymbols.end() )
2560 {
2561 // TODO: e.g. can depend on Template (RECORD=39
2562 m_errorMessages.emplace( wxString::Format( wxT( "Arc's owner (%d) not found." ), elem.ownerindex ),
2564 return;
2565 }
2566
2567 symbol = libSymbolIt->second;
2568 schsym = m_symbols.at( libSymbolIt->first );
2569 }
2570
2571 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2572 return;
2573
2574 if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
2575 {
2577 symbol->AddDrawItem( circle, false );
2578
2579 circle->SetUnit( std::max( 0, elem.ownerpartid ) );
2580
2581 if( schsym )
2583
2584 circle->SetPosition( center );
2585
2586 circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
2589 }
2590 else
2591 {
2593 symbol->AddDrawItem( arc, false );
2594 arc->SetUnit( std::max( 0, elem.ownerpartid ) );
2595
2596 if( schsym )
2598
2599 arc->SetCenter( center );
2600 arc->SetStart( center + startOffset );
2601 arc->SetEnd( center + endOffset );
2602
2605 }
2606 }
2607}
2608
2609
2610void SCH_IO_ALTIUM::ParseEllipticalArc( const std::map<wxString, wxString>& aProperties,
2611 std::vector<LIB_SYMBOL*>& aSymbol )
2612{
2613 ASCH_ARC elem( aProperties );
2614
2615 if( elem.m_Radius == elem.m_SecondaryRadius && elem.m_StartAngle == 0
2616 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
2617 {
2618 ParseCircle( aProperties, aSymbol );
2619 return;
2620 }
2621
2622 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2623 {
2624 SCH_SCREEN* currentScreen = getCurrentScreen();
2625 wxCHECK( currentScreen, /* void */ );
2626
2627 ELLIPSE<int> ellipse( elem.m_Center + m_sheetOffset, elem.m_Radius,
2630 EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
2631 std::vector<BEZIER<int>> beziers;
2632
2633 TransformEllipseToBeziers( ellipse, beziers );
2634
2635 for( const BEZIER<int>& bezier : beziers )
2636 {
2637 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER );
2638 schbezier->SetStart( bezier.Start );
2639 schbezier->SetBezierC1( bezier.C1 );
2640 schbezier->SetBezierC2( bezier.C2 );
2641 schbezier->SetEnd( bezier.End );
2642 schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2644
2645 currentScreen->Append( schbezier );
2646 }
2647 }
2648 else
2649 {
2650 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2651 : aSymbol[elem.ownerpartdisplaymode];
2652 SCH_SYMBOL* schsym = nullptr;
2653
2654 if( !symbol )
2655 {
2656 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2657
2658 if( libSymbolIt == m_libSymbols.end() )
2659 {
2660 // TODO: e.g. can depend on Template (RECORD=39
2661 m_errorMessages.emplace( wxString::Format( wxT( "Elliptical Arc's owner (%d) not found." ),
2662 elem.ownerindex ),
2664 return;
2665 }
2666
2667 symbol = libSymbolIt->second;
2668 schsym = m_symbols.at( libSymbolIt->first );
2669 }
2670
2671 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2672 return;
2673
2674 ELLIPSE<int> ellipse( elem.m_Center, elem.m_Radius,
2677 EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
2678 std::vector<BEZIER<int>> beziers;
2679
2680 TransformEllipseToBeziers( ellipse, beziers );
2681
2682 for( const BEZIER<int>& bezier : beziers )
2683 {
2684 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE );
2685 symbol->AddDrawItem( schbezier, false );
2686
2687 schbezier->SetUnit( std::max( 0, elem.ownerpartid ) );
2688
2689 if( schsym )
2690 {
2691 schbezier->SetStart( GetRelativePosition( bezier.Start + m_sheetOffset, schsym ) );
2692 schbezier->SetBezierC1( GetRelativePosition( bezier.C1 + m_sheetOffset, schsym ) );
2693 schbezier->SetBezierC2( GetRelativePosition( bezier.C2 + m_sheetOffset, schsym ) );
2694 schbezier->SetEnd( GetRelativePosition( bezier.End + m_sheetOffset, schsym ) );
2695 }
2696 else
2697 {
2698 schbezier->SetStart( bezier.Start );
2699 schbezier->SetBezierC1( bezier.C1 );
2700 schbezier->SetBezierC2( bezier.C2 );
2701 schbezier->SetEnd( bezier.End );
2702 }
2703
2706 }
2707 }
2708}
2709
2710
2711void SCH_IO_ALTIUM::ParsePieChart( const std::map<wxString, wxString>& aProperties,
2712 std::vector<LIB_SYMBOL*>& aSymbol )
2713{
2714 ParseArc( aProperties, aSymbol );
2715
2716 ASCH_PIECHART elem( aProperties );
2717
2718 int arc_radius = elem.m_Radius;
2719 VECTOR2I center = elem.m_Center;
2720 EDA_ANGLE startAngle( elem.m_EndAngle, DEGREES_T );
2721 EDA_ANGLE endAngle( elem.m_StartAngle, DEGREES_T );
2722 VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
2723 -KiROUND( arc_radius * startAngle.Sin() ) );
2724 VECTOR2I endOffset( KiROUND( arc_radius * endAngle.Cos() ),
2725 -KiROUND( arc_radius * endAngle.Sin() ) );
2726
2727 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2728 {
2729 SCH_SCREEN* screen = getCurrentScreen();
2730 wxCHECK( screen, /* void */ );
2731
2732 // close polygon
2734 line->SetEndPoint( center + startOffset + m_sheetOffset );
2736
2737 line->SetFlags( IS_NEW );
2738 screen->Append( line );
2739
2741 line->SetEndPoint( center + endOffset + m_sheetOffset );
2743
2744 line->SetFlags( IS_NEW );
2745 screen->Append( line );
2746 }
2747 else
2748 {
2749 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2750 : aSymbol[elem.ownerpartdisplaymode];
2751 SCH_SYMBOL* schsym = nullptr;
2752
2753 if( !symbol )
2754 {
2755 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2756
2757 if( libSymbolIt == m_libSymbols.end() )
2758 {
2759 // TODO: e.g. can depend on Template (RECORD=39
2760 m_errorMessages.emplace( wxString::Format( wxT( "Piechart's owner (%d) not found." ),
2761 elem.ownerindex ),
2763 return;
2764 }
2765
2766 symbol = libSymbolIt->second;
2767 schsym = m_symbols.at( libSymbolIt->first );
2768 }
2769
2770 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
2771 return;
2772
2774 symbol->AddDrawItem( line, false );
2775
2776 line->SetUnit( std::max( 0, elem.ownerpartid ) );
2777
2778 if( !schsym )
2779 {
2780 line->AddPoint( center + startOffset );
2781 line->AddPoint( center );
2782 line->AddPoint( center + endOffset );
2783 }
2784 else
2785 {
2786 line->AddPoint( GetRelativePosition( center + startOffset + m_sheetOffset, schsym ) );
2787 line->AddPoint( GetRelativePosition( center + m_sheetOffset, schsym ) );
2788 line->AddPoint( GetRelativePosition( center + endOffset + m_sheetOffset, schsym ) );
2789 }
2790
2792 }
2793}
2794
2795
2796void SCH_IO_ALTIUM::ParseEllipse( const std::map<wxString, wxString>& aProperties,
2797 std::vector<LIB_SYMBOL*>& aSymbol )
2798{
2799 ASCH_ELLIPSE elem( aProperties );
2800
2801 if( elem.Radius == elem.SecondaryRadius )
2802 {
2803 ParseCircle( aProperties, aSymbol );
2804 return;
2805 }
2806
2807 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2808 {
2809 SCH_SCREEN* screen = getCurrentScreen();
2810 wxCHECK( screen, /* void */ );
2811
2812 COLOR4D fillColor = GetColorFromInt( elem.AreaColor );
2813
2814 if( elem.IsTransparent )
2815 fillColor = fillColor.WithAlpha( 0.5 );
2816
2818
2819 ELLIPSE<int> ellipse( elem.Center + m_sheetOffset, elem.Radius,
2820 KiROUND( elem.SecondaryRadius ), ANGLE_0 );
2821
2822 std::vector<BEZIER<int>> beziers;
2823 std::vector<VECTOR2I> polyPoints;
2824
2825 TransformEllipseToBeziers( ellipse, beziers );
2826
2827 for( const BEZIER<int>& bezier : beziers )
2828 {
2829 SCH_SHAPE* schbezier = new SCH_SHAPE( SHAPE_T::BEZIER );
2830 schbezier->SetStart( bezier.Start );
2831 schbezier->SetBezierC1( bezier.C1 );
2832 schbezier->SetBezierC2( bezier.C2 );
2833 schbezier->SetEnd( bezier.End );
2834 schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
2835 schbezier->SetFillColor( fillColor );
2836 schbezier->SetFillMode( fillMode );
2837
2839 screen->Append( schbezier );
2840
2841 polyPoints.push_back( bezier.Start );
2842 }
2843
2844 if( fillMode != FILL_T::NO_FILL )
2845 {
2846 SCH_SHAPE* schpoly = new SCH_SHAPE( SHAPE_T::POLY );
2847 schpoly->SetFillColor( fillColor );
2848 schpoly->SetFillMode( fillMode );
2849 schpoly->SetWidth( -1 );
2850
2851 for( const VECTOR2I& point : polyPoints )
2852 schpoly->AddPoint( point );
2853
2854 schpoly->AddPoint( polyPoints[0] );
2855
2856 screen->Append( schpoly );
2857 }
2858 }
2859 else
2860 {
2861 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2862 : aSymbol[elem.ownerpartdisplaymode];
2863 SCH_SYMBOL* schsym = nullptr;
2864
2865 if( !symbol )
2866 {
2867 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2868
2869 if( libSymbolIt == m_libSymbols.end() )
2870 {
2871 // TODO: e.g. can depend on Template (RECORD=39
2872 m_errorMessages.emplace( wxString::Format( wxT( "Ellipse's owner (%d) not found." ), elem.ownerindex ),
2874 return;
2875 }
2876
2877 symbol = libSymbolIt->second;
2878 schsym = m_symbols.at( libSymbolIt->first );
2879 }
2880
2881 ELLIPSE<int> ellipse( elem.Center, elem.Radius, KiROUND( elem.SecondaryRadius ),
2882 ANGLE_0 );
2883
2884 std::vector<BEZIER<int>> beziers;
2885 std::vector<VECTOR2I> polyPoints;
2886
2887 TransformEllipseToBeziers( ellipse, beziers );
2888
2889 for( const BEZIER<int>& bezier : beziers )
2890 {
2891 SCH_SHAPE* libbezier = new SCH_SHAPE( SHAPE_T::BEZIER, LAYER_DEVICE );
2892 symbol->AddDrawItem( libbezier, false );
2893 libbezier->SetUnit( std::max( 0, elem.ownerpartid ) );
2894
2895 if( !schsym )
2896 {
2897 libbezier->SetStart( bezier.Start );
2898 libbezier->SetBezierC1( bezier.C1 );
2899 libbezier->SetBezierC2( bezier.C2 );
2900 libbezier->SetEnd( bezier.End );
2901 }
2902 else
2903 {
2904 libbezier->SetStart( GetRelativePosition( bezier.Start + m_sheetOffset, schsym ) );
2905 libbezier->SetBezierC1( GetRelativePosition( bezier.C1 + m_sheetOffset, schsym ) );
2906 libbezier->SetBezierC2( GetRelativePosition( bezier.C2 + m_sheetOffset, schsym ) );
2907 libbezier->SetEnd( GetRelativePosition( bezier.End + m_sheetOffset, schsym ) );
2908 }
2909
2910 SetLibShapeLine( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE );
2913
2914 polyPoints.push_back( libbezier->GetStart() );
2915 }
2916
2917 // A series of beziers won't fill the center, so if this is meant to be fully filled,
2918 // Add a polygon to fill the center
2919 if( elem.IsSolid )
2920 {
2921 SCH_SHAPE* libline = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2922 symbol->AddDrawItem( libline, false );
2923 libline->SetUnit( std::max( 0, elem.ownerpartid ) );
2924
2925 for( const VECTOR2I& point : polyPoints )
2926 libline->AddPoint( point );
2927
2928 libline->AddPoint( polyPoints[0] );
2929
2930 libline->SetWidth( -1 );
2932 }
2933 }
2934}
2935
2936
2937void SCH_IO_ALTIUM::ParseCircle( const std::map<wxString, wxString>& aProperties,
2938 std::vector<LIB_SYMBOL*>& aSymbol )
2939{
2940 ASCH_ELLIPSE elem( aProperties );
2941
2942 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
2943 {
2944 SCH_SCREEN* screen = getCurrentScreen();
2945 wxCHECK( screen, /* void */ );
2946
2948
2949 circle->SetPosition( elem.Center + m_sheetOffset );
2950 circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
2951 circle->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2952
2953 circle->SetFillColor( GetColorFromInt( elem.AreaColor ) );
2954
2955 if( elem.IsSolid )
2956 circle->SetFillMode( FILL_T::FILLED_WITH_COLOR );
2957 else
2958 circle->SetFilled( false );
2959
2960 screen->Append( circle );
2961 }
2962 else
2963 {
2964 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
2965 : aSymbol[elem.ownerpartdisplaymode];
2966 SCH_SYMBOL* schsym = nullptr;
2967
2968 if( !symbol )
2969 {
2970 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2971
2972 if( libSymbolIt == m_libSymbols.end() )
2973 {
2974 // TODO: e.g. can depend on Template (RECORD=39
2975 m_errorMessages.emplace( wxString::Format( wxT( "Ellipse's owner (%d) not found." ), elem.ownerindex ),
2977 return;
2978 }
2979
2980 symbol = libSymbolIt->second;
2981 schsym = m_symbols.at( libSymbolIt->first );
2982 }
2983
2984 VECTOR2I center = elem.Center;
2986 symbol->AddDrawItem( circle, false );
2987
2988 circle->SetUnit( std::max( 0, elem.ownerpartid ) );
2989
2990 if( schsym )
2992
2993 circle->SetPosition( center );
2994 circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.Radius, 0 ) );
2995
2998 }
2999}
3000
3001
3002void SCH_IO_ALTIUM::ParseLine( const std::map<wxString, wxString>& aProperties,
3003 std::vector<LIB_SYMBOL*>& aSymbol )
3004{
3005 ASCH_LINE elem( aProperties );
3006
3007 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
3008 {
3009 SCH_SCREEN* screen = getCurrentScreen();
3010 wxCHECK( screen, /* void */ );
3011
3012 // close polygon
3014 line->SetEndPoint( elem.point2 + m_sheetOffset );
3016 GetColorFromInt( elem.Color ) ) );
3017
3018 line->SetFlags( IS_NEW );
3019 screen->Append( line );
3020 }
3021 else
3022 {
3023 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
3024 : aSymbol[elem.ownerpartdisplaymode];
3025 SCH_SYMBOL* schsym = nullptr;
3026
3027 if( !symbol )
3028 {
3029 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
3030
3031 if( libSymbolIt == m_libSymbols.end() )
3032 {
3033 // TODO: e.g. can depend on Template (RECORD=39
3034 m_errorMessages.emplace( wxString::Format( wxT( "Line's owner (%d) not found." ), elem.ownerindex ),
3036 return;
3037 }
3038
3039 symbol = libSymbolIt->second;
3040 schsym = m_symbols.at( libSymbolIt->first );
3041 }
3042
3043 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
3044 return;
3045
3047 symbol->AddDrawItem( line, false );
3048
3049 line->SetUnit( std::max( 0, elem.ownerpartid ) );
3050
3051 if( !schsym )
3052 {
3053 line->AddPoint( elem.point1 );
3054 line->AddPoint( elem.point2 );
3055 }
3056 else
3057 {
3058 line->AddPoint( GetRelativePosition( elem.point1 + m_sheetOffset, schsym ) );
3059 line->AddPoint( GetRelativePosition( elem.point2 + m_sheetOffset, schsym ) );
3060 }
3061
3063 line->SetLineStyle( GetPlotDashType( elem.LineStyle ) );
3064 }
3065}
3066
3067
3068void SCH_IO_ALTIUM::ParseSignalHarness( const std::map<wxString, wxString>& aProperties )
3069{
3070 ASCH_SIGNAL_HARNESS elem( aProperties );
3071
3072 if( ShouldPutItemOnSheet( elem.ownerindex ) )
3073 {
3074 SCH_SCREEN* screen = getCurrentScreen();
3075 wxCHECK( screen, /* void */ );
3076
3077 for( size_t ii = 0; ii < elem.points.size() - 1; ii++ )
3078 {
3080 line->SetEndPoint( elem.points[ii + 1] + m_sheetOffset );
3082
3083 line->SetFlags( IS_NEW );
3084 screen->Append( line );
3085 }
3086 }
3087 else
3088 {
3089 // No clue if this situation can ever exist
3090 m_errorMessages.emplace( wxT( "Signal harness, belonging to the part is not currently supported." ),
3092 }
3093}
3094
3095
3096void SCH_IO_ALTIUM::ParseHarnessConnector( int aIndex, const std::map<wxString,
3097 wxString>& aProperties )
3098{
3099 ASCH_HARNESS_CONNECTOR elem( aProperties );
3100
3101 if( ShouldPutItemOnSheet( elem.ownerindex ) )
3102 {
3104 auto [it, _] = m_altiumHarnesses.insert( { m_harnessEntryParent, HARNESS()} );
3105
3106 HARNESS& harness = it->second;
3107 HARNESS::HARNESS_PORT& port = harness.m_entry;
3108 harness.m_location = elem.m_location + m_sheetOffset;
3109 harness.m_size = elem.m_size;
3110
3111 VECTOR2I pos = elem.m_location + m_sheetOffset;
3112 VECTOR2I size = elem.m_size;
3113
3114 switch( elem.m_harnessConnectorSide )
3115 {
3116 default:
3118 port.m_location = { pos.x, pos.y + elem.m_primaryConnectionPosition };
3119 break;
3121 port.m_location = { pos.x + size.x, pos.y + elem.m_primaryConnectionPosition };
3122 break;
3124 port.m_location = { pos.x + elem.m_primaryConnectionPosition, pos.y };
3125 break;
3127 port.m_location = { pos.x + elem.m_primaryConnectionPosition, pos.y + size.y };
3128 break;
3129 }
3130 }
3131 else
3132 {
3133 // I have no clue if this situation can ever exist
3134 m_errorMessages.emplace( wxT( "Harness connector, belonging to the part is not currently supported." ),
3136 }
3137}
3138
3139
3140void SCH_IO_ALTIUM::ParseHarnessEntry( const std::map<wxString, wxString>& aProperties )
3141{
3142 ASCH_HARNESS_ENTRY elem( aProperties );
3143
3144 auto harnessIt = m_altiumHarnesses.find( m_harnessEntryParent );
3145
3146 if( harnessIt == m_altiumHarnesses.end() )
3147 {
3148 m_errorMessages.emplace( wxString::Format( wxT( "Harness entry's parent (%d) not found." ),
3151 return;
3152 }
3153
3154 HARNESS& harness = harnessIt->second;
3156 port.m_name = elem.Name;
3157 port.m_harnessConnectorSide = elem.Side;
3159
3160 VECTOR2I pos = harness.m_location;
3161 VECTOR2I size = harness.m_size;
3162 int quadrant = 1;
3163
3164 switch( elem.Side )
3165 {
3166 default:
3168 port.m_location = { pos.x, pos.y + elem.DistanceFromTop };
3169 break;
3171 quadrant = 4;
3172 port.m_location = { pos.x + size.x, pos.y + elem.DistanceFromTop };
3173 break;
3175 port.m_location = { pos.x + elem.DistanceFromTop, pos.y };
3176 break;
3178 quadrant = 2;
3179 port.m_location = { pos.x + elem.DistanceFromTop, pos.y + size.y };
3180 break;
3181 }
3182
3183
3184 SCH_SCREEN* screen = getCurrentScreen();
3185 wxCHECK( screen, /* void */ );
3186
3187 SCH_BUS_WIRE_ENTRY* entry = new SCH_BUS_WIRE_ENTRY( port.m_location, quadrant );
3188 port.m_entryLocation = entry->GetPosition() + entry->GetSize();
3189 entry->SetFlags( IS_NEW );
3190 screen->Append( entry );
3191 harness.m_ports.emplace_back( port );
3192}
3193
3194
3195void SCH_IO_ALTIUM::ParseHarnessType( const std::map<wxString, wxString>& aProperties )
3196{
3197 ASCH_HARNESS_TYPE elem( aProperties );
3198
3199 auto harnessIt = m_altiumHarnesses.find( m_harnessEntryParent );
3200
3201 if( harnessIt == m_altiumHarnesses.end() )
3202 {
3203 m_errorMessages.emplace( wxString::Format( wxT( "Harness type's parent (%d) not found." ),
3206 return;
3207 }
3208
3209 HARNESS& harness = harnessIt->second;
3210 harness.m_name = elem.Text;
3211}
3212
3213
3214void SCH_IO_ALTIUM::ParseRectangle( const std::map<wxString, wxString>& aProperties,
3215 std::vector<LIB_SYMBOL*>& aSymbol )
3216{
3217 ASCH_RECTANGLE elem( aProperties );
3218
3219 VECTOR2I sheetTopRight = elem.TopRight + m_sheetOffset;
3220 VECTOR2I sheetBottomLeft = elem.BottomLeft + m_sheetOffset;
3221
3222 if( aSymbol.empty() && ShouldPutItemOnSheet( elem.ownerindex ) )
3223 {
3224 SCH_SCREEN* screen = getCurrentScreen();
3225 wxCHECK( screen, /* void */ );
3226
3227 SCH_SHAPE* rect = new SCH_SHAPE( SHAPE_T::RECTANGLE );
3228
3229 rect->SetPosition( sheetTopRight );
3230 rect->SetEnd( sheetBottomLeft );
3231 SetSchShapeLine( elem, rect );
3232 SetSchShapeFillAndColor( elem, rect );
3233 rect->SetFlags( IS_NEW );
3234
3235 screen->Append( rect );
3236 }
3237 else
3238 {
3239 LIB_SYMBOL* symbol = (int) aSymbol.size() <= elem.ownerpartdisplaymode ? nullptr
3240 : aSymbol[elem.ownerpartdisplaymode];
3241 SCH_SYMBOL* schsym = nullptr;
3242
3243 if( !symbol )
3244 {
3245 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
3246
3247 if( libSymbolIt == m_libSymbols.end() )
3248 {
3249 // TODO: e.g. can depend on Template (RECORD=39
3250 m_errorMessages.emplace( wxString::Format( wxT( "Rectangle's owner (%d) not found." ),
3251 elem.ownerindex ),
3253 return;
3254 }
3255
3256 symbol = libSymbolIt->second;
3257 schsym = m_symbols.at( libSymbolIt->first );
3258 }
3259
3260 if( aSymbol.empty() && !IsComponentPartVisible( elem ) )
3261 return;
3262
3264 symbol->AddDrawItem( rect, false );
3265
3266 rect->SetUnit( std::max( 0, elem.ownerpartid ) );
3267
3268 if( !schsym )
3269 {
3270 rect->SetPosition( sheetTopRight );
3271 rect->SetEnd( sheetBottomLeft );
3272 }
3273 else
3274 {
3275 rect->SetPosition( GetRelativePosition( sheetTopRight, schsym ) );
3276 rect->SetEnd( GetRelativePosition( sheetBottomLeft, schsym ) );
3277 }
3278
3281 }
3282}
3283
3284
3285void SCH_IO_ALTIUM::ParseSheetSymbol( int aIndex, const std::map<wxString, wxString>& aProperties )
3286{
3287 ASCH_SHEET_SYMBOL elem( aProperties );
3288
3289 SCH_SHEET* sheet = new SCH_SHEET( getCurrentSheet(), elem.location + m_sheetOffset, elem.size );
3290
3291 sheet->SetBorderColor( GetColorFromInt( elem.color ) );
3292
3293 if( elem.isSolid )
3295
3296 sheet->SetFlags( IS_NEW );
3297
3298 SCH_SCREEN* currentScreen = getCurrentScreen();
3299 wxCHECK( currentScreen, /* void */ );
3300 currentScreen->Append( sheet );
3301
3302 SCH_SHEET_PATH sheetpath = m_sheetPath;
3303 sheetpath.push_back( sheet );
3304
3305 // We'll update later if we find a pageNumber record for it.
3306 sheetpath.SetPageNumber( "#" );
3307
3308 SCH_SCREEN* rootScreen = m_rootSheet->GetScreen();
3309 wxCHECK( rootScreen, /* void */ );
3310
3311 SCH_SHEET_INSTANCE sheetInstance;
3312
3313 sheetInstance.m_Path = sheetpath.Path();
3314 sheetInstance.m_PageNumber = wxT( "#" );
3315
3316 rootScreen->m_sheetInstances.emplace_back( sheetInstance );
3317 m_sheets.insert( { aIndex, sheet } );
3318}
3319
3320
3321void SCH_IO_ALTIUM::ParseSheetEntry( const std::map<wxString, wxString>& aProperties )
3322{
3323 ASCH_SHEET_ENTRY elem( aProperties );
3324
3325 const auto& sheetIt = m_sheets.find( elem.ownerindex );
3326
3327 if( sheetIt == m_sheets.end() )
3328 {
3329 m_errorMessages.emplace( wxString::Format( wxT( "Sheet entry's owner (%d) not found." ), elem.ownerindex ),
3331 return;
3332 }
3333
3334 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
3335 sheetIt->second->AddPin( sheetPin );
3336
3337 sheetPin->SetText( elem.name );
3339 //sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
3340 //sheetPin->SetPosition( getKiCadPoint( term.Position ) );
3341
3342 VECTOR2I pos = sheetIt->second->GetPosition();
3343 VECTOR2I size = sheetIt->second->GetSize();
3344
3345 switch( elem.side )
3346 {
3347 default:
3349 sheetPin->SetPosition( { pos.x, pos.y + elem.distanceFromTop } );
3350 sheetPin->SetSpinStyle( SPIN_STYLE::LEFT );
3351 sheetPin->SetSide( SHEET_SIDE::LEFT );
3352 break;
3353
3355 sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.distanceFromTop } );
3356 sheetPin->SetSpinStyle( SPIN_STYLE::RIGHT );
3357 sheetPin->SetSide( SHEET_SIDE::RIGHT );
3358 break;
3359
3361 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y } );
3362 sheetPin->SetSpinStyle( SPIN_STYLE::UP );
3363 sheetPin->SetSide( SHEET_SIDE::TOP );
3364 break;
3365
3367 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y + size.y } );
3368 sheetPin->SetSpinStyle( SPIN_STYLE::BOTTOM );
3369 sheetPin->SetSide( SHEET_SIDE::BOTTOM );
3370 break;
3371 }
3372
3373 switch( elem.iotype )
3374 {
3375 default:
3378 break;
3379
3382 break;
3383
3386 break;
3387
3390 break;
3391 }
3392}
3393
3394
3396 REPORTER* aReporter )
3397{
3399 {
3401 line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3402 line1->AddPoint( { 0, 0 } );
3403 line1->AddPoint( { 0, schIUScale.MilsToIU( 50 ) } );
3404 aKsymbol->AddDrawItem( line1, false );
3405
3406 if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE )
3407 {
3409 circle->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), LINE_STYLE::SOLID ) );
3410 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 75 ) } );
3411 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 25 ), 0 ) );
3412 aKsymbol->AddDrawItem( circle, false );
3413 }
3414 else
3415 {
3417 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3418 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( 50 ) } );
3419 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( 50 ) } );
3420 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 100 ) } );
3421 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( 50 ) } );
3422 aKsymbol->AddDrawItem( line2, false );
3423 }
3424
3425 return { 0, schIUScale.MilsToIU( 150 ) };
3426 }
3427 else if( aStyle == ASCH_POWER_PORT_STYLE::WAVE )
3428 {
3430 line->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3431 line->AddPoint( { 0, 0 } );
3432 line->AddPoint( { 0, schIUScale.MilsToIU( 72 ) } );
3433 aKsymbol->AddDrawItem( line, false );
3434
3436 bezier->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), LINE_STYLE::SOLID ) );
3437 bezier->SetStart( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( 50 ) } );
3438 bezier->SetBezierC1( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( 87 ) } );
3439 bezier->SetBezierC2( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( 63 ) } );
3440 bezier->SetEnd( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( 100 ) } );
3441 aKsymbol->AddDrawItem( bezier, false );
3442
3443 return { 0, schIUScale.MilsToIU( 150 ) };
3444 }
3445 else if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND
3447 || aStyle == ASCH_POWER_PORT_STYLE::EARTH
3449 {
3451 line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3452 line1->AddPoint( { 0, 0 } );
3453 line1->AddPoint( { 0, schIUScale.MilsToIU( 100 ) } );
3454 aKsymbol->AddDrawItem( line1, false );
3455
3457 {
3459 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3460 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 100 ) } );
3461 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( 100 ) } );
3462 aKsymbol->AddDrawItem( line2, false );
3463
3465 line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3466 line3->AddPoint( { schIUScale.MilsToIU( -70 ), schIUScale.MilsToIU( 130 ) } );
3467 line3->AddPoint( { schIUScale.MilsToIU( 70 ), schIUScale.MilsToIU( 130 ) } );
3468 aKsymbol->AddDrawItem( line3, false );
3469
3471 line4->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3472 line4->AddPoint( { schIUScale.MilsToIU( -40 ), schIUScale.MilsToIU( 160 ) } );
3473 line4->AddPoint( { schIUScale.MilsToIU( 40 ), schIUScale.MilsToIU( 160 ) } );
3474 aKsymbol->AddDrawItem( line4, false );
3475
3477 line5->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3478 line5->AddPoint( { schIUScale.MilsToIU( -10 ), schIUScale.MilsToIU( 190 ) } );
3479 line5->AddPoint( { schIUScale.MilsToIU( 10 ), schIUScale.MilsToIU( 190 ) } );
3480 aKsymbol->AddDrawItem( line5, false );
3481 }
3482 else if( aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND )
3483 {
3485 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3486 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 100 ) } );
3487 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( 100 ) } );
3488 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 200 ) } );
3489 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 100 ) } );
3490 aKsymbol->AddDrawItem( line2, false );
3491 }
3492 else if( aStyle == ASCH_POWER_PORT_STYLE::EARTH )
3493 {
3495 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3496 line2->AddPoint( { schIUScale.MilsToIU( -150 ), schIUScale.MilsToIU( 200 ) } );
3497 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 100 ) } );
3498 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( 100 ) } );
3499 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 200 ) } );
3500 aKsymbol->AddDrawItem( line2, false );
3501
3503 line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3504 line3->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 100 ) } );
3505 line3->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( 200 ) } );
3506 aKsymbol->AddDrawItem( line3, false );
3507 }
3508 else // ASCH_POWER_PORT_STYLE::GOST_ARROW
3509 {
3511 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3512 line2->AddPoint( { schIUScale.MilsToIU( -25 ), schIUScale.MilsToIU( 50 ) } );
3513 line2->AddPoint( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 100 ) } );
3514 line2->AddPoint( { schIUScale.MilsToIU( 25 ), schIUScale.MilsToIU( 50 ) } );
3515 aKsymbol->AddDrawItem( line2, false );
3516
3517 return { 0, schIUScale.MilsToIU( 150 ) }; // special case
3518 }
3519
3520 return { 0, schIUScale.MilsToIU( 250 ) };
3521 }
3524 {
3526 line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3527 line1->AddPoint( { 0, 0 } );
3528 line1->AddPoint( { 0, schIUScale.MilsToIU( 160 ) } );
3529 aKsymbol->AddDrawItem( line1, false );
3530
3532 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3533 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 160 ) } );
3534 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( 160 ) } );
3535 aKsymbol->AddDrawItem( line2, false );
3536
3538 line3->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3539 line3->AddPoint( { schIUScale.MilsToIU( -60 ), schIUScale.MilsToIU( 200 ) } );
3540 line3->AddPoint( { schIUScale.MilsToIU( 60 ), schIUScale.MilsToIU( 200 ) } );
3541 aKsymbol->AddDrawItem( line3, false );
3542
3544 line4->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3545 line4->AddPoint( { schIUScale.MilsToIU( -20 ), schIUScale.MilsToIU( 240 ) } );
3546 line4->AddPoint( { schIUScale.MilsToIU( 20 ), schIUScale.MilsToIU( 240 ) } );
3547 aKsymbol->AddDrawItem( line4, false );
3548
3550 return { 0, schIUScale.MilsToIU( -300 ) };
3551
3553 circle->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3554 circle->SetPosition( { schIUScale.MilsToIU( 0 ), schIUScale.MilsToIU( 160 ) } );
3555 circle->SetEnd( circle->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 120 ), 0 ) );
3556 aKsymbol->AddDrawItem( circle, false );
3557
3558 return { 0, schIUScale.MilsToIU( 350 ) };
3559 }
3560 else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_BAR )
3561 {
3563 line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3564 line1->AddPoint( { 0, 0 } );
3565 line1->AddPoint( { 0, schIUScale.MilsToIU( 200 ) } );
3566 aKsymbol->AddDrawItem( line1, false );
3567
3569 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3570 line2->AddPoint( { schIUScale.MilsToIU( -100 ), schIUScale.MilsToIU( 200 ) } );
3571 line2->AddPoint( { schIUScale.MilsToIU( 100 ), schIUScale.MilsToIU( 200 ) } );
3572 aKsymbol->AddDrawItem( line2, false );
3573
3574 return { 0, schIUScale.MilsToIU( 250 ) };
3575 }
3576 else
3577 {
3578 if( aStyle != ASCH_POWER_PORT_STYLE::BAR )
3579 {
3580 aReporter->Report( _( "Power Port with unknown style imported as 'Bar' type." ),
3582 }
3583
3585 line1->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3586 line1->AddPoint( { 0, 0 } );
3587 line1->AddPoint( { 0, schIUScale.MilsToIU( 100 ) } );
3588 aKsymbol->AddDrawItem( line1, false );
3589
3591 line2->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 10 ), LINE_STYLE::SOLID ) );
3592 line2->AddPoint( { schIUScale.MilsToIU( -50 ), schIUScale.MilsToIU( 100 ) } );
3593 line2->AddPoint( { schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 100 ) } );
3594 aKsymbol->AddDrawItem( line2, false );
3595
3596 return { 0, schIUScale.MilsToIU( 150 ) };
3597 }
3598}
3599
3600
3601void SCH_IO_ALTIUM::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
3602{
3603 ASCH_POWER_PORT elem( aProperties );
3604
3605 wxString symName( elem.text );
3606 std::string styleName( magic_enum::enum_name<ASCH_POWER_PORT_STYLE>( elem.style ) );
3607
3608 if( !styleName.empty() )
3609 symName << '_' << styleName;
3610
3611 LIB_ID libId = AltiumToKiCadLibID( getLibName(), symName );
3612 LIB_SYMBOL* libSymbol = nullptr;
3613
3614 const auto& powerSymbolIt = m_powerSymbols.find( symName );
3615
3616 if( powerSymbolIt != m_powerSymbols.end() )
3617 {
3618 libSymbol = powerSymbolIt->second; // cache hit
3619 }
3620 else
3621 {
3622 libSymbol = new LIB_SYMBOL( wxEmptyString );
3623 libSymbol->SetGlobalPower();
3624 libSymbol->SetName( symName );
3625 libSymbol->GetReferenceField().SetText( "#PWR" );
3626 libSymbol->GetReferenceField().SetVisible( false );
3627 libSymbol->GetValueField().SetText( elem.text );
3628 libSymbol->GetValueField().SetVisible( true );
3629 libSymbol->SetDescription( wxString::Format( _( "Power symbol creates a global label with name '%s'" ),
3630 elem.text ) );
3631 libSymbol->SetKeyWords( "power-flag" );
3632 libSymbol->SetLibId( libId );
3633
3634 // generate graphic
3635 SCH_PIN* pin = new SCH_PIN( libSymbol );
3636 libSymbol->AddDrawItem( pin, false );
3637
3638 pin->SetName( elem.text );
3639 pin->SetPosition( { 0, 0 } );
3640 pin->SetLength( 0 );
3642 pin->SetVisible( false );
3643
3644 VECTOR2I valueFieldPos = HelperGeneratePowerPortGraphics( libSymbol, elem.style, m_reporter );
3645
3646 libSymbol->GetValueField().SetPosition( valueFieldPos );
3647
3648 // this has to be done after parsing the LIB_SYMBOL!
3649 m_powerSymbols.insert( { symName, libSymbol } );
3650 }
3651
3652 SCH_SCREEN* screen = getCurrentScreen();
3653 wxCHECK( screen, /* void */ );
3654
3655 SCH_SYMBOL* symbol = new SCH_SYMBOL();
3656 symbol->SetRef( &m_sheetPath, "#PWR?" );
3657 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( false );
3658 symbol->SetValueFieldText( elem.text );
3659 symbol->SetLibId( libId );
3660 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
3661
3662 SCH_FIELD* valueField = symbol->GetField( FIELD_T::VALUE );
3663 valueField->SetVisible( elem.showNetName );
3664 valueField->SetPosition( libSymbol->GetValueField().GetPosition() );
3665
3666 symbol->SetPosition( elem.location + m_sheetOffset );
3667
3668 switch( elem.orientation )
3669 {
3672 valueField->SetTextAngle( ANGLE_VERTICAL );
3674 break;
3675
3678 valueField->SetTextAngle( ANGLE_HORIZONTAL );
3680 break;
3681
3684 valueField->SetTextAngle( ANGLE_VERTICAL );
3686 break;
3687
3690 valueField->SetTextAngle( ANGLE_HORIZONTAL );
3692 break;
3693
3694 default:
3695 m_errorMessages.emplace( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
3696 break;
3697 }
3698
3699 screen->Append( symbol );
3700}
3701
3702
3704{
3705 ParsePortHelper( aElem );
3706}
3707
3708
3710{
3711 if( !aElem.HarnessType.IsEmpty() )
3712 {
3713 // Parse harness ports after "Additional" compound section is parsed
3714 m_altiumHarnessPortsCurrentSheet.emplace_back( aElem );
3715 return;
3716 }
3717
3718 ParsePortHelper( aElem );
3719}
3720
3721
3723{
3724 VECTOR2I start = aElem.Location + m_sheetOffset;
3725 VECTOR2I end = start;
3726
3727 switch( aElem.Style )
3728 {
3729 default:
3734 end.x += aElem.Width;
3735 break;
3736
3741 end.y -= aElem.Width;
3742 break;
3743 }
3744
3745 // Check which connection points exists in the schematic
3746 SCH_SCREEN* screen = getCurrentScreen();
3747 wxCHECK( screen, /* void */ );
3748
3749 bool startIsWireTerminal = screen->IsTerminalPoint( start, LAYER_WIRE );
3750 bool startIsBusTerminal = screen->IsTerminalPoint( start, LAYER_BUS );
3751
3752 bool endIsWireTerminal = screen->IsTerminalPoint( end, LAYER_WIRE );
3753 bool endIsBusTerminal = screen->IsTerminalPoint( end, LAYER_BUS );
3754
3755 // check if any of the points is a terminal point
3756 // TODO: there seems a problem to detect approximated connections towards component pins?
3757 bool connectionFound = startIsWireTerminal
3758 || startIsBusTerminal
3759 || endIsWireTerminal
3760 || endIsBusTerminal;
3761
3762 if( !connectionFound )
3763 {
3764 for( auto& [ _, harness ] : m_altiumHarnesses )
3765 {
3766 if( harness.m_name.CmpNoCase( aElem.HarnessType ) != 0 )
3767 continue;
3768
3769 BOX2I bbox( harness.m_location, harness.m_size );
3770 bbox.Inflate( 10 );
3771
3772 if( bbox.Contains( start ) )
3773 {
3774 startIsBusTerminal = true;
3775 connectionFound = true;
3776 break;
3777 }
3778
3779 if( bbox.Contains( end ) )
3780 {
3781 endIsBusTerminal = true;
3782 connectionFound = true;
3783 break;
3784 }
3785 }
3786
3787 if( !connectionFound )
3788 {
3789 m_errorMessages.emplace( wxString::Format( _( "Port %s has no connections." ), aElem.Name ),
3791 }
3792 }
3793
3794 // Select label position. In case both match, we will add a line later.
3795 VECTOR2I position = ( startIsWireTerminal || startIsBusTerminal ) ? start : end;
3796 SCH_LABEL_BASE* label;
3797
3798 // TODO: detect correct label type depending on sheet settings, etc.
3799#if 1 // Set to 1 to use SCH_HIERLABEL label, 0 to use SCH_GLOBALLABEL
3800 {
3801 label = new SCH_HIERLABEL( position, aElem.Name );
3802 }
3803#else
3804 label = new SCH_GLOBALLABEL( position, aElem.Name );
3805
3806 // Default "Sheet References" field should be hidden, at least for now
3807 label->GetField( INTERSHEET_REFS )->SetVisible( false );
3808#endif
3809
3810 switch( aElem.IOtype )
3811 {
3812 default:
3817 }
3818
3819 switch( aElem.Style )
3820 {
3821 default:
3826 if( ( startIsWireTerminal || startIsBusTerminal ) )
3828 else
3830
3831 break;
3832
3837 if( ( startIsWireTerminal || startIsBusTerminal ) )
3838 label->SetSpinStyle( SPIN_STYLE::UP );
3839 else
3841
3842 break;
3843 }
3844
3845 label->AutoplaceFields( screen, AUTOPLACE_AUTO );
3846 label->SetFlags( IS_NEW );
3847
3848 screen->Append( label );
3849
3850 // This is a hack, for the case both connection points are valid: add a small wire
3851 if( ( startIsWireTerminal && endIsWireTerminal ) )
3852 {
3853 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_WIRE );
3854 wire->SetEndPoint( end );
3855 wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
3856 wire->SetFlags( IS_NEW );
3857 screen->Append( wire );
3858 }
3859 else if( startIsBusTerminal && endIsBusTerminal )
3860 {
3861 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_BUS );
3862 wire->SetEndPoint( end );
3863 wire->SetLineWidth( schIUScale.MilsToIU( 2 ) );
3864 wire->SetFlags( IS_NEW );
3865 screen->Append( wire );
3866 }
3867}
3868
3869
3870void SCH_IO_ALTIUM::ParseNoERC( const std::map<wxString, wxString>& aProperties )
3871{
3872 ASCH_NO_ERC elem( aProperties );
3873
3874 SCH_SCREEN* screen = getCurrentScreen();
3875 wxCHECK( screen, /* void */ );
3876
3877 if( elem.isActive )
3878 {
3879 SCH_NO_CONNECT* noConnect = new SCH_NO_CONNECT( elem.location + m_sheetOffset );
3880
3881 noConnect->SetFlags( IS_NEW );
3882 screen->Append( noConnect );
3883 }
3884}
3885
3886
3887void SCH_IO_ALTIUM::ParseNetLabel( const std::map<wxString, wxString>& aProperties )
3888{
3889 ASCH_NET_LABEL elem( aProperties );
3890
3891 SCH_LABEL* label = new SCH_LABEL( elem.location + m_sheetOffset, elem.text );
3892
3893 SCH_SCREEN* screen = getCurrentScreen();
3894 wxCHECK( screen, /* void */ );
3895
3896 SetTextPositioning( label, elem.justification, elem.orientation );
3897
3898 label->SetFlags( IS_NEW );
3899 screen->Append( label );
3900}
3901
3902
3903void SCH_IO_ALTIUM::ParseBus( const std::map<wxString, wxString>& aProperties )
3904{
3905 ASCH_BUS elem( aProperties );
3906
3907 SCH_SCREEN* screen = getCurrentScreen();
3908 wxCHECK( screen, /* void */ );
3909
3910 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
3911 {
3912 SCH_LINE* bus = new SCH_LINE( elem.points.at( i ) + m_sheetOffset, SCH_LAYER_ID::LAYER_BUS );
3913 bus->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
3914 bus->SetLineWidth( elem.lineWidth );
3915
3916 bus->SetFlags( IS_NEW );
3917 screen->Append( bus );
3918 }
3919}
3920
3921
3922void SCH_IO_ALTIUM::ParseWire( const std::map<wxString, wxString>& aProperties )
3923{
3924 ASCH_WIRE elem( aProperties );
3925
3926 SCH_SCREEN* screen = getCurrentScreen();
3927 wxCHECK( screen, /* void */ );
3928
3929 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
3930 {
3931 SCH_LINE* wire = new SCH_LINE( elem.points.at( i ) + m_sheetOffset, SCH_LAYER_ID::LAYER_WIRE );
3932 wire->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
3933 // wire->SetLineWidth( elem.lineWidth );
3934
3935 wire->SetFlags( IS_NEW );
3936 screen->Append( wire );
3937 }
3938}
3939
3940
3941void SCH_IO_ALTIUM::ParseJunction( const std::map<wxString, wxString>& aProperties )
3942{
3943 SCH_SCREEN* screen = getCurrentScreen();
3944 wxCHECK( screen, /* void */ );
3945
3946 ASCH_JUNCTION elem( aProperties );
3947
3948 SCH_JUNCTION* junction = new SCH_JUNCTION( elem.location + m_sheetOffset );
3949
3950 junction->SetFlags( IS_NEW );
3951 screen->Append( junction );
3952}
3953
3954
3955void SCH_IO_ALTIUM::ParseImage( const std::map<wxString, wxString>& aProperties )
3956{
3957 ASCH_IMAGE elem( aProperties );
3958
3959 const auto& component = m_altiumComponents.find( elem.ownerindex );
3960
3961 //Hide the image if it is owned by a component but the part id do not match
3962 if( component != m_altiumComponents.end()
3963 && component->second.currentpartid != elem.ownerpartid )
3964 return;
3965
3966 VECTOR2I center = ( elem.location + elem.corner ) / 2 + m_sheetOffset;
3967 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
3968 REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
3969
3970 SCH_SCREEN* screen = getCurrentScreen();
3971 wxCHECK( screen, /* void */ );
3972
3973 if( elem.embedimage )
3974 {
3975 const ASCH_STORAGE_FILE* storageFile = GetFileFromStorage( elem.filename );
3976
3977 if( !storageFile )
3978 {
3979 m_errorMessages.emplace( wxString::Format( _( "Embedded file %s not found in storage." ),
3980 elem.filename ),
3982 return;
3983 }
3984
3985 wxString storagePath = wxFileName::CreateTempFileName( "kicad_import_" );
3986
3987 // As wxZlibInputStream is not seekable, we need to write a temporary file
3988 wxMemoryInputStream fileStream( storageFile->data.data(), storageFile->data.size() );
3989 wxZlibInputStream zlibInputStream( fileStream );
3990 wxFFileOutputStream outputStream( storagePath );
3991 outputStream.Write( zlibInputStream );
3992 outputStream.Close();
3993
3994 if( !refImage.ReadImageFile( storagePath ) )
3995 {
3996 m_errorMessages.emplace( wxString::Format( _( "Error reading image %s." ), storagePath ),
3998 return;
3999 }
4000
4001 // Remove temporary file
4002 wxRemoveFile( storagePath );
4003 }
4004 else
4005 {
4006 if( !wxFileExists( elem.filename ) )
4007 {
4008 m_errorMessages.emplace( wxString::Format( _( "File not found %s." ), elem.filename ),
4010 return;
4011 }
4012
4013 if( !refImage.ReadImageFile( elem.filename ) )
4014 {
4015 m_errorMessages.emplace( wxString::Format( _( "Error reading image %s." ), elem.filename ),
4017 return;
4018 }
4019 }
4020
4021 // we only support one scale, thus we need to select one in case it does not keep aspect ratio
4022 const VECTOR2I currentImageSize = refImage.GetSize();
4023 const VECTOR2I expectedImageSize = elem.location - elem.corner;
4024 const double scaleX = std::abs( static_cast<double>( expectedImageSize.x ) / currentImageSize.x );
4025 const double scaleY = std::abs( static_cast<double>( expectedImageSize.y ) / currentImageSize.y );
4026 refImage.SetImageScale( std::min( scaleX, scaleY ) );
4027
4028 bitmap->SetFlags( IS_NEW );
4029 screen->Append( bitmap.release() );
4030}
4031
4032
4033void SCH_IO_ALTIUM::ParseSheet( const std::map<wxString, wxString>& aProperties )
4034{
4035 m_altiumSheet = std::make_unique<ASCH_SHEET>( aProperties );
4036
4037 SCH_SCREEN* screen = getCurrentScreen();
4038 wxCHECK( screen, /* void */ );
4039
4040 PAGE_INFO pageInfo;
4041
4042 bool isPortrait = m_altiumSheet->sheetOrientation == ASCH_SHEET_WORKSPACEORIENTATION::PORTRAIT;
4043
4044 if( m_altiumSheet->useCustomSheet )
4045 {
4046 PAGE_INFO::SetCustomWidthMils( schIUScale.IUToMils( m_altiumSheet->customSize.x ) );
4047 PAGE_INFO::SetCustomHeightMils( schIUScale.IUToMils( m_altiumSheet->customSize.y ) );
4048 pageInfo.SetType( PAGE_SIZE_TYPE::User, isPortrait );
4049 }
4050 else
4051 {
4052 switch( m_altiumSheet->sheetSize )
4053 {
4054 default:
4055 case ASCH_SHEET_SIZE::A4: pageInfo.SetType( "A4", isPortrait ); break;
4056 case ASCH_SHEET_SIZE::A3: pageInfo.SetType( "A3", isPortrait ); break;
4057 case ASCH_SHEET_SIZE::A2: pageInfo.SetType( "A2", isPortrait ); break;
4058 case ASCH_SHEET_SIZE::A1: pageInfo.SetType( "A1", isPortrait ); break;
4059 case ASCH_SHEET_SIZE::A0: pageInfo.SetType( "A0", isPortrait ); break;
4060 case ASCH_SHEET_SIZE::A: pageInfo.SetType( "A", isPortrait ); break;
4061 case ASCH_SHEET_SIZE::B: pageInfo.SetType( "B", isPortrait ); break;
4062 case ASCH_SHEET_SIZE::C: pageInfo.SetType( "C", isPortrait ); break;
4063 case ASCH_SHEET_SIZE::D: pageInfo.SetType( "D", isPortrait ); break;
4064 case ASCH_SHEET_SIZE::E: pageInfo.SetType( "E", isPortrait ); break;
4065 case ASCH_SHEET_SIZE::LETTER: pageInfo.SetType( "USLetter", isPortrait ); break;
4066 case ASCH_SHEET_SIZE::LEGAL: pageInfo.SetType( "USLegal", isPortrait ); break;
4067 case ASCH_SHEET_SIZE::TABLOID: pageInfo.SetType( "A3", isPortrait ); break;
4068 case ASCH_SHEET_SIZE::ORCAD_A: pageInfo.SetType( "A", isPortrait ); break;
4069 case ASCH_SHEET_SIZE::ORCAD_B: pageInfo.SetType( "B", isPortrait ); break;
4070 case ASCH_SHEET_SIZE::ORCAD_C: pageInfo.SetType( "C", isPortrait ); break;
4071 case ASCH_SHEET_SIZE::ORCAD_D: pageInfo.SetType( "D", isPortrait ); break;
4072 case ASCH_SHEET_SIZE::ORCAD_E: pageInfo.SetType( "E", isPortrait ); break;
4073 }
4074 }
4075
4076 screen->SetPageSettings( pageInfo );
4077
4078 m_sheetOffset = { 0, pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) };
4079}
4080
4081
4082void SCH_IO_ALTIUM::ParseSheetName( const std::map<wxString, wxString>& aProperties )
4083{
4084 ASCH_SHEET_NAME elem( aProperties );
4085 SCH_SCREEN* currentScreen = getCurrentScreen();
4086
4087 wxCHECK( currentScreen, /* void */ );
4088
4089 const auto& sheetIt = m_sheets.find( elem.ownerindex );
4090
4091 if( sheetIt == m_sheets.end() )
4092 {
4093 m_errorMessages.emplace( wxString::Format( wxT( "Sheetname's owner (%d) not found." ),
4094 elem.ownerindex ),
4096 return;
4097 }
4098
4099 wxString sheetName = elem.text;
4100 std::set<wxString> sheetNames;
4101
4102 for( EDA_ITEM* item : currentScreen->Items().OfType( SCH_SHEET_T ) )
4103 {
4104 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
4105 sheetNames.insert( sheet->GetName() );
4106 }
4107
4108 for( int ii = 1; ; ++ii )
4109 {
4110 if( sheetNames.find( sheetName ) == sheetNames.end() )
4111 break;
4112
4113 sheetName = elem.text + wxString::Format( wxT( "_%d" ), ii );
4114 }
4115
4116 SCH_FIELD* sheetNameField = sheetIt->second->GetField( FIELD_T::SHEET_NAME );
4117
4118 sheetNameField->SetPosition( elem.location + m_sheetOffset );
4119 sheetNameField->SetText( sheetName );
4120 sheetNameField->SetVisible( !elem.isHidden );
4122}
4123
4124
4125void SCH_IO_ALTIUM::ParseFileName( const std::map<wxString, wxString>& aProperties )
4126{
4127 ASCH_FILE_NAME elem( aProperties );
4128
4129 const auto& sheetIt = m_sheets.find( elem.ownerindex );
4130
4131 if( sheetIt == m_sheets.end() )
4132 {
4133 m_errorMessages.emplace( wxString::Format( wxT( "Filename's owner (%d) not found." ),
4134 elem.ownerindex ),
4136 return;
4137 }
4138
4139 SCH_FIELD* filenameField = sheetIt->second->GetField( FIELD_T::SHEET_FILENAME );
4140
4141 filenameField->SetPosition( elem.location + m_sheetOffset );
4142
4143 // Keep the filename of the Altium file until after the file is actually loaded.
4144 filenameField->SetText( elem.text );
4145 filenameField->SetVisible( !elem.isHidden );
4147}
4148
4149
4150void SCH_IO_ALTIUM::ParseDesignator( const std::map<wxString, wxString>& aProperties )
4151{
4152 ASCH_DESIGNATOR elem( aProperties );
4153
4154 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
4155
4156 if( libSymbolIt == m_libSymbols.end() )
4157 {
4158 // TODO: e.g. can depend on Template (RECORD=39
4159 m_errorMessages.emplace( wxString::Format( wxT( "Designator's owner (%d) not found." ),
4160 elem.ownerindex ),
4162 return;
4163 }
4164
4165 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
4166 SCH_SHEET_PATH sheetpath;
4167
4168 SCH_SCREEN* screen = getCurrentScreen();
4169 wxCHECK( screen, /* void */ );
4170
4171 // Graphics symbols have no reference. '#GRAPHIC' allows them to not have footprint associated.
4172 // Note: not all unnamed imported symbols are necessarily graphics.
4173 bool emptyRef = elem.text.IsEmpty();
4174 symbol->SetRef( &m_sheetPath, emptyRef ? wxString( wxS( "#GRAPHIC" ) ) : elem.text );
4175
4176 // I am not sure value and ref should be invisible just because emptyRef is true
4177 // I have examples with this criteria fully incorrect.
4178 bool visible = !emptyRef;
4179
4180 symbol->GetField( FIELD_T::VALUE )->SetVisible( visible );
4181
4182 SCH_FIELD* field = symbol->GetField( FIELD_T::REFERENCE );
4183 field->SetVisible( visible );
4184 field->SetPosition( elem.location + m_sheetOffset );
4185 SetTextPositioning( field, elem.justification, elem.orientation );
4186}
4187
4188
4189void SCH_IO_ALTIUM::ParseLibDesignator( const std::map<wxString, wxString>& aProperties,
4190 std::vector<LIB_SYMBOL*>& aSymbol,
4191 std::vector<int>& aFontSizes )
4192{
4193 ASCH_DESIGNATOR elem( aProperties );
4194
4195 // Designators are shared by everyone
4196 for( LIB_SYMBOL* symbol : aSymbol )
4197 {
4198 bool emptyRef = elem.text.IsEmpty();
4199 SCH_FIELD& refField = symbol->GetReferenceField();
4200
4201 if( emptyRef )
4202 refField.SetText( wxT( "X" ) );
4203 else
4204 refField.SetText( elem.text.BeforeLast( '?' ) ); // remove the '?' at the end for KiCad-style
4205
4206 refField.SetPosition( elem.location );
4207
4208 if( elem.fontId > 0 && elem.fontId <= static_cast<int>( aFontSizes.size() ) )
4209 {
4210 int size = aFontSizes[elem.fontId - 1];
4211 refField.SetTextSize( { size, size } );
4212 }
4213 }
4214}
4215
4216
4217void SCH_IO_ALTIUM::ParseBusEntry( const std::map<wxString, wxString>& aProperties )
4218{
4219 ASCH_BUS_ENTRY elem( aProperties );
4220
4221 SCH_SCREEN* screen = getCurrentScreen();
4222 wxCHECK( screen, /* void */ );
4223
4224 SCH_BUS_WIRE_ENTRY* busWireEntry = new SCH_BUS_WIRE_ENTRY( elem.location + m_sheetOffset );
4225
4226 VECTOR2I vector = elem.corner - elem.location;
4227 busWireEntry->SetSize( { vector.x, vector.y } );
4228
4229 busWireEntry->SetFlags( IS_NEW );
4230 screen->Append( busWireEntry );
4231}
4232
4233
4234void SCH_IO_ALTIUM::ParseParameter( const std::map<wxString, wxString>& aProperties )
4235{
4236 ASCH_PARAMETER elem( aProperties );
4237
4238 // TODO: fill in replacements from variant, sheet and project
4239 static const std::map<wxString, wxString> variableMap = {
4240 { "COMMENT", "VALUE" },
4241 { "VALUE", "ALTIUM_VALUE" },
4242 };
4243
4244 if( elem.ownerindex <= 0 )
4245 {
4246 // This is some sheet parameter
4247 if( elem.text == "*" )
4248 return; // indicates parameter not set?
4249
4250 wxString paramName = elem.name.Upper();
4251
4252 if( paramName == "SHEETNUMBER" )
4253 {
4254 m_sheetPath.SetPageNumber( elem.text );
4255 }
4256 else if( paramName == "TITLE" )
4257 {
4258 m_currentTitleBlock->SetTitle( elem.text );
4259 }
4260 else if( paramName == "REVISION" )
4261 {
4262 m_currentTitleBlock->SetRevision( elem.text );
4263 }
4264 else if( paramName == "DATE" )
4265 {
4266 m_currentTitleBlock->SetDate( elem.text );
4267 }
4268 else if( paramName == "COMPANYNAME" )
4269 {
4270 m_currentTitleBlock->SetCompany( elem.text );
4271 }
4272 else
4273 {
4274 m_schematic->Project().GetTextVars()[ paramName ] = elem.text;
4275 }
4276 }
4277 else
4278 {
4279 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
4280
4281 if( libSymbolIt == m_libSymbols.end() )
4282 {
4283 // TODO: e.g. can depend on Template (RECORD=39
4284 return;
4285 }
4286
4287 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
4288 SCH_FIELD* field = nullptr;
4289 wxString upperName = elem.name.Upper();
4290
4291 if( upperName == "COMMENT" )
4292 {
4293 field = symbol->GetField( FIELD_T::VALUE );
4294 }
4295 else
4296 {
4297 wxString fieldName = elem.name.Upper();
4298
4299 if( fieldName.IsEmpty() )
4300 {
4301 int disambiguate = 1;
4302
4303 while( 1 )
4304 {
4305 fieldName = wxString::Format( "ALTIUM_UNNAMED_%d", disambiguate++ );
4306
4307 if( !symbol->GetField( fieldName ) )
4308 break;
4309 }
4310 }
4311 else if( fieldName == "VALUE" )
4312 {
4313 fieldName = "ALTIUM_VALUE";
4314 }
4315
4316 field = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, fieldName ) );
4317 }
4318
4319 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
4320 field->SetText( kicadText );
4321 field->SetPosition( elem.location + m_sheetOffset );
4322 field->SetVisible( !elem.isHidden );
4323 field->SetNameShown( elem.isShowName );
4324 SetTextPositioning( field, elem.justification, elem.orientation );
4325 }
4326}
4327
4328
4329void SCH_IO_ALTIUM::ParseLibParameter( const std::map<wxString, wxString>& aProperties,
4330 std::vector<LIB_SYMBOL*>& aSymbol,
4331 std::vector<int>& aFontSizes )
4332{
4333 ASCH_PARAMETER elem( aProperties );
4334
4335 // Part ID 1 is the current library part.
4336 // Part ID ALTIUM_COMPONENT_NONE(-1) means all parts
4337 // If a parameter is assigned to a specific element such as a pin,
4338 // we will need to handle it here.
4339 // TODO: Handle HIDDENNETNAME property (others?)
4340 if( elem.ownerpartid != 1 && elem.ownerpartid != ALTIUM_COMPONENT_NONE )
4341 return;
4342
4343 // If ownerindex is populated, this is parameter belongs to a subelement (e.g. pin).
4344 // Ignore for now.
4345 // TODO: Update this when KiCad supports parameters for any object
4346 if( elem.ownerindex != ALTIUM_COMPONENT_NONE )
4347 return;
4348
4349 // TODO: fill in replacements from variant, sheet and project
4350 // N.B. We do not keep the Altium "VALUE" variable here because
4351 // we don't have a way to assign variables to specific symbols
4352 std::map<wxString, wxString> variableMap = {
4353 { "COMMENT", "VALUE" },
4354 };
4355
4356 for( LIB_SYMBOL* libSymbol : aSymbol )
4357 {
4358 SCH_FIELD* field = nullptr;
4359 wxString upperName = elem.name.Upper();
4360
4361 if( upperName == "COMMENT" )
4362 {
4363 field = &libSymbol->GetValueField();
4364 }
4365 else
4366 {
4367 wxString fieldNameStem = elem.name;
4368 wxString fieldName = fieldNameStem;
4369 int disambiguate = 1;
4370
4371 if( fieldName.IsEmpty() )
4372 {
4373 fieldNameStem = "ALTIUM_UNNAMED";
4374 fieldName = "ALTIUM_UNNAMED_1";
4375 disambiguate = 2;
4376 }
4377 else if( upperName == "VALUE" )
4378 {
4379 fieldNameStem = "ALTIUM_VALUE";
4380 fieldName = "ALTIUM_VALUE";
4381 }
4382
4383 // Avoid adding duplicate fields
4384 while( libSymbol->GetField( fieldName ) )
4385 fieldName = wxString::Format( "%s_%d", fieldNameStem, disambiguate++ );
4386
4387 SCH_FIELD* new_field = new SCH_FIELD( libSymbol, FIELD_T::USER, fieldName );
4388 libSymbol->AddField( new_field );
4389 field = new_field;
4390 }
4391
4392 wxString kicadText = AltiumSchSpecialStringsToKiCadVariables( elem.text, variableMap );
4393 field->SetText( kicadText );
4394
4395 field->SetTextPos( elem.location );
4396 SetTextPositioning( field, elem.justification, elem.orientation );
4397 field->SetVisible( !elem.isHidden );
4398
4399 if( elem.fontId > 0 && elem.fontId <= static_cast<int>( aFontSizes.size() ) )
4400 {
4401 int size = aFontSizes[elem.fontId - 1];
4402 field->SetTextSize( { size, size } );
4403 }
4404 else
4405 {
4406 int size = schIUScale.MilsToIU( DEFAULT_TEXT_SIZE );
4407 field->SetTextSize( { size, size } );
4408 }
4409
4410 }
4411}
4412
4413
4415 const std::map<wxString, wxString>& aProperties )
4416{
4417 ASCH_IMPLEMENTATION_LIST elem( aProperties );
4418
4419 m_altiumImplementationList.emplace( aIndex, elem.ownerindex );
4420}
4421
4422
4423void SCH_IO_ALTIUM::ParseImplementation( const std::map<wxString, wxString>& aProperties,
4424 std::vector<LIB_SYMBOL*>& aSymbol )
4425{
4426 ASCH_IMPLEMENTATION elem( aProperties );
4427
4428 if( elem.type != wxS( "PCBLIB" ) )
4429 return;
4430
4431 // For schematic files, we need to check if the model is current.
4432 if( aSymbol.size() == 0 && !elem.isCurrent )
4433 return;
4434
4435 // For IntLibs we want to use the same lib name for footprints
4436 wxString libName = m_isIntLib ? m_libName : elem.libname;
4437
4438 wxArrayString fpFilters;
4439 fpFilters.Add( wxString::Format( wxS( "*%s*" ), elem.name ) );
4440
4441 // Parse the footprint fields for the library symbol
4442 if( !aSymbol.empty() )
4443 {
4444 for( LIB_SYMBOL* symbol : aSymbol )
4445 {
4446 LIB_ID fpLibId = AltiumToKiCadLibID( libName, elem.name );
4447
4448 symbol->SetFPFilters( fpFilters );
4449 symbol->GetField( FIELD_T::FOOTPRINT )->SetText( fpLibId.Format() );
4450 }
4451
4452 return;
4453 }
4454
4455 const auto& implementationOwnerIt = m_altiumImplementationList.find( elem.ownerindex );
4456
4457 if( implementationOwnerIt == m_altiumImplementationList.end() )
4458 {
4459 m_errorMessages.emplace( wxString::Format( wxT( "Implementation's owner (%d) not found." ),
4460 elem.ownerindex ),
4462 return;
4463 }
4464
4465 const auto& libSymbolIt = m_libSymbols.find( implementationOwnerIt->second );
4466
4467 if( libSymbolIt == m_libSymbols.end() )
4468 {
4469 m_errorMessages.emplace( wxString::Format( wxT( "Footprint's owner (%d) not found." ),
4470 implementationOwnerIt->second ),
4472 return;
4473 }
4474
4475 LIB_ID fpLibId = AltiumToKiCadLibID( libName, elem.name );
4476
4477 libSymbolIt->second->SetFPFilters( fpFilters ); // TODO: not ideal as we overwrite it
4478
4479 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
4480
4481 symbol->SetFootprintFieldText( fpLibId.Format() );
4482}
4483
4484
4485
4486std::vector<LIB_SYMBOL*> SCH_IO_ALTIUM::ParseLibComponent( const std::map<wxString,
4487 wxString>& aProperties )
4488{
4489 ASCH_SYMBOL elem( aProperties );
4490
4491 std::vector<LIB_SYMBOL*> symbols;
4492
4493 symbols.reserve( elem.displaymodecount );
4494
4495 for( int i = 0; i < elem.displaymodecount; i++ )
4496 {
4497 LIB_SYMBOL* symbol = new LIB_SYMBOL( wxEmptyString );
4498
4499 if( elem.displaymodecount > 1 )
4500 symbol->SetName( wxString::Format( "%s (Altium Display %d)", elem.libreference, i + 1 ) );
4501 else
4502 symbol->SetName( elem.libreference );
4503
4504 LIB_ID libId = AltiumToKiCadLibID( getLibName(), symbol->GetName() );
4505 symbol->SetDescription( elem.componentdescription );
4506 symbol->SetLibId( libId );
4507 symbol->SetUnitCount( elem.partcount - 1, true );
4508 symbols.push_back( symbol );
4509 }
4510
4511 return symbols;
4512}
4513
4514
4517{
4519 std::vector<int> fontSizes;
4520 struct SYMBOL_PIN_FRAC
4521 {
4522 int x_frac;
4523 int y_frac;
4524 int len_frac;
4525 };
4526
4527 ParseLibHeader( aAltiumLibFile, fontSizes );
4528
4529 std::map<wxString, ALTIUM_SYMBOL_DATA> syms = aAltiumLibFile.GetLibSymbols( nullptr );
4530
4531 for( auto& [name, entry] : syms )
4532 {
4533 std::map<int, SYMBOL_PIN_FRAC> pinFracs;
4534
4535 if( entry.m_pinsFrac )
4536 {
4537 auto parse_binary_pin_frac =
4538 [&]( const std::string& binaryData ) -> std::map<wxString, wxString>
4539 {
4540 std::map<wxString, wxString> result;
4541 ALTIUM_COMPRESSED_READER cmpreader( binaryData );
4542
4543 std::pair<int, std::string*> pinFracData = cmpreader.ReadCompressedString();
4544
4545 ALTIUM_BINARY_READER binreader( *pinFracData.second );
4546 SYMBOL_PIN_FRAC pinFrac;
4547
4548 pinFrac.x_frac = binreader.ReadInt32();
4549 pinFrac.y_frac = binreader.ReadInt32();
4550 pinFrac.len_frac = binreader.ReadInt32();
4551 pinFracs.insert( { pinFracData.first, pinFrac } );
4552
4553 return result;
4554 };
4555
4556 ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry.m_pinsFrac );
4557
4558 while( reader.GetRemainingBytes() > 0 )
4559 reader.ReadProperties( parse_binary_pin_frac );
4560 }
4561
4562 ALTIUM_BINARY_PARSER reader( aAltiumLibFile, entry.m_symbol );
4563 std::vector<LIB_SYMBOL*> symbols;
4564 int pin_index = 0;
4565
4566 if( reader.GetRemainingBytes() <= 0 )
4567 THROW_IO_ERROR( "LibSymbol does not contain any data" );
4568
4569 {
4570 std::map<wxString, wxString> properties = reader.ReadProperties();
4571 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
4572 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
4573
4574 if( record != ALTIUM_SCH_RECORD::COMPONENT )
4575 THROW_IO_ERROR( "LibSymbol does not start with COMPONENT record" );
4576
4577 symbols = ParseLibComponent( properties );
4578 }
4579
4580 auto handleBinaryPinLambda =
4581 [&]( const std::string& binaryData ) -> std::map<wxString, wxString>
4582 {
4583 std::map<wxString, wxString> result;
4584
4585 ALTIUM_BINARY_READER binreader( binaryData );
4586
4587 int32_t recordId = binreader.ReadInt32();
4588
4589 if( recordId != static_cast<int32_t>( ALTIUM_SCH_RECORD::PIN ) )
4590 THROW_IO_ERROR( "Binary record missing PIN record" );
4591
4592 result["RECORD"] = wxString::Format( "%d", recordId );
4593 binreader.ReadByte(); // unknown
4594 result["OWNERPARTID"] = wxString::Format( "%d", binreader.ReadInt16() );
4595 result["OWNERPARTDISPLAYMODE"] = wxString::Format( "%d", binreader.ReadByte() );
4596 result["SYMBOL_INNEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
4597 result["SYMBOL_OUTEREDGE"] = wxString::Format( "%d", binreader.ReadByte() );
4598 result["SYMBOL_INNER"] = wxString::Format( "%d", binreader.ReadByte() );
4599 result["SYMBOL_OUTER"] = wxString::Format( "%d", binreader.ReadByte() );
4600 result["TEXT"] = binreader.ReadShortPascalString();
4601 binreader.ReadByte(); // unknown
4602 result["ELECTRICAL"] = wxString::Format( "%d", binreader.ReadByte() );
4603 result["PINCONGLOMERATE"] = wxString::Format( "%d", binreader.ReadByte() );
4604 result["PINLENGTH"] = wxString::Format( "%d", binreader.ReadInt16() );
4605 result["LOCATION.X"] = wxString::Format( "%d", binreader.ReadInt16() );
4606 result["LOCATION.Y"] = wxString::Format( "%d", binreader.ReadInt16() );
4607 result["COLOR"] = wxString::Format( "%d", binreader.ReadInt32() );
4608 result["NAME"] = binreader.ReadShortPascalString();
4609 result["DESIGNATOR"] = binreader.ReadShortPascalString();
4610 result["SWAPIDGROUP"] = binreader.ReadShortPascalString();
4611
4612 if( auto it = pinFracs.find( pin_index ); it != pinFracs.end() )
4613 {
4614 result["LOCATION.X_FRAC"] = wxString::Format( "%d", it->second.x_frac );
4615 result["LOCATION.Y_FRAC"] = wxString::Format( "%d", it->second.y_frac );
4616 result["PINLENGTH_FRAC"] = wxString::Format( "%d", it->second.len_frac );
4617 }
4618
4619 std::string partSeq = binreader.ReadShortPascalString(); // This is 'part|&|seq'
4620 std::vector<std::string> partSeqSplit = split( partSeq, "|" );
4621
4622 if( partSeqSplit.size() == 3 )
4623 {
4624 result["PART"] = partSeqSplit[0];
4625 result["SEQ"] = partSeqSplit[2];
4626 }
4627
4628 return result;
4629 };
4630
4631 while( reader.GetRemainingBytes() > 0 )
4632 {
4633 std::map<wxString, wxString> properties = reader.ReadProperties( handleBinaryPinLambda );
4634
4635 if( properties.empty() )
4636 continue;
4637
4638 int recordId = ALTIUM_PROPS_UTILS::ReadInt( properties, "RECORD", 0 );
4639 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
4640
4641 switch( record )
4642 {
4644 ParsePin( properties, symbols );
4645 pin_index++;
4646 break;
4647
4648 case ALTIUM_SCH_RECORD::LABEL: ParseLabel( properties, symbols, fontSizes ); break;
4649 case ALTIUM_SCH_RECORD::BEZIER: ParseBezier( properties, symbols ); break;
4650 case ALTIUM_SCH_RECORD::POLYLINE: ParsePolyline( properties, symbols ); break;
4651 case ALTIUM_SCH_RECORD::POLYGON: ParsePolygon( properties, symbols ); break;
4652 case ALTIUM_SCH_RECORD::ELLIPSE: ParseEllipse( properties, symbols ); break;
4653 case ALTIUM_SCH_RECORD::PIECHART: ParsePieChart( properties, symbols ); break;
4654 case ALTIUM_SCH_RECORD::ROUND_RECTANGLE: ParseRoundRectangle( properties, symbols ); break;
4655 case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC: ParseEllipticalArc( properties, symbols ); break;
4656 case ALTIUM_SCH_RECORD::ARC: ParseArc( properties, symbols ); break;
4657 case ALTIUM_SCH_RECORD::LINE: ParseLine( properties, symbols ); break;
4658 case ALTIUM_SCH_RECORD::RECTANGLE: ParseRectangle( properties, symbols ); break;
4659 case ALTIUM_SCH_RECORD::DESIGNATOR: ParseLibDesignator( properties, symbols, fontSizes ); break;
4660 case ALTIUM_SCH_RECORD::PARAMETER: ParseLibParameter( properties, symbols, fontSizes ); break;
4661 case ALTIUM_SCH_RECORD::TEXT_FRAME: ParseTextFrame( properties, symbols, fontSizes ); break;
4662 case ALTIUM_SCH_RECORD::IMPLEMENTATION: ParseImplementation( properties, symbols ); break;
4663
4665 break;
4666
4669 break;
4670
4672 // TODO: add support for these. They are just drawn symbols, so we can probably hardcode
4673 break;
4674
4676 // TODO: Handle images once libedit supports them
4677 break;
4678
4680 // Nothing for now. TODO: Figure out how implementation lists are generated in libs
4681 break;
4682
4683 default:
4684 m_errorMessages.emplace( wxString::Format( _( "Unknown or unexpected record id %d found in %s." ),
4685 recordId,
4686 symbols[0]->GetName() ),
4688 break;
4689 }
4690 }
4691
4692 if( reader.HasParsingError() )
4693 THROW_IO_ERROR( "stream was not parsed correctly!" );
4694
4695 if( reader.GetRemainingBytes() != 0 )
4696 THROW_IO_ERROR( "stream is not fully parsed" );
4697
4698 for( size_t ii = 0; ii < symbols.size(); ii++ )
4699 {
4700 LIB_SYMBOL* symbol = symbols[ii];
4701 symbol->FixupDrawItems();
4702 fixupSymbolPinNameNumbers( symbol );
4703
4704 SCH_FIELD& valField = symbol->GetValueField();
4705
4706 if( valField.GetText().IsEmpty() )
4707 valField.SetText( name );
4708
4709 if( symbols.size() == 1 )
4710 ret[name] = symbol;
4711 else
4712 ret[wxString::Format( "%s (Altium Display %zd)", name, ii + 1 )] = symbol;
4713 }
4714 }
4715
4716 return ret;
4717}
4718
4719
4720long long SCH_IO_ALTIUM::getLibraryTimestamp( const wxString& aLibraryPath ) const
4721{
4722 wxFileName fn( aLibraryPath );
4723
4724 if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
4725 return fn.GetModificationTime().GetValue().GetValue();
4726 else
4727 return 0;
4728}
4729
4730
4731void SCH_IO_ALTIUM::ensureLoadedLibrary( const wxString& aLibraryPath,
4732 const std::map<std::string, UTF8>* aProperties )
4733{
4734 // Suppress font substitution warnings
4736
4737 if( m_libCache.count( aLibraryPath ) )
4738 {
4739 wxCHECK( m_timestamps.count( aLibraryPath ), /*void*/ );
4740
4741 if( m_timestamps.at( aLibraryPath ) == getLibraryTimestamp( aLibraryPath ) )
4742 return;
4743 }
4744
4745 std::vector<std::unique_ptr<ALTIUM_COMPOUND_FILE>> compoundFiles;
4746
4747 wxFileName fileName( aLibraryPath );
4748 m_libName = fileName.GetName();
4749
4750 try
4751 {
4752 if( aLibraryPath.Lower().EndsWith( wxS( ".schlib" ) ) )
4753 {
4754 m_isIntLib = false;
4755
4756 compoundFiles.push_back( std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath ) );
4757 }
4758 else if( aLibraryPath.Lower().EndsWith( wxS( ".intlib" ) ) )
4759 {
4760 m_isIntLib = true;
4761
4762 std::unique_ptr<ALTIUM_COMPOUND_FILE> intCom = std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath );
4763
4764 std::map<wxString, const CFB::COMPOUND_FILE_ENTRY*> schLibFiles = intCom->EnumDir( L"SchLib" );
4765
4766 for( const auto& [schLibName, cfe] : schLibFiles )
4767 {
4768 std::unique_ptr<ALTIUM_COMPOUND_FILE> decodedStream = std::make_unique<ALTIUM_COMPOUND_FILE>();
4769
4770 if( intCom->DecodeIntLibStream( *cfe, decodedStream.get() ) )
4771 compoundFiles.emplace_back( std::move( decodedStream ) );
4772 }
4773 }
4774
4775 CASE_INSENSITIVE_MAP<LIB_SYMBOL*>& cacheMapRef = m_libCache[aLibraryPath];
4776
4777 for( const std::unique_ptr<ALTIUM_COMPOUND_FILE>& altiumSchFilePtr : compoundFiles )
4778 {
4779 CASE_INSENSITIVE_MAP<LIB_SYMBOL*> parsed = ParseLibFile( *altiumSchFilePtr );
4780 cacheMapRef.insert( parsed.begin(), parsed.end() );
4781 }
4782
4783 m_timestamps[aLibraryPath] = getLibraryTimestamp( aLibraryPath );
4784 }
4785 catch( const CFB::CFBException& exception )
4786 {
4787 THROW_IO_ERROR( exception.what() );
4788 }
4789 catch( const std::exception& exc )
4790 {
4791 wxFAIL_MSG( wxString::Format( wxT( "Unhandled exception in Altium schematic parsers: %s." ),
4792 exc.what() ) );
4793 throw;
4794 }
4795}
4796
4797
4799 std::vector<int>& aFontSizes )
4800{
4801 const CFB::COMPOUND_FILE_ENTRY* file = aAltiumSchFile.FindStream( { "FileHeader" } );
4802
4803 if( file == nullptr )
4804 THROW_IO_ERROR( "FileHeader not found" );
4805
4806 ALTIUM_BINARY_PARSER reader( aAltiumSchFile, file );
4807
4808 if( reader.GetRemainingBytes() <= 0 )
4809 THROW_IO_ERROR( "FileHeader does not contain any data" );
4810
4811 std::map<wxString, wxString> properties = reader.ReadProperties();
4812
4813 wxString libtype = ALTIUM_PROPS_UTILS::ReadString( properties, "HEADER", "" );
4814
4815 if( libtype.CmpNoCase( "Protel for Windows - Schematic Library Editor Binary File Version 5.0" ) )
4816 THROW_IO_ERROR( _( "Expected Altium Schematic Library file version 5.0" ) );
4817
4818 for( auto& [key, value] : properties )
4819 {
4820 wxString upperKey = key.Upper();
4821 wxString remaining;
4822
4823 if( upperKey.StartsWith( "SIZE", &remaining ) )
4824 {
4825 if( !remaining.empty() )
4826 {
4827 int ind = wxAtoi( remaining );
4828
4829 if( static_cast<int>( aFontSizes.size() ) < ind )
4830 aFontSizes.resize( ind );
4831
4832 // Altium stores in pt. 1 pt = 1/72 inch. 1 mil = 1/1000 inch.
4833 int scaled = schIUScale.MilsToIU( wxAtoi( value ) * 72.0 / 10.0 );
4834 aFontSizes[ind - 1] = scaled;
4835 }
4836 }
4837 }
4838}
4839
4840
4841void SCH_IO_ALTIUM::doEnumerateSymbolLib( const wxString& aLibraryPath,
4842 const std::map<std::string, UTF8>* aProperties,
4843 std::function<void(const wxString&, LIB_SYMBOL*)> aInserter )
4844{
4845 ensureLoadedLibrary( aLibraryPath, aProperties );
4846
4847 bool powerSymbolsOnly = ( aProperties && aProperties->contains( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) );
4848
4849 auto it = m_libCache.find( aLibraryPath );
4850
4851 if( it != m_libCache.end() )
4852 {
4853 for( auto& [libnameStr, libSymbol] : it->second )
4854 {
4855 if( powerSymbolsOnly && !libSymbol->IsPower() )
4856 continue;
4857
4858 aInserter( libnameStr, libSymbol );
4859 }
4860 }
4861}
4862
4863
4864void SCH_IO_ALTIUM::EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath,
4865 const std::map<std::string, UTF8>* aProperties )
4866{
4867 doEnumerateSymbolLib( aLibraryPath, aProperties,
4868 [&]( const wxString& aStr, LIB_SYMBOL* )
4869 {
4870 aSymbolNameList.Add( aStr );
4871 } );
4872}
4873
4874
4875void SCH_IO_ALTIUM::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
4876 const wxString& aLibraryPath,
4877 const std::map<std::string, UTF8>* aProperties )
4878{
4879 doEnumerateSymbolLib( aLibraryPath, aProperties,
4880 [&]( const wxString&, LIB_SYMBOL* aSymbol )
4881 {
4882 aSymbolList.emplace_back( aSymbol );
4883 } );
4884}
4885
4886
4887LIB_SYMBOL* SCH_IO_ALTIUM::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
4888 const std::map<std::string, UTF8>* aProperties )
4889{
4890 ensureLoadedLibrary( aLibraryPath, aProperties );
4891
4892 auto it = m_libCache.find( aLibraryPath );
4893
4894 if( it != m_libCache.end() )
4895 {
4896 auto it2 = it->second.find( aAliasName );
4897
4898 if( it2 != it->second.end() )
4899 return it2->second;
4900 }
4901
4902 return nullptr;
4903}
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:80
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:544
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:589
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:428
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:397
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:346
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:281
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:310
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:318
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:420
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:87
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:150
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:165
void SetKeyWords(const wxString &aKeyWords)
Definition lib_symbol.h:182
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:338
int GetUnitCount() const override
void SetLibId(const LIB_ID &aLibId)
Definition lib_symbol.h:157
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:342
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:202
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
void ParseFileHeader(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
void ParseSignalHarness(const std::map< wxString, wxString > &aProperties)
std::map< int, ASCH_TEMPLATE > m_altiumTemplates
std::map< int, ASCH_SYMBOL > m_altiumComponents
void ParsePort(const ASCH_PORT &aElem)
bool IsComponentPartVisible(const ASCH_OWNER_INTERFACE &aElem) const
void ParseNote(const std::map< wxString, wxString > &aProperties)
void ParseAltiumSch(const wxString &aFileName)
std::vector< ASCH_PORT > m_altiumPortsCurrentSheet
void ParseSheetName(const std::map< wxString, wxString > &aProperties)
void ParseBusEntry(const std::map< wxString, wxString > &aProperties)
SCH_SHEET * getCurrentSheet()
void ParseStorage(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
std::map< wxString, LIB_SYMBOL * > m_powerSymbols
void ParseBus(const std::map< wxString, wxString > &aProperties)
void ParseFileName(const std::map< wxString, wxString > &aProperties)
static bool isASCIIFile(const wxString &aFileName)
wxString m_libName
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
std::map< int, SCH_SHEET * > m_sheets
void ParseLibHeader(const ALTIUM_COMPOUND_FILE &aAltiumSchFile, std::vector< int > &aFontSizes)
void ParseHarnessPort(const ASCH_PORT &aElem)
void ParseRoundRectangle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
int GetModifyHash() const override
Return the modification hash from the library cache.
void ParseLibDesignator(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
std::map< wxString, CASE_INSENSITIVE_MAP< LIB_SYMBOL * > > m_libCache
std::map< int, int > m_altiumImplementationList
void ParseTextFrame(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
void ParsePolygon(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void fixupSymbolPinNameNumbers(SYMBOL *aSymbol)
VECTOR2I m_sheetOffset
void ParseRecord(int index, std::map< wxString, wxString > &properties, const wxString &aSectionName)
std::vector< ASCH_PORT > m_altiumHarnessPortsCurrentSheet
void ParseDesignator(const std::map< wxString, wxString > &aProperties)
int m_harnessOwnerIndexOffset
void ParsePortHelper(const ASCH_PORT &aElem)
static bool checkFileHeader(const wxString &aFileName)
long long getLibraryTimestamp(const wxString &aLibraryPath) const
void ParseSheetEntry(const std::map< wxString, wxString > &aProperties)
SCH_SHEET * m_rootSheet
static bool isBinaryFile(const wxString &aFileName)
void ParseHarnessType(const std::map< wxString, wxString > &aProperties)
wxString m_rootFilepath
void ParseJunction(const std::map< wxString, wxString > &aProperties)
SCHEMATIC * m_schematic
void ParseLibParameter(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
void ParseASCIISchematic(const wxString &aFileName)
void ParsePolyline(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::unique_ptr< ASCH_SHEET > m_altiumSheet
void ParseComponent(int aIndex, const std::map< wxString, wxString > &aProperties)
std::unique_ptr< TITLE_BLOCK > m_currentTitleBlock
SCH_SHEET * LoadSchematicProject(SCHEMATIC *aSchematic, const std::map< std::string, UTF8 > *aProperties)
void ParseImage(const std::map< wxString, wxString > &aProperties)
void ParseArc(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseNetLabel(const std::map< wxString, wxString > &aProperties)
void ParseNoERC(const std::map< wxString, wxString > &aProperties)
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
std::unordered_map< wxString, SEVERITY > m_errorMessages
void ParseImplementationList(int aIndex, const std::map< wxString, wxString > &aProperties)
std::vector< LIB_SYMBOL * > ParseLibComponent(const std::map< wxString, wxString > &aProperties)
void ParseSheet(const std::map< wxString, wxString > &aProperties)
void ParseParameter(const std::map< wxString, wxString > &aProperties)
bool ShouldPutItemOnSheet(int aOwnerindex)
void AddLibTextBox(const ASCH_TEXT_FRAME *aElem, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_IO can read the specified schematic file.
void ParsePieChart(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseEllipticalArc(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::map< int, HARNESS > m_altiumHarnesses
void ParseEllipse(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseWire(const std::map< wxString, wxString > &aProperties)
void ParseHarnessEntry(const std::map< wxString, wxString > &aProperties)
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
void ParseImplementation(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseTemplate(int aIndex, const std::map< wxString, wxString > &aProperties)
void ParseAdditional(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
void AddTextBox(const ASCH_TEXT_FRAME *aElem)
void ParsePowerPort(const std::map< wxString, wxString > &aProperties)
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
const ASCH_STORAGE_FILE * GetFileFromStorage(const wxString &aFilename) const
void ParseRectangle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void doEnumerateSymbolLib(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties, std::function< void(const wxString &, LIB_SYMBOL *)> aInserter)
wxString getLibName()
std::vector< ASCH_STORAGE_FILE > m_altiumStorage
SCH_SHEET_PATH m_sheetPath
void ParseLabel(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym, std::vector< int > &aFontSize=nullint)
CASE_INSENSITIVE_MAP< LIB_SYMBOL * > ParseLibFile(const ALTIUM_COMPOUND_FILE &aAltiumSchFile)
void ParseBezier(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseLine(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
void ParseCircle(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::map< int, SCH_SYMBOL * > m_symbols
void ParseSheetSymbol(int aIndex, const std::map< wxString, wxString > &aProperties)
std::map< wxString, long long > m_timestamps
wxFileName getLibFileName()
SCH_SCREEN * getCurrentScreen()
void ParsePin(const std::map< wxString, wxString > &aProperties, std::vector< LIB_SYMBOL * > &aSymbol=nullsym)
std::map< int, LIB_SYMBOL * > m_libSymbols
void ParseHarnessConnector(int aIndex, const std::map< wxString, wxString > &aProperties)
void ensureLoadedLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties)
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition sch_io.cpp:45
SCH_IO(const wxString &aName)
Definition sch_io.h: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:817
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Definition sch_line.cpp:717
bool IsWire() const
Return true if the line is a wire.
Definition sch_line.cpp:989
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition sch_line.cpp:233
void SetLineColor(const COLOR4D &aColor)
Definition sch_line.cpp:281
void SetLineWidth(const int aSize)
Definition sch_line.cpp:347
VECTOR2I GetEndPoint() const
Definition sch_line.h:148
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
Definition sch_line.h:158
bool IsBus() const
Return true if the line is a bus.
Definition sch_line.cpp:995
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_line.h:202
int GetLineWidth() const
Definition sch_line.h:198
COLOR4D GetLineColor() const
Return COLOR4D::UNSPECIFIED if a custom color hasn't been set for this line.
Definition sch_line.cpp:305
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:149
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:731
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:709
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition sch_screen.h:165
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition.
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:140
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
const KIID & GetUuid() const
Definition sch_screen.h:523
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:809
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:808
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
VECTOR2I GetPosition() const override
Definition sch_text.h:150
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_text.h:151
Simple container to manage line stroke parameters.
int GetWidth() const
void SetLineStyle(LINE_STYLE aLineStyle)
void SetWidth(int aWidth)
void SetColor(const KIGFX::COLOR4D &aColor)
KIGFX::COLOR4D GetColor() const
static const char * PropPowerSymsOnly
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:169
const TRANSFORM & GetTransform() const
Definition symbol.h:218
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:466
@ LAYER_WIRE
Definition layer_ids.h:452
@ LAYER_NOTES
Definition layer_ids.h:467
@ LAYER_BUS
Definition layer_ids.h:453
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h: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:167
@ SCH_LABEL_T
Definition typeinfo.h:171
@ SCH_SHEET_T
Definition typeinfo.h:179
@ SCH_HIER_LABEL_T
Definition typeinfo.h:173
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
Definition of file extensions used in Kicad.