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