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