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