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