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
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
121 m_libName = m_schematic->Project().GetProjectName();
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 {
174
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
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
363 if( !m_progressReporter->KeepRefreshing() )
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.
420 m_sheetPath.push_back( m_rootSheet );
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.
453 m_schematic->Project().SetElem( PROJECT::ELEM::SYMBOL_LIB_TABLE, nullptr );
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
563 if( !m_progressReporter->KeepRefreshing() )
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 );
730 m_sheetPath.pop_back();
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
761 VECTOR2I pageSizeIU = m_rootSheet->GetScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
762 BOX2I sheetBbox = getSheetBbox( m_rootSheet );
763 VECTOR2I newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() );
764 int maxY = sheetBbox.GetY();
765
766 SCH_SHEET_PATH sheetpath;
767 m_rootSheet->LocatePathOfScreen( m_rootSheet->GetScreen(), &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();
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
1070
1071 if( port->direction )
1072 {
1073 if( *port->direction == "in" )
1074 pinType = LABEL_FLAG_SHAPE::L_INPUT;
1075 else if( *port->direction == "out" )
1077 else if( *port->direction == "io" )
1078 pinType = LABEL_FLAG_SHAPE::L_BIDI;
1079 else if( *port->direction == "hiz" )
1081 else
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();
1145 m_sheetPath.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" )
1618 else if( direction == "out" )
1620 else if( direction == "io" )
1622 else if( direction == "hiz" )
1624 else
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, true );
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, true );
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
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 {
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
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 {
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 ) );
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" ) )
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 {
2798 return VECTOR2I( schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signX,
2799 schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signY );
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:
3376 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3377 break;
3379 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3380 break;
3382 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3383 break;
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, "," );
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
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
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
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
void SetCenter(const VECTOR2I &aCenter)
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.
void SetFillMode(FILL_T aFill)
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:146
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:534
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:579
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:418
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:199
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:387
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:336
bool IsBold() const
Definition eda_text.h:183
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:202
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:271
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:300
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:308
VECTOR2I GetTextSize() const
Definition eda_text.h:260
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:410
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition sch_rtree.h:246
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:307
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.
std::vector< SCH_PIN * > GetPins() const override
bool IsGlobalPower() const override
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:79
void SetHeightMils(double aHeightInMils)
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition page_info.h:177
void SetWidthMils(double aWidthInMils)
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
@ SYMBOL_LIB_TABLE
Definition project.h:77
Holds all the data relating to one schematic.
Definition schematic.h:88
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:156
SCH_SHEET & Root() const
Definition schematic.h:140
Class for a wire to bus entry.
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
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
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
std::unique_ptr< EAGLE_DOC > m_eagleDoc
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
SCH_SHEET_PATH m_sheetPath
The current sheet path of the schematic being loaded.
wxString m_libName
Library name to save symbols.
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
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.
int GetModifyHash() const override
Return the modification hash from the library cache.
std::map< wxString, int > m_netCounts
wxFileName m_filename
std::map< wxString, EAGLE_LIBRARY > m_eagleLibs
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)
std::map< VECTOR2I, std::set< const EDA_ITEM * > > m_connPoints
The fully parsed Eagle schematic file.
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.
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
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.
void getEagleSymbolFieldAttributes(const std::unique_ptr< EINSTANCE > &aInstance, const wxString &aEagleFieldName, SCH_FIELD *aField)
std::map< wxString, const EPART * > m_partlist
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.
void countNets(const ESCHEMATIC &aSchematic)
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded.
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
void loadFrame(const std::unique_ptr< EFRAME > &aFrame, std::vector< SCH_ITEM * > &aItems)
const int ARC_ACCURACY
std::vector< SEG_DESC > m_segments
Nets as defined in the <nets> sections of an Eagle schematic file.
std::vector< EMODULE * > m_modules
The current module stack being loaded.
std::vector< EMODULEINST * > m_moduleInstances
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 ...
virtual bool CanReadSchematicFile(const wxString &aFileName) const
Checks if this SCH_IO can read the specified schematic file.
Definition sch_io.cpp:45
SCH_IO(const wxString &aName)
Definition sch_io.h:373
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
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:238
virtual void SetUnit(int aUnit)
Definition sch_item.h:237
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:181
void SetPosition(const VECTOR2I &aPosition) override
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:961
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition sch_line.cpp:231
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:967
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:145
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:633
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)
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.
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:86
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:61
VECTOR2I GetCenter() const
Definition sch_shape.h:88
void AddPoint(const VECTOR2I &aPosition)
VECTOR2I GetPosition() const override
Definition sch_shape.h:85
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.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
void SetPosition(const VECTOR2I &aPosition) override
void SetSide(SHEET_SIDE aEdge)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:327
void SetName(const wxString &aName)
Definition sch_sheet.h:114
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:116
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
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.
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.
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:437
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.
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.
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:190
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
#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.
OPTIONAL_XML_ATTRIBUTE< double > opt_double
#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.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
@ ERCE_BUS_ENTRY_NEEDED
Importer failed to auto-place a bus entry.
static const std::string KiCadSchematicFileExtension
static const std::string KiCadSymbolLibFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:448
@ LAYER_DEVICE
Definition layer_ids.h:465
@ LAYER_WIRE
Definition layer_ids.h:451
@ LAYER_NOTES
Definition layer_ids.h:466
@ LAYER_BUS
Definition layer_ids.h:452
STL namespace.
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:37
@ PT_NC
not connected (must be left open)
Definition pin_type.h:50
@ PT_OUTPUT
usual output
Definition pin_type.h:38
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:39
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:48
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:46
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:43
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:127
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:135
@ RPT_SEVERITY_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:70
LABEL_FLAG_SHAPE
Definition sch_label.h:99
@ L_BIDI
Definition sch_label.h:102
@ L_TRISTATE
Definition sch_label.h:103
@ L_UNSPECIFIED
Definition sch_label.h:104
@ L_OUTPUT
Definition sch_label.h:101
@ L_INPUT
Definition sch_label.h:100
LABEL_SHAPE
Definition sch_label.h:117
@ LABEL_BIDI
Definition sch_label.h:120
@ LABEL_INPUT
Definition sch_label.h:118
@ LABEL_OUTPUT
Definition sch_label.h:119
@ LABEL_PASSIVE
Definition sch_label.h:122
@ LABEL_TRISTATE
Definition sch_label.h:121
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.
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
@ CTX_NETNAME
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > KiCadSymbols
std::unordered_map< wxString, wxString > package
wxString name
std::unordered_map< wxString, int > GateToUnitMap
Map Eagle gate unit number (which are strings) to KiCad library symbol unit number.
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
@ BOTTOM_RIGHT
@ CENTER_RIGHT
@ CENTER_LEFT
@ BOTTOM_LEFT
Map references to missing symbol units data.
std::map< int, bool > units
Segments representing wires for intersection checking.
std::vector< SEG > segs
std::vector< SCH_TEXT * > labels
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
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
@ 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:165
@ SCH_SYMBOL_T
Definition typeinfo.h:174
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
Definition of file extensions used in Kicad.