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