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