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