KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_eagle.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) 2017 CERN
5 * Copyright (C) 2017-2024 Kicad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Alejandro GarcĂ­a Montoro <[email protected]>
8 * @author Maciej Suminski <[email protected]>
9 * @author Russell Oliver <[email protected]>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 3
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
26
27#include <locale_io.h>
28
29#include <algorithm>
30#include <memory>
31#include <wx/filename.h>
32#include <wx/string.h>
33#include <wx/tokenzr.h>
34#include <wx/wfstream.h>
35#include <wx/txtstrm.h>
36#include <wx/xml/xml.h>
37
38#include <font/fontconfig.h>
40#include <lib_id.h>
41#include <progress_reporter.h>
42#include <project.h>
44#include <project_sch.h>
45#include <sch_bus_entry.h>
46#include <sch_edit_frame.h>
48#include <sch_junction.h>
49#include <sch_label.h>
50#include <sch_marker.h>
51#include <sch_pin.h>
52#include <sch_screen.h>
53#include <sch_shape.h>
54#include <sch_sheet.h>
55#include <sch_sheet_path.h>
56#include <sch_sheet_pin.h>
57#include <sch_symbol.h>
58#include <schematic.h>
59#include <string_utils.h>
60#include <symbol_lib_table.h>
62
63
64// Eagle schematic axes are aligned with x increasing left to right and Y increasing bottom to top
65// KiCad schematic axes are aligned with x increasing left to right and Y increasing top to bottom.
66
67using namespace std;
68
72static const std::map<wxString, ELECTRICAL_PINTYPE> pinDirectionsMap = {
73 { wxT( "sup" ), ELECTRICAL_PINTYPE::PT_POWER_IN },
74 { wxT( "pas" ), ELECTRICAL_PINTYPE::PT_PASSIVE },
75 { wxT( "out" ), ELECTRICAL_PINTYPE::PT_OUTPUT },
76 { wxT( "in" ), ELECTRICAL_PINTYPE::PT_INPUT },
77 { wxT( "nc" ), ELECTRICAL_PINTYPE::PT_NC },
78 { wxT( "io" ), ELECTRICAL_PINTYPE::PT_BIDI },
80 { wxT( "hiz" ), ELECTRICAL_PINTYPE::PT_TRISTATE },
81 { wxT( "pwr" ), ELECTRICAL_PINTYPE::PT_POWER_IN },
82};
83
84
86static BOX2I getSheetBbox( SCH_SHEET* aSheet )
87{
88 BOX2I bbox;
89
90 for( SCH_ITEM* item : aSheet->GetScreen()->Items() )
91 bbox.Merge( item->GetBoundingBox() );
92
93 return bbox;
94}
95
96
98static inline wxString extractNetName( const wxString& aPinName )
99{
100 return aPinName.BeforeFirst( '@' );
101}
102
103
105{
106 return m_sheetPath.Last();
107}
108
109
111{
112 SCH_SHEET* currentSheet = m_sheetPath.Last();
113 wxCHECK( currentSheet, nullptr );
114 return currentSheet->GetScreen();
115}
116
117
119{
120 if( m_libName.IsEmpty() )
121 {
122 // Try to come up with a meaningful name
124
125 if( m_libName.IsEmpty() )
126 {
127 wxFileName fn( m_rootSheet->GetFileName() );
128 m_libName = fn.GetName();
129 }
130
131 if( m_libName.IsEmpty() )
132 m_libName = wxT( "noname" );
133
134 m_libName += wxT( "-eagle-import" );
136 }
137
138 return m_libName;
139}
140
141
143{
144 wxFileName fn;
145
146 wxCHECK( m_schematic, fn );
147
148 fn.Assign( m_schematic->Prj().GetProjectPath(), getLibName(),
150
151 return fn;
152}
153
154
155void SCH_IO_EAGLE::loadLayerDefs( const std::vector<std::unique_ptr<ELAYER>>& aLayers )
156{
157 // match layers based on their names
158 for( const std::unique_ptr<ELAYER>& elayer : aLayers )
159 {
177 if( elayer->name == wxT( "Nets" ) )
178 m_layerMap[elayer->number] = LAYER_WIRE;
179 else if( elayer->name == wxT( "Info" ) || elayer->name == wxT( "Guide" ) )
180 m_layerMap[elayer->number] = LAYER_NOTES;
181 else if( elayer->name == wxT( "Busses" ) )
182 m_layerMap[elayer->number] = LAYER_BUS;
183 }
184}
185
186
188{
189 auto it = m_layerMap.find( aEagleLayer );
190 return it == m_layerMap.end() ? LAYER_NOTES : it->second;
191}
192
193
194// Return the KiCad symbol orientation based on eagle rotation degrees.
196{
197 int roti = int( eagleDegrees );
198
199 switch( roti )
200 {
201 case 0: return SYM_ORIENT_0;
202 case 90: return SYM_ORIENT_90;
203 case 180: return SYM_ORIENT_180;
204 case 270: return SYM_ORIENT_270;
205
206 default:
207 wxASSERT_MSG( false, wxString::Format( wxT( "Unhandled orientation (%d degrees)" ),
208 roti ) );
209 return SYM_ORIENT_0;
210 }
211}
212
213
214// Calculate text alignment based on the given Eagle text alignment parameters.
215static void eagleToKicadAlignment( EDA_TEXT* aText, int aEagleAlignment, int aRelDegress,
216 bool aMirror, bool aSpin, int aAbsDegress )
217{
218 int align = aEagleAlignment;
219
220 if( aRelDegress == 90 )
221 {
223 }
224 else if( aRelDegress == 180 )
225 {
226 align = -align;
227 }
228 else if( aRelDegress == 270 )
229 {
231 align = -align;
232 }
233
234 if( aMirror == true )
235 {
236 if( aAbsDegress == 90 || aAbsDegress == 270 )
237 {
238 if( align == ETEXT::BOTTOM_RIGHT )
239 align = ETEXT::TOP_RIGHT;
240 else if( align == ETEXT::BOTTOM_LEFT )
241 align = ETEXT::TOP_LEFT;
242 else if( align == ETEXT::TOP_LEFT )
243 align = ETEXT::BOTTOM_LEFT;
244 else if( align == ETEXT::TOP_RIGHT )
245 align = ETEXT::BOTTOM_RIGHT;
246 }
247 else if( aAbsDegress == 0 || aAbsDegress == 180 )
248 {
249 if( align == ETEXT::BOTTOM_RIGHT )
250 align = ETEXT::BOTTOM_LEFT;
251 else if( align == ETEXT::BOTTOM_LEFT )
252 align = ETEXT::BOTTOM_RIGHT;
253 else if( align == ETEXT::TOP_LEFT )
254 align = ETEXT::TOP_RIGHT;
255 else if( align == ETEXT::TOP_RIGHT )
256 align = ETEXT::TOP_LEFT;
257 else if( align == ETEXT::CENTER_LEFT )
258 align = ETEXT::CENTER_RIGHT;
259 else if( align == ETEXT::CENTER_RIGHT )
260 align = ETEXT::CENTER_LEFT;
261 }
262 }
263
264 switch( align )
265 {
266 case ETEXT::CENTER:
269 break;
270
274 break;
275
279 break;
280
284 break;
285
286 case ETEXT::TOP_LEFT:
289 break;
290
291 case ETEXT::TOP_RIGHT:
294 break;
295
299 break;
300
304 break;
305
309 break;
310
311 default:
314 break;
315 }
316}
317
318
319SCH_IO_EAGLE::SCH_IO_EAGLE() : SCH_IO( wxS( "EAGLE" ) ),
320 m_rootSheet( nullptr ),
321 m_schematic( nullptr ),
322 m_module( nullptr ),
323 m_sheetIndex( 1 )
324{
326}
327
328
330{
331}
332
333
335{
336 return 0;
337}
338
339
340SCH_SHEET* SCH_IO_EAGLE::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic,
341 SCH_SHEET* aAppendToMe,
342 const std::map<std::string, UTF8>* aProperties )
343{
344 wxASSERT( !aFileName || aSchematic != nullptr );
345 LOCALE_IO toggle; // toggles on, then off, the C locale.
346
347 // Show the font substitution warnings
349
350 m_filename = aFileName;
351 m_schematic = aSchematic;
352
354 {
355 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
356
358 THROW_IO_ERROR( ( "Open canceled by user." ) );
359 }
360
361 // Load the document
362 wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
363
364 // Retrieve the root as current node
365 wxXmlNode* currentNode = xmlDocument.GetRoot();
366
368 m_progressReporter->SetNumPhases( static_cast<int>( GetNodeCount( currentNode ) ) );
369
370 // Delete on exception, if I own m_rootSheet, according to aAppendToMe
371 unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
372
373 wxFileName newFilename( m_filename );
374 newFilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
375
376 if( aAppendToMe )
377 {
378 wxCHECK_MSG( aSchematic->IsValid(), nullptr,
379 wxT( "Can't append to a schematic with no root!" ) );
380
381 m_rootSheet = &aSchematic->Root();
382 }
383 else
384 {
385 m_rootSheet = new SCH_SHEET( aSchematic );
386 m_rootSheet->SetFileName( newFilename.GetFullPath() );
387 aSchematic->SetRoot( m_rootSheet );
388 }
389
390 if( !m_rootSheet->GetScreen() )
391 {
392 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
393 screen->SetFileName( newFilename.GetFullPath() );
394 m_rootSheet->SetScreen( screen );
395
396 // Virtual root sheet UUID must be the same as the schematic file UUID.
397 const_cast<KIID&>( m_rootSheet->m_Uuid ) = screen->GetUuid();
398 }
399
401
402 wxCHECK_MSG( libTable, nullptr, wxT( "Could not load symbol lib table." ) );
403
404 m_pi.reset( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
405 m_properties = std::make_unique<std::map<std::string, UTF8>>();
406 ( *m_properties )[SCH_IO_KICAD_LEGACY::PropBuffering] = "";
407
410 if( !libTable->HasLibrary( getLibName() ) )
411 {
412 // Create a new empty symbol library.
413 m_pi->CreateLibrary( getLibFileName().GetFullPath() );
414 wxString libTableUri = wxT( "${KIPRJMOD}/" ) + getLibFileName().GetFullName();
415
416 // Add the new library to the project symbol library table.
417 libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
418 wxT( "KiCad" ) ) );
419
420 // Save project symbol library table.
421 wxFileName fn( m_schematic->Prj().GetProjectPath(),
423
424 // So output formatter goes out of scope and closes the file before reloading.
425 {
426 FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
427 libTable->Format( &formatter, 0 );
428 }
429
430 // Reload the symbol library table.
433 }
434
435 m_eagleDoc = std::make_unique<EAGLE_DOC>( currentNode, this );
436
437 // If the attribute is found, store the Eagle version;
438 // otherwise, store the dummy "0.0" version.
439 m_version = ( m_eagleDoc->version.IsEmpty() ) ? wxString( wxS( "0.0" ) ) : m_eagleDoc->version;
440
441 // Load drawing
442 loadDrawing( m_eagleDoc->drawing );
443
444 m_pi->SaveLibrary( getLibFileName().GetFullPath() );
445
446 SCH_SCREENS allSheets( m_rootSheet );
447 allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
448
449 return m_rootSheet;
450}
451
452
453void SCH_IO_EAGLE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
454 const wxString& aLibraryPath,
455 const std::map<std::string, UTF8>* aProperties )
456{
457 m_filename = aLibraryPath;
458 m_libName = m_filename.GetName();
459
460 ensureLoadedLibrary( aLibraryPath );
461
462 auto it = m_eagleLibs.find( m_libName );
463
464 if( it != m_eagleLibs.end() )
465 {
466 for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
467 aSymbolNameList.push_back( symName );
468 }
469}
470
471
472void SCH_IO_EAGLE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
473 const wxString& aLibraryPath,
474 const std::map<std::string, UTF8>* aProperties )
475{
476 m_filename = aLibraryPath;
477 m_libName = m_filename.GetName();
478
479 ensureLoadedLibrary( aLibraryPath );
480
481 auto it = m_eagleLibs.find( m_libName );
482
483 if( it != m_eagleLibs.end() )
484 {
485 for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
486 aSymbolList.push_back( libSymbol.get() );
487 }
488}
489
490
491LIB_SYMBOL* SCH_IO_EAGLE::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
492 const std::map<std::string, UTF8>* aProperties )
493{
494 m_filename = aLibraryPath;
495 m_libName = m_filename.GetName();
496
497 ensureLoadedLibrary( aLibraryPath );
498
499 auto it = m_eagleLibs.find( m_libName );
500
501 if( it != m_eagleLibs.end() )
502 {
503 auto it2 = it->second.KiCadSymbols.find( aAliasName );
504
505 if( it2 != it->second.KiCadSymbols.end() )
506 return it2->second.get();
507 }
508
509 return nullptr;
510}
511
512
513long long SCH_IO_EAGLE::getLibraryTimestamp( const wxString& aLibraryPath ) const
514{
515 wxFileName fn( aLibraryPath );
516
517 if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
518 return fn.GetModificationTime().GetValue().GetValue();
519 else
520 return wxDateTime( 0.0 ).GetValue().GetValue();
521}
522
523
524void SCH_IO_EAGLE::ensureLoadedLibrary( const wxString& aLibraryPath )
525{
526 // Suppress font substitution warnings
528
529 if( m_eagleLibs.find( m_libName ) != m_eagleLibs.end() )
530 {
531 wxCHECK( m_timestamps.count( m_libName ), /*void*/ );
532
533 if( m_timestamps.at( m_libName ) == getLibraryTimestamp( aLibraryPath ) )
534 return;
535 }
536
537 LOCALE_IO toggle; // toggles on, then off, the C locale.
538
540 {
541 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aLibraryPath ) );
542
544 THROW_IO_ERROR( ( "Open canceled by user." ) );
545 }
546
547 // Load the document
548 wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
549
550 // Retrieve the root as current node
551 std::unique_ptr<EAGLE_DOC> doc = std::make_unique<EAGLE_DOC>( xmlDocument.GetRoot(), this );
552
553 // If the attribute is found, store the Eagle version;
554 // otherwise, store the dummy "0.0" version.
555 m_version = ( doc->version.IsEmpty() ) ? wxString( wxS( "0.0" ) ) : doc->version;
556
557 // Load drawing
558 loadDrawing( doc->drawing );
559
560 // Remember timestamp
561 m_timestamps[m_libName] = getLibraryTimestamp( aLibraryPath );
562}
563
564
565wxXmlDocument SCH_IO_EAGLE::loadXmlDocument( const wxString& aFileName )
566{
567 wxXmlDocument xmlDocument;
568 wxFFileInputStream stream( m_filename.GetFullPath() );
569
570 if( !stream.IsOk() )
571 {
573 wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) );
574 }
575
576 // read first line to check for Eagle XML format file
577 wxTextInputStream text( stream );
578 wxString line = text.ReadLine();
579
580 if( !line.StartsWith( wxT( "<?xml" ) ) && !line.StartsWith( wxT( "<!--" ) ) )
581 {
582 THROW_IO_ERROR( wxString::Format( _( "'%s' is an Eagle binary-format file; "
583 "only Eagle XML-format files can be imported." ),
584 m_filename.GetFullPath() ) );
585 }
586
587 if( !xmlDocument.Load( stream ) )
588 {
590 wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) );
591 }
592
593 return xmlDocument;
594}
595
596
597void SCH_IO_EAGLE::loadDrawing( const std::unique_ptr<EDRAWING>& aDrawing )
598{
599 wxCHECK( aDrawing, /* void */ );
600
601 loadLayerDefs( aDrawing->layers );
602
603 if( aDrawing->library )
604 {
606 elib.name = m_libName;
607
608 loadLibrary( &aDrawing->library.value(), &elib );
609 }
610
611 if( aDrawing->schematic )
612 loadSchematic( *aDrawing->schematic );
613}
614
615
616void SCH_IO_EAGLE::countNets( const ESCHEMATIC& aSchematic )
617{
618 for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
619 {
620 for( const std::unique_ptr<ENET>& enet : esheet->nets )
621 {
622 wxString netName = enet->netname;
623
624 if( m_netCounts.count( netName ) )
625 m_netCounts[netName] = m_netCounts[netName] + 1;
626 else
627 m_netCounts[netName] = 1;
628 }
629 }
630
631 for( const auto& [modname, emodule] : aSchematic.modules )
632 {
633 for( const std::unique_ptr<ESHEET>& esheet : emodule->sheets )
634 {
635 for( const std::unique_ptr<ENET>& enet : esheet->nets )
636 {
637 wxString netName = enet->netname;
638
639 if( m_netCounts.count( netName ) )
640 m_netCounts[netName] = m_netCounts[netName] + 1;
641 else
642 m_netCounts[netName] = 1;
643 }
644 }
645 }
646}
647
648
650{
651 // Map all children into a readable dictionary
652 if( aSchematic.sheets.empty() )
653 return;
654
655 // N.B. Eagle parts are case-insensitive in matching but we keep the display case
656 for( const auto& [name, epart] : aSchematic.parts )
657 m_partlist[name.Upper()] = epart.get();
658
659 for( const auto& [modname, emodule] : aSchematic.modules )
660 {
661 for( const auto& [name, epart] : emodule->parts )
662 m_partlist[name.Upper()] = epart.get();
663 }
664
665 if( !aSchematic.libraries.empty() )
666 {
667 for( const auto& [name, elibrary] : aSchematic.libraries )
668 {
669 wxString libName = elibrary->name;
670
671 if( elibrary->urn )
672 {
673 wxString tmp = *elibrary->urn;
674
675 libName += tmp.AfterLast( '/' );
676 }
677
678 EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
679 elib->name = libName;
680
681 loadLibrary( elibrary.get(), &m_eagleLibs[libName] );
682 }
683
684 m_pi->SaveLibrary( getLibFileName().GetFullPath() );
685 }
686
687 // find all nets and count how many sheets they appear on.
688 // local labels will be used for nets found only on that sheet.
689 countNets( aSchematic );
690
691 // There is always at least a root sheet.
693 m_sheetPath.SetPageNumber( wxT( "1" ) );
694
695 size_t sheetCount = aSchematic.sheets.size();
696
697 if( sheetCount > 1 )
698 {
699 int x, y;
700 x = 1;
701 y = 1;
702
703 for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
704 {
705 VECTOR2I pos = VECTOR2I( x * schIUScale.MilsToIU( 1000 ),
706 y * schIUScale.MilsToIU( 1000 ) );
707
708 // Eagle schematics are never more than one sheet deep so the parent sheet is
709 // always the root sheet.
710 std::unique_ptr<SCH_SHEET> sheet = std::make_unique<SCH_SHEET>( m_rootSheet, pos );
711 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
712 sheet->SetScreen( screen );
713 screen->SetFileName( sheet->GetFileName() );
714
715 wxCHECK2( sheet && screen, continue );
716
717 wxString pageNo = wxString::Format( wxT( "%d" ), m_sheetIndex );
718
719 m_sheetPath.push_back( sheet.get() );
720 loadSheet( esheet );
721
722 m_sheetPath.SetPageNumber( pageNo );
724
725 SCH_SCREEN* currentScreen = m_rootSheet->GetScreen();
726
727 wxCHECK2( currentScreen, continue );
728
729 currentScreen->Append( sheet.release() );
730
731 x += 2;
732
733 if( x > 10 ) // Start next row of sheets.
734 {
735 x = 1;
736 y += 2;
737 }
738
739 m_sheetIndex++;
740 }
741 }
742 else
743 {
744 for( const std::unique_ptr<ESHEET>& esheet : aSchematic.sheets )
745 loadSheet( esheet );
746 }
747
748 // Handle the missing symbol units that need to be instantiated
749 // to create the missing implicit connections
750
751 // Calculate the already placed items bounding box and the page size to determine
752 // placement for the new symbols
754 BOX2I sheetBbox = getSheetBbox( m_rootSheet );
755 VECTOR2I newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() );
756 int maxY = sheetBbox.GetY();
757
758 SCH_SHEET_PATH sheetpath;
760
761 for( auto& cmp : m_missingCmps )
762 {
763 const SCH_SYMBOL* origSymbol = cmp.second.cmp;
764
765 for( auto& unitEntry : cmp.second.units )
766 {
767 if( unitEntry.second == false )
768 continue; // unit has been already processed
769
770 // Instantiate the missing symbol unit
771 int unit = unitEntry.first;
772 const wxString reference = origSymbol->GetField( REFERENCE_FIELD )->GetText();
773 std::unique_ptr<SCH_SYMBOL> symbol( (SCH_SYMBOL*) origSymbol->Duplicate() );
774
775 symbol->SetUnitSelection( &sheetpath, unit );
776 symbol->SetUnit( unit );
777 symbol->SetOrientation( 0 );
778 symbol->AddHierarchicalReference( sheetpath.Path(), reference, unit );
779
780 // Calculate the placement position
781 BOX2I cmpBbox = symbol->GetBoundingBox();
782 int posY = newCmpPosition.y + cmpBbox.GetHeight();
783 symbol->SetPosition( VECTOR2I( newCmpPosition.x, posY ) );
784 newCmpPosition.x += cmpBbox.GetWidth();
785 maxY = std::max( maxY, posY );
786
787 if( newCmpPosition.x >= pageSizeIU.x ) // reached the page boundary?
788 newCmpPosition = VECTOR2I( sheetBbox.GetLeft(), maxY ); // then start a new row
789
790 // Add the global net labels to recreate the implicit connections
791 addImplicitConnections( symbol.get(), m_rootSheet->GetScreen(), false );
792 m_rootSheet->GetScreen()->Append( symbol.release() );
793 }
794 }
795
796 m_missingCmps.clear();
797}
798
799
800void SCH_IO_EAGLE::loadSheet( const std::unique_ptr<ESHEET>& aSheet )
801{
802 SCH_SHEET* sheet = getCurrentSheet();
803 SCH_SCREEN* screen = getCurrentScreen();
804
805 wxCHECK( sheet && screen, /* void */ );
806
807 if( !m_module )
808 {
809 std::string filename;
810 wxFileName fn = m_filename;
811
813
814 filename = wxString::Format( wxT( "%s_%d" ), m_filename.GetName(), m_sheetIndex );
815 sheet->SetName( filename );
816
817 ReplaceIllegalFileNameChars( &filename );
818 replace( filename.begin(), filename.end(), ' ', '_' );
819
820 fn.SetName( filename );
821
822 sheet->SetFileName( fn.GetFullName() );
823 screen->SetFileName( fn.GetFullPath() );
824 }
825
826 sheet->AutoplaceFields( screen, true );
827
828 if( aSheet->plain )
829 {
830 for( const std::unique_ptr<EPOLYGON>& epoly : aSheet->plain->polygons )
831 screen->Append( loadPolyLine( epoly ) );
832
833 for( const std::unique_ptr<EWIRE>& ewire : aSheet->plain->wires )
834 {
835 SEG endpoints;
836 screen->Append( loadWire( ewire, endpoints ) );
837 }
838
839 for( const std::unique_ptr<ETEXT>& etext : aSheet->plain->texts )
840 screen->Append( loadPlainText( etext ) );
841
842 for( const std::unique_ptr<ECIRCLE>& ecircle : aSheet->plain->circles )
843 screen->Append( loadCircle( ecircle ) );
844
845 for( const std::unique_ptr<ERECT>& erectangle : aSheet->plain->rectangles )
846 screen->Append( loadRectangle( erectangle ) );
847
848 for( const std::unique_ptr<EFRAME>& eframe : aSheet->plain->frames )
849 {
850 std::vector<SCH_ITEM*> frameItems;
851
852 loadFrame( eframe, frameItems );
853
854 for( SCH_ITEM* item : frameItems )
855 screen->Append( item );
856 }
857
858 // Holes and splines currently not handled. Not sure hole has any meaning in scheamtics.
859 }
860
861 for( const auto& [name, moduleinst] : aSheet->moduleinsts )
862 {
863 SCH_SHEET* modSheet = loadModuleInstance( moduleinst );
864 screen->Append( modSheet );
865 }
866
867 for( const std::unique_ptr<EINSTANCE>& einstance : aSheet->instances )
868 {
869 if( m_module )
870 loadInstance( einstance, m_module->parts );
871 else
872 loadInstance( einstance, m_eagleDoc->drawing->schematic->parts );
873 }
874
875 // Loop through all buses
876 // From the DTD: "Buses receive names which determine which signals they include.
877 // A bus is a drawing object. It does not create any electrical connections.
878 // These are always created by means of the nets and their names."
879 for( const std::unique_ptr<EBUS>& ebus : aSheet->busses )
880 {
881 // Get the bus name
882 wxString busName = translateEagleBusName( ebus->name );
883
884 // Load segments of this bus
885 loadSegments( ebus->segments, busName, wxString() );
886 }
887
888 for( const std::unique_ptr<ENET>& enet : aSheet->nets )
889 {
890 // Get the net name and class
891 wxString netName = enet->netname;
892 wxString netClass = wxString::Format( wxS( "%i" ), enet->netcode );
893
894 // Load segments of this net
895 loadSegments( enet->segments, netName, netClass );
896 }
897
898 adjustNetLabels(); // needs to be called before addBusEntries()
900
901 // Calculate the new sheet size.
902 BOX2I sheetBoundingBox = getSheetBbox( sheet );
903 VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
904 targetSheetSize += VECTOR2I( schIUScale.MilsToIU( 1500 ), schIUScale.MilsToIU( 1500 ) );
905
906 // Get current Eeschema sheet size.
907 VECTOR2I pageSizeIU = screen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
908 PAGE_INFO pageInfo = screen->GetPageSettings();
909
910 // Increase if necessary
911 if( pageSizeIU.x < targetSheetSize.x )
912 pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
913
914 if( pageSizeIU.y < targetSheetSize.y )
915 pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
916
917 // Set the new sheet size.
918 screen->SetPageSettings( pageInfo );
919
920 pageSizeIU = screen->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
921 VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
922 VECTOR2I itemsCentre = sheetBoundingBox.Centre();
923
924 // round the translation to nearest 100mil to place it on the grid.
925 VECTOR2I translation = sheetcentre - itemsCentre;
926 translation.x = translation.x - translation.x % schIUScale.MilsToIU( 100 );
927 translation.y = translation.y - translation.y % schIUScale.MilsToIU( 100 );
928
929 // Add global net labels for the named power input pins in this sheet
930 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
931 {
932 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
933 addImplicitConnections( symbol, screen, true );
934 }
935
936 m_connPoints.clear();
937
938 // Translate the items.
939 std::vector<SCH_ITEM*> allItems;
940
941 std::copy( screen->Items().begin(), screen->Items().end(), std::back_inserter( allItems ) );
942
943 for( SCH_ITEM* item : allItems )
944 {
945 item->SetPosition( item->GetPosition() + translation );
946
947 // We don't read positions of Eagle label fields (primarily intersheet refs), so we
948 // need to autoplace them after applying the translation.
949 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
950 label->AutoplaceFields( screen, false );
951
952 item->ClearFlags();
953 screen->Update( item );
954 }
955}
956
957
958SCH_SHEET* SCH_IO_EAGLE::loadModuleInstance( const std::unique_ptr<EMODULEINST>& aModuleInstance )
959{
960 SCH_SHEET* currentSheet = getCurrentSheet();
961 SCH_SCREEN* currentScreen = getCurrentScreen();
962
963 wxCHECK( currentSheet &&currentScreen, nullptr );
964
965 m_sheetIndex++;
966
967 // Eagle document has already be checked for drawing and schematic nodes so this
968 // should not segfault.
969 auto it = m_eagleDoc->drawing->schematic->modules.find( aModuleInstance->moduleinst );
970
971 // Find the module referenced by the module instance.
972 if( it == m_eagleDoc->drawing->schematic->modules.end() )
973 {
974 THROW_IO_ERROR( wxString::Format( _( "No module instance '%s' found in schematic "
975 "file:\n%s" ),
976 aModuleInstance->name, m_filename.GetFullPath() ) );
977 }
978
979
980 wxFileName fn = m_filename;
981 fn.SetName( aModuleInstance->name );
983
984 VECTOR2I portExtWireEndpoint;
985 VECTOR2I size( it->second->dx.ToSchUnits(), it->second->dy.ToSchUnits() );
986
987 int halfX = KiROUND( size.x / 2.0 );
988 int halfY = KiROUND( size.y / 2.0 );
989 int portExtWireLength = schIUScale.mmToIU( 5.08 );
990 VECTOR2I pos( aModuleInstance->x.ToSchUnits() - halfX,
991 -aModuleInstance->y.ToSchUnits() - halfY );
992
993 std::unique_ptr<SCH_SHEET> newSheet = std::make_unique<SCH_SHEET>( currentSheet, pos, size );
994
995 SCH_SCREEN* newScreen = new SCH_SCREEN( m_schematic );
996
997 wxCHECK( newSheet && newScreen, nullptr );
998
999 newSheet->SetScreen( newScreen );
1000 newSheet->SetFileName( fn.GetFullName() );
1001 newSheet->SetName( aModuleInstance->name );
1002 newScreen->SetFileName( fn.GetFullPath() );
1003
1004 for( const auto& [portName, port] : it->second->ports )
1005 {
1006 VECTOR2I pinPos( 0, 0 );
1007 int pinOffset = port->coord.ToSchUnits();
1008 SHEET_SIDE side = SHEET_SIDE::LEFT;
1009
1010 if( port->side == "left" )
1011 {
1012 side = SHEET_SIDE::LEFT;
1013 pinPos.x = pos.x;
1014 pinPos.y = pos.y + halfY - pinOffset;
1015 portExtWireEndpoint = pinPos;
1016 portExtWireEndpoint.x -= portExtWireLength;
1017 }
1018 else if( port->side == "right" )
1019 {
1020 side = SHEET_SIDE::RIGHT;
1021 pinPos.x = pos.x + size.x;
1022 pinPos.y = pos.y + halfY - pinOffset;
1023 portExtWireEndpoint = pinPos;
1024 portExtWireEndpoint.x += portExtWireLength;
1025 }
1026 else if( port->side == "top" )
1027 {
1028 side = SHEET_SIDE::TOP;
1029 pinPos.x = pos.x + halfX + pinOffset;
1030 pinPos.y = pos.y;
1031 portExtWireEndpoint = pinPos;
1032 portExtWireEndpoint.y -= portExtWireLength;
1033 }
1034 else if( port->side == "bottom" )
1035 {
1036 side = SHEET_SIDE::BOTTOM;
1037 pinPos.x = pos.x + halfX + pinOffset;
1038 pinPos.y = pos.y + size.y;
1039 portExtWireEndpoint = pinPos;
1040 portExtWireEndpoint.y += portExtWireLength;
1041 }
1042
1043 SCH_LINE* portExtWire = new SCH_LINE( pinPos, LAYER_WIRE );
1044 portExtWire->SetEndPoint( portExtWireEndpoint );
1045 currentScreen->Append( portExtWire );
1046
1047 LABEL_FLAG_SHAPE pinType = LABEL_FLAG_SHAPE::L_UNSPECIFIED;
1048
1049 if( port->direction )
1050 {
1051 if( *port->direction == "in" )
1052 pinType = LABEL_FLAG_SHAPE::L_INPUT;
1053 else if( *port->direction == "out" )
1054 pinType = LABEL_FLAG_SHAPE::L_OUTPUT;
1055 else if( *port->direction == "io" )
1056 pinType = LABEL_FLAG_SHAPE::L_BIDI;
1057 else if( *port->direction == "hiz" )
1058 pinType = LABEL_FLAG_SHAPE::L_TRISTATE;
1059 else
1060 pinType = LABEL_FLAG_SHAPE::L_UNSPECIFIED;
1061
1062 // KiCad does not support passive, power, open collector, or no-connect sheet
1063 // pins that Eagle ports support. They are set to unspecified to minimize
1064 // ERC issues.
1065 }
1066
1067 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( newSheet.get(), VECTOR2I( 0, 0 ), portName );
1068
1069 sheetPin->SetShape( pinType );
1070 sheetPin->SetPosition( pinPos );
1071 sheetPin->SetSide( side );
1072 newSheet->AddPin( sheetPin );
1073 }
1074
1075 wxString pageNo = wxString::Format( wxT( "%d" ), m_sheetIndex );
1076
1077 m_sheetPath.push_back( newSheet.get() );
1078
1079 m_module = it->second.get();
1080
1081 // It's not clear if Eagle modules can have more than one sheet so this may not be correct.
1082 if( it->second->sheets.size() == 1 )
1083 {
1084 loadSheet( it->second->sheets.at( 0 ) );
1085 }
1086 else
1087 {
1088 int i = 0;
1089 int x = 1;
1090 int y = 1;
1091
1092 for( const std::unique_ptr<ESHEET>& esheet : it->second->sheets )
1093 {
1094 pos = VECTOR2I( x * schIUScale.MilsToIU( 1000 ),
1095 y * schIUScale.MilsToIU( 1000 ) );
1096
1097 std::unique_ptr<SCH_SHEET> sheet = std::make_unique<SCH_SHEET>( newSheet.get(), pos );
1098 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
1099 sheet->SetScreen( screen );
1100
1101 wxString newFileName = fn.GetName();
1102
1103 newFileName += wxString::Format( wxS( "_%d" ), i + 1 );
1104 fn.SetName( newFileName );
1105 screen->SetFileName( fn.GetFullPath() );
1106 sheet->SetFileName( fn.GetFullName() );
1107
1108 wxCHECK2( sheet && screen, continue );
1109
1110 wxString subSheetPageNo = wxString::Format( wxT( "%d" ), m_sheetIndex );
1111
1112 m_sheetPath.push_back( sheet.get() );
1113 loadSheet( esheet );
1114
1115 m_sheetPath.SetPageNumber( subSheetPageNo );
1117
1118 newScreen->Append( sheet.release() );
1119
1120 x += 2;
1121
1122 if( x > 10 ) // Start next row of sheets.
1123 {
1124 x = 1;
1125 y += 2;
1126 }
1127
1128 m_sheetIndex++;
1129 }
1130 }
1131
1132 m_sheetPath.SetPageNumber( pageNo );
1134
1135 m_module = nullptr;
1136
1137 return newSheet.release();
1138}
1139
1140
1141void SCH_IO_EAGLE::loadFrame( const std::unique_ptr<EFRAME>& aFrame,
1142 std::vector<SCH_ITEM*>& aItems )
1143{
1144 int xMin = aFrame->x1.ToSchUnits();
1145 int xMax = aFrame->x2.ToSchUnits();
1146 int yMin = -aFrame->y1.ToSchUnits();
1147 int yMax = -aFrame->y2.ToSchUnits();
1148
1149 if( xMin > xMax )
1150 std::swap( xMin, xMax );
1151
1152 if( yMin > yMax )
1153 std::swap( yMin, yMax );
1154
1155 SCH_SHAPE* lines = new SCH_SHAPE( SHAPE_T::POLY );
1156 lines->AddPoint( VECTOR2I( xMin, yMin ) );
1157 lines->AddPoint( VECTOR2I( xMax, yMin ) );
1158 lines->AddPoint( VECTOR2I( xMax, yMax ) );
1159 lines->AddPoint( VECTOR2I( xMin, yMax ) );
1160 lines->AddPoint( VECTOR2I( xMin, yMin ) );
1161 aItems.push_back( lines );
1162
1163 if( !( aFrame->border_left == false ) )
1164 {
1165 lines = new SCH_SHAPE( SHAPE_T::POLY );
1166 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1167 yMin + schIUScale.MilsToIU( 150 ) ) );
1168 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1169 yMax - schIUScale.MilsToIU( 150 ) ) );
1170 aItems.push_back( lines );
1171
1172 int i;
1173 int height = yMax - yMin;
1174 int x1 = xMin;
1175 int x2 = x1 + schIUScale.MilsToIU( 150 );
1176 int legendPosX = xMin + schIUScale.MilsToIU( 75 );
1177 double rowSpacing = height / double( aFrame->rows );
1178 double legendPosY = yMin + ( rowSpacing / 2 );
1179
1180 for( i = 1; i < aFrame->rows; i++ )
1181 {
1182 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
1183 lines = new SCH_SHAPE( SHAPE_T::POLY );
1184 lines->AddPoint( VECTOR2I( x1, newY ) );
1185 lines->AddPoint( VECTOR2I( x2, newY ) );
1186 aItems.push_back( lines );
1187 }
1188
1189 char legendChar = 'A';
1190
1191 for( i = 0; i < aFrame->rows; i++ )
1192 {
1193 SCH_TEXT* legendText = new SCH_TEXT();
1194 legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
1197 legendText->SetText( wxString( legendChar ) );
1198 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1199 schIUScale.MilsToIU( 100 ) ) );
1200 aItems.push_back( legendText );
1201 legendChar++;
1202 legendPosY += rowSpacing;
1203 }
1204 }
1205
1206 if( !( aFrame->border_right == false ) )
1207 {
1208 lines = new SCH_SHAPE( SHAPE_T::POLY );
1209 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1210 yMin + schIUScale.MilsToIU( 150 ) ) );
1211 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1212 yMax - schIUScale.MilsToIU( 150 ) ) );
1213 aItems.push_back( lines );
1214
1215 int i;
1216 int height = yMax - yMin;
1217 int x1 = xMax - schIUScale.MilsToIU( 150 );
1218 int x2 = xMax;
1219 int legendPosX = xMax - schIUScale.MilsToIU( 75 );
1220 double rowSpacing = height / double( aFrame->rows );
1221 double legendPosY = yMin + ( rowSpacing / 2 );
1222
1223 for( i = 1; i < aFrame->rows; i++ )
1224 {
1225 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
1226 lines = new SCH_SHAPE( SHAPE_T::POLY );
1227 lines->AddPoint( VECTOR2I( x1, newY ) );
1228 lines->AddPoint( VECTOR2I( x2, newY ) );
1229 aItems.push_back( lines );
1230 }
1231
1232 char legendChar = 'A';
1233
1234 for( i = 0; i < aFrame->rows; i++ )
1235 {
1236 SCH_TEXT* legendText = new SCH_TEXT();
1237 legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
1240 legendText->SetText( wxString( legendChar ) );
1241 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1242 schIUScale.MilsToIU( 100 ) ) );
1243 aItems.push_back( legendText );
1244 legendChar++;
1245 legendPosY += rowSpacing;
1246 }
1247 }
1248
1249 if( !( aFrame->border_top == false ) )
1250 {
1251 lines = new SCH_SHAPE( SHAPE_T::POLY );
1252 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1253 yMin + schIUScale.MilsToIU( 150 ) ) );
1254 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1255 yMin + schIUScale.MilsToIU( 150 ) ) );
1256 aItems.push_back( lines );
1257
1258 int i;
1259 int width = xMax - xMin;
1260 int y1 = yMin;
1261 int y2 = yMin + schIUScale.MilsToIU( 150 );
1262 int legendPosY = yMin + schIUScale.MilsToIU( 75 );
1263 double columnSpacing = width / double( aFrame->columns );
1264 double legendPosX = xMin + ( columnSpacing / 2 );
1265
1266 for( i = 1; i < aFrame->columns; i++ )
1267 {
1268 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
1269 lines = new SCH_SHAPE( SHAPE_T::POLY );
1270 lines->AddPoint( VECTOR2I( newX, y1 ) );
1271 lines->AddPoint( VECTOR2I( newX, y2 ) );
1272 aItems.push_back( lines );
1273 }
1274
1275 char legendChar = '1';
1276
1277 for( i = 0; i < aFrame->columns; i++ )
1278 {
1279 SCH_TEXT* legendText = new SCH_TEXT();
1280 legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
1283 legendText->SetText( wxString( legendChar ) );
1284 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1285 schIUScale.MilsToIU( 100 ) ) );
1286 aItems.push_back( legendText );
1287 legendChar++;
1288 legendPosX += columnSpacing;
1289 }
1290 }
1291
1292 if( !( aFrame->border_bottom == false ) )
1293 {
1294 lines = new SCH_SHAPE( SHAPE_T::POLY );
1295 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1296 yMax - schIUScale.MilsToIU( 150 ) ) );
1297 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1298 yMax - schIUScale.MilsToIU( 150 ) ) );
1299 aItems.push_back( lines );
1300
1301 int i;
1302 int width = xMax - xMin;
1303 int y1 = yMax - schIUScale.MilsToIU( 150 );
1304 int y2 = yMax;
1305 int legendPosY = yMax - schIUScale.MilsToIU( 75 );
1306 double columnSpacing = width / double( aFrame->columns );
1307 double legendPosX = xMin + ( columnSpacing / 2 );
1308
1309 for( i = 1; i < aFrame->columns; i++ )
1310 {
1311 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
1312 lines = new SCH_SHAPE( SHAPE_T::POLY );
1313 lines->AddPoint( VECTOR2I( newX, y1 ) );
1314 lines->AddPoint( VECTOR2I( newX, y2 ) );
1315 aItems.push_back( lines );
1316 }
1317
1318 char legendChar = '1';
1319
1320 for( i = 0; i < aFrame->columns; i++ )
1321 {
1322 SCH_TEXT* legendText = new SCH_TEXT();
1323 legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
1326 legendText->SetText( wxString( legendChar ) );
1327 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1328 schIUScale.MilsToIU( 100 ) ) );
1329 aItems.push_back( legendText );
1330 legendChar++;
1331 legendPosX += columnSpacing;
1332 }
1333 }
1334}
1335
1336
1337void SCH_IO_EAGLE::loadSegments( const std::vector<std::unique_ptr<ESEGMENT>>& aSegments,
1338 const wxString& netName,
1339 const wxString& aNetClass )
1340{
1341 // Loop through all segments
1342 SCH_SCREEN* screen = getCurrentScreen();
1343
1344 wxCHECK( screen, /* void */ );
1345
1346 size_t segmentCount = aSegments.size();
1347
1348 for( const std::unique_ptr<ESEGMENT>& esegment : aSegments )
1349 {
1350 bool labelled = false; // has a label been added to this continuously connected segment
1351 bool firstWireFound = false;
1352 SEG firstWire;
1353
1354 m_segments.emplace_back();
1355 SEG_DESC& segDesc = m_segments.back();
1356
1357 for( const std::unique_ptr<EWIRE>& ewire : esegment->wires )
1358 {
1359 // TODO: Check how intersections used in adjustNetLabels should be
1360 // calculated - for now we pretend that all wires are line segments.
1361 SEG thisWire;
1362 SCH_ITEM* wire = loadWire( ewire, thisWire );
1363 m_connPoints[thisWire.A].emplace( wire );
1364 m_connPoints[thisWire.B].emplace( wire );
1365
1366 if( !firstWireFound )
1367 {
1368 firstWire = thisWire;
1369 firstWireFound = true;
1370 }
1371
1372 // Test for intersections with other wires
1373 for( SEG_DESC& desc : m_segments )
1374 {
1375 if( !desc.labels.empty() && desc.labels.front()->GetText() == netName )
1376 continue; // no point in saving intersections of the same net
1377
1378 for( const SEG& seg : desc.segs )
1379 {
1380 OPT_VECTOR2I intersection = thisWire.Intersect( seg, true );
1381
1382 if( intersection )
1383 m_wireIntersections.push_back( *intersection );
1384 }
1385 }
1386
1387 segDesc.segs.push_back( thisWire );
1388 screen->Append( wire );
1389 }
1390
1391 for( const std::unique_ptr<EJUNCTION>& ejunction : esegment->junctions )
1392 screen->Append( loadJunction( ejunction ) );
1393
1394 for( const std::unique_ptr<ELABEL>& elabel : esegment->labels )
1395 {
1396 SCH_TEXT* label = loadLabel( elabel, netName );
1397 screen->Append( label );
1398
1399 wxASSERT( segDesc.labels.empty()
1400 || segDesc.labels.front()->GetText() == label->GetText() );
1401
1402 segDesc.labels.push_back( label );
1403 labelled = true;
1404 }
1405
1406 for( const std::unique_ptr<EPINREF>& epinref : esegment->pinRefs )
1407 {
1408 wxString part = epinref->part;
1409 wxString pin = epinref->pin;
1410
1411 auto powerPort = m_powerPorts.find( wxT( "#" ) + part );
1412
1413 if( powerPort != m_powerPorts.end()
1414 && powerPort->second == EscapeString( pin, CTX_NETNAME ) )
1415 {
1416 labelled = true;
1417 }
1418 }
1419
1420 // Add a small label to the net segment if it hasn't been labeled already or is not
1421 // connect to a power symbol with a pin on the same net. This preserves the named net
1422 // feature of Eagle schematics.
1423 if( !labelled && firstWireFound )
1424 {
1425 std::unique_ptr<SCH_LABEL_BASE> label;
1426
1427 // Add a global label if the net appears on more than one Eagle sheet
1428 if( m_netCounts[netName.ToStdString()] > 1 )
1429 label.reset( new SCH_GLOBALLABEL );
1430 else if( segmentCount > 1 )
1431 label.reset( new SCH_LABEL );
1432
1433 if( label )
1434 {
1435 label->SetPosition( firstWire.A );
1436 label->SetText( escapeName( netName ) );
1437 label->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
1438 schIUScale.MilsToIU( 40 ) ) );
1439
1440 if( firstWire.B.x > firstWire.A.x )
1441 label->SetSpinStyle( SPIN_STYLE::LEFT );
1442 else
1443 label->SetSpinStyle( SPIN_STYLE::RIGHT );
1444
1445 screen->Append( label.release() );
1446 }
1447 }
1448 }
1449}
1450
1451
1452SCH_SHAPE* SCH_IO_EAGLE::loadPolyLine( const std::unique_ptr<EPOLYGON>& aPolygon )
1453{
1454 std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY );
1455 VECTOR2I pt, prev_pt;
1456 opt_double prev_curve;
1457
1458 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
1459 {
1460 pt = VECTOR2I( evertex->x.ToSchUnits(), -evertex->y.ToSchUnits() );
1461
1462 if( prev_curve )
1463 {
1464 SHAPE_ARC arc;
1465 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
1466 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
1467 }
1468 else
1469 {
1470 poly->AddPoint( pt );
1471 }
1472
1473 prev_pt = pt;
1474 prev_curve = evertex->curve;
1475 }
1476
1477 poly->SetLayer( kiCadLayer( aPolygon->layer ) );
1478 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1479 poly->SetFillMode( FILL_T::FILLED_SHAPE );
1480
1481 return poly.release();
1482}
1483
1484
1485SCH_ITEM* SCH_IO_EAGLE::loadWire( const std::unique_ptr<EWIRE>& aWire, SEG& endpoints )
1486{
1487 VECTOR2I start, end;
1488
1489 start.x = aWire->x1.ToSchUnits();
1490 start.y = -aWire->y1.ToSchUnits();
1491 end.x = aWire->x2.ToSchUnits();
1492 end.y = -aWire->y2.ToSchUnits();
1493
1494 // For segment wires.
1495 endpoints = SEG( start, end );
1496
1497 if( aWire->curve )
1498 {
1499 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC );
1500
1501 VECTOR2I center = ConvertArcCenter( start, end, *aWire->curve );
1502 arc->SetCenter( center );
1503 arc->SetStart( start );
1504
1505 // KiCad rotates the other way.
1506 arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
1507 arc->SetLayer( kiCadLayer( aWire->layer ) );
1508 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1509
1510 return arc.release();
1511 }
1512 else
1513 {
1514 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>();
1515
1516 line->SetStartPoint( start );
1517 line->SetEndPoint( end );
1518 line->SetLayer( kiCadLayer( aWire->layer ) );
1519 line->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1520
1521 return line.release();
1522 }
1523}
1524
1525
1526SCH_SHAPE* SCH_IO_EAGLE::loadCircle( const std::unique_ptr<ECIRCLE>& aCircle )
1527{
1528 std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
1529 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
1530
1531 circle->SetLayer( kiCadLayer( aCircle->layer ) );
1532 circle->SetPosition( center );
1533 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
1534 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1535
1536 return circle.release();
1537}
1538
1539
1540SCH_SHAPE* SCH_IO_EAGLE::loadRectangle( const std::unique_ptr<ERECT>& aRectangle )
1541{
1542 std::unique_ptr<SCH_SHAPE> rectangle = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
1543
1544 rectangle->SetLayer( kiCadLayer( aRectangle->layer ) );
1545 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
1546 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
1547
1548 if( aRectangle->rot )
1549 {
1550 VECTOR2I pos( rectangle->GetPosition() );
1551 VECTOR2I end( rectangle->GetEnd() );
1552 VECTOR2I center( rectangle->GetCenter() );
1553
1554 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
1555 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
1556
1557 rectangle->SetPosition( pos );
1558 rectangle->SetEnd( end );
1559 }
1560
1561 // Eagle rectangles are filled by definition.
1562 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
1563
1564 return rectangle.release();
1565}
1566
1567
1568SCH_JUNCTION* SCH_IO_EAGLE::loadJunction( const std::unique_ptr<EJUNCTION>& aJunction )
1569{
1570 std::unique_ptr<SCH_JUNCTION> junction = std::make_unique<SCH_JUNCTION>();
1571
1572 VECTOR2I pos( aJunction->x.ToSchUnits(), -aJunction->y.ToSchUnits() );
1573
1574 junction->SetPosition( pos );
1575
1576 return junction.release();
1577}
1578
1579
1580SCH_TEXT* SCH_IO_EAGLE::loadLabel( const std::unique_ptr<ELABEL>& aLabel,
1581 const wxString& aNetName )
1582{
1583 VECTOR2I elabelpos( aLabel->x.ToSchUnits(), -aLabel->y.ToSchUnits() );
1584
1585 // Determine if the label is local or global depending on
1586 // the number of sheets the net appears in
1587 bool global = m_netCounts[aNetName] > 1;
1588 std::unique_ptr<SCH_LABEL_BASE> label;
1589
1590 VECTOR2I textSize = VECTOR2I( KiROUND( aLabel->size.ToSchUnits() * 0.7 ),
1591 KiROUND( aLabel->size.ToSchUnits() * 0.7 ) );
1592
1593 if( m_module )
1594 {
1595 if( m_module->ports.find( aNetName ) != m_module->ports.end() )
1596 {
1597 label = std::make_unique<SCH_HIERLABEL>();
1598 label->SetText( escapeName( aNetName ) );
1599
1600 const auto it = m_module->ports.find( aNetName );
1601
1602 LABEL_SHAPE type;
1603
1604 if( it->second->direction )
1605 {
1606 wxString direction = *it->second->direction;
1607
1608 if( direction == "in" )
1609 type = LABEL_SHAPE::LABEL_INPUT;
1610 else if( direction == "out" )
1611 type = LABEL_SHAPE::LABEL_OUTPUT;
1612 else if( direction == "io" )
1613 type = LABEL_SHAPE::LABEL_BIDI;
1614 else if( direction == "hiz" )
1615 type = LABEL_SHAPE::LABEL_TRISTATE;
1616 else
1617 type = LABEL_SHAPE::LABEL_PASSIVE;
1618
1619 // KiCad does not support passive, power, open collector, or no-connect sheet
1620 // pins that Eagle ports support. They are set to unspecified to minimize
1621 // ERC issues.
1622 label->SetLabelShape( type );
1623 }
1624 }
1625 else
1626 {
1627 label = std::make_unique<SCH_LABEL>();
1628 label->SetText( escapeName( aNetName ) );
1629 }
1630 }
1631 else if( global )
1632 {
1633 label = std::make_unique<SCH_GLOBALLABEL>();
1634 label->SetText( escapeName( aNetName ) );
1635 }
1636 else
1637 {
1638 label = std::make_unique<SCH_LABEL>();
1639 label->SetText( escapeName( aNetName ) );
1640 }
1641
1642 label->SetPosition( elabelpos );
1643 label->SetTextSize( textSize );
1644 label->SetSpinStyle( SPIN_STYLE::RIGHT );
1645
1646 if( aLabel->rot )
1647 {
1648 for( int i = 0; i < KiROUND( aLabel->rot->degrees / 90 ) %4; ++i )
1649 label->Rotate90( false );
1650
1651 if( aLabel->rot->mirror )
1652 label->MirrorSpinStyle( false );
1653 }
1654
1655 return label.release();
1656}
1657
1658
1659std::pair<VECTOR2I, const SEG*>
1661 const std::vector<SEG>& aLines ) const
1662{
1663 VECTOR2I nearestPoint;
1664 const SEG* nearestLine = nullptr;
1665
1666 float d, mindistance = std::numeric_limits<float>::max();
1667
1668 // Find the nearest start, middle or end of a line from the list of lines.
1669 for( const SEG& line : aLines )
1670 {
1671 VECTOR2I testpoint = line.A;
1672 d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1673
1674 if( d < mindistance )
1675 {
1676 mindistance = d;
1677 nearestPoint = testpoint;
1678 nearestLine = &line;
1679 }
1680
1681 testpoint = line.Center();
1682 d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1683
1684 if( d < mindistance )
1685 {
1686 mindistance = d;
1687 nearestPoint = testpoint;
1688 nearestLine = &line;
1689 }
1690
1691 testpoint = line.B;
1692 d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1693
1694 if( d < mindistance )
1695 {
1696 mindistance = d;
1697 nearestPoint = testpoint;
1698 nearestLine = &line;
1699 }
1700 }
1701
1702 return std::make_pair( nearestPoint, nearestLine );
1703}
1704
1705
1706void SCH_IO_EAGLE::loadInstance( const std::unique_ptr<EINSTANCE>& aInstance,
1707 const std::map<wxString, std::unique_ptr<EPART>>& aParts )
1708{
1709 wxCHECK( aInstance, /* void */ );
1710
1711 SCH_SCREEN* screen = getCurrentScreen();
1712
1713 wxCHECK( screen, /* void */ );
1714
1715 const auto partIt = aParts.find( aInstance->part );
1716
1717 if( partIt == aParts.end() )
1718 {
1719 Report( wxString::Format( _( "Error parsing Eagle file. Could not find '%s' "
1720 "instance but it is referenced in the schematic." ),
1721 aInstance->part ),
1723
1724 return;
1725 }
1726
1727 const std::unique_ptr<EPART>& epart = partIt->second;
1728
1729 wxString libName = epart->library;
1730
1731 // Correctly handle versioned libraries.
1732 if( epart->libraryUrn )
1733 {
1734 wxString tmp = *epart->libraryUrn;
1735
1736 libName += tmp.AfterLast( '/' );
1737 }
1738
1739 wxString gatename = epart->deviceset + wxS( "_" ) + epart->device + wxS( "_" ) +
1740 aInstance->gate;
1741 wxString symbolname = wxString( epart->deviceset + epart->device );
1742 symbolname.Replace( wxT( "*" ), wxEmptyString );
1743 wxString kisymbolname = EscapeString( symbolname, CTX_LIBID );
1744
1745 // Eagle schematics can have multiple libraries containing symbols with duplicate symbol
1746 // names. Because this parser stores all of the symbols in a single library, the
1747 // loadSymbol() function, prefixed the original Eagle library name to the symbol name
1748 // in case of a name clash. Check for the prefixed symbol first. This ensures that
1749 // the correct library symbol gets mapped on load.
1750 wxString altSymbolName = libName + wxT( "_" ) + symbolname;
1751 altSymbolName = EscapeString( altSymbolName, CTX_LIBID );
1752
1753 wxString libIdSymbolName = altSymbolName;
1754
1755 const auto libIt = m_eagleLibs.find( libName );
1756
1757 if( libIt == m_eagleLibs.end() )
1758 {
1759 Report( wxString::Format( wxS( "Eagle library '%s' not found while looking up symbol for"
1760 "deviceset '%s', device '%s', and gate '%s." ),
1761 libName, epart->deviceset, epart->device, aInstance->gate ) );
1762 return;
1763 }
1764
1765 const auto gateIt = libIt->second.GateToUnitMap.find( gatename );
1766
1767 if( gateIt == libIt->second.GateToUnitMap.end() )
1768 {
1769 Report( wxString::Format( wxS( "Symbol not found for deviceset '%s', device '%s', and "
1770 "gate '%s in library '%s'." ),
1771 epart->deviceset, epart->device, aInstance->gate, libName ) );
1772 return;
1773 }
1774
1775 int unit = gateIt->second;
1776
1777 wxString package;
1778 EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
1779
1780 auto p = elib->package.find( kisymbolname );
1781
1782 if( p != elib->package.end() )
1783 package = p->second;
1784
1785 LIB_SYMBOL* part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), altSymbolName,
1786 m_properties.get() );
1787
1788 if( !part )
1789 {
1790 part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname,
1791 m_properties.get() );
1792 libIdSymbolName = kisymbolname;
1793 }
1794
1795 if( !part )
1796 {
1797 Report( wxString::Format( _( "Could not find '%s' in the imported library." ),
1798 UnescapeString( kisymbolname ) ),
1800 return;
1801 }
1802
1803 LIB_ID libId( getLibName(), libIdSymbolName );
1804 std::unique_ptr<SCH_SYMBOL> symbol = std::make_unique<SCH_SYMBOL>();
1805 symbol->SetLibId( libId );
1806 symbol->SetUnit( unit );
1807 symbol->SetPosition( VECTOR2I( aInstance->x.ToSchUnits(), -aInstance->y.ToSchUnits() ) );
1808
1809 // assume that footprint library is identical to project name
1810 if( !package.IsEmpty() )
1811 {
1812 wxString footprint = m_schematic->Prj().GetProjectName() + wxT( ":" ) + package;
1813 symbol->GetField( FOOTPRINT_FIELD )->SetText( footprint );
1814 }
1815
1816 if( aInstance->rot )
1817 {
1818 symbol->SetOrientation( kiCadComponentRotation( aInstance->rot->degrees ) );
1819
1820 if( aInstance->rot->mirror )
1821 symbol->MirrorHorizontally( aInstance->x.ToSchUnits() );
1822 }
1823
1824 std::vector<SCH_FIELD*> partFields;
1825 part->GetFields( partFields );
1826
1827 for( const SCH_FIELD* field : partFields )
1828 {
1829 symbol->GetFieldById( field->GetId() )->ImportValues( *field );
1830 symbol->GetFieldById( field->GetId() )->SetTextPos( (VECTOR2I)symbol->GetPosition()
1831 + field->GetTextPos() );
1832 }
1833
1834 // If there is no footprint assigned, then prepend the reference value
1835 // with a hash character to mute netlist updater complaints
1836 wxString reference = package.IsEmpty() ? '#' + aInstance->part : aInstance->part;
1837
1838 // reference must end with a number but EAGLE does not enforce this
1839 if( reference.find_last_not_of( wxT( "0123456789" ) ) == ( reference.Length()-1 ) )
1840 reference.Append( wxT( "0" ) );
1841
1842 // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
1843 // parts to have non-digit + digit annotation. If the reference begins with a number,
1844 // we prepend 'UNK' (unknown) for the symbol designator
1845 if( reference.find_first_not_of( wxT( "0123456789" ) ) != 0 )
1846 reference.Prepend( wxT( "UNK" ) );
1847
1848 // EAGLE allows designator to start with # but that is used in KiCad
1849 // for symbols which do not have a footprint
1850 if( aInstance->part.find_first_not_of( wxT( "#" ) ) != 0 )
1851 reference.Prepend( wxT( "UNK" ) );
1852
1853 SCH_FIELD* referenceField = symbol->GetField( REFERENCE_FIELD );
1854 referenceField->SetText( reference );
1855
1856 SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
1857 bool userValue = m_userValue.at( libIdSymbolName );
1858
1859 if( part->GetUnitCount() > 1 )
1860 {
1861 getEagleSymbolFieldAttributes( aInstance, wxS( ">NAME" ), referenceField );
1862 getEagleSymbolFieldAttributes( aInstance, wxS( ">VALUE" ), valueField );
1863 }
1864
1865 if( epart->value && !epart->value.CGet().IsEmpty() )
1866 {
1867 valueField->SetText( *epart->value );
1868 }
1869 else
1870 {
1871 valueField->SetText( kisymbolname );
1872
1873 if( userValue )
1874 valueField->SetVisible( false );
1875 }
1876
1877 for( const auto& [ attrName, attr ] : epart->attributes )
1878 {
1879 VECTOR2I newFieldPosition( 0, 0 );
1880 SCH_FIELD* lastField = symbol->GetFieldById( symbol->GetFieldCount() - 1 );
1881
1882 if( lastField )
1883 newFieldPosition = lastField->GetPosition();
1884
1885 SCH_FIELD newField( newFieldPosition, symbol->GetFieldCount(), symbol.get() );
1886
1887 newField.SetName( attrName );
1888
1889 if( attr->value )
1890 newField.SetText( *attr->value );
1891
1892 newField.SetVisible( ( attr->display == EATTR::Off ) ? false : true );
1893
1894 symbol->AddField( newField );
1895 }
1896
1897 for( const auto& [variantName, variant] : epart->variants )
1898 {
1899 SCH_FIELD* field = symbol->AddField( *symbol->GetField( VALUE_FIELD ) );
1900 field->SetName( wxT( "VARIANT_" ) + variant->name );
1901
1902 if( variant->value )
1903 field->SetText( *variant->value );
1904
1905 field->SetVisible( false );
1906 }
1907
1908 bool valueAttributeFound = false;
1909 bool nameAttributeFound = false;
1910
1911 // Parse attributes for the instance
1912 for( auto& [name, eattr] : aInstance->attributes )
1913 {
1914 SCH_FIELD* field = nullptr;
1915
1916 if( eattr->name.Lower() == wxT( "name" ) )
1917 {
1918 field = symbol->GetField( REFERENCE_FIELD );
1919 nameAttributeFound = true;
1920 }
1921 else if( eattr->name.Lower() == wxT( "value" ) )
1922 {
1923 field = symbol->GetField( VALUE_FIELD );
1924 valueAttributeFound = true;
1925 }
1926 else
1927 {
1928 field = symbol->FindField( eattr->name );
1929
1930 if( field )
1931 field->SetVisible( false );
1932 }
1933
1934 if( field )
1935 {
1936 field->SetPosition( VECTOR2I( eattr->x->ToSchUnits(), -eattr->y->ToSchUnits() ) );
1937 int align = eattr->align ? *eattr->align : ETEXT::BOTTOM_LEFT;
1938 int absdegrees = eattr->rot ? eattr->rot->degrees : 0;
1939 bool mirror = eattr->rot ? eattr->rot->mirror : false;
1940
1941 if( aInstance->rot && aInstance->rot->mirror )
1942 mirror = !mirror;
1943
1944 bool spin = eattr->rot ? eattr->rot->spin : false;
1945
1946 if( eattr->display == EATTR::Off || eattr->display == EATTR::NAME )
1947 field->SetVisible( false );
1948
1949 int rotation = aInstance->rot ? aInstance->rot->degrees : 0;
1950 int reldegrees = ( absdegrees - rotation + 360.0 );
1951 reldegrees %= 360;
1952
1953 eagleToKicadAlignment( field, align, reldegrees, mirror, spin, absdegrees );
1954 }
1955 }
1956
1957 // Use the instance attribute to determine the reference and value field visibility.
1958 if( aInstance->smashed && aInstance->smashed.Get() )
1959 {
1960 symbol->GetField( VALUE_FIELD )->SetVisible( valueAttributeFound );
1961 symbol->GetField( REFERENCE_FIELD )->SetVisible( nameAttributeFound );
1962 }
1963
1964 symbol->AddHierarchicalReference( m_sheetPath.Path(), reference, unit );
1965
1966 // Save the pin positions
1967 SYMBOL_LIB_TABLE& schLibTable = *PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
1968 LIB_SYMBOL* libSymbol = schLibTable.LoadSymbol( symbol->GetLibId() );
1969
1970 wxCHECK( libSymbol, /*void*/ );
1971
1972 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
1973
1974 for( const SCH_PIN* pin : symbol->GetLibPins() )
1975 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
1976
1977 if( part->IsPower() )
1978 m_powerPorts[ reference ] = symbol->GetField( VALUE_FIELD )->GetText();
1979
1980 symbol->ClearFlags();
1981
1982 screen->Append( symbol.release() );
1983}
1984
1985
1987{
1988 wxCHECK( aLibrary && aEagleLibrary, nullptr );
1989
1990 // Loop through the device sets and load each of them
1991 for( const auto& [name, edeviceset] : aLibrary->devicesets )
1992 {
1993 // Get Device set information
1994 wxString prefix = edeviceset->prefix ? edeviceset->prefix.Get() : wxString( wxT( "" ) );
1995 wxString deviceSetDescr;
1996
1997 if( edeviceset->description )
1998 deviceSetDescr = convertDescription( UnescapeHTML( edeviceset->description->text ) );
1999
2000 // For each device in the device set:
2001 for( const std::unique_ptr<EDEVICE>& edevice : edeviceset->devices )
2002 {
2003 // Create symbol name from deviceset and device names.
2004 wxString symbolName = edeviceset->name + edevice->name;
2005 symbolName.Replace( wxT( "*" ), wxEmptyString );
2006 wxASSERT( !symbolName.IsEmpty() );
2007 symbolName = EscapeString( symbolName, CTX_LIBID );
2008
2009 if( edevice->package )
2010 aEagleLibrary->package[symbolName] = edevice->package.Get();
2011
2012 // Create KiCad symbol.
2013 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2014
2015 // Process each gate in the deviceset for this device.
2016 int gate_count = static_cast<int>( edeviceset->gates.size() );
2017 libSymbol->SetUnitCount( gate_count );
2018 libSymbol->LockUnits( true );
2019
2020 SCH_FIELD* reference = libSymbol->GetFieldById( REFERENCE_FIELD );
2021
2022 if( prefix.length() == 0 )
2023 {
2024 reference->SetVisible( false );
2025 }
2026 else
2027 {
2028 // If there is no footprint assigned, then prepend the reference value
2029 // with a hash character to mute netlist updater complaints
2030 reference->SetText( edevice->package ? prefix : '#' + prefix );
2031 }
2032
2033 libSymbol->GetFieldById( VALUE_FIELD )->SetVisible( true );
2034
2035 int gateindex = 1;
2036 bool ispower = false;
2037
2038 for( const auto& [gateName, egate] : edeviceset->gates )
2039 {
2040 const auto it = aLibrary->symbols.find( egate->symbol );
2041
2042 if( it == aLibrary->symbols.end() )
2043 {
2044 Report( wxString::Format( wxS( "Eagle symbol '%s' not found in library '%s'." ),
2045 egate->symbol, aLibrary->name ) );
2046 continue;
2047 }
2048
2049 wxString gateMapName = edeviceset->name + wxS( "_" ) + edevice->name +
2050 wxS( "_" ) + egate->name;
2051 aEagleLibrary->GateToUnitMap[gateMapName] = gateindex;
2052 ispower = loadSymbol( it->second, libSymbol, edevice, gateindex, egate->name );
2053
2054 gateindex++;
2055 }
2056
2057 libSymbol->SetUnitCount( gate_count );
2058
2059 if( gate_count == 1 && ispower )
2060 libSymbol->SetPower();
2061
2062 // Don't set the footprint field if no package is defined in the Eagle schematic.
2063 if( edevice->package )
2064 {
2065 wxString libName;
2066
2067 if( m_schematic )
2068 {
2069 // assume that footprint library is identical to project name
2070 libName = m_schematic->Prj().GetProjectName();
2071 }
2072 else
2073 {
2074 libName = m_libName;
2075 }
2076
2077 wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
2078
2079 libSymbol->GetFootprintField().SetText( packageString );
2080 }
2081
2082 wxString libName = libSymbol->GetName();
2083 libSymbol->SetName( libName );
2084 libSymbol->SetDescription( deviceSetDescr );
2085
2086 if( m_pi )
2087 {
2088 // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
2089 // Eagle symbol library name to the symbol which should ensure that it is unique.
2090 try
2091 {
2092 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
2093 {
2094 libName = aEagleLibrary->name + wxT( "_" ) + libName;
2095 libName = EscapeString( libName, CTX_LIBID );
2096 libSymbol->SetName( libName );
2097 }
2098
2099 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
2100 new LIB_SYMBOL( *libSymbol.get() ), m_properties.get() );
2101 }
2102 catch(...)
2103 {
2104 // A library symbol cannot be loaded for some reason.
2105 // Just skip this symbol creating an issue.
2106 // The issue will be reported later by the Reporter
2107 }
2108 }
2109
2110 aEagleLibrary->KiCadSymbols[ libName ] = std::move( libSymbol );
2111
2112 // Store information on whether the value of VALUE_FIELD for a part should be
2113 // part/@value or part/@deviceset + part/@device.
2114 m_userValue.emplace( std::make_pair( libName, edeviceset->uservalue == true ) );
2115 }
2116 }
2117
2118 return aEagleLibrary;
2119}
2120
2121
2122bool SCH_IO_EAGLE::loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
2123 std::unique_ptr<LIB_SYMBOL>& aSymbol,
2124 const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
2125 const wxString& aGateName )
2126{
2127 wxCHECK( aEsymbol && aSymbol && aDevice, false );
2128
2129 wxString symbolName = aEsymbol->name;
2130 std::vector<SCH_ITEM*> items;
2131
2132 bool showRefDes = false;
2133 bool showValue = false;
2134 bool ispower = false;
2135 int pincount = 0;
2136
2137 for( const std::unique_ptr<ECIRCLE>& ecircle : aEsymbol->circles )
2138 aSymbol->AddDrawItem( loadSymbolCircle( aSymbol, ecircle, aGateNumber ) );
2139
2140 for( const std::unique_ptr<EPIN>& epin : aEsymbol->pins )
2141 {
2142 std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, epin, aGateNumber ) );
2143 pincount++;
2144
2145 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
2146
2147 if( epin->direction )
2148 {
2149 for( const auto& pinDir : pinDirectionsMap )
2150 {
2151 if( epin->direction->Lower() == pinDir.first )
2152 {
2153 pin->SetType( pinDir.second );
2154
2155 if( pinDir.first == wxT( "sup" ) ) // power supply symbol
2156 ispower = true;
2157
2158 break;
2159 }
2160 }
2161
2162 }
2163
2164 if( aDevice->connects.size() != 0 )
2165 {
2166 for( const std::unique_ptr<ECONNECT>& connect : aDevice->connects )
2167 {
2168 if( connect->gate == aGateName && pin->GetName() == connect->pin )
2169 {
2170 wxArrayString pads = wxSplit( wxString( connect->pad ), ' ' );
2171
2172 pin->SetUnit( aGateNumber );
2173 pin->SetName( escapeName( pin->GetName() ) );
2174
2175 if( pads.GetCount() > 1 )
2176 {
2177 pin->SetNumberTextSize( 0 );
2178 }
2179
2180 for( unsigned i = 0; i < pads.GetCount(); i++ )
2181 {
2182 SCH_PIN* apin = new SCH_PIN( *pin );
2183
2184 wxString padname( pads[i] );
2185 apin->SetNumber( padname );
2186 aSymbol->AddDrawItem( apin );
2187 }
2188
2189 break;
2190 }
2191 }
2192 }
2193 else
2194 {
2195 pin->SetUnit( aGateNumber );
2196 pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
2197 aSymbol->AddDrawItem( pin.release() );
2198 }
2199 }
2200
2201 for( const std::unique_ptr<EPOLYGON>& epolygon : aEsymbol->polygons )
2202 aSymbol->AddDrawItem( loadSymbolPolyLine( aSymbol, epolygon, aGateNumber ) );
2203
2204 for( const std::unique_ptr<ERECT>& erectangle : aEsymbol->rectangles )
2205 aSymbol->AddDrawItem( loadSymbolRectangle( aSymbol, erectangle, aGateNumber ) );
2206
2207 for( const std::unique_ptr<ETEXT>& etext : aEsymbol->texts )
2208 {
2209 std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( aSymbol, etext, aGateNumber ) );
2210
2211 if( libtext->GetText() == wxT( "${REFERENCE}" ) )
2212 {
2213 // Move text & attributes to Reference field and discard LIB_TEXT item
2214 SCH_FIELD* field = aSymbol->GetFieldById( REFERENCE_FIELD );
2215 loadFieldAttributes( field, libtext.get() );
2216
2217 // Show Reference field if Eagle reference was uppercase
2218 showRefDes = etext->text == wxT( ">NAME" );
2219 }
2220 else if( libtext->GetText() == wxT( "${VALUE}" ) )
2221 {
2222 // Move text & attributes to Value field and discard LIB_TEXT item
2223 SCH_FIELD* field = aSymbol->GetFieldById( VALUE_FIELD );
2224 loadFieldAttributes( field, libtext.get() );
2225
2226 // Show Value field if Eagle reference was uppercase
2227 showValue = etext->text == wxT( ">VALUE" );
2228 }
2229 else
2230 {
2231 aSymbol->AddDrawItem( libtext.release() );
2232 }
2233 }
2234
2235 for( const std::unique_ptr<EWIRE>& ewire : aEsymbol->wires )
2236 aSymbol->AddDrawItem( loadSymbolWire( aSymbol, ewire, aGateNumber ) );
2237
2238 for( const std::unique_ptr<EFRAME>& eframe : aEsymbol->frames )
2239 {
2240 std::vector<SCH_ITEM*> frameItems;
2241
2242 loadFrame( eframe, frameItems );
2243
2244 for( SCH_ITEM* item : frameItems )
2245 {
2246 item->SetParent( aSymbol.get() );
2247 item->SetUnit( aGateNumber );
2248 aSymbol->AddDrawItem( item );
2249 }
2250 }
2251
2252 aSymbol->GetFieldById( REFERENCE_FIELD )->SetVisible( showRefDes );
2253 aSymbol->GetFieldById( VALUE_FIELD )->SetVisible( showValue );
2254
2255 return pincount == 1 ? ispower : false;
2256}
2257
2258
2259SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2260 const std::unique_ptr<ECIRCLE>& aCircle,
2261 int aGateNumber )
2262{
2263 wxCHECK( aSymbol && aCircle, nullptr );
2264
2265 // Parse the circle properties
2266 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
2267 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
2268
2269 circle->SetParent( aSymbol.get() );
2270 circle->SetPosition( center );
2271 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
2272 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2273 circle->SetUnit( aGateNumber );
2274
2275 return circle;
2276}
2277
2278
2279SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2280 const std::unique_ptr<ERECT>& aRectangle,
2281 int aGateNumber )
2282{
2283 wxCHECK( aSymbol && aRectangle, nullptr );
2284
2285 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2286
2287 rectangle->SetParent( aSymbol.get() );
2288 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
2289 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
2290
2291 if( aRectangle->rot )
2292 {
2293 VECTOR2I pos( rectangle->GetPosition() );
2294 VECTOR2I end( rectangle->GetEnd() );
2295 VECTOR2I center( rectangle->GetCenter() );
2296
2297 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2298 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2299
2300 rectangle->SetPosition( pos );
2301 rectangle->SetEnd( end );
2302 }
2303
2304 rectangle->SetUnit( aGateNumber );
2305
2306 // Eagle rectangles are filled by definition.
2307 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2308
2309 return rectangle;
2310}
2311
2312
2313SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2314 const std::unique_ptr<EWIRE>& aWire, int aGateNumber )
2315{
2316 wxCHECK( aSymbol && aWire, nullptr );
2317
2318 VECTOR2I begin, end;
2319
2320 begin.x = aWire->x1.ToSchUnits();
2321 begin.y = -aWire->y1.ToSchUnits();
2322 end.x = aWire->x2.ToSchUnits();
2323 end.y = -aWire->y2.ToSchUnits();
2324
2325 if( begin == end )
2326 return nullptr;
2327
2328 // if the wire is an arc
2329 if( aWire->curve )
2330 {
2331 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2332 VECTOR2I center = ConvertArcCenter( begin, end, *aWire->curve * -1 );
2333 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2334 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2335
2336 arc->SetParent( aSymbol.get() );
2337
2338 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2339 if( aWire->cap == EWIRE::FLAT && aWire->width.ToSchUnits() >= 2 * radius )
2340 {
2341 VECTOR2I centerStartVector = ( begin - center ) *
2342 ( aWire->width.ToSchUnits() / radius );
2343 begin = center + centerStartVector;
2344
2345 arc->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2346 arc->SetFillMode( FILL_T::FILLED_SHAPE );
2347 }
2348 else
2349 {
2350 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2351 }
2352
2353 arc->SetCenter( center );
2354 arc->SetStart( begin );
2355 arc->SetArcAngleAndEnd( EDA_ANGLE( *aWire->curve * -1, DEGREES_T ), true );
2356 arc->SetUnit( aGateNumber );
2357
2358 return arc;
2359 }
2360 else
2361 {
2362 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2363
2364 poly->AddPoint( begin );
2365 poly->AddPoint( end );
2366 poly->SetUnit( aGateNumber );
2367 poly->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2368
2369 return poly;
2370 }
2371}
2372
2373
2374SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2375 const std::unique_ptr<EPOLYGON>& aPolygon,
2376 int aGateNumber )
2377{
2378 wxCHECK( aSymbol && aPolygon, nullptr );
2379
2380 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
2381 VECTOR2I pt, prev_pt;
2382 opt_double prev_curve;
2383
2384 poly->SetParent( aSymbol.get() );
2385
2386 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
2387 {
2388 pt = VECTOR2I( evertex->x.ToSchUnits(), evertex->y.ToSchUnits() );
2389
2390 if( prev_curve )
2391 {
2392 SHAPE_ARC arc;
2393 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2394 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2395 }
2396 else
2397 {
2398 poly->AddPoint( pt );
2399 }
2400
2401 prev_pt = pt;
2402 prev_curve = evertex->curve;
2403 }
2404
2405 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2406 poly->SetFillMode( FILL_T::FILLED_SHAPE );
2407 poly->SetUnit( aGateNumber );
2408
2409 return poly;
2410}
2411
2412
2413SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2414 const std::unique_ptr<EPIN>& aPin, int aGateNumber )
2415{
2416 wxCHECK( aSymbol && aPin, nullptr );
2417
2418 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2419 pin->SetPosition( VECTOR2I( aPin->x.ToSchUnits(), -aPin->y.ToSchUnits() ) );
2420 pin->SetName( aPin->name );
2421 pin->SetUnit( aGateNumber );
2422
2423 int roti = aPin->rot ? aPin->rot->degrees : 0;
2424
2425 switch( roti )
2426 {
2427 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2428 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2429 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2430 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2431 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2432 }
2433
2434 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2435
2436 if( aPin->length )
2437 {
2438 wxString length = aPin->length.Get();
2439
2440 if( length == wxT( "short" ) )
2441 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2442 else if( length == wxT( "middle" ) )
2443 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2444 else if( length == wxT( "long" ) )
2445 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2446 else if( length == wxT( "point" ) )
2447 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2448 }
2449
2450 // emulate the visibility of pin elements
2451 if( aPin->visible )
2452 {
2453 wxString visible = aPin->visible.Get();
2454
2455 if( visible == wxT( "off" ) )
2456 {
2457 pin->SetNameTextSize( 0 );
2458 pin->SetNumberTextSize( 0 );
2459 }
2460 else if( visible == wxT( "pad" ) )
2461 {
2462 pin->SetNameTextSize( 0 );
2463 }
2464 else if( visible == wxT( "pin" ) )
2465 {
2466 pin->SetNumberTextSize( 0 );
2467 }
2468
2469 /*
2470 * else if( visible == wxT( "both" ) )
2471 * {
2472 * }
2473 */
2474 }
2475
2476 if( aPin->function )
2477 {
2478 wxString function = aPin->function.Get();
2479
2480 if( function == wxT( "dot" ) )
2481 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2482 else if( function == wxT( "clk" ) )
2483 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2484 else if( function == wxT( "dotclk" ) )
2485 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
2486 }
2487
2488 return pin.release();
2489}
2490
2491
2492SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2493 const std::unique_ptr<ETEXT>& aText, int aGateNumber )
2494{
2495 wxCHECK( aSymbol && aText, nullptr );
2496
2497 std::unique_ptr<SCH_TEXT> libtext = std::make_unique<SCH_TEXT>();
2498
2499 libtext->SetParent( aSymbol.get() );
2500 libtext->SetUnit( aGateNumber );
2501 libtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2502
2503 const wxString& eagleText = aText->text;
2504 wxString adjustedText;
2505 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2506
2507 // Strip the whitespace from both ends of each line.
2508 while( tokenizer.HasMoreTokens() )
2509 {
2510 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2511
2512 if( tokenizer.HasMoreTokens() )
2513 tmp += wxT( "\n" );
2514
2515 adjustedText += tmp;
2516 }
2517
2518 libtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "~" ) ) : adjustedText );
2519
2520 loadTextAttributes( libtext.get(), aText );
2521
2522 return libtext.release();
2523}
2524
2525
2526SCH_TEXT* SCH_IO_EAGLE::loadPlainText( const std::unique_ptr<ETEXT>& aText )
2527{
2528 wxCHECK( aText, nullptr );
2529
2530 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2531
2532 const wxString& eagleText = aText->text;
2533 wxString adjustedText;
2534 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2535
2536 // Strip the whitespace from both ends of each line.
2537 while( tokenizer.HasMoreTokens() )
2538 {
2539 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2540
2541 if( tokenizer.HasMoreTokens() )
2542 tmp += wxT( "\n" );
2543
2544 adjustedText += tmp;
2545 }
2546
2547 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "\" \"" ) )
2548 : escapeName( adjustedText ) );
2549
2550 schtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2551 loadTextAttributes( schtext.get(), aText );
2552 schtext->SetItalic( false );
2553
2554 return schtext.release();
2555}
2556
2557
2559 const std::unique_ptr<ETEXT>& aAttributes ) const
2560{
2561 wxCHECK( aText && aAttributes, /* void */ );
2562
2563 aText->SetTextSize( aAttributes->ConvertSize() );
2564
2565 // Must come after SetTextSize()
2566 if( aAttributes->ratio && aAttributes->ratio.CGet() > 12 )
2567 aText->SetBold( true );
2568
2569 int align = aAttributes->align ? *aAttributes->align : ETEXT::BOTTOM_LEFT;
2570 int degrees = aAttributes->rot ? aAttributes->rot->degrees : 0;
2571 bool mirror = aAttributes->rot ? aAttributes->rot->mirror : false;
2572 bool spin = aAttributes->rot ? aAttributes->rot->spin : false;
2573
2574 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
2575}
2576
2577
2578void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
2579{
2580 wxCHECK( aField && aText, /* void */ );
2581
2582 aField->SetTextPos( aText->GetPosition() );
2583 aField->SetTextSize( aText->GetTextSize() );
2584 aField->SetTextAngle( aText->GetTextAngle() );
2585
2586 // Must come after SetTextSize()
2587 aField->SetBold( aText->IsBold() );
2588 aField->SetItalic( false );
2589
2590 aField->SetVertJustify( aText->GetVertJustify() );
2591 aField->SetHorizJustify( aText->GetHorizJustify() );
2592}
2593
2594
2596{
2597 // Eagle supports detached labels, so a label does not need to be placed on a wire
2598 // to be associated with it. KiCad needs to move them, so the labels actually touch the
2599 // corresponding wires.
2600
2601 // Sort the intersection points to speed up the search process
2602 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
2603
2604 auto onIntersection =
2605 [&]( const VECTOR2I& aPos )
2606 {
2607 return std::binary_search( m_wireIntersections.begin(),
2608 m_wireIntersections.end(), aPos );
2609 };
2610
2611 for( SEG_DESC& segDesc : m_segments )
2612 {
2613 for( SCH_TEXT* label : segDesc.labels )
2614 {
2615 VECTOR2I labelPos( label->GetPosition() );
2616 const SEG* segAttached = segDesc.LabelAttached( label );
2617
2618 if( segAttached && !onIntersection( labelPos ) )
2619 continue; // label is placed correctly
2620
2621 // Move the label to the nearest wire
2622 if( !segAttached )
2623 {
2624 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
2625 segDesc.segs );
2626
2627 if( !segAttached ) // we cannot do anything
2628 continue;
2629 }
2630
2631 // Create a vector pointing in the direction of the wire, 50 mils long
2632 VECTOR2I wireDirection( segAttached->B - segAttached->A );
2633 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
2634 const VECTOR2I origPos( labelPos );
2635
2636 // Flags determining the search direction
2637 bool checkPositive = true, checkNegative = true, move = false;
2638 int trial = 0;
2639
2640 // Be sure the label is not placed on a wire intersection
2641 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
2642 {
2643 move = false;
2644
2645 // Move along the attached wire to find the new label position
2646 if( trial % 2 == 1 )
2647 {
2648 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
2649 move = checkPositive = segAttached->Contains( labelPos );
2650 }
2651 else
2652 {
2653 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
2654 move = checkNegative = segAttached->Contains( labelPos );
2655 }
2656
2657 ++trial;
2658 }
2659
2660 if( move )
2661 label->SetPosition( VECTOR2I( labelPos ) );
2662 }
2663 }
2664
2665 m_segments.clear();
2666 m_wireIntersections.clear();
2667}
2668
2669
2670bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
2671{
2672 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
2673 return false;
2674
2675 return checkHeader( aFileName );
2676}
2677
2678
2679bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
2680{
2681 if( !SCH_IO::CanReadLibrary( aFileName ) )
2682 return false;
2683
2684 return checkHeader( aFileName );
2685}
2686
2687
2688bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
2689{
2690 wxFileInputStream input( aFileName );
2691
2692 if( !input.IsOk() )
2693 return false;
2694
2695 wxTextInputStream text( input );
2696
2697 for( int i = 0; i < 4; i++ )
2698 {
2699 if( input.Eof() )
2700 return false;
2701
2702 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
2703 return true;
2704 }
2705
2706 return false;
2707}
2708
2709
2710void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
2711{
2712 wxCHECK( aWire, /* void */ );
2713
2714 SCH_SCREEN* screen = getCurrentScreen();
2715
2716 wxCHECK( screen, /* void */ );
2717
2718 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
2719 {
2720 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
2721 continue;
2722
2723 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
2724 item->SetPosition( aNewEndPoint );
2725 }
2726}
2727
2728
2730{
2731 // Add bus entry symbols
2732 // TODO: Cleanup this function and break into pieces
2733
2734 // for each wire segment, compare each end with all busses.
2735 // If the wire end is found to end on a bus segment, place a bus entry symbol.
2736
2737 std::vector<SCH_LINE*> buses;
2738 std::vector<SCH_LINE*> wires;
2739
2740 SCH_SCREEN* screen = getCurrentScreen();
2741
2742 wxCHECK( screen, /* void */ );
2743
2744 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
2745 {
2746 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
2747
2748 if( line->IsBus() )
2749 buses.push_back( line );
2750 else if( line->IsWire() )
2751 wires.push_back( line );
2752 }
2753
2754 for( SCH_LINE* wire : wires )
2755 {
2756 VECTOR2I wireStart = wire->GetStartPoint();
2757 VECTOR2I wireEnd = wire->GetEndPoint();
2758
2759 for( SCH_LINE* bus : buses )
2760 {
2761 VECTOR2I busStart = bus->GetStartPoint();
2762 VECTOR2I busEnd = bus->GetEndPoint();
2763
2764 auto entrySize =
2765 []( int signX, int signY ) -> VECTOR2I
2766 {
2769 };
2770
2771 auto testBusHit =
2772 [&]( const VECTOR2I& aPt ) -> bool
2773 {
2774 return TestSegmentHit( aPt, busStart, busEnd, 0 );
2775 };
2776
2777 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
2778 {
2779 // Horizontal wire and vertical bus
2780
2781 if( testBusHit( wireStart ) )
2782 {
2783 // Wire start is on the vertical bus
2784
2785 if( wireEnd.x < busStart.x )
2786 {
2787 /* the end of the wire is to the left of the bus
2788 * ⎥⎢
2789 * ——————⎥⎢
2790 * ⎥⎢
2791 */
2792 VECTOR2I p = wireStart + entrySize( -1, 0 );
2793
2794 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2795 {
2796 /* there is room above the wire for the bus entry
2797 * ⎥⎢
2798 * _____/⎥⎢
2799 * ⎥⎢
2800 */
2801 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2802 busEntry->SetFlags( IS_NEW );
2803 screen->Append( busEntry );
2804 moveLabels( wire, p );
2805 wire->SetStartPoint( p );
2806 }
2807 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2808 {
2809 /* there is room below the wire for the bus entry
2810 * _____ ⎥⎢
2811 * \⎥⎢
2812 * ⎥⎢
2813 */
2814 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2815 busEntry->SetFlags( IS_NEW );
2816 screen->Append( busEntry );
2817 moveLabels( wire, p );
2818 wire->SetStartPoint( p );
2819 }
2820 else
2821 {
2822 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2823 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
2824 screen->Append( marker );
2825 }
2826 }
2827 else
2828 {
2829 /* the wire end is to the right of the bus
2830 * ⎥⎢
2831 * ⎥⎢——————
2832 * ⎥⎢
2833 */
2834 VECTOR2I p = wireStart + entrySize( 1, 0 );
2835
2836 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2837 {
2838 /* There is room above the wire for the bus entry
2839 * ⎥⎢
2840 * ⎥⎢\_____
2841 * ⎥⎢
2842 */
2843 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
2844 busEntry->SetFlags( IS_NEW );
2845 screen->Append( busEntry );
2846 moveLabels( wire, p );
2847 wire->SetStartPoint( p );
2848 }
2849 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2850 {
2851 /* There is room below the wire for the bus entry
2852 * ⎥⎢ _____
2853 * ⎥⎢/
2854 * ⎥⎢
2855 */
2856 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2857 busEntry->SetFlags( IS_NEW );
2858 screen->Append( busEntry );
2859 moveLabels( wire, p );
2860 wire->SetStartPoint( p );
2861 }
2862 else
2863 {
2864 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2865 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
2866 screen->Append( marker );
2867 }
2868 }
2869
2870 break;
2871 }
2872 else if( testBusHit( wireEnd ) )
2873 {
2874 // Wire end is on the vertical bus
2875
2876 if( wireStart.x < busStart.x )
2877 {
2878 /* start of the wire is to the left of the bus
2879 * ⎥⎢
2880 * ——————⎥⎢
2881 * ⎥⎢
2882 */
2883 VECTOR2I p = wireEnd + entrySize( -1, 0 );
2884
2885 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2886 {
2887 /* there is room above the wire for the bus entry
2888 * ⎥⎢
2889 * _____/⎥⎢
2890 * ⎥⎢
2891 */
2892 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2893 busEntry->SetFlags( IS_NEW );
2894 screen->Append( busEntry );
2895 moveLabels( wire, p );
2896 wire->SetEndPoint( p );
2897 }
2898 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2899 {
2900 /* there is room below the wire for the bus entry
2901 * _____ ⎥⎢
2902 * \⎥⎢
2903 * ⎥⎢
2904 */
2905 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2906 busEntry->SetFlags( IS_NEW );
2907 screen->Append( busEntry );
2908 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
2909 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
2910 }
2911 else
2912 {
2913 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2914 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
2915 screen->Append( marker );
2916 }
2917 }
2918 else
2919 {
2920 /* the start of the wire is to the right of the bus
2921 * ⎥⎢
2922 * ⎥⎢——————
2923 * ⎥⎢
2924 */
2925 VECTOR2I p = wireEnd + entrySize( 1, 0 );
2926
2927 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2928 {
2929 /* There is room above the wire for the bus entry
2930 * ⎥⎢
2931 * ⎥⎢\_____
2932 * ⎥⎢
2933 */
2934 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
2935 busEntry->SetFlags( IS_NEW );
2936 screen->Append( busEntry );
2937 moveLabels( wire, p );
2938 wire->SetEndPoint( p );
2939 }
2940 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
2941 {
2942 /* There is room below the wire for the bus entry
2943 * ⎥⎢ _____
2944 * ⎥⎢/
2945 * ⎥⎢
2946 */
2947 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2948 busEntry->SetFlags( IS_NEW );
2949 screen->Append( busEntry );
2950 moveLabels( wire, p );
2951 wire->SetEndPoint( p );
2952 }
2953 else
2954 {
2955 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2956 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
2957 screen->Append( marker );
2958 }
2959 }
2960
2961 break;
2962 }
2963 }
2964 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
2965 {
2966 // Vertical wire and horizontal bus
2967
2968 if( testBusHit( wireStart ) )
2969 {
2970 // Wire start is on the bus
2971
2972 if( wireEnd.y < busStart.y )
2973 {
2974 /* the end of the wire is above the bus
2975 * |
2976 * |
2977 * |
2978 * =======
2979 */
2980 VECTOR2I p = wireStart + entrySize( 0, -1 );
2981
2982 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
2983 {
2984 /* there is room to the left of the wire for the bus entry
2985 * |
2986 * |
2987 * /
2988 * =======
2989 */
2990 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2991 busEntry->SetFlags( IS_NEW );
2992 screen->Append( busEntry );
2993 moveLabels( wire, p );
2994 wire->SetStartPoint( p );
2995 }
2996 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
2997 {
2998 /* there is room to the right of the wire for the bus entry
2999 * |
3000 * |
3001 * \
3002 * =======
3003 */
3004 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3005 busEntry->SetFlags( IS_NEW );
3006 screen->Append( busEntry );
3007 moveLabels( wire, p );
3008 wire->SetStartPoint( p );
3009 }
3010 else
3011 {
3012 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3013 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3014 screen->Append( marker );
3015 }
3016 }
3017 else
3018 {
3019 /* wire end is below the bus
3020 * =======
3021 * |
3022 * |
3023 * |
3024 */
3025 VECTOR2I p = wireStart + entrySize( 0, 1 );
3026
3027 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3028 {
3029 /* there is room to the left of the wire for the bus entry
3030 * =======
3031 * \
3032 * |
3033 * |
3034 */
3035 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3036 busEntry->SetFlags( IS_NEW );
3037 screen->Append( busEntry );
3038 moveLabels( wire, p );
3039 wire->SetStartPoint( p );
3040 }
3041 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3042 {
3043 /* there is room to the right of the wire for the bus entry
3044 * =======
3045 * /
3046 * |
3047 * |
3048 */
3049 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3050 busEntry->SetFlags( IS_NEW );
3051 screen->Append( busEntry );
3052 moveLabels( wire, p );
3053 wire->SetStartPoint( p );
3054 }
3055 else
3056 {
3057 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3058 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3059 screen->Append( marker );
3060 }
3061 }
3062
3063 break;
3064 }
3065 else if( testBusHit( wireEnd ) )
3066 {
3067 // Wire end is on the bus
3068
3069 if( wireStart.y < busStart.y )
3070 {
3071 /* the start of the wire is above the bus
3072 * |
3073 * |
3074 * |
3075 * =======
3076 */
3077 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3078
3079 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3080 {
3081 /* there is room to the left of the wire for the bus entry
3082 * |
3083 * |
3084 * /
3085 * =======
3086 */
3087 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3088 busEntry->SetFlags( IS_NEW );
3089 screen->Append( busEntry );
3090 moveLabels( wire, p );
3091 wire->SetEndPoint( p );
3092 }
3093 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3094 {
3095 /* there is room to the right of the wire for the bus entry
3096 * |
3097 * |
3098 * \
3099 * =======
3100 */
3101 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3102 busEntry->SetFlags( IS_NEW );
3103 screen->Append( busEntry );
3104 moveLabels( wire, p );
3105 wire->SetEndPoint( p );
3106 }
3107 else
3108 {
3109 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3110 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3111 screen->Append( marker );
3112 }
3113 }
3114 else
3115 {
3116 /* wire start is below the bus
3117 * =======
3118 * |
3119 * |
3120 * |
3121 */
3122 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3123
3124 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3125 {
3126 /* there is room to the left of the wire for the bus entry
3127 * =======
3128 * \
3129 * |
3130 * |
3131 */
3132 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3133 busEntry->SetFlags( IS_NEW );
3134 screen->Append( busEntry );
3135 moveLabels( wire, p );
3136 wire->SetEndPoint( p );
3137 }
3138 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3139 {
3140 /* there is room to the right of the wire for the bus entry
3141 * =======
3142 * /
3143 * |
3144 * |
3145 */
3146 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3147 busEntry->SetFlags( IS_NEW );
3148 screen->Append( busEntry );
3149 moveLabels( wire, p );
3150 wire->SetEndPoint( p );
3151 }
3152 else
3153 {
3154 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3155 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3156 screen->Append( marker );
3157 }
3158 }
3159
3160 break;
3161 }
3162 }
3163 else
3164 {
3165 // Wire isn't horizontal or vertical
3166
3167 if( testBusHit( wireStart ) )
3168 {
3169 VECTOR2I wirevector = wireStart - wireEnd;
3170
3171 if( wirevector.x > 0 )
3172 {
3173 if( wirevector.y > 0 )
3174 {
3175 VECTOR2I p = wireStart + entrySize( -1, -1 );
3176 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3177 busEntry->SetFlags( IS_NEW );
3178 screen->Append( busEntry );
3179
3180 moveLabels( wire, p );
3181 wire->SetStartPoint( p );
3182 }
3183 else
3184 {
3185 VECTOR2I p = wireStart + entrySize( -1, 1 );
3186 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3187 busEntry->SetFlags( IS_NEW );
3188 screen->Append( busEntry );
3189
3190 moveLabels( wire, p );
3191 wire->SetStartPoint( p );
3192 }
3193 }
3194 else
3195 {
3196 if( wirevector.y > 0 )
3197 {
3198 VECTOR2I p = wireStart + entrySize( 1, -1 );
3199 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3200 busEntry->SetFlags( IS_NEW );
3201 screen->Append( busEntry );
3202
3203 moveLabels( wire, p );
3204 wire->SetStartPoint( p );
3205 }
3206 else
3207 {
3208 VECTOR2I p = wireStart + entrySize( 1, 1 );
3209 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3210 busEntry->SetFlags( IS_NEW );
3211 screen->Append( busEntry );
3212
3213 moveLabels( wire, p );
3214 wire->SetStartPoint( p );
3215 }
3216 }
3217
3218 break;
3219 }
3220 else if( testBusHit( wireEnd ) )
3221 {
3222 VECTOR2I wirevector = wireStart - wireEnd;
3223
3224 if( wirevector.x > 0 )
3225 {
3226 if( wirevector.y > 0 )
3227 {
3228 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3229 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3230 busEntry->SetFlags( IS_NEW );
3231 screen->Append( busEntry );
3232
3233 moveLabels( wire, p );
3234 wire->SetEndPoint( p );
3235 }
3236 else
3237 {
3238 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3239 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3240 busEntry->SetFlags( IS_NEW );
3241 screen->Append( busEntry );
3242
3243 moveLabels( wire, p );
3244 wire->SetEndPoint( p );
3245 }
3246 }
3247 else
3248 {
3249 if( wirevector.y > 0 )
3250 {
3251 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3252 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3253 busEntry->SetFlags( IS_NEW );
3254 screen->Append( busEntry );
3255
3256 moveLabels( wire, p );
3257 wire->SetEndPoint( p );
3258 }
3259 else
3260 {
3261 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3262 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3263 busEntry->SetFlags( IS_NEW );
3264 screen->Append( busEntry );
3265
3266 moveLabels( wire, p );
3267 wire->SetEndPoint( p );
3268 }
3269 }
3270
3271 break;
3272 }
3273 }
3274 }
3275 }
3276}
3277
3278
3280{
3281 wxCHECK( aLabel, nullptr );
3282
3283 VECTOR2I labelPos( aLabel->GetPosition() );
3284
3285 for( const SEG& seg : segs )
3286 {
3287 if( seg.Contains( labelPos ) )
3288 return &seg;
3289 }
3290
3291 return nullptr;
3292}
3293
3294
3295// TODO could be used to place junctions, instead of IsJunctionNeeded()
3296// (see SCH_EDIT_FRAME::importFile())
3297bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3298{
3299 wxCHECK( aSymbol && aPin, false );
3300
3301 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3302 auto pointIt = m_connPoints.find( pinPosition );
3303
3304 if( pointIt == m_connPoints.end() )
3305 return false;
3306
3307 const auto& items = pointIt->second;
3308
3309 wxCHECK( items.find( aPin ) != items.end(), false );
3310
3311 return items.size() > 1;
3312}
3313
3314
3316 bool aUpdateSet )
3317{
3318 wxCHECK( aSymbol && aScreen && aSymbol->GetLibSymbolRef(), /*void*/ );
3319
3320 // Normally power parts also have power input pins,
3321 // but they already force net names on the attached wires
3322 if( aSymbol->GetLibSymbolRef()->IsPower() )
3323 return;
3324
3325 int unit = aSymbol->GetUnit();
3326 const wxString reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
3327 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetAllLibPins();
3328 std::set<int> missingUnits;
3329
3330 // Search all units for pins creating implicit connections
3331 for( const SCH_PIN* pin : pins )
3332 {
3333 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3334 {
3335 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3336
3337 // Create a global net label only if there are no other wires/pins attached
3338 if( pinInUnit )
3339 {
3340 if( !checkConnections( aSymbol, pin ) )
3341 {
3342 // Create a net label to force the net name on the pin
3343 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3344 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3345 netLabel->SetText( extractNetName( pin->GetName() ) );
3346 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3347 schIUScale.MilsToIU( 40 ) ) );
3348
3349 switch( pin->GetOrientation() )
3350 {
3351 default:
3352 case PIN_ORIENTATION::PIN_RIGHT:
3353 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3354 break;
3355 case PIN_ORIENTATION::PIN_LEFT:
3356 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3357 break;
3358 case PIN_ORIENTATION::PIN_UP:
3359 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3360 break;
3361 case PIN_ORIENTATION::PIN_DOWN:
3362 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3363 break;
3364 }
3365
3366 aScreen->Append( netLabel );
3367 }
3368 }
3369 else if( aUpdateSet )
3370 {
3371 // Found a pin creating implicit connection information in another unit.
3372 // Such units will be instantiated if they do not appear in another sheet and
3373 // processed later.
3374 wxASSERT( pin->GetUnit() );
3375 missingUnits.insert( pin->GetUnit() );
3376 }
3377 }
3378 }
3379
3380 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3381 {
3382 auto cmpIt = m_missingCmps.find( reference );
3383
3384 // The first unit found has always already been processed.
3385 if( cmpIt == m_missingCmps.end() )
3386 {
3387 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3388 entry.cmp = aSymbol;
3389 entry.units.emplace( unit, false );
3390 }
3391 else
3392 {
3393 // Set the flag indicating this unit has been processed.
3394 cmpIt->second.units[unit] = false;
3395 }
3396
3397 if( !missingUnits.empty() ) // Save the units that need later processing
3398 {
3399 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3400 entry.cmp = aSymbol;
3401
3402 // Add units that haven't already been processed.
3403 for( int i : missingUnits )
3404 {
3405 if( entry.units.find( i ) != entry.units.end() )
3406 entry.units.emplace( i, true );
3407 }
3408 }
3409 }
3410}
3411
3412
3413wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3414{
3415 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3416 return aEagleName;
3417
3418 wxString ret = wxT( "{" );
3419
3420 wxStringTokenizer tokenizer( aEagleName, wxT( "," ) );
3421
3422 while( tokenizer.HasMoreTokens() )
3423 {
3424 wxString member = tokenizer.GetNextToken();
3425
3426 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3427 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3428 // if there is an odd number of overbar markers in this net name, we need to append one
3429 // to close it out before appending the space.
3430
3431 if( member.Freq( '!' ) % 2 > 0 )
3432 member << wxT( "!" );
3433
3434 ret << member << wxS( " " );
3435 }
3436
3437 ret.Trim( true );
3438 ret << wxT( "}" );
3439
3440 return ret;
3441}
3442
3443
3444const ESYMBOL* SCH_IO_EAGLE::getEagleSymbol( const std::unique_ptr<EINSTANCE>& aInstance )
3445{
3446 wxCHECK( m_eagleDoc && m_eagleDoc->drawing && m_eagleDoc->drawing->schematic && aInstance,
3447 nullptr );
3448
3449 std::unique_ptr<EPART>& epart = m_eagleDoc->drawing->schematic->parts[aInstance->part];
3450
3451 if( !epart || epart->deviceset.IsEmpty() )
3452 return nullptr;
3453
3454 std::unique_ptr<ELIBRARY>& elibrary = m_eagleDoc->drawing->schematic->libraries[epart->library];
3455
3456 if( !elibrary )
3457 return nullptr;
3458
3459 std::unique_ptr<EDEVICE_SET>& edeviceset = elibrary->devicesets[epart->deviceset];
3460
3461 if( !edeviceset )
3462 return nullptr;
3463
3464 std::unique_ptr<EGATE>& egate = edeviceset->gates[aInstance->gate];
3465
3466 if( !egate )
3467 return nullptr;
3468
3469 std::unique_ptr<ESYMBOL>& esymbol = elibrary->symbols[egate->symbol];
3470
3471 if( esymbol )
3472 return esymbol.get();
3473
3474 return nullptr;
3475}
3476
3477
3478void SCH_IO_EAGLE::getEagleSymbolFieldAttributes( const std::unique_ptr<EINSTANCE>& aInstance,
3479 const wxString& aEagleFieldName,
3480 SCH_FIELD* aField )
3481{
3482 wxCHECK( aField && !aEagleFieldName.IsEmpty(), /* void */ );
3483
3484 const ESYMBOL* esymbol = getEagleSymbol( aInstance );
3485
3486 if( esymbol )
3487 {
3488 for( const std::unique_ptr<ETEXT>& text : esymbol->texts )
3489 {
3490 if( text->text == aEagleFieldName )
3491 {
3492 aField->SetVisible( true );
3493 VECTOR2I pos( text->x.ToSchUnits() + aInstance->x.ToSchUnits(),
3494 -text->y.ToSchUnits() - aInstance->y.ToSchUnits() );
3495
3496 bool mirror = text->rot ? text->rot->mirror : false;
3497
3498 if( aInstance->rot && aInstance->rot->mirror )
3499 mirror = !mirror;
3500
3501 if( mirror )
3502 pos.y = -aInstance->y.ToSchUnits() + text->y.ToSchUnits();
3503
3504 aField->SetPosition( pos );
3505 }
3506 }
3507 }
3508}
const char * name
Definition: DXF_plotter.cpp:57
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
constexpr coord_type GetY() const
Definition: box2.h:208
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:658
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr coord_type GetBottom() const
Definition: box2.h:222
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
const KIID m_Uuid
Definition: eda_item.h:489
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:527
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:279
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:134
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:171
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:673
void SetFillMode(FILL_T aFill)
Definition: eda_shape.h:106
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:130
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:404
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:94
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:449
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:306
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:183
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:275
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition: eda_text.cpp:240
bool IsBold() const
Definition: eda_text.h:167
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:186
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:204
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:212
VECTOR2I GetTextSize() const
Definition: eda_text.h:241
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:298
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
iterator end()
Returns a read/write iterator that points to one past the last element in the EE_RTREE.
Definition: sch_rtree.h:285
iterator begin()
Returns a read/write iterator that points to the first element in the EE_RTREE N.B.
Definition: sch_rtree.h:276
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:298
Used for text file output.
Definition: richio.h:478
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition: io_base.h:218
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:221
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition: io_base.cpp:69
virtual void Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Definition: io_base.cpp:122
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
Define a library symbol object.
Definition: lib_symbol.h:78
bool IsPower() const override
Definition: lib_symbol.cpp:389
void GetFields(std::vector< SCH_FIELD * > &aList)
Return a list of fields within this symbol.
int GetUnitCount() const override
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
void SetHeightMils(double aHeightInMils)
Definition: page_info.cpp:261
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition: page_info.h:171
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:247
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetNumPhases(int aNumPhases)=0
Set the number of phases.
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition: project.cpp:348
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:147
Holds all the data relating to one schematic.
Definition: schematic.h:77
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:194
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:137
SCH_SHEET & Root() const
Definition: schematic.h:121
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:92
Class for a wire to bus entry.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1485
bool IsEmpty()
Return true if both the name and value of the field are empty.
Definition: sch_field.h:163
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1465
void SetName(const wxString &aName)
Definition: sch_field.cpp:1202
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1212
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1908
std::unique_ptr< EAGLE_DOC > m_eagleDoc
Definition: sch_io_eagle.h:298
SCH_ITEM * loadWire(const std::unique_ptr< EWIRE > &aWire, SEG &endpoints)
void loadTextAttributes(EDA_TEXT *aText, const std::unique_ptr< ETEXT > &aAttributes) const
SCH_TEXT * loadLabel(const std::unique_ptr< ELABEL > &aLabel, const wxString &aNetName)
void ensureLoadedLibrary(const wxString &aLibraryPath)
void loadSchematic(const ESCHEMATIC &aSchematic)
SCH_TEXT * loadPlainText(const std::unique_ptr< ETEXT > &aSchText)
void loadSheet(const std::unique_ptr< ESHEET > &aSheet)
void loadLayerDefs(const std::vector< std::unique_ptr< ELAYER > > &aLayers)
const ESYMBOL * getEagleSymbol(const std::unique_ptr< EINSTANCE > &aInstance)
EAGLE_LIBRARY * loadLibrary(const ELIBRARY *aLibrary, EAGLE_LIBRARY *aEagleLib)
wxXmlDocument loadXmlDocument(const wxString &aFileName)
wxString translateEagleBusName(const wxString &aEagleName) const
Translate an Eagle-style bus name into one that is KiCad-compatible.
void loadFieldAttributes(SCH_FIELD *aField, const SCH_TEXT *aText) const
Move net labels that are detached from any wire to the nearest wire.
std::map< wxString, wxString > m_powerPorts
map from symbol reference to global label equivalent
Definition: sch_io_eagle.h:271
SCH_SHEET_PATH m_sheetPath
The current sheet path of the schematic being loaded.
Definition: sch_io_eagle.h:250
wxString m_libName
Library name to save symbols.
Definition: sch_io_eagle.h:253
EMODULE * m_module
The current module being loaded or nullptr.
Definition: sch_io_eagle.h:255
SCH_TEXT * loadSymbolText(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< ETEXT > &aText, int aGateNumber)
std::pair< VECTOR2I, const SEG * > findNearestLinePoint(const VECTOR2I &aPoint, const std::vector< SEG > &aLines) const
const double ARC_ACCURACY
Definition: sch_io_eagle.h:81
std::map< wxString, long long > m_timestamps
Definition: sch_io_eagle.h:258
void adjustNetLabels()
void loadInstance(const std::unique_ptr< EINSTANCE > &aInstance, const std::map< wxString, std::unique_ptr< EPART > > &aParts)
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
std::unordered_map< wxString, bool > m_userValue
deviceset/@uservalue for device.
Definition: sch_io_eagle.h:262
int GetModifyHash() const override
Return the modification hash from the library cache.
std::map< wxString, int > m_netCounts
Definition: sch_io_eagle.h:269
wxFileName m_filename
Definition: sch_io_eagle.h:252
std::map< wxString, EAGLE_LIBRARY > m_eagleLibs
Definition: sch_io_eagle.h:259
bool loadSymbol(const std::unique_ptr< ESYMBOL > &aEsymbol, std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< EDEVICE > &aDevice, int aGateNumber, const wxString &aGateName)
SCH_SHEET * getCurrentSheet()
void loadDrawing(const std::unique_ptr< EDRAWING > &aDrawing)
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
SCH_SHAPE * loadSymbolPolyLine(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< EPOLYGON > &aPolygon, int aGateNumber)
std::vector< VECTOR2I > m_wireIntersections
Wires and labels of a single connection (segment in Eagle nomenclature)
Definition: sch_io_eagle.h:276
std::map< VECTOR2I, std::set< const EDA_ITEM * > > m_connPoints
The fully parsed Eagle schematic file.
Definition: sch_io_eagle.h:295
void loadSegments(const std::vector< std::unique_ptr< ESEGMENT > > &aSegments, const wxString &aNetName, const wxString &aNetClass)
bool checkConnections(const SCH_SYMBOL *aSymbol, const SCH_PIN *aPin) const
std::unique_ptr< std::map< std::string, UTF8 > > m_properties
Library plugin properties.
Definition: sch_io_eagle.h:265
IO_RELEASER< SCH_IO > m_pi
PI to create KiCad symbol library.
Definition: sch_io_eagle.h:264
SCH_SHAPE * loadRectangle(const std::unique_ptr< ERECT > &aRect)
void addBusEntries()
This function finds best way to place a bus entry symbol for when an Eagle wire segment ends on an Ea...
SCH_SHEET * loadModuleInstance(const std::unique_ptr< EMODULEINST > &aModuleInstance)
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_IO can read the specified schematic file.
void addImplicitConnections(SCH_SYMBOL *aSymbol, SCH_SCREEN *aScreen, bool aUpdateSet)
Create net labels to emulate implicit connections in Eagle.
std::map< int, SCH_LAYER_ID > m_layerMap
Definition: sch_io_eagle.h:270
SCH_LAYER_ID kiCadLayer(int aEagleLayer)
Return the matching layer or return LAYER_NOTES.
wxString getLibName()
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,...
SCH_PIN * loadPin(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< EPIN > &aPin, int aGateNumber)
SCH_SHAPE * loadCircle(const std::unique_ptr< ECIRCLE > &aCircle)
wxFileName getLibFileName()
Checks if there are other wires or pins at the position of the tested pin.
SCH_SHAPE * loadSymbolRectangle(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< ERECT > &aRectangle, int aGateNumber)
SCH_JUNCTION * loadJunction(const std::unique_ptr< EJUNCTION > &aJunction)
wxString m_version
Eagle file version.
Definition: sch_io_eagle.h:251
void getEagleSymbolFieldAttributes(const std::unique_ptr< EINSTANCE > &aInstance, const wxString &aEagleFieldName, SCH_FIELD *aField)
std::map< wxString, const EPART * > m_partlist
Definition: sch_io_eagle.h:257
void moveLabels(SCH_LINE *aWire, const VECTOR2I &aNewEndPoint)
Move any labels on the wire to the new end point of the wire.
bool checkHeader(const wxString &aFileName) const
SCHEMATIC * m_schematic
Passed to Load(), the schematic object being loaded.
Definition: sch_io_eagle.h:254
void countNets(const ESCHEMATIC &aSchematic)
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded.
Definition: sch_io_eagle.h:249
SCH_SHAPE * loadPolyLine(const std::unique_ptr< EPOLYGON > &aPolygon)
SCH_SHAPE * loadSymbolCircle(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< ECIRCLE > &aCircle, int aGateNumber)
SCH_SCREEN * getCurrentScreen()
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
std::map< wxString, EAGLE_MISSING_CMP > m_missingCmps
Definition: sch_io_eagle.h:247
void loadFrame(const std::unique_ptr< EFRAME > &aFrame, std::vector< SCH_ITEM * > &aItems)
std::vector< SEG_DESC > m_segments
Nets as defined in the <nets> sections of an Eagle schematic file.
Definition: sch_io_eagle.h:289
SCH_ITEM * loadSymbolWire(std::unique_ptr< LIB_SYMBOL > &aSymbol, const std::unique_ptr< EWIRE > &aWire, int aGateNumber)
long long getLibraryTimestamp(const wxString &aLibraryPath) const
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io.h:57
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition: sch_io.cpp:45
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:166
int GetUnit() const
Definition: sch_item.h:229
virtual void SetUnit(int aUnit)
Definition: sch_item.h:228
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:131
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:178
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:422
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:41
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:977
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_line.cpp:227
VECTOR2I GetEndPoint() const
Definition: sch_line.h:141
VECTOR2I GetStartPoint() const
Definition: sch_line.h:136
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:983
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:142
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:475
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:712
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
const PAGE_INFO & GetPageSettings() const
Definition: sch_screen.h:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:153
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:131
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
const KIID & GetUuid() const
Definition: sch_screen.h:531
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:118
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
Definition: sch_screen.cpp:316
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:71
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
VECTOR2I GetCenter() const
Definition: sch_shape.h:73
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:576
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
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.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
void SetPosition(const VECTOR2I &aPosition) override
void SetSide(SHEET_SIDE aEdge)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:312
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:306
bool LocatePathOfScreen(SCH_SCREEN *aScreen, SCH_SHEET_PATH *aList)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:819
void SetName(const wxString &aName)
Definition: sch_sheet.h:108
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:173
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:664
Schematic symbol object.
Definition: sch_symbol.h:104
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:935
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:212
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
VECTOR2I GetPosition() const override
Definition: sch_text.h:141
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:142
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:254
bool Contains(const SEG &aSeg) const
Definition: seg.h:314
SHAPE_ARC & ConstructFromStartEndAngle(const VECTOR2I &aStart, const VECTOR2I &aEnd, const EDA_ANGLE &aAngle, double aWidth=0)
Construct this arc from the given start, end and angle.
Definition: shape_arc.cpp:194
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
Simple container to manage line stroke parameters.
Definition: stroke_params.h:79
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
static const wxString & GetSymbolLibTableFileName()
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indentation level of aIndentLevel.
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
wxString wx_str() const
Definition: utf8.cpp:45
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
static REPORTER & GetInstance()
Definition: reporter.cpp:199
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
Definition: fontconfig.cpp:64
#define DEFAULT_SCH_ENTRY_SIZE
The default text size in mils. (can be changed in preference menu)
wxString escapeName(const wxString &aNetName)
Interprets special characters in Eagle text and converts them to KiCAD notation.
wxString interpretText(const wxString &aText)
Translates Eagle special text reference to a KiCad variable reference.
size_t GetNodeCount(const wxXmlNode *aNode)
Fetch the number of XML nodes within aNode.
VECTOR2I ConvertArcCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle)
wxString convertDescription(wxString aDescr)
#define _(s)
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:398
#define IS_NEW
New item, just created.
@ ERCE_BUS_ENTRY_NEEDED
Importer failed to auto-place a bus entry.
Definition: erc_settings.h:86
static const std::string KiCadSchematicFileExtension
static const std::string KiCadSymbolLibFileExtension
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:354
@ LAYER_DEVICE
Definition: layer_ids.h:371
@ LAYER_WIRE
Definition: layer_ids.h:357
@ LAYER_NOTES
Definition: layer_ids.h:372
@ LAYER_BUS
Definition: layer_ids.h:358
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
@ PT_INPUT
usual pin input: must be connected
@ PT_NC
not connected (must be left open)
@ PT_OUTPUT
usual output
@ PT_TRISTATE
tris state bus pin
@ PT_BIDI
input or output (like port for a microprocessor)
@ PT_OPENCOLLECTOR
pin type open collector
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin
@ RPT_SEVERITY_ERROR
static wxString extractNetName(const wxString &aPinName)
static const std::map< wxString, ELECTRICAL_PINTYPE > pinDirectionsMap
Map of EAGLE pin type values to KiCad pin type values.
static SYMBOL_ORIENTATION_T kiCadComponentRotation(float eagleDegrees)
static void eagleToKicadAlignment(EDA_TEXT *aText, int aEagleAlignment, int aRelDegress, bool aMirror, bool aSpin, int aAbsDegress)
static BOX2I getSheetBbox(SCH_SHEET *aSheet)
Extract the net name part from a pin name (e.g. return 'GND' for pin named 'GND@2')
LABEL_FLAG_SHAPE
Definition: sch_label.h:98
LABEL_SHAPE
Definition: sch_label.h:116
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
Definition: sch_sheet_pin.h:46
SYMBOL_ORIENTATION_T
enum used in RotationMiroir()
Definition: sch_symbol.h:76
@ SYM_ORIENT_270
Definition: sch_symbol.h:83
@ SYM_ORIENT_180
Definition: sch_symbol.h:82
@ SYM_ORIENT_90
Definition: sch_symbol.h:81
@ SYM_ORIENT_0
Definition: sch_symbol.h:80
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
wxString UnescapeString(const wxString &aSource)
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
wxString UnescapeHTML(const wxString &aString)
Return a new wxString unescaped from HTML format.
@ CTX_LIBID
Definition: string_utils.h:54
@ CTX_NETNAME
Definition: string_utils.h:53
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > KiCadSymbols
Definition: sch_io_eagle.h:59
std::unordered_map< wxString, wxString > package
Definition: sch_io_eagle.h:69
wxString name
Definition: sch_io_eagle.h:58
std::unordered_map< wxString, int > GateToUnitMap
Map Eagle gate unit number (which are strings) to KiCad library symbol unit number.
Definition: sch_io_eagle.h:68
constexpr int IUToMils(int iu) const
Definition: base_units.h:99
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
std::map< wxString, std::unique_ptr< EDEVICE_SET > > devicesets
wxString name
std::map< wxString, std::unique_ptr< ESYMBOL > > symbols
std::map< wxString, std::unique_ptr< EPART > > parts
std::map< wxString, std::unique_ptr< EPORT > > ports
std::map< wxString, std::unique_ptr< EMODULE > > modules
std::vector< std::unique_ptr< ESHEET > > sheets
std::map< wxString, std::unique_ptr< EPART > > parts
std::map< wxString, std::unique_ptr< ELIBRARY > > libraries
std::vector< std::unique_ptr< ETEXT > > texts
@ BOTTOM_CENTER
Definition: eagle_parser.h:928
@ BOTTOM_RIGHT
Definition: eagle_parser.h:930
@ TOP_CENTER
Definition: eagle_parser.h:922
@ TOP_LEFT
Definition: eagle_parser.h:923
@ TOP_RIGHT
Definition: eagle_parser.h:924
@ CENTER_RIGHT
Definition: eagle_parser.h:927
@ CENTER_LEFT
Definition: eagle_parser.h:921
@ BOTTOM_LEFT
Definition: eagle_parser.h:929
Map references to missing symbol units data.
Definition: sch_io_eagle.h:230
std::map< int, bool > units
Definition: sch_io_eagle.h:243
Segments representing wires for intersection checking.
Definition: sch_io_eagle.h:280
std::vector< SEG > segs
Definition: sch_io_eagle.h:285
std::vector< SCH_TEXT * > labels
Definition: sch_io_eagle.h:284
const SEG * LabelAttached(const SCH_TEXT *aLabel) const
< Test if a particular label is attached to any of the stored segments
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:175
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
Definition of file extensions used in Kicad.