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