KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <alejandro.garciamontoro@gmail.com>
8 * @author Maciej Suminski <maciej.suminski@cern.ch>
9 * @author Russell Oliver <roliver8143@gmail.com>
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( FIELD_T::REFERENCE )->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( FIELD_T::FOOTPRINT )->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* partField : partFields )
1835 {
1836 SCH_FIELD* symbolField;
1837
1838 if( partField->IsMandatory() )
1839 symbolField = symbol->GetField( partField->GetId() );
1840 else
1841 symbolField = symbol->GetField( partField->GetName() );
1842
1843 symbolField->ImportValues( *partField );
1844 symbolField->SetTextPos( symbol->GetPosition() + partField->GetTextPos() );
1845 }
1846
1847 // If there is no footprint assigned, then prepend the reference value
1848 // with a hash character to mute netlist updater complaints
1849 wxString reference = package.IsEmpty() ? '#' + aInstance->part : aInstance->part;
1850
1851 // reference must end with a number but EAGLE does not enforce this
1852 if( reference.find_last_not_of( wxT( "0123456789" ) ) == ( reference.Length()-1 ) )
1853 reference.Append( wxT( "0" ) );
1854
1855 // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
1856 // parts to have non-digit + digit annotation. If the reference begins with a number,
1857 // we prepend 'UNK' (unknown) for the symbol designator
1858 if( reference.find_first_not_of( wxT( "0123456789" ) ) != 0 )
1859 reference.Prepend( wxT( "UNK" ) );
1860
1861 // EAGLE allows designator to start with # but that is used in KiCad
1862 // for symbols which do not have a footprint
1863 if( aInstance->part.find_first_not_of( wxT( "#" ) ) != 0 )
1864 reference.Prepend( wxT( "UNK" ) );
1865
1866 SCH_FIELD* referenceField = symbol->GetField( FIELD_T::REFERENCE );
1867 referenceField->SetText( reference );
1868
1869 SCH_FIELD* valueField = symbol->GetField( FIELD_T::VALUE );
1870 bool userValue = m_userValue.at( libIdSymbolName );
1871
1872 if( part->GetUnitCount() > 1 )
1873 {
1874 getEagleSymbolFieldAttributes( aInstance, wxS( ">NAME" ), referenceField );
1875 getEagleSymbolFieldAttributes( aInstance, wxS( ">VALUE" ), valueField );
1876 }
1877
1878 if( epart->value && !epart->value.CGet().IsEmpty() )
1879 {
1880 valueField->SetText( *epart->value );
1881 }
1882 else
1883 {
1884 valueField->SetText( kisymbolname );
1885
1886 if( userValue )
1887 valueField->SetVisible( false );
1888 }
1889
1890 for( const auto& [ attrName, attr ] : epart->attributes )
1891 {
1892 VECTOR2I newFieldPosition( 0, 0 );
1893
1894 if( !symbol->GetFields().empty() )
1895 newFieldPosition = symbol->GetFields().back().GetPosition();
1896
1897 SCH_FIELD newField( newFieldPosition, FIELD_T::USER, symbol.get() );
1898
1899 newField.SetName( attrName );
1900
1901 if( attr->value )
1902 newField.SetText( *attr->value );
1903
1904 newField.SetVisible( ( attr->display == EATTR::Off ) ? false : true );
1905
1906 symbol->AddField( newField );
1907 }
1908
1909 for( const auto& [variantName, variant] : epart->variants )
1910 {
1911 SCH_FIELD* field = symbol->AddField( *symbol->GetField( FIELD_T::VALUE ) );
1912 field->SetName( wxT( "VARIANT_" ) + variant->name );
1913
1914 if( variant->value )
1915 field->SetText( *variant->value );
1916
1917 field->SetVisible( false );
1918 }
1919
1920 bool valueAttributeFound = false;
1921 bool nameAttributeFound = false;
1922
1923 // Parse attributes for the instance
1924 for( auto& [name, eattr] : aInstance->attributes )
1925 {
1926 SCH_FIELD* field = nullptr;
1927
1928 if( eattr->name.Lower() == wxT( "name" ) )
1929 {
1930 field = symbol->GetField( FIELD_T::REFERENCE );
1931 nameAttributeFound = true;
1932 }
1933 else if( eattr->name.Lower() == wxT( "value" ) )
1934 {
1935 field = symbol->GetField( FIELD_T::VALUE );
1936 valueAttributeFound = true;
1937 }
1938 else
1939 {
1940 field = symbol->GetField( eattr->name );
1941
1942 if( field )
1943 field->SetVisible( false );
1944 }
1945
1946 if( field )
1947 {
1948 field->SetPosition( VECTOR2I( eattr->x->ToSchUnits(), -eattr->y->ToSchUnits() ) );
1949 int align = eattr->align ? *eattr->align : ETEXT::BOTTOM_LEFT;
1950 int absdegrees = eattr->rot ? eattr->rot->degrees : 0;
1951 bool mirror = eattr->rot ? eattr->rot->mirror : false;
1952
1953 if( aInstance->rot && aInstance->rot->mirror )
1954 mirror = !mirror;
1955
1956 bool spin = eattr->rot ? eattr->rot->spin : false;
1957
1958 if( eattr->display == EATTR::Off || eattr->display == EATTR::NAME )
1959 field->SetVisible( false );
1960
1961 int rotation = aInstance->rot ? aInstance->rot->degrees : 0;
1962 int reldegrees = ( absdegrees - rotation + 360.0 );
1963 reldegrees %= 360;
1964
1965 eagleToKicadAlignment( field, align, reldegrees, mirror, spin, absdegrees );
1966 }
1967 }
1968
1969 // Use the instance attribute to determine the reference and value field visibility.
1970 if( aInstance->smashed && aInstance->smashed.Get() )
1971 {
1972 symbol->GetField( FIELD_T::VALUE )->SetVisible( valueAttributeFound );
1973 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( nameAttributeFound );
1974 }
1975
1976 // Eagle has a brain dead module reference scheme where the module names separated by colons
1977 // are prefixed to the symbol references. This will get blown away in KiCad the first time
1978 // any annotation is performed. It is required for the initial synchronization between the
1979 // schematic and the board.
1980 wxString refPrefix;
1981
1982 for( const EMODULEINST* emoduleInst : m_moduleInstances )
1983 {
1984 wxCHECK2( emoduleInst, continue );
1985
1986 refPrefix += emoduleInst->name + wxS( ":" );
1987 }
1988
1989 symbol->AddHierarchicalReference( m_sheetPath.Path(), refPrefix + reference, unit );
1990
1991 // Save the pin positions
1992 SYMBOL_LIB_TABLE& schLibTable = *PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
1993 LIB_SYMBOL* libSymbol = schLibTable.LoadSymbol( symbol->GetLibId() );
1994
1995 wxCHECK( libSymbol, /*void*/ );
1996
1997 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
1998
1999 for( const SCH_PIN* pin : symbol->GetLibPins() )
2000 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
2001
2002 if( part->IsGlobalPower() )
2003 m_powerPorts[ reference ] = symbol->GetField( FIELD_T::VALUE )->GetText();
2004
2005 symbol->ClearFlags();
2006
2007 screen->Append( symbol.release() );
2008}
2009
2010
2012{
2013 wxCHECK( aLibrary && aEagleLibrary, nullptr );
2014
2015 // Loop through the device sets and load each of them
2016 for( const auto& [name, edeviceset] : aLibrary->devicesets )
2017 {
2018 // Get Device set information
2019 wxString prefix = edeviceset->prefix ? edeviceset->prefix.Get() : wxString( wxT( "" ) );
2020 wxString deviceSetDescr;
2021
2022 if( edeviceset->description )
2023 deviceSetDescr = convertDescription( UnescapeHTML( edeviceset->description->text ) );
2024
2025 // For each device in the device set:
2026 for( const std::unique_ptr<EDEVICE>& edevice : edeviceset->devices )
2027 {
2028 // Create symbol name from deviceset and device names.
2029 wxString symbolName = edeviceset->name + edevice->name;
2030 symbolName.Replace( wxT( "*" ), wxEmptyString );
2031 wxASSERT( !symbolName.IsEmpty() );
2032 symbolName = EscapeString( symbolName, CTX_LIBID );
2033
2034 if( edevice->package )
2035 aEagleLibrary->package[symbolName] = edevice->package.Get();
2036
2037 // Create KiCad symbol.
2038 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2039
2040 // Process each gate in the deviceset for this device.
2041 int gate_count = static_cast<int>( edeviceset->gates.size() );
2042 libSymbol->SetUnitCount( gate_count );
2043 libSymbol->LockUnits( true );
2044
2045 SCH_FIELD* reference = libSymbol->GetField( FIELD_T::REFERENCE );
2046
2047 if( prefix.length() == 0 )
2048 {
2049 reference->SetVisible( false );
2050 }
2051 else
2052 {
2053 // If there is no footprint assigned, then prepend the reference value
2054 // with a hash character to mute netlist updater complaints
2055 reference->SetText( edevice->package ? prefix : '#' + prefix );
2056 }
2057
2058 libSymbol->GetValueField().SetVisible( true );
2059
2060 int gateindex = 1;
2061 bool ispower = false;
2062
2063 for( const auto& [gateName, egate] : edeviceset->gates )
2064 {
2065 const auto it = aLibrary->symbols.find( egate->symbol );
2066
2067 if( it == aLibrary->symbols.end() )
2068 {
2069 Report( wxString::Format( wxS( "Eagle symbol '%s' not found in library '%s'." ),
2070 egate->symbol, aLibrary->GetName() ) );
2071 continue;
2072 }
2073
2074 wxString gateMapName = edeviceset->name + wxS( "_" ) + edevice->name +
2075 wxS( "_" ) + egate->name;
2076 aEagleLibrary->GateToUnitMap[gateMapName] = gateindex;
2077 ispower = loadSymbol( it->second, libSymbol, edevice, gateindex, egate->name );
2078
2079 gateindex++;
2080 }
2081
2082 libSymbol->SetUnitCount( gate_count );
2083
2084 if( gate_count == 1 && ispower )
2085 libSymbol->SetGlobalPower();
2086
2087 // Don't set the footprint field if no package is defined in the Eagle schematic.
2088 if( edevice->package )
2089 {
2090 wxString libName;
2091
2092 if( m_schematic )
2093 {
2094 // assume that footprint library is identical to project name
2095 libName = m_schematic->Prj().GetProjectName();
2096 }
2097 else
2098 {
2099 libName = m_libName;
2100 }
2101
2102 wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
2103
2104 libSymbol->GetFootprintField().SetText( packageString );
2105 }
2106
2107 wxString libName = libSymbol->GetName();
2108 libSymbol->SetName( libName );
2109 libSymbol->SetDescription( deviceSetDescr );
2110
2111 if( m_pi )
2112 {
2113 // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
2114 // Eagle symbol library name to the symbol which should ensure that it is unique.
2115 try
2116 {
2117 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
2118 {
2119 libName = aEagleLibrary->name + wxT( "_" ) + libName;
2120 libName = EscapeString( libName, CTX_LIBID );
2121 libSymbol->SetName( libName );
2122 }
2123
2124 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
2125 new LIB_SYMBOL( *libSymbol.get() ), m_properties.get() );
2126 }
2127 catch(...)
2128 {
2129 // A library symbol cannot be loaded for some reason.
2130 // Just skip this symbol creating an issue.
2131 // The issue will be reported later by the Reporter
2132 }
2133 }
2134
2135 aEagleLibrary->KiCadSymbols[ libName ] = std::move( libSymbol );
2136
2137 // Store information on whether the value of FIELD_T::VALUE for a part should be
2138 // part/@value or part/@deviceset + part/@device.
2139 m_userValue.emplace( std::make_pair( libName, edeviceset->uservalue == true ) );
2140 }
2141 }
2142
2143 return aEagleLibrary;
2144}
2145
2146
2147bool SCH_IO_EAGLE::loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
2148 std::unique_ptr<LIB_SYMBOL>& aSymbol,
2149 const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
2150 const wxString& aGateName )
2151{
2152 wxCHECK( aEsymbol && aSymbol && aDevice, false );
2153
2154 wxString symbolName = aEsymbol->name;
2155 std::vector<SCH_ITEM*> items;
2156
2157 bool showRefDes = false;
2158 bool showValue = false;
2159 bool ispower = false;
2160 int pincount = 0;
2161
2162 for( const std::unique_ptr<ECIRCLE>& ecircle : aEsymbol->circles )
2163 aSymbol->AddDrawItem( loadSymbolCircle( aSymbol, ecircle, aGateNumber ) );
2164
2165 for( const std::unique_ptr<EPIN>& epin : aEsymbol->pins )
2166 {
2167 std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, epin, aGateNumber ) );
2168 pincount++;
2169
2170 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
2171
2172 if( epin->direction )
2173 {
2174 for( const auto& pinDir : pinDirectionsMap )
2175 {
2176 if( epin->direction->Lower() == pinDir.first )
2177 {
2178 pin->SetType( pinDir.second );
2179
2180 if( pinDir.first == wxT( "sup" ) ) // power supply symbol
2181 ispower = true;
2182
2183 break;
2184 }
2185 }
2186
2187 }
2188
2189 if( aDevice->connects.size() != 0 )
2190 {
2191 for( const std::unique_ptr<ECONNECT>& connect : aDevice->connects )
2192 {
2193 if( connect->gate == aGateName && pin->GetName() == connect->pin )
2194 {
2195 wxArrayString pads = wxSplit( wxString( connect->pad ), ' ' );
2196
2197 pin->SetUnit( aGateNumber );
2198 pin->SetName( escapeName( pin->GetName() ) );
2199
2200 if( pads.GetCount() > 1 )
2201 {
2202 pin->SetNumberTextSize( 0 );
2203 }
2204
2205 for( unsigned i = 0; i < pads.GetCount(); i++ )
2206 {
2207 SCH_PIN* apin = new SCH_PIN( *pin );
2208
2209 wxString padname( pads[i] );
2210 apin->SetNumber( padname );
2211 aSymbol->AddDrawItem( apin );
2212 }
2213
2214 break;
2215 }
2216 }
2217 }
2218 else
2219 {
2220 pin->SetUnit( aGateNumber );
2221 pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
2222 aSymbol->AddDrawItem( pin.release() );
2223 }
2224 }
2225
2226 for( const std::unique_ptr<EPOLYGON>& epolygon : aEsymbol->polygons )
2227 aSymbol->AddDrawItem( loadSymbolPolyLine( aSymbol, epolygon, aGateNumber ) );
2228
2229 for( const std::unique_ptr<ERECT>& erectangle : aEsymbol->rectangles )
2230 aSymbol->AddDrawItem( loadSymbolRectangle( aSymbol, erectangle, aGateNumber ) );
2231
2232 for( const std::unique_ptr<ETEXT>& etext : aEsymbol->texts )
2233 {
2234 std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( aSymbol, etext, aGateNumber ) );
2235
2236 if( libtext->GetText() == wxT( "${REFERENCE}" ) )
2237 {
2238 // Move text & attributes to Reference field and discard LIB_TEXT item
2239 loadFieldAttributes( &aSymbol->GetReferenceField(), libtext.get() );
2240
2241 // Show Reference field if Eagle reference was uppercase
2242 showRefDes = etext->text == wxT( ">NAME" );
2243 }
2244 else if( libtext->GetText() == wxT( "${VALUE}" ) )
2245 {
2246 // Move text & attributes to Value field and discard LIB_TEXT item
2247 loadFieldAttributes( &aSymbol->GetValueField(), libtext.get() );
2248
2249 // Show Value field if Eagle reference was uppercase
2250 showValue = etext->text == wxT( ">VALUE" );
2251 }
2252 else
2253 {
2254 aSymbol->AddDrawItem( libtext.release() );
2255 }
2256 }
2257
2258 for( const std::unique_ptr<EWIRE>& ewire : aEsymbol->wires )
2259 aSymbol->AddDrawItem( loadSymbolWire( aSymbol, ewire, aGateNumber ) );
2260
2261 for( const std::unique_ptr<EFRAME>& eframe : aEsymbol->frames )
2262 {
2263 std::vector<SCH_ITEM*> frameItems;
2264
2265 loadFrame( eframe, frameItems );
2266
2267 for( SCH_ITEM* item : frameItems )
2268 {
2269 item->SetParent( aSymbol.get() );
2270 item->SetUnit( aGateNumber );
2271 aSymbol->AddDrawItem( item );
2272 }
2273 }
2274
2275 aSymbol->GetReferenceField().SetVisible( showRefDes );
2276 aSymbol->GetValueField().SetVisible( showValue );
2277
2278 return pincount == 1 ? ispower : false;
2279}
2280
2281
2282SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2283 const std::unique_ptr<ECIRCLE>& aCircle,
2284 int aGateNumber )
2285{
2286 wxCHECK( aSymbol && aCircle, nullptr );
2287
2288 // Parse the circle properties
2289 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
2290 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
2291
2292 circle->SetParent( aSymbol.get() );
2293 circle->SetPosition( center );
2294 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
2295 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2296 circle->SetUnit( aGateNumber );
2297
2298 return circle;
2299}
2300
2301
2302SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2303 const std::unique_ptr<ERECT>& aRectangle,
2304 int aGateNumber )
2305{
2306 wxCHECK( aSymbol && aRectangle, nullptr );
2307
2308 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE );
2309
2310 rectangle->SetParent( aSymbol.get() );
2311 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
2312 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
2313
2314 if( aRectangle->rot )
2315 {
2316 VECTOR2I pos( rectangle->GetPosition() );
2317 VECTOR2I end( rectangle->GetEnd() );
2318 VECTOR2I center( rectangle->GetCenter() );
2319
2320 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2321 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2322
2323 rectangle->SetPosition( pos );
2324 rectangle->SetEnd( end );
2325 }
2326
2327 rectangle->SetUnit( aGateNumber );
2328
2329 // Eagle rectangles are filled by definition.
2330 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2331
2332 return rectangle;
2333}
2334
2335
2336SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2337 const std::unique_ptr<EWIRE>& aWire, int aGateNumber )
2338{
2339 wxCHECK( aSymbol && aWire, nullptr );
2340
2341 VECTOR2I begin, end;
2342
2343 begin.x = aWire->x1.ToSchUnits();
2344 begin.y = -aWire->y1.ToSchUnits();
2345 end.x = aWire->x2.ToSchUnits();
2346 end.y = -aWire->y2.ToSchUnits();
2347
2348 if( begin == end )
2349 return nullptr;
2350
2351 // if the wire is an arc
2352 if( aWire->curve )
2353 {
2354 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2355 VECTOR2I center = ConvertArcCenter( begin, end, *aWire->curve * -1 );
2356 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2357 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2358
2359 arc->SetParent( aSymbol.get() );
2360
2361 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2362 if( aWire->cap == EWIRE::FLAT && aWire->width.ToSchUnits() >= 2 * radius )
2363 {
2364 VECTOR2I centerStartVector = ( begin - center ) *
2365 ( aWire->width.ToSchUnits() / radius );
2366 begin = center + centerStartVector;
2367
2368 arc->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2369 arc->SetFillMode( FILL_T::FILLED_SHAPE );
2370 }
2371 else
2372 {
2373 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2374 }
2375
2376 arc->SetCenter( center );
2377 arc->SetStart( begin );
2378 arc->SetArcAngleAndEnd( EDA_ANGLE( *aWire->curve * -1, DEGREES_T ), true );
2379 arc->SetUnit( aGateNumber );
2380
2381 return arc;
2382 }
2383 else
2384 {
2385 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2386
2387 poly->AddPoint( begin );
2388 poly->AddPoint( end );
2389 poly->SetUnit( aGateNumber );
2390 poly->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2391
2392 return poly;
2393 }
2394}
2395
2396
2397SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2398 const std::unique_ptr<EPOLYGON>& aPolygon,
2399 int aGateNumber )
2400{
2401 wxCHECK( aSymbol && aPolygon, nullptr );
2402
2403 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
2404 VECTOR2I pt, prev_pt;
2405 opt_double prev_curve;
2406
2407 poly->SetParent( aSymbol.get() );
2408
2409 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
2410 {
2411 pt = VECTOR2I( evertex->x.ToSchUnits(), evertex->y.ToSchUnits() );
2412
2413 if( prev_curve )
2414 {
2415 SHAPE_ARC arc;
2416 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2417 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2418 }
2419 else
2420 {
2421 poly->AddPoint( pt );
2422 }
2423
2424 prev_pt = pt;
2425 prev_curve = evertex->curve;
2426 }
2427
2428 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2429 poly->SetFillMode( FILL_T::FILLED_SHAPE );
2430 poly->SetUnit( aGateNumber );
2431
2432 return poly;
2433}
2434
2435
2436SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2437 const std::unique_ptr<EPIN>& aPin, int aGateNumber )
2438{
2439 wxCHECK( aSymbol && aPin, nullptr );
2440
2441 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2442 pin->SetPosition( VECTOR2I( aPin->x.ToSchUnits(), -aPin->y.ToSchUnits() ) );
2443 pin->SetName( aPin->name );
2444 pin->SetUnit( aGateNumber );
2445
2446 int roti = aPin->rot ? aPin->rot->degrees : 0;
2447
2448 switch( roti )
2449 {
2450 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2451 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2452 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2453 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2454 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2455 }
2456
2457 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2458
2459 if( aPin->length )
2460 {
2461 wxString length = aPin->length.Get();
2462
2463 if( length == wxT( "short" ) )
2464 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2465 else if( length == wxT( "middle" ) )
2466 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2467 else if( length == wxT( "long" ) )
2468 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2469 else if( length == wxT( "point" ) )
2470 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2471 }
2472
2473 // Pin names and numbers are fixed size in Eagle.
2474 pin->SetNumberTextSize( schIUScale.MilsToIU( 60 ) );
2475 pin->SetNameTextSize( schIUScale.MilsToIU( 60 ) );
2476
2477 // emulate the visibility of pin elements
2478 if( aPin->visible )
2479 {
2480 wxString visible = aPin->visible.Get();
2481
2482 if( visible == wxT( "off" ) )
2483 {
2484 pin->SetNameTextSize( 0 );
2485 pin->SetNumberTextSize( 0 );
2486 }
2487 else if( visible == wxT( "pad" ) )
2488 {
2489 pin->SetNameTextSize( 0 );
2490 }
2491 else if( visible == wxT( "pin" ) )
2492 {
2493 pin->SetNumberTextSize( 0 );
2494 }
2495
2496 /*
2497 * else if( visible == wxT( "both" ) )
2498 * {
2499 * }
2500 */
2501 }
2502
2503 if( aPin->function )
2504 {
2505 wxString function = aPin->function.Get();
2506
2507 if( function == wxT( "dot" ) )
2508 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2509 else if( function == wxT( "clk" ) )
2510 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2511 else if( function == wxT( "dotclk" ) )
2512 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
2513 }
2514
2515 return pin.release();
2516}
2517
2518
2519SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2520 const std::unique_ptr<ETEXT>& aText, int aGateNumber )
2521{
2522 wxCHECK( aSymbol && aText, nullptr );
2523
2524 std::unique_ptr<SCH_TEXT> libtext = std::make_unique<SCH_TEXT>();
2525
2526 libtext->SetParent( aSymbol.get() );
2527 libtext->SetUnit( aGateNumber );
2528 libtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2529
2530 const wxString& eagleText = aText->text;
2531 wxString adjustedText;
2532 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2533
2534 // Strip the whitespace from both ends of each line.
2535 while( tokenizer.HasMoreTokens() )
2536 {
2537 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2538
2539 if( tokenizer.HasMoreTokens() )
2540 tmp += wxT( "\n" );
2541
2542 adjustedText += tmp;
2543 }
2544
2545 libtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "~" ) ) : adjustedText );
2546
2547 loadTextAttributes( libtext.get(), aText );
2548
2549 return libtext.release();
2550}
2551
2552
2553SCH_TEXT* SCH_IO_EAGLE::loadPlainText( const std::unique_ptr<ETEXT>& aText )
2554{
2555 wxCHECK( aText, nullptr );
2556
2557 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2558
2559 const wxString& eagleText = aText->text;
2560 wxString adjustedText;
2561 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2562
2563 // Strip the whitespace from both ends of each line.
2564 while( tokenizer.HasMoreTokens() )
2565 {
2566 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2567
2568 if( tokenizer.HasMoreTokens() )
2569 tmp += wxT( "\n" );
2570
2571 adjustedText += tmp;
2572 }
2573
2574 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "\" \"" ) )
2575 : escapeName( adjustedText ) );
2576
2577 schtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2578 loadTextAttributes( schtext.get(), aText );
2579 schtext->SetItalic( false );
2580
2581 return schtext.release();
2582}
2583
2584
2586 const std::unique_ptr<ETEXT>& aAttributes ) const
2587{
2588 wxCHECK( aText && aAttributes, /* void */ );
2589
2590 aText->SetTextSize( aAttributes->ConvertSize() );
2591
2592 // Must come after SetTextSize()
2593 if( aAttributes->ratio && aAttributes->ratio.CGet() > 12 )
2594 aText->SetBold( true );
2595
2596 int align = aAttributes->align ? *aAttributes->align : ETEXT::BOTTOM_LEFT;
2597 int degrees = aAttributes->rot ? aAttributes->rot->degrees : 0;
2598 bool mirror = aAttributes->rot ? aAttributes->rot->mirror : false;
2599 bool spin = aAttributes->rot ? aAttributes->rot->spin : false;
2600
2601 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
2602}
2603
2604
2605void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
2606{
2607 wxCHECK( aField && aText, /* void */ );
2608
2609 aField->SetTextPos( aText->GetPosition() );
2610 aField->SetTextSize( aText->GetTextSize() );
2611 aField->SetTextAngle( aText->GetTextAngle() );
2612
2613 // Must come after SetTextSize()
2614 aField->SetBold( aText->IsBold() );
2615 aField->SetItalic( false );
2616
2617 aField->SetVertJustify( aText->GetVertJustify() );
2618 aField->SetHorizJustify( aText->GetHorizJustify() );
2619}
2620
2621
2623{
2624 // Eagle supports detached labels, so a label does not need to be placed on a wire
2625 // to be associated with it. KiCad needs to move them, so the labels actually touch the
2626 // corresponding wires.
2627
2628 // Sort the intersection points to speed up the search process
2629 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
2630
2631 auto onIntersection =
2632 [&]( const VECTOR2I& aPos )
2633 {
2634 return std::binary_search( m_wireIntersections.begin(),
2635 m_wireIntersections.end(), aPos );
2636 };
2637
2638 for( SEG_DESC& segDesc : m_segments )
2639 {
2640 for( SCH_TEXT* label : segDesc.labels )
2641 {
2642 VECTOR2I labelPos( label->GetPosition() );
2643 const SEG* segAttached = segDesc.LabelAttached( label );
2644
2645 if( segAttached && !onIntersection( labelPos ) )
2646 continue; // label is placed correctly
2647
2648 // Move the label to the nearest wire
2649 if( !segAttached )
2650 {
2651 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
2652 segDesc.segs );
2653
2654 if( !segAttached ) // we cannot do anything
2655 continue;
2656 }
2657
2658 // Create a vector pointing in the direction of the wire, 50 mils long
2659 VECTOR2I wireDirection( segAttached->B - segAttached->A );
2660 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
2661 const VECTOR2I origPos( labelPos );
2662
2663 // Flags determining the search direction
2664 bool checkPositive = true, checkNegative = true, move = false;
2665 int trial = 0;
2666
2667 // Be sure the label is not placed on a wire intersection
2668 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
2669 {
2670 move = false;
2671
2672 // Move along the attached wire to find the new label position
2673 if( trial % 2 == 1 )
2674 {
2675 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
2676 move = checkPositive = segAttached->Contains( labelPos );
2677 }
2678 else
2679 {
2680 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
2681 move = checkNegative = segAttached->Contains( labelPos );
2682 }
2683
2684 ++trial;
2685 }
2686
2687 if( move )
2688 label->SetPosition( VECTOR2I( labelPos ) );
2689 }
2690 }
2691
2692 m_segments.clear();
2693 m_wireIntersections.clear();
2694}
2695
2696
2697bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
2698{
2699 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
2700 return false;
2701
2702 return checkHeader( aFileName );
2703}
2704
2705
2706bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
2707{
2708 if( !SCH_IO::CanReadLibrary( aFileName ) )
2709 return false;
2710
2711 return checkHeader( aFileName );
2712}
2713
2714
2715bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
2716{
2717 wxFileInputStream input( aFileName );
2718
2719 if( !input.IsOk() )
2720 return false;
2721
2722 wxTextInputStream text( input );
2723
2724 for( int i = 0; i < 8; i++ )
2725 {
2726 if( input.Eof() )
2727 return false;
2728
2729 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
2730 return true;
2731 }
2732
2733 return false;
2734}
2735
2736
2737void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
2738{
2739 wxCHECK( aWire, /* void */ );
2740
2741 SCH_SCREEN* screen = getCurrentScreen();
2742
2743 wxCHECK( screen, /* void */ );
2744
2745 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
2746 {
2747 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
2748 continue;
2749
2750 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
2751 item->SetPosition( aNewEndPoint );
2752 }
2753}
2754
2755
2757{
2758 // Add bus entry symbols
2759 // TODO: Cleanup this function and break into pieces
2760
2761 // for each wire segment, compare each end with all busses.
2762 // If the wire end is found to end on a bus segment, place a bus entry symbol.
2763
2764 std::vector<SCH_LINE*> buses;
2765 std::vector<SCH_LINE*> wires;
2766
2767 SCH_SCREEN* screen = getCurrentScreen();
2768
2769 wxCHECK( screen, /* void */ );
2770
2771 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
2772 {
2773 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
2774
2775 if( line->IsBus() )
2776 buses.push_back( line );
2777 else if( line->IsWire() )
2778 wires.push_back( line );
2779 }
2780
2781 for( SCH_LINE* wire : wires )
2782 {
2783 VECTOR2I wireStart = wire->GetStartPoint();
2784 VECTOR2I wireEnd = wire->GetEndPoint();
2785
2786 for( SCH_LINE* bus : buses )
2787 {
2788 VECTOR2I busStart = bus->GetStartPoint();
2789 VECTOR2I busEnd = bus->GetEndPoint();
2790
2791 auto entrySize =
2792 []( int signX, int signY ) -> VECTOR2I
2793 {
2796 };
2797
2798 auto testBusHit =
2799 [&]( const VECTOR2I& aPt ) -> bool
2800 {
2801 return TestSegmentHit( aPt, busStart, busEnd, 0 );
2802 };
2803
2804 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
2805 {
2806 // Horizontal wire and vertical bus
2807
2808 if( testBusHit( wireStart ) )
2809 {
2810 // Wire start is on the vertical bus
2811
2812 if( wireEnd.x < busStart.x )
2813 {
2814 /* the end of the wire is to the left of the bus
2815 * ⎥⎢
2816 * ——————⎥⎢
2817 * ⎥⎢
2818 */
2819 VECTOR2I p = wireStart + entrySize( -1, 0 );
2820
2821 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2822 {
2823 /* there is room above the wire for the bus entry
2824 * ⎥⎢
2825 * _____/⎥⎢
2826 * ⎥⎢
2827 */
2828 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2829 busEntry->SetFlags( IS_NEW );
2830 screen->Append( busEntry );
2831 moveLabels( wire, p );
2832 wire->SetStartPoint( p );
2833 }
2834 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2835 {
2836 /* there is room below the wire for the bus entry
2837 * _____ ⎥⎢
2838 * \⎥⎢
2839 * ⎥⎢
2840 */
2841 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2842 busEntry->SetFlags( IS_NEW );
2843 screen->Append( busEntry );
2844 moveLabels( wire, p );
2845 wire->SetStartPoint( p );
2846 }
2847 else
2848 {
2849 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2850 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
2851 screen->Append( marker );
2852 }
2853 }
2854 else
2855 {
2856 /* the wire end is to the right of the bus
2857 * ⎥⎢
2858 * ⎥⎢——————
2859 * ⎥⎢
2860 */
2861 VECTOR2I p = wireStart + entrySize( 1, 0 );
2862
2863 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2864 {
2865 /* There is room above the wire for the bus entry
2866 * ⎥⎢
2867 * ⎥⎢\_____
2868 * ⎥⎢
2869 */
2870 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
2871 busEntry->SetFlags( IS_NEW );
2872 screen->Append( busEntry );
2873 moveLabels( wire, p );
2874 wire->SetStartPoint( p );
2875 }
2876 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2877 {
2878 /* There is room below the wire for the bus entry
2879 * ⎥⎢ _____
2880 * ⎥⎢/
2881 * ⎥⎢
2882 */
2883 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2884 busEntry->SetFlags( IS_NEW );
2885 screen->Append( busEntry );
2886 moveLabels( wire, p );
2887 wire->SetStartPoint( p );
2888 }
2889 else
2890 {
2891 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2892 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
2893 screen->Append( marker );
2894 }
2895 }
2896
2897 break;
2898 }
2899 else if( testBusHit( wireEnd ) )
2900 {
2901 // Wire end is on the vertical bus
2902
2903 if( wireStart.x < busStart.x )
2904 {
2905 /* start of the wire is to the left of the bus
2906 * ⎥⎢
2907 * ——————⎥⎢
2908 * ⎥⎢
2909 */
2910 VECTOR2I p = wireEnd + entrySize( -1, 0 );
2911
2912 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2913 {
2914 /* there is room above the wire for the bus entry
2915 * ⎥⎢
2916 * _____/⎥⎢
2917 * ⎥⎢
2918 */
2919 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2920 busEntry->SetFlags( IS_NEW );
2921 screen->Append( busEntry );
2922 moveLabels( wire, p );
2923 wire->SetEndPoint( p );
2924 }
2925 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2926 {
2927 /* there is room below the wire for the bus entry
2928 * _____ ⎥⎢
2929 * \⎥⎢
2930 * ⎥⎢
2931 */
2932 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2933 busEntry->SetFlags( IS_NEW );
2934 screen->Append( busEntry );
2935 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
2936 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
2937 }
2938 else
2939 {
2940 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2941 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
2942 screen->Append( marker );
2943 }
2944 }
2945 else
2946 {
2947 /* the start of the wire is to the right of the bus
2948 * ⎥⎢
2949 * ⎥⎢——————
2950 * ⎥⎢
2951 */
2952 VECTOR2I p = wireEnd + entrySize( 1, 0 );
2953
2954 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
2955 {
2956 /* There is room above the wire for the bus entry
2957 * ⎥⎢
2958 * ⎥⎢\_____
2959 * ⎥⎢
2960 */
2961 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
2962 busEntry->SetFlags( IS_NEW );
2963 screen->Append( busEntry );
2964 moveLabels( wire, p );
2965 wire->SetEndPoint( p );
2966 }
2967 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
2968 {
2969 /* There is room below the wire for the bus entry
2970 * ⎥⎢ _____
2971 * ⎥⎢/
2972 * ⎥⎢
2973 */
2974 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
2975 busEntry->SetFlags( IS_NEW );
2976 screen->Append( busEntry );
2977 moveLabels( wire, p );
2978 wire->SetEndPoint( p );
2979 }
2980 else
2981 {
2982 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
2983 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
2984 screen->Append( marker );
2985 }
2986 }
2987
2988 break;
2989 }
2990 }
2991 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
2992 {
2993 // Vertical wire and horizontal bus
2994
2995 if( testBusHit( wireStart ) )
2996 {
2997 // Wire start is on the bus
2998
2999 if( wireEnd.y < busStart.y )
3000 {
3001 /* the end of the wire is above the bus
3002 * |
3003 * |
3004 * |
3005 * =======
3006 */
3007 VECTOR2I p = wireStart + entrySize( 0, -1 );
3008
3009 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3010 {
3011 /* there is room to the left of the wire for the bus entry
3012 * |
3013 * |
3014 * /
3015 * =======
3016 */
3017 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3018 busEntry->SetFlags( IS_NEW );
3019 screen->Append( busEntry );
3020 moveLabels( wire, p );
3021 wire->SetStartPoint( p );
3022 }
3023 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3024 {
3025 /* there is room to the right of the wire for the bus entry
3026 * |
3027 * |
3028 * \
3029 * =======
3030 */
3031 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3032 busEntry->SetFlags( IS_NEW );
3033 screen->Append( busEntry );
3034 moveLabels( wire, p );
3035 wire->SetStartPoint( p );
3036 }
3037 else
3038 {
3039 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3040 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3041 screen->Append( marker );
3042 }
3043 }
3044 else
3045 {
3046 /* wire end is below the bus
3047 * =======
3048 * |
3049 * |
3050 * |
3051 */
3052 VECTOR2I p = wireStart + entrySize( 0, 1 );
3053
3054 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3055 {
3056 /* there is room to the left of the wire for the bus entry
3057 * =======
3058 * \
3059 * |
3060 * |
3061 */
3062 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3063 busEntry->SetFlags( IS_NEW );
3064 screen->Append( busEntry );
3065 moveLabels( wire, p );
3066 wire->SetStartPoint( p );
3067 }
3068 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3069 {
3070 /* there is room to the right of the wire for the bus entry
3071 * =======
3072 * /
3073 * |
3074 * |
3075 */
3076 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3077 busEntry->SetFlags( IS_NEW );
3078 screen->Append( busEntry );
3079 moveLabels( wire, p );
3080 wire->SetStartPoint( p );
3081 }
3082 else
3083 {
3084 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3085 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3086 screen->Append( marker );
3087 }
3088 }
3089
3090 break;
3091 }
3092 else if( testBusHit( wireEnd ) )
3093 {
3094 // Wire end is on the bus
3095
3096 if( wireStart.y < busStart.y )
3097 {
3098 /* the start of the wire is above the bus
3099 * |
3100 * |
3101 * |
3102 * =======
3103 */
3104 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3105
3106 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3107 {
3108 /* there is room to the left of the wire for the bus entry
3109 * |
3110 * |
3111 * /
3112 * =======
3113 */
3114 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3115 busEntry->SetFlags( IS_NEW );
3116 screen->Append( busEntry );
3117 moveLabels( wire, p );
3118 wire->SetEndPoint( p );
3119 }
3120 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3121 {
3122 /* there is room to the right of the wire for the bus entry
3123 * |
3124 * |
3125 * \
3126 * =======
3127 */
3128 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3129 busEntry->SetFlags( IS_NEW );
3130 screen->Append( busEntry );
3131 moveLabels( wire, p );
3132 wire->SetEndPoint( p );
3133 }
3134 else
3135 {
3136 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3137 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3138 screen->Append( marker );
3139 }
3140 }
3141 else
3142 {
3143 /* wire start is below the bus
3144 * =======
3145 * |
3146 * |
3147 * |
3148 */
3149 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3150
3151 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3152 {
3153 /* there is room to the left of the wire for the bus entry
3154 * =======
3155 * \
3156 * |
3157 * |
3158 */
3159 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3160 busEntry->SetFlags( IS_NEW );
3161 screen->Append( busEntry );
3162 moveLabels( wire, p );
3163 wire->SetEndPoint( p );
3164 }
3165 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3166 {
3167 /* there is room to the right of the wire for the bus entry
3168 * =======
3169 * /
3170 * |
3171 * |
3172 */
3173 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3174 busEntry->SetFlags( IS_NEW );
3175 screen->Append( busEntry );
3176 moveLabels( wire, p );
3177 wire->SetEndPoint( p );
3178 }
3179 else
3180 {
3181 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3182 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3183 screen->Append( marker );
3184 }
3185 }
3186
3187 break;
3188 }
3189 }
3190 else
3191 {
3192 // Wire isn't horizontal or vertical
3193
3194 if( testBusHit( wireStart ) )
3195 {
3196 VECTOR2I wirevector = wireStart - wireEnd;
3197
3198 if( wirevector.x > 0 )
3199 {
3200 if( wirevector.y > 0 )
3201 {
3202 VECTOR2I p = wireStart + entrySize( -1, -1 );
3203 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3204 busEntry->SetFlags( IS_NEW );
3205 screen->Append( busEntry );
3206
3207 moveLabels( wire, p );
3208 wire->SetStartPoint( p );
3209 }
3210 else
3211 {
3212 VECTOR2I p = wireStart + entrySize( -1, 1 );
3213 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3214 busEntry->SetFlags( IS_NEW );
3215 screen->Append( busEntry );
3216
3217 moveLabels( wire, p );
3218 wire->SetStartPoint( p );
3219 }
3220 }
3221 else
3222 {
3223 if( wirevector.y > 0 )
3224 {
3225 VECTOR2I p = wireStart + entrySize( 1, -1 );
3226 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3227 busEntry->SetFlags( IS_NEW );
3228 screen->Append( busEntry );
3229
3230 moveLabels( wire, p );
3231 wire->SetStartPoint( p );
3232 }
3233 else
3234 {
3235 VECTOR2I p = wireStart + entrySize( 1, 1 );
3236 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3237 busEntry->SetFlags( IS_NEW );
3238 screen->Append( busEntry );
3239
3240 moveLabels( wire, p );
3241 wire->SetStartPoint( p );
3242 }
3243 }
3244
3245 break;
3246 }
3247 else if( testBusHit( wireEnd ) )
3248 {
3249 VECTOR2I wirevector = wireStart - wireEnd;
3250
3251 if( wirevector.x > 0 )
3252 {
3253 if( wirevector.y > 0 )
3254 {
3255 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3256 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3257 busEntry->SetFlags( IS_NEW );
3258 screen->Append( busEntry );
3259
3260 moveLabels( wire, p );
3261 wire->SetEndPoint( p );
3262 }
3263 else
3264 {
3265 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3266 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3267 busEntry->SetFlags( IS_NEW );
3268 screen->Append( busEntry );
3269
3270 moveLabels( wire, p );
3271 wire->SetEndPoint( p );
3272 }
3273 }
3274 else
3275 {
3276 if( wirevector.y > 0 )
3277 {
3278 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3279 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3280 busEntry->SetFlags( IS_NEW );
3281 screen->Append( busEntry );
3282
3283 moveLabels( wire, p );
3284 wire->SetEndPoint( p );
3285 }
3286 else
3287 {
3288 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3289 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3290 busEntry->SetFlags( IS_NEW );
3291 screen->Append( busEntry );
3292
3293 moveLabels( wire, p );
3294 wire->SetEndPoint( p );
3295 }
3296 }
3297
3298 break;
3299 }
3300 }
3301 }
3302 }
3303}
3304
3305
3307{
3308 wxCHECK( aLabel, nullptr );
3309
3310 VECTOR2I labelPos( aLabel->GetPosition() );
3311
3312 for( const SEG& seg : segs )
3313 {
3314 if( seg.Contains( labelPos ) )
3315 return &seg;
3316 }
3317
3318 return nullptr;
3319}
3320
3321
3322// TODO could be used to place junctions, instead of IsJunctionNeeded()
3323// (see SCH_EDIT_FRAME::importFile())
3324bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3325{
3326 wxCHECK( aSymbol && aPin, false );
3327
3328 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3329 auto pointIt = m_connPoints.find( pinPosition );
3330
3331 if( pointIt == m_connPoints.end() )
3332 return false;
3333
3334 const auto& items = pointIt->second;
3335
3336 wxCHECK( items.find( aPin ) != items.end(), false );
3337
3338 return items.size() > 1;
3339}
3340
3341
3343 bool aUpdateSet )
3344{
3345 wxCHECK( aSymbol && aScreen && aSymbol->GetLibSymbolRef(), /*void*/ );
3346
3347 // Normally power parts also have power input pins,
3348 // but they already force net names on the attached wires
3349 if( aSymbol->GetLibSymbolRef()->IsGlobalPower() )
3350 return;
3351
3352 int unit = aSymbol->GetUnit();
3353 const wxString reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
3354 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetPins();
3355 std::set<int> missingUnits;
3356
3357 // Search all units for pins creating implicit connections
3358 for( const SCH_PIN* pin : pins )
3359 {
3360 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3361 {
3362 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3363
3364 // Create a global net label only if there are no other wires/pins attached
3365 if( pinInUnit )
3366 {
3367 if( !checkConnections( aSymbol, pin ) )
3368 {
3369 // Create a net label to force the net name on the pin
3370 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3371 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3372 netLabel->SetText( extractNetName( pin->GetName() ) );
3373 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3374 schIUScale.MilsToIU( 40 ) ) );
3375
3376 switch( pin->GetOrientation() )
3377 {
3378 default:
3379 case PIN_ORIENTATION::PIN_RIGHT:
3380 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3381 break;
3382 case PIN_ORIENTATION::PIN_LEFT:
3383 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3384 break;
3385 case PIN_ORIENTATION::PIN_UP:
3386 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3387 break;
3388 case PIN_ORIENTATION::PIN_DOWN:
3389 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3390 break;
3391 }
3392
3393 aScreen->Append( netLabel );
3394 }
3395 }
3396 else if( aUpdateSet )
3397 {
3398 // Found a pin creating implicit connection information in another unit.
3399 // Such units will be instantiated if they do not appear in another sheet and
3400 // processed later.
3401 wxASSERT( pin->GetUnit() );
3402 missingUnits.insert( pin->GetUnit() );
3403 }
3404 }
3405 }
3406
3407 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3408 {
3409 auto cmpIt = m_missingCmps.find( reference );
3410
3411 // The first unit found has always already been processed.
3412 if( cmpIt == m_missingCmps.end() )
3413 {
3414 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3415 entry.cmp = aSymbol;
3416 entry.units.emplace( unit, false );
3417 }
3418 else
3419 {
3420 // Set the flag indicating this unit has been processed.
3421 cmpIt->second.units[unit] = false;
3422 }
3423
3424 if( !missingUnits.empty() ) // Save the units that need later processing
3425 {
3426 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3427 entry.cmp = aSymbol;
3428
3429 // Add units that haven't already been processed.
3430 for( int i : missingUnits )
3431 {
3432 if( entry.units.find( i ) != entry.units.end() )
3433 entry.units.emplace( i, true );
3434 }
3435 }
3436 }
3437}
3438
3439
3440wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3441{
3442 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3443 return aEagleName;
3444
3445 wxString ret = wxT( "{" );
3446
3447 wxStringTokenizer tokenizer( aEagleName, wxT( "," ) );
3448
3449 while( tokenizer.HasMoreTokens() )
3450 {
3451 wxString member = tokenizer.GetNextToken();
3452
3453 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3454 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3455 // if there is an odd number of overbar markers in this net name, we need to append one
3456 // to close it out before appending the space.
3457
3458 if( member.Freq( '!' ) % 2 > 0 )
3459 member << wxT( "!" );
3460
3461 ret << member << wxS( " " );
3462 }
3463
3464 ret.Trim( true );
3465 ret << wxT( "}" );
3466
3467 return ret;
3468}
3469
3470
3471const ESYMBOL* SCH_IO_EAGLE::getEagleSymbol( const std::unique_ptr<EINSTANCE>& aInstance )
3472{
3473 wxCHECK( m_eagleDoc && m_eagleDoc->drawing && m_eagleDoc->drawing->schematic && aInstance,
3474 nullptr );
3475
3476 std::unique_ptr<EPART>& epart = m_eagleDoc->drawing->schematic->parts[aInstance->part];
3477
3478 if( !epart || epart->deviceset.IsEmpty() )
3479 return nullptr;
3480
3481 std::unique_ptr<ELIBRARY>& elibrary = m_eagleDoc->drawing->schematic->libraries[epart->library];
3482
3483 if( !elibrary )
3484 return nullptr;
3485
3486 std::unique_ptr<EDEVICE_SET>& edeviceset = elibrary->devicesets[epart->deviceset];
3487
3488 if( !edeviceset )
3489 return nullptr;
3490
3491 std::unique_ptr<EGATE>& egate = edeviceset->gates[aInstance->gate];
3492
3493 if( !egate )
3494 return nullptr;
3495
3496 std::unique_ptr<ESYMBOL>& esymbol = elibrary->symbols[egate->symbol];
3497
3498 if( esymbol )
3499 return esymbol.get();
3500
3501 return nullptr;
3502}
3503
3504
3505void SCH_IO_EAGLE::getEagleSymbolFieldAttributes( const std::unique_ptr<EINSTANCE>& aInstance,
3506 const wxString& aEagleFieldName,
3507 SCH_FIELD* aField )
3508{
3509 wxCHECK( aField && !aEagleFieldName.IsEmpty(), /* void */ );
3510
3511 const ESYMBOL* esymbol = getEagleSymbol( aInstance );
3512
3513 if( esymbol )
3514 {
3515 for( const std::unique_ptr<ETEXT>& text : esymbol->texts )
3516 {
3517 if( text->text == aEagleFieldName )
3518 {
3519 aField->SetVisible( true );
3520 VECTOR2I pos( text->x.ToSchUnits() + aInstance->x.ToSchUnits(),
3521 -text->y.ToSchUnits() - aInstance->y.ToSchUnits() );
3522
3523 bool mirror = text->rot ? text->rot->mirror : false;
3524
3525 if( aInstance->rot && aInstance->rot->mirror )
3526 mirror = !mirror;
3527
3528 if( mirror )
3529 pos.y = -aInstance->y.ToSchUnits() + text->y.ToSchUnits();
3530
3531 aField->SetPosition( pos );
3532 }
3533 }
3534 }
3535}
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:131
const KIID m_Uuid
Definition: eda_item.h:494
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:110
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:912
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:337
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:215
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:177
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:1061
void SetFillMode(FILL_T aFill)
Definition: eda_shape.cpp:536
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:192
Define a library symbol object.
Definition: lib_symbol.h:85
void GetFields(std::vector< SCH_FIELD * > &aList, bool aVisibleOnly=false) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
bool IsGlobalPower() const override
Definition: lib_symbol.cpp:451
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:69
PROJECT & Prj() const
Return a reference to the project this schematic is part of.
Definition: schematic.h:84
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:188
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:133
SCH_SHEET & Root() const
Definition: schematic.h:117
Class for a wire to bus entry.
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
Definition: sch_field.cpp:398
bool IsEmpty()
Return true if both the name and value of the field are empty.
Definition: sch_field.h:163
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1294
void SetName(const wxString &aName)
Definition: sch_field.cpp:1059
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1069
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1886
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:168
int GetUnit() const
Definition: sch_item.h:240
virtual void SetUnit(int aUnit)
Definition: sch_item.h:239
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:136
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:177
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_label.cpp:376
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:933
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:939
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:144
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:545
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:734
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:134
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:155
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:135
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:112
const KIID & GetUuid() const
Definition: sch_screen.h:530
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:82
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
VECTOR2I GetCenter() const
Definition: sch_shape.h:84
void AddPoint(const VECTOR2I &aPosition)
Definition: sch_shape.cpp:394
VECTOR2I GetPosition() const override
Definition: sch_shape.h:81
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:47
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:327
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:321
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:789
void SetName(const wxString &aName)
Definition: sch_sheet.h:114
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:116
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:137
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Definition: sch_sheet.cpp:637
Schematic symbol object.
Definition: sch_symbol.h:75
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition: sch_symbol.h:134
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
Definition: sch_symbol.cpp:511
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:183
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:813
VECTOR2I GetPosition() const override
Definition: sch_text.h:139
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_text.h:140
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:216
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:71
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
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:175
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Definition of file extensions used in Kicad.