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 = KiROUND( aLabel->size.ToSchUnits() * 0.7, aLabel->size.ToSchUnits() * 0.7 );
1625
1626 if( m_modules.size() )
1627 {
1628 if( m_modules.back()->ports.find( aNetName ) != m_modules.back()->ports.end() )
1629 {
1630 label = std::make_unique<SCH_HIERLABEL>();
1631 label->SetText( escapeName( aNetName ) );
1632
1633 const auto it = m_modules.back()->ports.find( aNetName );
1634
1635 LABEL_SHAPE type;
1636
1637 if( it->second->direction )
1638 {
1639 wxString direction = *it->second->direction;
1640
1641 if( direction == "in" )
1643 else if( direction == "out" )
1645 else if( direction == "io" )
1647 else if( direction == "hiz" )
1649 else
1651
1652 // KiCad does not support passive, power, open collector, or no-connect sheet
1653 // pins that Eagle ports support. They are set to unspecified to minimize
1654 // ERC issues.
1655 label->SetLabelShape( type );
1656 }
1657 }
1658 else
1659 {
1660 label = std::make_unique<SCH_LABEL>();
1661 label->SetText( escapeName( aNetName ) );
1662 }
1663 }
1664 else if( global )
1665 {
1666 label = std::make_unique<SCH_GLOBALLABEL>();
1667 label->SetText( escapeName( aNetName ) );
1668 }
1669 else
1670 {
1671 label = std::make_unique<SCH_LABEL>();
1672 label->SetText( escapeName( aNetName ) );
1673 }
1674
1675 label->SetPosition( elabelpos );
1676 label->SetTextSize( textSize );
1677 label->SetSpinStyle( SPIN_STYLE::RIGHT );
1678
1679 if( aLabel->rot )
1680 {
1681 for( int i = 0; i < KiROUND( aLabel->rot->degrees / 90.0 ) %4; ++i )
1682 label->Rotate90( false );
1683
1684 if( aLabel->rot->mirror )
1685 label->MirrorSpinStyle( false );
1686 }
1687
1688 return label.release();
1689}
1690
1691
1692std::pair<VECTOR2I, const SEG*>
1694 const std::vector<SEG>& aLines ) const
1695{
1696 VECTOR2I nearestPoint;
1697 const SEG* nearestLine = nullptr;
1698
1699 double d, mindistance = std::numeric_limits<double>::max();
1700
1701 // Find the nearest start, middle or end of a line from the list of lines.
1702 for( const SEG& line : aLines )
1703 {
1704 VECTOR2I testpoint = line.A;
1705 d = aPoint.Distance( testpoint );
1706
1707 if( d < mindistance )
1708 {
1709 mindistance = d;
1710 nearestPoint = testpoint;
1711 nearestLine = &line;
1712 }
1713
1714 testpoint = line.Center();
1715 d = aPoint.Distance( testpoint );
1716
1717 if( d < mindistance )
1718 {
1719 mindistance = d;
1720 nearestPoint = testpoint;
1721 nearestLine = &line;
1722 }
1723
1724 testpoint = line.B;
1725 d = aPoint.Distance( testpoint );
1726
1727 if( d < mindistance )
1728 {
1729 mindistance = d;
1730 nearestPoint = testpoint;
1731 nearestLine = &line;
1732 }
1733 }
1734
1735 return std::make_pair( nearestPoint, nearestLine );
1736}
1737
1738
1739void SCH_IO_EAGLE::loadInstance( const std::unique_ptr<EINSTANCE>& aInstance,
1740 const std::map<wxString, std::unique_ptr<EPART>>& aParts )
1741{
1742 wxCHECK( aInstance, /* void */ );
1743
1744 SCH_SCREEN* screen = getCurrentScreen();
1745
1746 wxCHECK( screen, /* void */ );
1747
1748 const auto partIt = aParts.find( aInstance->part );
1749
1750 if( partIt == aParts.end() )
1751 {
1752 Report( wxString::Format( _( "Error parsing Eagle file. Could not find '%s' "
1753 "instance but it is referenced in the schematic." ),
1754 aInstance->part ),
1756
1757 return;
1758 }
1759
1760 const std::unique_ptr<EPART>& epart = partIt->second;
1761
1762 wxString libName = epart->library;
1763
1764 // Correctly handle versioned libraries.
1765 if( epart->libraryUrn )
1766 libName += wxS( "_" ) + epart->libraryUrn->assetId;
1767
1768 wxString gatename = epart->deviceset + wxS( "_" ) + epart->device + wxS( "_" ) +
1769 aInstance->gate;
1770 wxString symbolname = wxString( epart->deviceset + epart->device );
1771 symbolname.Replace( wxT( "*" ), wxEmptyString );
1772 wxString kisymbolname = EscapeString( symbolname, CTX_LIBID );
1773
1774 // Eagle schematics can have multiple libraries containing symbols with duplicate symbol
1775 // names. Because this parser stores all of the symbols in a single library, the
1776 // loadSymbol() function, prefixed the original Eagle library name to the symbol name
1777 // in case of a name clash. Check for the prefixed symbol first. This ensures that
1778 // the correct library symbol gets mapped on load.
1779 wxString altSymbolName = libName + wxT( "_" ) + symbolname;
1780 altSymbolName = EscapeString( altSymbolName, CTX_LIBID );
1781
1782 wxString libIdSymbolName = altSymbolName;
1783
1784 const auto libIt = m_eagleLibs.find( libName );
1785
1786 if( libIt == m_eagleLibs.end() )
1787 {
1788 Report( wxString::Format( wxS( "Eagle library '%s' not found while looking up symbol for "
1789 "deviceset '%s', device '%s', and gate '%s." ),
1790 libName, epart->deviceset, epart->device, aInstance->gate ) );
1791 return;
1792 }
1793
1794 const auto gateIt = libIt->second.GateToUnitMap.find( gatename );
1795
1796 if( gateIt == libIt->second.GateToUnitMap.end() )
1797 {
1798 Report( wxString::Format( wxS( "Symbol not found for deviceset '%s', device '%s', and "
1799 "gate '%s in library '%s'." ),
1800 epart->deviceset, epart->device, aInstance->gate, libName ) );
1801 return;
1802 }
1803
1804 int unit = gateIt->second;
1805
1806 wxString package;
1807 EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
1808
1809 auto p = elib->package.find( kisymbolname );
1810
1811 if( p != elib->package.end() )
1812 package = p->second;
1813
1814 // set properties to prevent save file on every symbol save
1815 std::map<std::string, UTF8> properties;
1816 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
1817
1818 LIB_SYMBOL* part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), altSymbolName, &properties );
1819
1820 if( !part )
1821 {
1822 part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname, &properties );
1823 libIdSymbolName = kisymbolname;
1824 }
1825
1826 if( !part )
1827 {
1828 Report( wxString::Format( _( "Could not find '%s' in the imported library." ),
1829 UnescapeString( kisymbolname ) ),
1831 return;
1832 }
1833
1834 LIB_ID libId( getLibName(), libIdSymbolName );
1835 std::unique_ptr<SCH_SYMBOL> symbol = std::make_unique<SCH_SYMBOL>();
1836 symbol->SetLibId( libId );
1837 symbol->SetUnit( unit );
1838 symbol->SetPosition( VECTOR2I( aInstance->x.ToSchUnits(), -aInstance->y.ToSchUnits() ) );
1839
1840 // assume that footprint library is identical to project name
1841 if( !package.IsEmpty() )
1842 {
1843 wxString footprint = m_schematic->Project().GetProjectName() + wxT( ":" ) + package;
1844 symbol->GetField( FIELD_T::FOOTPRINT )->SetText( footprint );
1845 }
1846
1847 if( aInstance->rot )
1848 {
1849 symbol->SetOrientation( kiCadComponentRotation( aInstance->rot->degrees ) );
1850
1851 if( aInstance->rot->mirror )
1852 symbol->MirrorHorizontally( aInstance->x.ToSchUnits() );
1853 }
1854
1855 std::vector<SCH_FIELD*> partFields;
1856 part->GetFields( partFields );
1857
1858 for( const SCH_FIELD* partField : partFields )
1859 {
1860 SCH_FIELD* symbolField;
1861
1862 if( partField->IsMandatory() )
1863 symbolField = symbol->GetField( partField->GetId() );
1864 else
1865 symbolField = symbol->GetField( partField->GetName() );
1866
1867 wxCHECK2( symbolField, continue );
1868
1869 symbolField->ImportValues( *partField );
1870 symbolField->SetTextPos( symbol->GetPosition() + partField->GetTextPos() );
1871 }
1872
1873 // If there is no footprint assigned, then prepend the reference value
1874 // with a hash character to mute netlist updater complaints
1875 wxString reference = package.IsEmpty() ? '#' + aInstance->part : aInstance->part;
1876
1877 // reference must end with a number but EAGLE does not enforce this
1878 if( reference.find_last_not_of( wxT( "0123456789" ) ) == ( reference.Length()-1 ) )
1879 reference.Append( wxT( "0" ) );
1880
1881 // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
1882 // parts to have non-digit + digit annotation. If the reference begins with a number,
1883 // we prepend 'UNK' (unknown) for the symbol designator
1884 if( reference.find_first_not_of( wxT( "0123456789" ) ) != 0 )
1885 reference.Prepend( wxT( "UNK" ) );
1886
1887 // EAGLE allows designator to start with # but that is used in KiCad
1888 // for symbols which do not have a footprint
1889 if( aInstance->part.find_first_not_of( wxT( "#" ) ) != 0 )
1890 reference.Prepend( wxT( "UNK" ) );
1891
1892 SCH_FIELD* referenceField = symbol->GetField( FIELD_T::REFERENCE );
1893 referenceField->SetText( reference );
1894
1895 SCH_FIELD* valueField = symbol->GetField( FIELD_T::VALUE );
1896 bool userValue = m_userValue.at( libIdSymbolName );
1897
1898 if( part->GetUnitCount() > 1 )
1899 {
1900 getEagleSymbolFieldAttributes( aInstance, wxS( ">NAME" ), referenceField );
1901 getEagleSymbolFieldAttributes( aInstance, wxS( ">VALUE" ), valueField );
1902 }
1903
1904 if( epart->value && !epart->value.CGet().IsEmpty() )
1905 {
1906 valueField->SetText( *epart->value );
1907 }
1908 else
1909 {
1910 valueField->SetText( kisymbolname );
1911
1912 if( userValue )
1913 valueField->SetVisible( false );
1914 }
1915
1916 for( const auto& [ attrName, attr ] : epart->attributes )
1917 {
1918 SCH_FIELD newField( symbol.get(), FIELD_T::USER );
1919
1920 newField.SetName( attrName );
1921
1922 if( !symbol->GetFields().empty() )
1923 newField.SetTextPos( symbol->GetFields().back().GetPosition() );
1924
1925 if( attr->value )
1926 newField.SetText( *attr->value );
1927
1928 newField.SetVisible( ( attr->display == EATTR::Off ) ? false : true );
1929
1930 symbol->AddField( newField );
1931 }
1932
1933 for( const auto& [variantName, variant] : epart->variants )
1934 {
1935 SCH_FIELD* field = symbol->AddField( *symbol->GetField( FIELD_T::VALUE ) );
1936 field->SetName( wxT( "VARIANT_" ) + variant->name );
1937
1938 if( variant->value )
1939 field->SetText( *variant->value );
1940
1941 field->SetVisible( false );
1942 }
1943
1944 bool valueAttributeFound = false;
1945 bool nameAttributeFound = false;
1946
1947 // Parse attributes for the instance
1948 for( auto& [name, eattr] : aInstance->attributes )
1949 {
1950 SCH_FIELD* field = nullptr;
1951
1952 if( eattr->name.Lower() == wxT( "name" ) )
1953 {
1954 field = symbol->GetField( FIELD_T::REFERENCE );
1955 nameAttributeFound = true;
1956 }
1957 else if( eattr->name.Lower() == wxT( "value" ) )
1958 {
1959 field = symbol->GetField( FIELD_T::VALUE );
1960 valueAttributeFound = true;
1961 }
1962 else
1963 {
1964 field = symbol->GetField( eattr->name );
1965
1966 if( field )
1967 field->SetVisible( false );
1968 }
1969
1970 if( field )
1971 {
1972 field->SetPosition( VECTOR2I( eattr->x->ToSchUnits(), -eattr->y->ToSchUnits() ) );
1973 int align = eattr->align ? *eattr->align : ETEXT::BOTTOM_LEFT;
1974 int absdegrees = eattr->rot ? eattr->rot->degrees : 0;
1975 bool mirror = eattr->rot ? eattr->rot->mirror : false;
1976
1977 if( aInstance->rot && aInstance->rot->mirror )
1978 mirror = !mirror;
1979
1980 bool spin = eattr->rot ? eattr->rot->spin : false;
1981
1982 if( eattr->display == EATTR::Off || eattr->display == EATTR::NAME )
1983 field->SetVisible( false );
1984
1985 int rotation = aInstance->rot ? aInstance->rot->degrees : 0;
1986 int reldegrees = ( absdegrees - rotation + 360.0 );
1987 reldegrees %= 360;
1988
1989 eagleToKicadAlignment( field, align, reldegrees, mirror, spin, absdegrees );
1990 }
1991 }
1992
1993 // Use the instance attribute to determine the reference and value field visibility.
1994 if( aInstance->smashed && aInstance->smashed.Get() )
1995 {
1996 symbol->GetField( FIELD_T::VALUE )->SetVisible( valueAttributeFound );
1997 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( nameAttributeFound );
1998 }
1999
2000 // Eagle has a brain dead module reference scheme where the module names separated by colons
2001 // are prefixed to the symbol references. This will get blown away in KiCad the first time
2002 // any annotation is performed. It is required for the initial synchronization between the
2003 // schematic and the board.
2004 wxString refPrefix;
2005
2006 for( const EMODULEINST* emoduleInst : m_moduleInstances )
2007 {
2008 wxCHECK2( emoduleInst, continue );
2009
2010 refPrefix += emoduleInst->name + wxS( ":" );
2011 }
2012
2013 symbol->AddHierarchicalReference( m_sheetPath.Path(), refPrefix + reference, unit );
2014
2015 // Save the pin positions
2016 LIB_SYMBOL* libSymbol =
2017 PROJECT_SCH::SymbolLibAdapter( &m_schematic->Project() )->LoadSymbol( symbol->GetLibId() );
2018
2019 wxCHECK( libSymbol, /*void*/ );
2020
2021 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
2022
2023 for( const SCH_PIN* pin : symbol->GetLibPins() )
2024 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
2025
2026 if( part->IsGlobalPower() )
2027 m_powerPorts[ reference ] = symbol->GetField( FIELD_T::VALUE )->GetText();
2028
2029 symbol->ClearFlags();
2030
2031 screen->Append( symbol.release() );
2032}
2033
2034
2036{
2037 wxCHECK( aLibrary && aEagleLibrary, nullptr );
2038
2039 // Loop through the device sets and load each of them
2040 for( const auto& [name, edeviceset] : aLibrary->devicesets )
2041 {
2042 // Get Device set information
2043 wxString prefix = edeviceset->prefix ? edeviceset->prefix.Get() : wxString( wxT( "" ) );
2044 wxString deviceSetDescr;
2045
2046 if( edeviceset->description )
2047 deviceSetDescr = convertDescription( UnescapeHTML( edeviceset->description->text ) );
2048
2049 // For each device in the device set:
2050 for( const std::unique_ptr<EDEVICE>& edevice : edeviceset->devices )
2051 {
2052 // Create symbol name from deviceset and device names.
2053 wxString symbolName = edeviceset->name + edevice->name;
2054 symbolName.Replace( wxT( "*" ), wxEmptyString );
2055 wxASSERT( !symbolName.IsEmpty() );
2056 symbolName = EscapeString( symbolName, CTX_LIBID );
2057
2058 if( edevice->package )
2059 aEagleLibrary->package[symbolName] = edevice->package.Get();
2060
2061 // Create KiCad symbol.
2062 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2063
2064 // Process each gate in the deviceset for this device.
2065 int gate_count = static_cast<int>( edeviceset->gates.size() );
2066 libSymbol->SetUnitCount( gate_count, true );
2067 libSymbol->LockUnits( true );
2068
2069 SCH_FIELD* reference = libSymbol->GetField( FIELD_T::REFERENCE );
2070
2071 if( prefix.length() == 0 )
2072 {
2073 reference->SetVisible( false );
2074 }
2075 else
2076 {
2077 // If there is no footprint assigned, then prepend the reference value
2078 // with a hash character to mute netlist updater complaints
2079 reference->SetText( edevice->package ? prefix : '#' + prefix );
2080 }
2081
2082 libSymbol->GetValueField().SetVisible( true );
2083
2084 int gateindex = 1;
2085 bool ispower = false;
2086
2087 for( const auto& [gateName, egate] : edeviceset->gates )
2088 {
2089 const auto it = aLibrary->symbols.find( egate->symbol );
2090
2091 if( it == aLibrary->symbols.end() )
2092 {
2093 Report( wxString::Format( wxS( "Eagle symbol '%s' not found in library '%s'." ),
2094 egate->symbol, aLibrary->GetName() ) );
2095 continue;
2096 }
2097
2098 wxString gateMapName = edeviceset->name + wxS( "_" ) + edevice->name +
2099 wxS( "_" ) + egate->name;
2100 aEagleLibrary->GateToUnitMap[gateMapName] = gateindex;
2101 ispower = loadSymbol( it->second, libSymbol, edevice, gateindex, egate->name );
2102
2103 gateindex++;
2104 }
2105
2106 libSymbol->SetUnitCount( gate_count, true );
2107
2108 if( gate_count == 1 && ispower )
2109 libSymbol->SetGlobalPower();
2110
2111 // Don't set the footprint field if no package is defined in the Eagle schematic.
2112 if( edevice->package )
2113 {
2114 wxString libName;
2115
2116 if( m_schematic )
2117 {
2118 // assume that footprint library is identical to project name
2119 libName = m_schematic->Project().GetProjectName();
2120 }
2121 else
2122 {
2123 libName = m_libName;
2124 }
2125
2126 wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
2127
2128 libSymbol->GetFootprintField().SetText( packageString );
2129 }
2130
2131 wxString libName = libSymbol->GetName();
2132 libSymbol->SetName( libName );
2133 libSymbol->SetDescription( deviceSetDescr );
2134
2135 if( m_pi )
2136 {
2137 // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
2138 // Eagle symbol library name to the symbol which should ensure that it is unique.
2139 try
2140 {
2141 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
2142 {
2143 libName = aEagleLibrary->name + wxT( "_" ) + libName;
2144 libName = EscapeString( libName, CTX_LIBID );
2145 libSymbol->SetName( libName );
2146 }
2147
2148 // set properties to prevent save file on every symbol save
2149 std::map<std::string, UTF8> properties;
2150 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
2151
2152 m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_SYMBOL( *libSymbol.get() ),
2153 &properties );
2154 }
2155 catch(...)
2156 {
2157 // A library symbol cannot be loaded for some reason.
2158 // Just skip this symbol creating an issue.
2159 // The issue will be reported later by the Reporter
2160 }
2161 }
2162
2163 aEagleLibrary->KiCadSymbols[ libName ] = std::move( libSymbol );
2164
2165 // Store information on whether the value of FIELD_T::VALUE for a part should be
2166 // part/@value or part/@deviceset + part/@device.
2167 m_userValue.emplace( std::make_pair( libName, edeviceset->uservalue == true ) );
2168 }
2169 }
2170
2171 return aEagleLibrary;
2172}
2173
2174
2175bool SCH_IO_EAGLE::loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
2176 std::unique_ptr<LIB_SYMBOL>& aSymbol,
2177 const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
2178 const wxString& aGateName )
2179{
2180 wxCHECK( aEsymbol && aSymbol && aDevice, false );
2181
2182 std::vector<SCH_ITEM*> items;
2183
2184 bool showRefDes = false;
2185 bool showValue = false;
2186 bool ispower = false;
2187 int pincount = 0;
2188
2189 for( const std::unique_ptr<ECIRCLE>& ecircle : aEsymbol->circles )
2190 aSymbol->AddDrawItem( loadSymbolCircle( aSymbol, ecircle, aGateNumber ) );
2191
2192 for( const std::unique_ptr<EPIN>& epin : aEsymbol->pins )
2193 {
2194 std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, epin, aGateNumber ) );
2195 pincount++;
2196
2197 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
2198
2199 if( epin->direction )
2200 {
2201 for( const auto& pinDir : pinDirectionsMap )
2202 {
2203 if( epin->direction->Lower() == pinDir.first )
2204 {
2205 pin->SetType( pinDir.second );
2206
2207 if( pinDir.first == wxT( "sup" ) ) // power supply symbol
2208 ispower = true;
2209
2210 break;
2211 }
2212 }
2213
2214 }
2215
2216 if( aDevice->connects.size() != 0 )
2217 {
2218 for( const std::unique_ptr<ECONNECT>& connect : aDevice->connects )
2219 {
2220 if( connect->gate == aGateName && pin->GetName() == connect->pin )
2221 {
2222 wxArrayString pads = wxSplit( wxString( connect->pad ), ' ' );
2223
2224 pin->SetUnit( aGateNumber );
2225 pin->SetName( escapeName( pin->GetName() ) );
2226
2227 if( pads.GetCount() > 1 )
2228 {
2229 pin->SetNumberTextSize( 0 );
2230 }
2231
2232 for( unsigned i = 0; i < pads.GetCount(); i++ )
2233 {
2234 SCH_PIN* apin = new SCH_PIN( *pin );
2235
2236 wxString padname( pads[i] );
2237 apin->SetNumber( padname );
2238 aSymbol->AddDrawItem( apin );
2239 }
2240
2241 break;
2242 }
2243 }
2244 }
2245 else
2246 {
2247 pin->SetUnit( aGateNumber );
2248 pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
2249 aSymbol->AddDrawItem( pin.release() );
2250 }
2251 }
2252
2253 for( const std::unique_ptr<EPOLYGON>& epolygon : aEsymbol->polygons )
2254 aSymbol->AddDrawItem( loadSymbolPolyLine( aSymbol, epolygon, aGateNumber ) );
2255
2256 for( const std::unique_ptr<ERECT>& erectangle : aEsymbol->rectangles )
2257 aSymbol->AddDrawItem( loadSymbolRectangle( aSymbol, erectangle, aGateNumber ) );
2258
2259 for( const std::unique_ptr<ETEXT>& etext : aEsymbol->texts )
2260 {
2261 std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( aSymbol, etext, aGateNumber ) );
2262
2263 if( libtext->GetText() == wxT( "${REFERENCE}" ) )
2264 {
2265 // Move text & attributes to Reference field and discard LIB_TEXT item
2266 loadFieldAttributes( &aSymbol->GetReferenceField(), libtext.get() );
2267
2268 // Show Reference field if Eagle reference was uppercase
2269 showRefDes = etext->text == wxT( ">NAME" );
2270 }
2271 else if( libtext->GetText() == wxT( "${VALUE}" ) )
2272 {
2273 // Move text & attributes to Value field and discard LIB_TEXT item
2274 loadFieldAttributes( &aSymbol->GetValueField(), libtext.get() );
2275
2276 // Show Value field if Eagle reference was uppercase
2277 showValue = etext->text == wxT( ">VALUE" );
2278 }
2279 else
2280 {
2281 aSymbol->AddDrawItem( libtext.release() );
2282 }
2283 }
2284
2285 for( const std::unique_ptr<EWIRE>& ewire : aEsymbol->wires )
2286 aSymbol->AddDrawItem( loadSymbolWire( aSymbol, ewire, aGateNumber ) );
2287
2288 for( const std::unique_ptr<EFRAME>& eframe : aEsymbol->frames )
2289 {
2290 std::vector<SCH_ITEM*> frameItems;
2291
2292 loadFrame( eframe, frameItems );
2293
2294 for( SCH_ITEM* item : frameItems )
2295 {
2296 item->SetParent( aSymbol.get() );
2297 item->SetUnit( aGateNumber );
2298 aSymbol->AddDrawItem( item );
2299 }
2300 }
2301
2302 aSymbol->GetReferenceField().SetVisible( showRefDes );
2303 aSymbol->GetValueField().SetVisible( showValue );
2304
2305 return pincount == 1 ? ispower : false;
2306}
2307
2308
2309SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2310 const std::unique_ptr<ECIRCLE>& aCircle,
2311 int aGateNumber )
2312{
2313 wxCHECK( aSymbol && aCircle, nullptr );
2314
2315 // Parse the circle properties
2317 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
2318
2319 circle->SetParent( aSymbol.get() );
2320 circle->SetPosition( center );
2321 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
2322 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2323 circle->SetUnit( aGateNumber );
2324
2325 return circle;
2326}
2327
2328
2329SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2330 const std::unique_ptr<ERECT>& aRectangle,
2331 int aGateNumber )
2332{
2333 wxCHECK( aSymbol && aRectangle, nullptr );
2334
2335 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2336
2337 rectangle->SetParent( aSymbol.get() );
2338 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
2339 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
2340
2341 if( aRectangle->rot )
2342 {
2343 VECTOR2I pos( rectangle->GetPosition() );
2344 VECTOR2I end( rectangle->GetEnd() );
2345 VECTOR2I center( rectangle->GetCenter() );
2346
2347 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2348 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2349
2350 rectangle->SetPosition( pos );
2351 rectangle->SetEnd( end );
2352 }
2353
2354 rectangle->SetUnit( aGateNumber );
2355
2356 // Eagle rectangles are filled by definition.
2357 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2358
2359 return rectangle;
2360}
2361
2362
2363SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2364 const std::unique_ptr<EWIRE>& aWire, int aGateNumber )
2365{
2366 wxCHECK( aSymbol && aWire, nullptr );
2367
2368 VECTOR2I begin, end;
2369
2370 begin.x = aWire->x1.ToSchUnits();
2371 begin.y = -aWire->y1.ToSchUnits();
2372 end.x = aWire->x2.ToSchUnits();
2373 end.y = -aWire->y2.ToSchUnits();
2374
2375 if( begin == end )
2376 return nullptr;
2377
2378 // if the wire is an arc
2379 if( aWire->curve )
2380 {
2382 VECTOR2I center = ConvertArcCenter( begin, end, *aWire->curve );
2383 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2384 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2385
2386 arc->SetParent( aSymbol.get() );
2387
2388 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2389 if( aWire->cap == EWIRE::FLAT && aWire->width.ToSchUnits() >= 2 * radius )
2390 {
2391 VECTOR2I centerStartVector = ( begin - center ) *
2392 ( aWire->width.ToSchUnits() / radius );
2393 begin = center + centerStartVector;
2394
2397 }
2398 else
2399 {
2400 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2401 }
2402
2403 arc->SetCenter( center );
2404 arc->SetStart( begin );
2405
2406 // KiCad rotates the other way.
2407 arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
2408 arc->SetUnit( aGateNumber );
2409
2410 return arc;
2411 }
2412 else
2413 {
2415
2416 poly->AddPoint( begin );
2417 poly->AddPoint( end );
2418 poly->SetUnit( aGateNumber );
2419 poly->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2420
2421 return poly;
2422 }
2423}
2424
2425
2426SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2427 const std::unique_ptr<EPOLYGON>& aPolygon,
2428 int aGateNumber )
2429{
2430 wxCHECK( aSymbol && aPolygon, nullptr );
2431
2432 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
2433 VECTOR2I pt, prev_pt;
2434 opt_double prev_curve;
2435
2436 poly->SetParent( aSymbol.get() );
2437
2438 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
2439 {
2440 pt = VECTOR2I( evertex->x.ToSchUnits(), evertex->y.ToSchUnits() );
2441
2442 if( prev_curve )
2443 {
2444 SHAPE_ARC arc;
2445 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2446 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2447 }
2448 else
2449 {
2450 poly->AddPoint( pt );
2451 }
2452
2453 prev_pt = pt;
2454 prev_curve = evertex->curve;
2455 }
2456
2457 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2459 poly->SetUnit( aGateNumber );
2460
2461 return poly;
2462}
2463
2464
2465SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2466 const std::unique_ptr<EPIN>& aPin, int aGateNumber )
2467{
2468 wxCHECK( aSymbol && aPin, nullptr );
2469
2470 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2471 pin->SetPosition( VECTOR2I( aPin->x.ToSchUnits(), -aPin->y.ToSchUnits() ) );
2472 pin->SetName( aPin->name );
2473 pin->SetUnit( aGateNumber );
2474
2475 int roti = aPin->rot ? aPin->rot->degrees : 0;
2476
2477 switch( roti )
2478 {
2479 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2480 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2481 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2482 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2483 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2484 }
2485
2486 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2487
2488 if( aPin->length )
2489 {
2490 wxString length = aPin->length.Get();
2491
2492 if( length == wxT( "short" ) )
2493 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2494 else if( length == wxT( "middle" ) )
2495 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2496 else if( length == wxT( "long" ) )
2497 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2498 else if( length == wxT( "point" ) )
2499 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2500 }
2501
2502 // Pin names and numbers are fixed size in Eagle.
2503 pin->SetNumberTextSize( schIUScale.MilsToIU( 60 ) );
2504 pin->SetNameTextSize( schIUScale.MilsToIU( 60 ) );
2505
2506 // emulate the visibility of pin elements
2507 if( aPin->visible )
2508 {
2509 wxString visible = aPin->visible.Get();
2510
2511 if( visible == wxT( "off" ) )
2512 {
2513 pin->SetNameTextSize( 0 );
2514 pin->SetNumberTextSize( 0 );
2515 }
2516 else if( visible == wxT( "pad" ) )
2517 {
2518 pin->SetNameTextSize( 0 );
2519 }
2520 else if( visible == wxT( "pin" ) )
2521 {
2522 pin->SetNumberTextSize( 0 );
2523 }
2524
2525 /*
2526 * else if( visible == wxT( "both" ) )
2527 * {
2528 * }
2529 */
2530 }
2531
2532 if( aPin->function )
2533 {
2534 wxString function = aPin->function.Get();
2535
2536 if( function == wxT( "dot" ) )
2537 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2538 else if( function == wxT( "clk" ) )
2539 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2540 else if( function == wxT( "dotclk" ) )
2542 }
2543
2544 return pin.release();
2545}
2546
2547
2548SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2549 const std::unique_ptr<ETEXT>& aText, int aGateNumber )
2550{
2551 wxCHECK( aSymbol && aText, nullptr );
2552
2553 std::unique_ptr<SCH_TEXT> libtext = std::make_unique<SCH_TEXT>();
2554
2555 libtext->SetParent( aSymbol.get() );
2556 libtext->SetUnit( aGateNumber );
2557 libtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2558
2559 const wxString& eagleText = aText->text;
2560 wxString adjustedText;
2561 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2562
2563 // Strip the whitespace from both ends of each line.
2564 while( tokenizer.HasMoreTokens() )
2565 {
2566 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2567
2568 if( tokenizer.HasMoreTokens() )
2569 tmp += wxT( "\n" );
2570
2571 adjustedText += tmp;
2572 }
2573
2574 libtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "~" ) ) : adjustedText );
2575
2576 loadTextAttributes( libtext.get(), aText );
2577
2578 return libtext.release();
2579}
2580
2581
2582SCH_TEXT* SCH_IO_EAGLE::loadPlainText( const std::unique_ptr<ETEXT>& aText )
2583{
2584 wxCHECK( aText, nullptr );
2585
2586 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2587
2588 const wxString& eagleText = aText->text;
2589 wxString adjustedText;
2590 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2591
2592 // Strip the whitespace from both ends of each line.
2593 while( tokenizer.HasMoreTokens() )
2594 {
2595 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2596
2597 if( tokenizer.HasMoreTokens() )
2598 tmp += wxT( "\n" );
2599
2600 adjustedText += tmp;
2601 }
2602
2603 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "\" \"" ) )
2604 : escapeName( adjustedText ) );
2605
2606 schtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2607 loadTextAttributes( schtext.get(), aText );
2608 schtext->SetItalic( false );
2609
2610 return schtext.release();
2611}
2612
2613
2615 const std::unique_ptr<ETEXT>& aAttributes ) const
2616{
2617 wxCHECK( aText && aAttributes, /* void */ );
2618
2619 aText->SetTextSize( aAttributes->ConvertSize() );
2620
2621 // Must come after SetTextSize()
2622 if( aAttributes->ratio && aAttributes->ratio.CGet() > 12 )
2623 aText->SetBold( true );
2624
2625 int align = aAttributes->align ? *aAttributes->align : ETEXT::BOTTOM_LEFT;
2626 int degrees = aAttributes->rot ? aAttributes->rot->degrees : 0;
2627 bool mirror = aAttributes->rot ? aAttributes->rot->mirror : false;
2628 bool spin = aAttributes->rot ? aAttributes->rot->spin : false;
2629
2630 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
2631}
2632
2633
2634void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
2635{
2636 wxCHECK( aField && aText, /* void */ );
2637
2638 aField->SetTextPos( aText->GetPosition() );
2639 aField->SetTextSize( aText->GetTextSize() );
2640 aField->SetTextAngle( aText->GetTextAngle() );
2641
2642 // Must come after SetTextSize()
2643 aField->SetBold( aText->IsBold() );
2644 aField->SetItalic( false );
2645
2646 aField->SetVertJustify( aText->GetVertJustify() );
2647 aField->SetHorizJustify( aText->GetHorizJustify() );
2648}
2649
2650
2652{
2653 // Eagle supports detached labels, so a label does not need to be placed on a wire
2654 // to be associated with it. KiCad needs to move them, so the labels actually touch the
2655 // corresponding wires.
2656
2657 // Sort the intersection points to speed up the search process
2658 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
2659
2660 auto onIntersection =
2661 [&]( const VECTOR2I& aPos )
2662 {
2663 return std::binary_search( m_wireIntersections.begin(),
2664 m_wireIntersections.end(), aPos );
2665 };
2666
2667 for( SEG_DESC& segDesc : m_segments )
2668 {
2669 for( SCH_TEXT* label : segDesc.labels )
2670 {
2671 VECTOR2I labelPos( label->GetPosition() );
2672 const SEG* segAttached = segDesc.LabelAttached( label );
2673
2674 if( segAttached && !onIntersection( labelPos ) )
2675 continue; // label is placed correctly
2676
2677 // Move the label to the nearest wire
2678 if( !segAttached )
2679 {
2680 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
2681 segDesc.segs );
2682
2683 if( !segAttached ) // we cannot do anything
2684 continue;
2685 }
2686
2687 // Create a vector pointing in the direction of the wire, 50 mils long
2688 VECTOR2I wireDirection( segAttached->B - segAttached->A );
2689 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
2690 const VECTOR2I origPos( labelPos );
2691
2692 // Flags determining the search direction
2693 bool checkPositive = true, checkNegative = true, move = false;
2694 int trial = 0;
2695
2696 // Be sure the label is not placed on a wire intersection
2697 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
2698 {
2699 move = false;
2700
2701 // Move along the attached wire to find the new label position
2702 if( trial % 2 == 1 )
2703 {
2704 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
2705 move = checkPositive = segAttached->Contains( labelPos );
2706 }
2707 else
2708 {
2709 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
2710 move = checkNegative = segAttached->Contains( labelPos );
2711 }
2712
2713 ++trial;
2714 }
2715
2716 if( move )
2717 label->SetPosition( VECTOR2I( labelPos ) );
2718 }
2719 }
2720
2721 m_segments.clear();
2722 m_wireIntersections.clear();
2723}
2724
2725
2726bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
2727{
2728 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
2729 return false;
2730
2731 return checkHeader( aFileName );
2732}
2733
2734
2735bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
2736{
2737 if( !SCH_IO::CanReadLibrary( aFileName ) )
2738 return false;
2739
2740 return checkHeader( aFileName );
2741}
2742
2743
2744bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
2745{
2746 wxFileInputStream input( aFileName );
2747
2748 if( !input.IsOk() )
2749 return false;
2750
2751 wxTextInputStream text( input );
2752
2753 for( int i = 0; i < 8; i++ )
2754 {
2755 if( input.Eof() )
2756 return false;
2757
2758 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
2759 return true;
2760 }
2761
2762 return false;
2763}
2764
2765
2766void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
2767{
2768 wxCHECK( aWire, /* void */ );
2769
2770 SCH_SCREEN* screen = getCurrentScreen();
2771
2772 wxCHECK( screen, /* void */ );
2773
2774 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
2775 {
2776 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
2777 continue;
2778
2779 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
2780 item->SetPosition( aNewEndPoint );
2781 }
2782}
2783
2784
2786{
2787 // Add bus entry symbols
2788 // TODO: Cleanup this function and break into pieces
2789
2790 // for each wire segment, compare each end with all busses.
2791 // If the wire end is found to end on a bus segment, place a bus entry symbol.
2792
2793 std::vector<SCH_LINE*> buses;
2794 std::vector<SCH_LINE*> wires;
2795
2796 SCH_SCREEN* screen = getCurrentScreen();
2797
2798 wxCHECK( screen, /* void */ );
2799
2800 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
2801 {
2802 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
2803
2804 if( line->IsBus() )
2805 buses.push_back( line );
2806 else if( line->IsWire() )
2807 wires.push_back( line );
2808 }
2809
2810 for( SCH_LINE* wire : wires )
2811 {
2812 VECTOR2I wireStart = wire->GetStartPoint();
2813 VECTOR2I wireEnd = wire->GetEndPoint();
2814
2815 for( SCH_LINE* bus : buses )
2816 {
2817 VECTOR2I busStart = bus->GetStartPoint();
2818 VECTOR2I busEnd = bus->GetEndPoint();
2819
2820 auto entrySize =
2821 []( int signX, int signY ) -> VECTOR2I
2822 {
2823 return VECTOR2I( schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signX,
2824 schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signY );
2825 };
2826
2827 auto testBusHit =
2828 [&]( const VECTOR2I& aPt ) -> bool
2829 {
2830 return TestSegmentHit( aPt, busStart, busEnd, 0 );
2831 };
2832
2833 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
2834 {
2835 // Horizontal wire and vertical bus
2836
2837 if( testBusHit( wireStart ) )
2838 {
2839 // Wire start is on the vertical bus
2840
2841 if( wireEnd.x < busStart.x )
2842 {
2843 /* the end of the wire is to the left of the bus
2844 * ⎥⎢
2845 * ——————⎥⎢
2846 * ⎥⎢
2847 */
2848 VECTOR2I p = wireStart + entrySize( -1, 0 );
2849
2850 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2851 {
2852 /* there is room above the wire for the bus entry
2853 * ⎥⎢
2854 * _____/⎥⎢
2855 * ⎥⎢
2856 */
2857 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2858 busEntry->SetFlags( IS_NEW );
2859 screen->Append( busEntry );
2860 moveLabels( wire, p );
2861 wire->SetStartPoint( p );
2862 }
2863 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2864 {
2865 /* there is room below the wire for the bus entry
2866 * _____ ⎥⎢
2867 * \⎥⎢
2868 * ⎥⎢
2869 */
2870 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2871 busEntry->SetFlags( IS_NEW );
2872 screen->Append( busEntry );
2873 moveLabels( wire, p );
2874 wire->SetStartPoint( p );
2875 }
2876 else
2877 {
2878 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2879 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
2880 }
2881 }
2882 else
2883 {
2884 /* the wire end is to the right of the bus
2885 * ⎥⎢
2886 * ⎥⎢——————
2887 * ⎥⎢
2888 */
2889 VECTOR2I p = wireStart + entrySize( 1, 0 );
2890
2891 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2892 {
2893 /* There is room above the wire for the bus entry
2894 * ⎥⎢
2895 * ⎥⎢\_____
2896 * ⎥⎢
2897 */
2898 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
2899 busEntry->SetFlags( IS_NEW );
2900 screen->Append( busEntry );
2901 moveLabels( wire, p );
2902 wire->SetStartPoint( p );
2903 }
2904 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2905 {
2906 /* There is room below the wire for the bus entry
2907 * ⎥⎢ _____
2908 * ⎥⎢/
2909 * ⎥⎢
2910 */
2911 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2912 busEntry->SetFlags( IS_NEW );
2913 screen->Append( busEntry );
2914 moveLabels( wire, p );
2915 wire->SetStartPoint( p );
2916 }
2917 else
2918 {
2919 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2920 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
2921 }
2922 }
2923
2924 break;
2925 }
2926 else if( testBusHit( wireEnd ) )
2927 {
2928 // Wire end is on the vertical bus
2929
2930 if( wireStart.x < busStart.x )
2931 {
2932 /* start of the wire is to the left of the bus
2933 * ⎥⎢
2934 * ——————⎥⎢
2935 * ⎥⎢
2936 */
2937 VECTOR2I p = wireEnd + entrySize( -1, 0 );
2938
2939 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2940 {
2941 /* there is room above the wire for the bus entry
2942 * ⎥⎢
2943 * _____/⎥⎢
2944 * ⎥⎢
2945 */
2946 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2947 busEntry->SetFlags( IS_NEW );
2948 screen->Append( busEntry );
2949 moveLabels( wire, p );
2950 wire->SetEndPoint( p );
2951 }
2952 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2953 {
2954 /* there is room below the wire for the bus entry
2955 * _____ ⎥⎢
2956 * \⎥⎢
2957 * ⎥⎢
2958 */
2959 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2960 busEntry->SetFlags( IS_NEW );
2961 screen->Append( busEntry );
2962 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
2963 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
2964 }
2965 else
2966 {
2967 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2968 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
2969 }
2970 }
2971 else
2972 {
2973 /* the start of the wire is to the right of the bus
2974 * ⎥⎢
2975 * ⎥⎢——————
2976 * ⎥⎢
2977 */
2978 VECTOR2I p = wireEnd + entrySize( 1, 0 );
2979
2980 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2981 {
2982 /* There is room above the wire for the bus entry
2983 * ⎥⎢
2984 * ⎥⎢\_____
2985 * ⎥⎢
2986 */
2987 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
2988 busEntry->SetFlags( IS_NEW );
2989 screen->Append( busEntry );
2990 moveLabels( wire, p );
2991 wire->SetEndPoint( p );
2992 }
2993 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
2994 {
2995 /* There is room below the wire for the bus entry
2996 * ⎥⎢ _____
2997 * ⎥⎢/
2998 * ⎥⎢
2999 */
3000 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3001 busEntry->SetFlags( IS_NEW );
3002 screen->Append( busEntry );
3003 moveLabels( wire, p );
3004 wire->SetEndPoint( p );
3005 }
3006 else
3007 {
3008 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3009 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3010 }
3011 }
3012
3013 break;
3014 }
3015 }
3016 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
3017 {
3018 // Vertical wire and horizontal bus
3019
3020 if( testBusHit( wireStart ) )
3021 {
3022 // Wire start is on the bus
3023
3024 if( wireEnd.y < busStart.y )
3025 {
3026 /* the end of the wire is above the bus
3027 * |
3028 * |
3029 * |
3030 * =======
3031 */
3032 VECTOR2I p = wireStart + entrySize( 0, -1 );
3033
3034 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3035 {
3036 /* there is room to the left of the wire for the bus entry
3037 * |
3038 * |
3039 * /
3040 * =======
3041 */
3042 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3043 busEntry->SetFlags( IS_NEW );
3044 screen->Append( busEntry );
3045 moveLabels( wire, p );
3046 wire->SetStartPoint( p );
3047 }
3048 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3049 {
3050 /* there is room to the right of the wire for the bus entry
3051 * |
3052 * |
3053 * \
3054 * =======
3055 */
3056 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3057 busEntry->SetFlags( IS_NEW );
3058 screen->Append( busEntry );
3059 moveLabels( wire, p );
3060 wire->SetStartPoint( p );
3061 }
3062 else
3063 {
3064 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3065 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3066 }
3067 }
3068 else
3069 {
3070 /* wire end is below the bus
3071 * =======
3072 * |
3073 * |
3074 * |
3075 */
3076 VECTOR2I p = wireStart + entrySize( 0, 1 );
3077
3078 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3079 {
3080 /* there is room to the left of the wire for the bus entry
3081 * =======
3082 * \
3083 * |
3084 * |
3085 */
3086 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3087 busEntry->SetFlags( IS_NEW );
3088 screen->Append( busEntry );
3089 moveLabels( wire, p );
3090 wire->SetStartPoint( p );
3091 }
3092 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3093 {
3094 /* there is room to the right of the wire for the bus entry
3095 * =======
3096 * /
3097 * |
3098 * |
3099 */
3100 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3101 busEntry->SetFlags( IS_NEW );
3102 screen->Append( busEntry );
3103 moveLabels( wire, p );
3104 wire->SetStartPoint( p );
3105 }
3106 else
3107 {
3108 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3109 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3110 }
3111 }
3112
3113 break;
3114 }
3115 else if( testBusHit( wireEnd ) )
3116 {
3117 // Wire end is on the bus
3118
3119 if( wireStart.y < busStart.y )
3120 {
3121 /* the start of the wire is above the bus
3122 * |
3123 * |
3124 * |
3125 * =======
3126 */
3127 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3128
3129 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3130 {
3131 /* there is room to the left of the wire for the bus entry
3132 * |
3133 * |
3134 * /
3135 * =======
3136 */
3137 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3138 busEntry->SetFlags( IS_NEW );
3139 screen->Append( busEntry );
3140 moveLabels( wire, p );
3141 wire->SetEndPoint( p );
3142 }
3143 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3144 {
3145 /* there is room to the right of the wire for the bus entry
3146 * |
3147 * |
3148 * \
3149 * =======
3150 */
3151 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3152 busEntry->SetFlags( IS_NEW );
3153 screen->Append( busEntry );
3154 moveLabels( wire, p );
3155 wire->SetEndPoint( p );
3156 }
3157 else
3158 {
3159 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3160 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3161 }
3162 }
3163 else
3164 {
3165 /* wire start is below the bus
3166 * =======
3167 * |
3168 * |
3169 * |
3170 */
3171 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3172
3173 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3174 {
3175 /* there is room to the left of the wire for the bus entry
3176 * =======
3177 * \
3178 * |
3179 * |
3180 */
3181 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3182 busEntry->SetFlags( IS_NEW );
3183 screen->Append( busEntry );
3184 moveLabels( wire, p );
3185 wire->SetEndPoint( p );
3186 }
3187 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3188 {
3189 /* there is room to the right of the wire for the bus entry
3190 * =======
3191 * /
3192 * |
3193 * |
3194 */
3195 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3196 busEntry->SetFlags( IS_NEW );
3197 screen->Append( busEntry );
3198 moveLabels( wire, p );
3199 wire->SetEndPoint( p );
3200 }
3201 else
3202 {
3203 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3204 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3205 }
3206 }
3207
3208 break;
3209 }
3210 }
3211 else
3212 {
3213 // Wire isn't horizontal or vertical
3214
3215 if( testBusHit( wireStart ) )
3216 {
3217 VECTOR2I wirevector = wireStart - wireEnd;
3218
3219 if( wirevector.x > 0 )
3220 {
3221 if( wirevector.y > 0 )
3222 {
3223 VECTOR2I p = wireStart + entrySize( -1, -1 );
3224 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3225 busEntry->SetFlags( IS_NEW );
3226 screen->Append( busEntry );
3227
3228 moveLabels( wire, p );
3229 wire->SetStartPoint( p );
3230 }
3231 else
3232 {
3233 VECTOR2I p = wireStart + entrySize( -1, 1 );
3234 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3235 busEntry->SetFlags( IS_NEW );
3236 screen->Append( busEntry );
3237
3238 moveLabels( wire, p );
3239 wire->SetStartPoint( p );
3240 }
3241 }
3242 else
3243 {
3244 if( wirevector.y > 0 )
3245 {
3246 VECTOR2I p = wireStart + entrySize( 1, -1 );
3247 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3248 busEntry->SetFlags( IS_NEW );
3249 screen->Append( busEntry );
3250
3251 moveLabels( wire, p );
3252 wire->SetStartPoint( p );
3253 }
3254 else
3255 {
3256 VECTOR2I p = wireStart + entrySize( 1, 1 );
3257 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3258 busEntry->SetFlags( IS_NEW );
3259 screen->Append( busEntry );
3260
3261 moveLabels( wire, p );
3262 wire->SetStartPoint( p );
3263 }
3264 }
3265
3266 break;
3267 }
3268 else if( testBusHit( wireEnd ) )
3269 {
3270 VECTOR2I wirevector = wireStart - wireEnd;
3271
3272 if( wirevector.x > 0 )
3273 {
3274 if( wirevector.y > 0 )
3275 {
3276 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3277 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3278 busEntry->SetFlags( IS_NEW );
3279 screen->Append( busEntry );
3280
3281 moveLabels( wire, p );
3282 wire->SetEndPoint( p );
3283 }
3284 else
3285 {
3286 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3287 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3288 busEntry->SetFlags( IS_NEW );
3289 screen->Append( busEntry );
3290
3291 moveLabels( wire, p );
3292 wire->SetEndPoint( p );
3293 }
3294 }
3295 else
3296 {
3297 if( wirevector.y > 0 )
3298 {
3299 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3300 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3301 busEntry->SetFlags( IS_NEW );
3302 screen->Append( busEntry );
3303
3304 moveLabels( wire, p );
3305 wire->SetEndPoint( p );
3306 }
3307 else
3308 {
3309 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3310 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3311 busEntry->SetFlags( IS_NEW );
3312 screen->Append( busEntry );
3313
3314 moveLabels( wire, p );
3315 wire->SetEndPoint( p );
3316 }
3317 }
3318
3319 break;
3320 }
3321 }
3322 }
3323 }
3324}
3325
3326
3328{
3329 wxCHECK( aLabel, nullptr );
3330
3331 VECTOR2I labelPos( aLabel->GetPosition() );
3332
3333 for( const SEG& seg : segs )
3334 {
3335 if( seg.Contains( labelPos ) )
3336 return &seg;
3337 }
3338
3339 return nullptr;
3340}
3341
3342
3343// TODO could be used to place junctions, instead of IsJunctionNeeded()
3344// (see SCH_EDIT_FRAME::importFile())
3345bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3346{
3347 wxCHECK( aSymbol && aPin, false );
3348
3349 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3350 auto pointIt = m_connPoints.find( pinPosition );
3351
3352 if( pointIt == m_connPoints.end() )
3353 return false;
3354
3355 const auto& items = pointIt->second;
3356
3357 wxCHECK( items.find( aPin ) != items.end(), false );
3358
3359 return items.size() > 1;
3360}
3361
3362
3364 bool aUpdateSet )
3365{
3366 wxCHECK( aSymbol && aScreen && aSymbol->GetLibSymbolRef(), /*void*/ );
3367
3368 // Normally power parts also have power input pins,
3369 // but they already force net names on the attached wires
3370 if( aSymbol->GetLibSymbolRef()->IsGlobalPower() )
3371 return;
3372
3373 int unit = aSymbol->GetUnit();
3374 const wxString reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
3375 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetPins();
3376 std::set<int> missingUnits;
3377
3378 // Search all units for pins creating implicit connections
3379 for( const SCH_PIN* pin : pins )
3380 {
3381 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3382 {
3383 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3384
3385 // Create a global net label only if there are no other wires/pins attached
3386 if( pinInUnit )
3387 {
3388 if( !checkConnections( aSymbol, pin ) )
3389 {
3390 // Create a net label to force the net name on the pin
3391 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3392 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3393 netLabel->SetText( extractNetName( pin->GetName() ) );
3394 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3395 schIUScale.MilsToIU( 40 ) ) );
3396
3397 switch( pin->GetOrientation() )
3398 {
3399 default:
3401 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3402 break;
3404 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3405 break;
3407 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3408 break;
3410 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3411 break;
3412 }
3413
3414 aScreen->Append( netLabel );
3415 }
3416 }
3417 else if( aUpdateSet )
3418 {
3419 // Found a pin creating implicit connection information in another unit.
3420 // Such units will be instantiated if they do not appear in another sheet and
3421 // processed later.
3422 wxASSERT( pin->GetUnit() );
3423 missingUnits.insert( pin->GetUnit() );
3424 }
3425 }
3426 }
3427
3428 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3429 {
3430 auto cmpIt = m_missingCmps.find( reference );
3431
3432 // The first unit found has always already been processed.
3433 if( cmpIt == m_missingCmps.end() )
3434 {
3435 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3436 entry.cmp = aSymbol;
3437 entry.units.emplace( unit, false );
3438 }
3439 else
3440 {
3441 // Set the flag indicating this unit has been processed.
3442 cmpIt->second.units[unit] = false;
3443 }
3444
3445 if( !missingUnits.empty() ) // Save the units that need later processing
3446 {
3447 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3448 entry.cmp = aSymbol;
3449
3450 // Add units that haven't already been processed.
3451 for( int i : missingUnits )
3452 {
3453 if( entry.units.find( i ) != entry.units.end() )
3454 entry.units.emplace( i, true );
3455 }
3456 }
3457 }
3458}
3459
3460
3461wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3462{
3463 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3464 return aEagleName;
3465
3466 wxString ret = wxT( "{" );
3467
3468 wxStringTokenizer tokenizer( aEagleName, "," );
3469
3470 while( tokenizer.HasMoreTokens() )
3471 {
3472 wxString member = tokenizer.GetNextToken();
3473
3474 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3475 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3476 // if there is an odd number of overbar markers in this net name, we need to append one
3477 // to close it out before appending the space.
3478
3479 if( member.Freq( '!' ) % 2 > 0 )
3480 member << wxT( "!" );
3481
3482 ret << member << wxS( " " );
3483 }
3484
3485 ret.Trim( true );
3486 ret << wxT( "}" );
3487
3488 return ret;
3489}
3490
3491
3492const ESYMBOL* SCH_IO_EAGLE::getEagleSymbol( const std::unique_ptr<EINSTANCE>& aInstance )
3493{
3494 wxCHECK( m_eagleDoc && m_eagleDoc->drawing && m_eagleDoc->drawing->schematic && aInstance,
3495 nullptr );
3496
3497 std::unique_ptr<EPART>& epart = m_eagleDoc->drawing->schematic->parts[aInstance->part];
3498
3499 if( !epart || epart->deviceset.IsEmpty() )
3500 return nullptr;
3501
3502 std::unique_ptr<ELIBRARY>& elibrary = m_eagleDoc->drawing->schematic->libraries[epart->library];
3503
3504 if( !elibrary )
3505 return nullptr;
3506
3507 std::unique_ptr<EDEVICE_SET>& edeviceset = elibrary->devicesets[epart->deviceset];
3508
3509 if( !edeviceset )
3510 return nullptr;
3511
3512 std::unique_ptr<EGATE>& egate = edeviceset->gates[aInstance->gate];
3513
3514 if( !egate )
3515 return nullptr;
3516
3517 std::unique_ptr<ESYMBOL>& esymbol = elibrary->symbols[egate->symbol];
3518
3519 if( esymbol )
3520 return esymbol.get();
3521
3522 return nullptr;
3523}
3524
3525
3526void SCH_IO_EAGLE::getEagleSymbolFieldAttributes( const std::unique_ptr<EINSTANCE>& aInstance,
3527 const wxString& aEagleFieldName,
3528 SCH_FIELD* aField )
3529{
3530 wxCHECK( aField && !aEagleFieldName.IsEmpty(), /* void */ );
3531
3532 const ESYMBOL* esymbol = getEagleSymbol( aInstance );
3533
3534 if( esymbol )
3535 {
3536 for( const std::unique_ptr<ETEXT>& text : esymbol->texts )
3537 {
3538 if( text->text == aEagleFieldName )
3539 {
3540 aField->SetVisible( true );
3541 VECTOR2I pos( text->x.ToSchUnits() + aInstance->x.ToSchUnits(),
3542 -text->y.ToSchUnits() - aInstance->y.ToSchUnits() );
3543
3544 bool mirror = text->rot ? text->rot->mirror : false;
3545
3546 if( aInstance->rot && aInstance->rot->mirror )
3547 mirror = !mirror;
3548
3549 if( mirror )
3550 pos.y = -aInstance->y.ToSchUnits() + text->y.ToSchUnits();
3551
3552 aField->SetPosition( pos );
3553 }
3554 }
3555 }
3556}
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:540
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:584
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:425
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:200
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:394
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:343
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:278
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:307
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:315
VECTOR2I GetTextSize() const
Definition eda_text.h:261
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:417
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:237
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:240
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:83
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:988
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:994
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...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
wxString wx_str() const
Definition utf8.cpp:45
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:561
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:385
static REPORTER & GetInstance()
Definition reporter.cpp:190
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
#define DEFAULT_SCH_ENTRY_SIZE
The default text size in mils. (can be changed in preference menu)
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
wxString interpretText(const wxString &aText)
Interprets special characters in Eagle text and converts them to KiCAD notation.
size_t GetNodeCount(const wxXmlNode *aNode)
Fetch the number of XML nodes within aNode.
VECTOR2I ConvertArcCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC.
wxString convertDescription(wxString aDescr)
Converts Eagle's HTML description into KiCad description format.
OPTIONAL_XML_ATTRIBUTE< double > opt_double
#define _(s)
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#define IS_NEW
New item, just created.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
@ ERCE_BUS_ENTRY_NEEDED
Importer failed to auto-place a bus entry.
static const std::string KiCadSchematicFileExtension
static const std::string KiCadSymbolLibFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
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".
KIBIS_PIN * pin
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition trigo.cpp: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.