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