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, std::vector<SCH_ITEM*>& aItems,
1287 SCH_LAYER_ID aLayer )
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, aLayer );
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, aLayer );
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, aLayer );
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->SetLayer( aLayer );
1340 legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
1343 legendText->SetText( wxString( legendChar ) );
1344 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1345 schIUScale.MilsToIU( 100 ) ) );
1346 aItems.push_back( legendText );
1347 legendChar++;
1348 legendPosY += rowSpacing;
1349 }
1350 }
1351
1352 if( !( aFrame->border_right == false ) )
1353 {
1354 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1355 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1356 yMin + schIUScale.MilsToIU( 150 ) ) );
1357 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1358 yMax - schIUScale.MilsToIU( 150 ) ) );
1359 aItems.push_back( lines );
1360
1361 int i;
1362 int height = yMax - yMin;
1363 int x1 = xMax - schIUScale.MilsToIU( 150 );
1364 int x2 = xMax;
1365 int legendPosX = xMax - schIUScale.MilsToIU( 75 );
1366 double rowSpacing = height / double( aFrame->rows );
1367 double legendPosY = yMin + ( rowSpacing / 2 );
1368
1369 for( i = 1; i < aFrame->rows; i++ )
1370 {
1371 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
1372 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1373 lines->AddPoint( VECTOR2I( x1, newY ) );
1374 lines->AddPoint( VECTOR2I( x2, newY ) );
1375 aItems.push_back( lines );
1376 }
1377
1378 char legendChar = 'A';
1379
1380 for( i = 0; i < aFrame->rows; i++ )
1381 {
1382 SCH_TEXT* legendText = new SCH_TEXT();
1383 legendText->SetLayer( aLayer );
1384 legendText->SetPosition( VECTOR2I( legendPosX, KiROUND( legendPosY ) ) );
1387 legendText->SetText( wxString( legendChar ) );
1388 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1389 schIUScale.MilsToIU( 100 ) ) );
1390 aItems.push_back( legendText );
1391 legendChar++;
1392 legendPosY += rowSpacing;
1393 }
1394 }
1395
1396 if( !( aFrame->border_top == false ) )
1397 {
1398 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1399 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1400 yMin + schIUScale.MilsToIU( 150 ) ) );
1401 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1402 yMin + schIUScale.MilsToIU( 150 ) ) );
1403 aItems.push_back( lines );
1404
1405 int i;
1406 int width = xMax - xMin;
1407 int y1 = yMin;
1408 int y2 = yMin + schIUScale.MilsToIU( 150 );
1409 int legendPosY = yMin + schIUScale.MilsToIU( 75 );
1410 double columnSpacing = width / double( aFrame->columns );
1411 double legendPosX = xMin + ( columnSpacing / 2 );
1412
1413 for( i = 1; i < aFrame->columns; i++ )
1414 {
1415 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
1416 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1417 lines->AddPoint( VECTOR2I( newX, y1 ) );
1418 lines->AddPoint( VECTOR2I( newX, y2 ) );
1419 aItems.push_back( lines );
1420 }
1421
1422 char legendChar = '1';
1423
1424 for( i = 0; i < aFrame->columns; i++ )
1425 {
1426 SCH_TEXT* legendText = new SCH_TEXT();
1427 legendText->SetLayer( aLayer );
1428 legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
1431 legendText->SetText( wxString( legendChar ) );
1432 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1433 schIUScale.MilsToIU( 100 ) ) );
1434 aItems.push_back( legendText );
1435 legendChar++;
1436 legendPosX += columnSpacing;
1437 }
1438 }
1439
1440 if( !( aFrame->border_bottom == false ) )
1441 {
1442 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1443 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
1444 yMax - schIUScale.MilsToIU( 150 ) ) );
1445 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
1446 yMax - schIUScale.MilsToIU( 150 ) ) );
1447 aItems.push_back( lines );
1448
1449 int i;
1450 int width = xMax - xMin;
1451 int y1 = yMax - schIUScale.MilsToIU( 150 );
1452 int y2 = yMax;
1453 int legendPosY = yMax - schIUScale.MilsToIU( 75 );
1454 double columnSpacing = width / double( aFrame->columns );
1455 double legendPosX = xMin + ( columnSpacing / 2 );
1456
1457 for( i = 1; i < aFrame->columns; i++ )
1458 {
1459 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
1460 lines = new SCH_SHAPE( SHAPE_T::POLY, aLayer );
1461 lines->AddPoint( VECTOR2I( newX, y1 ) );
1462 lines->AddPoint( VECTOR2I( newX, y2 ) );
1463 aItems.push_back( lines );
1464 }
1465
1466 char legendChar = '1';
1467
1468 for( i = 0; i < aFrame->columns; i++ )
1469 {
1470 SCH_TEXT* legendText = new SCH_TEXT();
1471 legendText->SetLayer( aLayer );
1472 legendText->SetPosition( VECTOR2I( KiROUND( legendPosX ), legendPosY ) );
1475 legendText->SetText( wxString( legendChar ) );
1476 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
1477 schIUScale.MilsToIU( 100 ) ) );
1478 aItems.push_back( legendText );
1479 legendChar++;
1480 legendPosX += columnSpacing;
1481 }
1482 }
1483}
1484
1485
1486void SCH_IO_EAGLE::loadSegments( const std::vector<std::unique_ptr<ESEGMENT>>& aSegments,
1487 const wxString& netName,
1488 const wxString& aNetClass,
1489 bool aIsBus )
1490{
1491 // Loop through all segments
1492 SCH_SCREEN* screen = getCurrentScreen();
1493
1494 wxCHECK( screen, /* void */ );
1495
1496 size_t segmentCount = aSegments.size();
1497
1498 for( const std::unique_ptr<ESEGMENT>& esegment : aSegments )
1499 {
1500 bool labelled = false; // has a label been added to this continuously connected segment
1501 bool firstWireFound = false;
1502 SEG firstWire;
1503
1504 m_segments.emplace_back();
1505 SEG_DESC& segDesc = m_segments.back();
1506
1507 for( const std::unique_ptr<EWIRE>& ewire : esegment->wires )
1508 {
1509 // TODO: Check how intersections used in adjustNetLabels should be
1510 // calculated - for now we pretend that all wires are line segments.
1511 SEG thisWire;
1512 SCH_ITEM* wire = loadWire( ewire, thisWire );
1513 m_connPoints[thisWire.A].emplace( wire );
1514 m_connPoints[thisWire.B].emplace( wire );
1515
1516 if( !firstWireFound )
1517 {
1518 firstWire = thisWire;
1519 firstWireFound = true;
1520 }
1521
1522 // Test for intersections with other wires
1523 for( SEG_DESC& desc : m_segments )
1524 {
1525 if( !desc.labels.empty() && desc.labels.front()->GetText() == netName )
1526 continue; // no point in saving intersections of the same net
1527
1528 for( const SEG& seg : desc.segs )
1529 {
1530 OPT_VECTOR2I intersection = thisWire.Intersect( seg, true );
1531
1532 if( intersection )
1533 m_wireIntersections.push_back( *intersection );
1534 }
1535 }
1536
1537 segDesc.segs.push_back( thisWire );
1538 screen->Append( wire );
1539 }
1540
1541 for( const std::unique_ptr<EJUNCTION>& ejunction : esegment->junctions )
1542 screen->Append( loadJunction( ejunction ) );
1543
1544 for( const std::unique_ptr<ELABEL>& elabel : esegment->labels )
1545 {
1546 SCH_LABEL_BASE* label = loadLabel( elabel, netName, aIsBus );
1547 screen->Append( label );
1548
1549 wxASSERT( segDesc.labels.empty()
1550 || segDesc.labels.front()->GetText() == label->GetText() );
1551
1552 segDesc.labels.push_back( label );
1553 labelled = true;
1554 }
1555
1556 for( const std::unique_ptr<EPINREF>& epinref : esegment->pinRefs )
1557 {
1558 wxString part = epinref->part;
1559 wxString pin = epinref->pin;
1560
1561 auto powerPort = m_powerPorts.find( wxT( "#" ) + part );
1562
1563 if( powerPort != m_powerPorts.end()
1564 && powerPort->second == EscapeString( pin, CTX_NETNAME ) )
1565 {
1566 labelled = true;
1567 }
1568 }
1569
1570 // Add a small label to the net segment if it hasn't been labeled already or is not
1571 // connect to a power symbol with a pin on the same net. This preserves the named net
1572 // feature of Eagle schematics.
1573 if( !labelled && firstWireFound )
1574 {
1575 std::unique_ptr<SCH_LABEL_BASE> label;
1576
1577 // Eagle uses a flat net namespace, so a named net should retain its name across
1578 // every segment and every sheet. The PCB importer carries Eagle signal names
1579 // through verbatim, so we must use a global label here too: a local SCH_LABEL
1580 // would prepend the sheet path (e.g. "/+24V_SWD") and split the net from the
1581 // matching PCB signal on net update.
1582 //
1583 // Two exceptions: (1) buses are conceptual groupings in Eagle, not electrical
1584 // signals, so a global bus label would join same-named buses project-wide where
1585 // Eagle only had visual grouping; (2) nets inside module instances are scoped
1586 // by the module's ports, so a global label would punch through the hierarchy.
1587 if( segmentCount > 1 || m_netCounts[netName] > 1 )
1588 {
1589 if( aIsBus || !m_modules.empty() )
1590 label.reset( new SCH_LABEL );
1591 else
1592 label.reset( new SCH_GLOBALLABEL );
1593 }
1594
1595 if( label )
1596 {
1597 label->SetPosition( firstWire.A );
1598 label->SetText( escapeName( netName ) );
1599 label->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
1600 schIUScale.MilsToIU( 40 ) ) );
1601
1602 if( firstWire.A.y == firstWire.B.y ) // Horizontal wire.
1603 {
1604 if( firstWire.B.x > firstWire.A.x )
1605 label->SetSpinStyle( SPIN_STYLE::LEFT );
1606 else
1607 label->SetSpinStyle( SPIN_STYLE::RIGHT );
1608 }
1609 else if( firstWire.A.x == firstWire.B.x ) // Vertical wire.
1610 {
1611 if( firstWire.B.y > firstWire.A.y )
1612 label->SetSpinStyle( SPIN_STYLE::BOTTOM );
1613 else
1614 label->SetSpinStyle( SPIN_STYLE::UP );
1615 }
1616
1617 screen->Append( label.release() );
1618 }
1619 }
1620 }
1621}
1622
1623
1624SCH_SHAPE* SCH_IO_EAGLE::loadPolyLine( const std::unique_ptr<EPOLYGON>& aPolygon )
1625{
1626 if( !aPolygon->IsValidOutline() )
1627 return nullptr;
1628
1629 std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>( SHAPE_T::POLY );
1630 VECTOR2I pt, prev_pt;
1631 opt_double prev_curve;
1632
1633 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
1634 {
1635 pt = VECTOR2I( evertex->x.ToSchUnits(), -evertex->y.ToSchUnits() );
1636
1637 if( prev_curve )
1638 {
1639 SHAPE_ARC arc;
1640 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
1641 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
1642 }
1643 else
1644 {
1645 poly->AddPoint( pt );
1646 }
1647
1648 prev_pt = pt;
1649 prev_curve = evertex->curve;
1650 }
1651
1652 poly->SetLayer( kiCadLayer( aPolygon->layer ) );
1653 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1654 poly->SetFillMode( FILL_T::FILLED_SHAPE );
1655
1656 return poly.release();
1657}
1658
1659
1660SCH_ITEM* SCH_IO_EAGLE::loadWire( const std::unique_ptr<EWIRE>& aWire, SEG& endpoints )
1661{
1662 VECTOR2I start, end;
1663
1664 start.x = aWire->x1.ToSchUnits();
1665 start.y = -aWire->y1.ToSchUnits();
1666 end.x = aWire->x2.ToSchUnits();
1667 end.y = -aWire->y2.ToSchUnits();
1668
1669 // For segment wires.
1670 endpoints = SEG( start, end );
1671
1672 int kicadLayer = kiCadLayer( aWire->layer );
1673
1674 // Don't process curved wires on an electrical layer into arcs, they aren't supported
1675 // in the rest of the code
1676 // TODO: When curved wires/buses are added, remove this restriction
1677 if( (kicadLayer == LAYER_NOTES) && aWire->curve )
1678 {
1679 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC );
1680
1681 VECTOR2I center = ConvertArcCenter( start, end, *aWire->curve );
1682 arc->SetCenter( center );
1683 arc->SetStart( start );
1684
1685 // KiCad rotates the other way.
1686 arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
1687 arc->SetLayer( kiCadLayer( aWire->layer ) );
1688 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1689
1690 return arc.release();
1691 }
1692 else
1693 {
1694 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>();
1695
1696 line->SetStartPoint( start );
1697 line->SetEndPoint( end );
1698 line->SetLayer( kiCadLayer( aWire->layer ) );
1699 line->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1700
1701 return line.release();
1702 }
1703}
1704
1705
1706SCH_SHAPE* SCH_IO_EAGLE::loadCircle( const std::unique_ptr<ECIRCLE>& aCircle )
1707{
1708 std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
1709 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
1710
1711 circle->SetLayer( kiCadLayer( aCircle->layer ) );
1712 circle->SetPosition( center );
1713 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
1714 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
1715
1716 return circle.release();
1717}
1718
1719
1720SCH_SHAPE* SCH_IO_EAGLE::loadRectangle( const std::unique_ptr<ERECT>& aRectangle )
1721{
1722 std::unique_ptr<SCH_SHAPE> rectangle = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
1723
1724 rectangle->SetLayer( kiCadLayer( aRectangle->layer ) );
1725 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
1726 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
1727
1728 if( aRectangle->rot )
1729 {
1730 VECTOR2I pos( rectangle->GetPosition() );
1731 VECTOR2I end( rectangle->GetEnd() );
1732 VECTOR2I center( rectangle->GetCenter() );
1733
1734 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
1735 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
1736
1737 rectangle->SetPosition( pos );
1738 rectangle->SetEnd( end );
1739 }
1740
1741 // Eagle rectangles are filled by definition.
1742 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
1743
1744 return rectangle.release();
1745}
1746
1747
1748SCH_JUNCTION* SCH_IO_EAGLE::loadJunction( const std::unique_ptr<EJUNCTION>& aJunction )
1749{
1750 std::unique_ptr<SCH_JUNCTION> junction = std::make_unique<SCH_JUNCTION>();
1751
1752 VECTOR2I pos( aJunction->x.ToSchUnits(), -aJunction->y.ToSchUnits() );
1753
1754 junction->SetPosition( pos );
1755
1756 return junction.release();
1757}
1758
1759
1760SCH_LABEL_BASE* SCH_IO_EAGLE::loadLabel( const std::unique_ptr<ELABEL>& aLabel,
1761 const wxString& aNetName, bool aIsBus )
1762{
1763 VECTOR2I elabelpos( aLabel->x.ToSchUnits(), -aLabel->y.ToSchUnits() );
1764
1765 // Label-kind decision mirrors loadSegments(): SCH_HIERLABEL for module ports,
1766 // SCH_LABEL for buses and module-internal nets, SCH_GLOBALLABEL otherwise so the
1767 // Eagle flat net namespace round-trips through the matching PCB signal name.
1768 std::unique_ptr<SCH_LABEL_BASE> label;
1769
1770 VECTOR2I textSize = KiROUND( aLabel->size.ToSchUnits() * 0.7, aLabel->size.ToSchUnits() * 0.7 );
1771
1772 auto findModulePort =
1773 [&]() -> const EPORT*
1774 {
1775 if( m_modules.empty() )
1776 return nullptr;
1777
1778 const auto& ports = m_modules.back()->ports;
1779 const auto it = ports.find( aNetName );
1780 return it == ports.end() ? nullptr : it->second.get();
1781 };
1782
1783 const EPORT* port = findModulePort();
1784
1785 if( port )
1786 {
1787 auto hierLabel = std::make_unique<SCH_HIERLABEL>();
1788
1789 if( port->direction )
1790 {
1791 wxString direction = *port->direction;
1792 LABEL_SHAPE type;
1793
1794 if( direction == "in" )
1796 else if( direction == "out" )
1798 else if( direction == "io" )
1800 else if( direction == "hiz" )
1802 else
1804
1805 // KiCad does not support passive, power, open collector, or no-connect sheet
1806 // pins that Eagle ports support. They are set to unspecified to minimize
1807 // ERC issues.
1808 hierLabel->SetLabelShape( type );
1809 }
1810
1811 label = std::move( hierLabel );
1812 }
1813 else if( aIsBus || !m_modules.empty() )
1814 {
1815 label = std::make_unique<SCH_LABEL>();
1816 }
1817 else
1818 {
1819 label = std::make_unique<SCH_GLOBALLABEL>();
1820 }
1821
1822 label->SetText( escapeName( aNetName ) );
1823 label->SetPosition( elabelpos );
1824 label->SetTextSize( textSize );
1825 label->SetSpinStyle( SPIN_STYLE::RIGHT );
1826
1827 if( aLabel->rot )
1828 {
1829 // According to the Eagle DTD, labels can only be rotated in 90 degree increments.
1830 int angle = KiROUND( aLabel->rot->degrees );
1831
1832 switch( angle )
1833 {
1834 case 90:
1835 label->SetSpinStyle( aLabel->rot->mirror ? SPIN_STYLE::BOTTOM : SPIN_STYLE::UP );
1836 break;
1837 case 180:
1838 label->SetSpinStyle( aLabel->rot->mirror ? SPIN_STYLE::RIGHT : SPIN_STYLE::LEFT );
1839 break;
1840 case 270:
1841 label->SetSpinStyle( aLabel->rot->mirror ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM );
1842 break;
1843 default:
1844 label->SetSpinStyle( aLabel->rot->mirror ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT );
1845 break;
1846 }
1847 }
1848
1849 return label.release();
1850}
1851
1852
1853std::pair<VECTOR2I, const SEG*>
1855 const std::vector<SEG>& aLines ) const
1856{
1857 VECTOR2I nearestPoint;
1858 const SEG* nearestLine = nullptr;
1859
1860 double d, mindistance = std::numeric_limits<double>::max();
1861
1862 // Project the label onto the closest wire. Snapping to the perpendicular foot keeps a
1863 // detached Eagle label at its position along the wire; snapping only to the wire's
1864 // endpoints or midpoint would slide it far along a long wire and pile parallel labels
1865 // onto the same point.
1866 for( const SEG& line : aLines )
1867 {
1868 VECTOR2I testpoint = line.NearestPoint( aPoint );
1869 d = aPoint.Distance( testpoint );
1870
1871 if( d < mindistance )
1872 {
1873 mindistance = d;
1874 nearestPoint = testpoint;
1875 nearestLine = &line;
1876 }
1877 }
1878
1879 return std::make_pair( nearestPoint, nearestLine );
1880}
1881
1882
1883void SCH_IO_EAGLE::loadInstance( const std::unique_ptr<EINSTANCE>& aInstance,
1884 const std::map<wxString, std::unique_ptr<EPART>>& aParts )
1885{
1886 wxCHECK( aInstance, /* void */ );
1887
1888 SCH_SCREEN* screen = getCurrentScreen();
1889
1890 wxCHECK( screen, /* void */ );
1891
1892 const auto partIt = aParts.find( aInstance->part );
1893
1894 if( partIt == aParts.end() )
1895 {
1896 Report( wxString::Format( _( "Error parsing Eagle file. Could not find '%s' "
1897 "instance but it is referenced in the schematic." ),
1898 aInstance->part ),
1900
1901 return;
1902 }
1903
1904 const std::unique_ptr<EPART>& epart = partIt->second;
1905
1906 wxString libName = epart->library;
1907
1908 // Correctly handle versioned libraries.
1909 if( epart->libraryUrn )
1910 libName += wxS( "_" ) + epart->libraryUrn->assetId;
1911
1912 wxString gatename = epart->deviceset + wxS( "_" ) + epart->device + wxS( "_" ) +
1913 aInstance->gate;
1914 wxString symbolname = wxString( epart->deviceset + epart->device );
1915 wxString kiPackageName = epart->deviceset + epart->device;
1916
1917 if( epart->technology )
1918 symbolname += *epart->technology;
1919
1920 symbolname.Replace( wxT( "*" ), wxEmptyString );
1921 kiPackageName.Replace( wxT( "*" ), wxEmptyString );
1922
1923 wxString kisymbolname = EscapeString( symbolname, CTX_LIBID );
1924
1925 // Eagle schematics can have multiple libraries containing symbols with duplicate symbol
1926 // names. Because this parser stores all of the symbols in a single library, the
1927 // loadSymbol() function, prefixed the original Eagle library name to the symbol name
1928 // in case of a name clash. Check for the prefixed symbol first. This ensures that
1929 // the correct library symbol gets mapped on load.
1930 wxString altSymbolName = libName + wxT( "_" ) + symbolname;
1931 altSymbolName = EscapeString( altSymbolName, CTX_LIBID );
1932
1933 wxString libIdSymbolName = altSymbolName;
1934
1935 const auto libIt = m_eagleLibs.find( libName );
1936
1937 if( libIt == m_eagleLibs.end() )
1938 {
1939 Report( wxString::Format( wxS( "Eagle library '%s' not found while looking up symbol for "
1940 "deviceset '%s', device '%s', and gate '%s." ),
1941 libName, epart->deviceset, epart->device, aInstance->gate ) );
1942 return;
1943 }
1944
1945 const auto gateIt = libIt->second.GateToUnitMap.find( gatename );
1946
1947 if( gateIt == libIt->second.GateToUnitMap.end() )
1948 {
1949 Report( wxString::Format( wxS( "Symbol not found for deviceset '%s', device '%s', and "
1950 "gate '%s in library '%s'." ),
1951 epart->deviceset, epart->device, aInstance->gate, libName ) );
1952 return;
1953 }
1954
1955 int unit = gateIt->second;
1956
1957 wxString package;
1958 EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
1959
1960 auto p = elib->package.find( kisymbolname );
1961
1962 if( p != elib->package.end() )
1963 {
1964 package = p->second;
1965 }
1966 else
1967 {
1968 p = elib->package.find( kiPackageName );
1969
1970 if( p != elib->package.end() )
1971 package = p->second;
1972 }
1973
1974 // set properties to prevent save file on every symbol save
1975 std::map<std::string, UTF8> properties;
1976 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
1977
1978 LIB_SYMBOL* part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), altSymbolName, &properties );
1979
1980 if( !part )
1981 {
1982 part = m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname, &properties );
1983 libIdSymbolName = kisymbolname;
1984 }
1985
1986 if( !part )
1987 {
1988 Report( wxString::Format( _( "Could not find '%s' in the imported library." ),
1989 UnescapeString( kisymbolname ) ),
1991 return;
1992 }
1993
1994 LIB_ID libId( getLibName(), libIdSymbolName );
1995 std::unique_ptr<SCH_SYMBOL> symbol = std::make_unique<SCH_SYMBOL>();
1996 symbol->SetLibId( libId );
1997 symbol->SetUnit( unit );
1998 symbol->SetPosition( VECTOR2I( aInstance->x.ToSchUnits(), -aInstance->y.ToSchUnits() ) );
1999
2000 // assume that footprint library is identical to project name
2001 if( !package.IsEmpty() )
2002 {
2003 wxString footprint = m_schematic->Project().GetProjectName() + wxT( ":" ) + package;
2004 symbol->GetField( FIELD_T::FOOTPRINT )->SetText( footprint );
2005 }
2006
2007 if( aInstance->rot )
2008 {
2009 symbol->SetOrientation( kiCadComponentRotation( aInstance->rot->degrees ) );
2010
2011 if( aInstance->rot->mirror )
2012 symbol->MirrorHorizontally( aInstance->x.ToSchUnits() );
2013 }
2014
2015 std::vector<SCH_FIELD*> partFields;
2016 part->GetFields( partFields );
2017
2018 VECTOR2I nextFieldPosition = getLastSymbolFieldPosition( part ) + symbol->GetPosition();
2019
2020 for( const SCH_FIELD* partField : partFields )
2021 {
2022 SCH_FIELD* symbolField = nullptr;
2023
2024 if( partField->IsMandatory() )
2025 symbolField = symbol->GetField( partField->GetId() );
2026 else
2027 symbolField = symbol->GetField( partField->GetName() );
2028
2029 if( !symbolField )
2030 {
2031 SCH_FIELD newField( symbol.get(), FIELD_T::USER, partField->GetName() );
2032
2033 newField.SetVisible( false );
2034 newField.SetText( partField->GetText() );
2035
2036 nextFieldPosition.y += newField.GetTextHeight() + schIUScale.MilsToIU( 10 );
2037 newField.SetPosition( nextFieldPosition );
2038 symbol->AddField( newField );
2039 }
2040 else
2041 {
2042 symbolField->ImportValues( *partField );
2043 symbolField->SetTextPos( symbol->GetPosition() + partField->GetTextPos() );
2044 }
2045 }
2046
2047 // If there is no footprint assigned, then prepend the reference value
2048 // with a hash character to mute netlist updater complaints
2049 wxString reference = package.IsEmpty() ? '#' + aInstance->part : aInstance->part;
2050
2051 // reference must end with a number but EAGLE does not enforce this
2052 if( reference.find_last_not_of( wxT( "0123456789" ) ) == ( reference.Length()-1 ) )
2053 reference.Append( wxT( "0" ) );
2054
2055 // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
2056 // parts to have non-digit + digit annotation. If the reference begins with a number,
2057 // we prepend 'UNK' (unknown) for the symbol designator
2058 if( reference.find_first_not_of( wxT( "0123456789" ) ) != 0 )
2059 reference.Prepend( wxT( "UNK" ) );
2060
2061 // EAGLE allows designator to start with # but that is used in KiCad
2062 // for symbols which do not have a footprint
2063 if( aInstance->part.find_first_not_of( wxT( "#" ) ) != 0 )
2064 reference.Prepend( wxT( "UNK" ) );
2065
2066 SCH_FIELD* referenceField = symbol->GetField( FIELD_T::REFERENCE );
2067 referenceField->SetText( reference );
2068
2069 SCH_FIELD* valueField = symbol->GetField( FIELD_T::VALUE );
2070 bool userValue = m_userValue.at( libIdSymbolName );
2071
2072 if( part->GetUnitCount() > 1 )
2073 {
2074 getEagleSymbolFieldAttributes( aInstance, wxS( ">NAME" ), referenceField );
2075 getEagleSymbolFieldAttributes( aInstance, wxS( ">VALUE" ), valueField );
2076 }
2077
2078 if( epart->value && !epart->value.CGet().IsEmpty() )
2079 {
2080 valueField->SetText( *epart->value );
2081 }
2082 else
2083 {
2084 valueField->SetText( kisymbolname );
2085
2086 if( userValue )
2087 valueField->SetVisible( false );
2088 }
2089
2090 for( const auto& [ attrName, attr ] : epart->attributes )
2091 {
2092 SCH_FIELD newField( symbol.get(), FIELD_T::USER );
2093
2094 newField.SetName( attrName );
2095
2096 if( !symbol->GetFields().empty() )
2097 newField.SetTextPos( symbol->GetFields().back().GetPosition() );
2098
2099 if( attr->value )
2100 newField.SetText( *attr->value );
2101
2102 newField.SetVisible( ( attr->display == EATTR::Off ) ? false : true );
2103
2104 symbol->AddField( newField );
2105 }
2106
2107 bool valueAttributeFound = false;
2108 bool nameAttributeFound = false;
2109
2110 // Parse attributes for the instance
2111 for( auto& [name, eattr] : aInstance->attributes )
2112 {
2113 SCH_FIELD* field = nullptr;
2114
2115 if( eattr->name.Lower() == wxT( "name" ) )
2116 {
2117 field = symbol->GetField( FIELD_T::REFERENCE );
2118 nameAttributeFound = true;
2119 }
2120 else if( eattr->name.Lower() == wxT( "value" ) )
2121 {
2122 field = symbol->GetField( FIELD_T::VALUE );
2123 valueAttributeFound = true;
2124 }
2125 else
2126 {
2127 field = symbol->GetField( eattr->name );
2128 }
2129
2130 if( field )
2131 {
2132 field->SetVisible( true );
2133 field->SetPosition( VECTOR2I( eattr->x->ToSchUnits(), -eattr->y->ToSchUnits() ) );
2134
2135 if( eattr->size )
2136 field->SetTextSize( ConvertEagleTextSize( eattr->font, eattr->size.Get() ) );
2137
2138 int align = eattr->align ? *eattr->align : ETEXT::BOTTOM_LEFT;
2139 int absdegrees = eattr->rot ? eattr->rot->degrees : 0;
2140 bool mirror = eattr->rot ? eattr->rot->mirror : false;
2141
2142 if( aInstance->rot && aInstance->rot->mirror )
2143 mirror = !mirror;
2144
2145 bool spin = eattr->rot ? eattr->rot->spin : false;
2146
2147 if( eattr->display == EATTR::Off || eattr->display == EATTR::NAME )
2148 field->SetVisible( false );
2149
2150 int rotation = aInstance->rot ? aInstance->rot->degrees : 0;
2151 int reldegrees = ( absdegrees - rotation + 360.0 );
2152 reldegrees %= 360;
2153
2154 eagleToKicadAlignment( field, align, reldegrees, mirror, spin, absdegrees );
2155 }
2156 }
2157
2158 // Use the instance attribute to determine the reference and value field visibility.
2159 if( aInstance->smashed && aInstance->smashed.Get() )
2160 {
2161 symbol->GetField( FIELD_T::VALUE )->SetVisible( valueAttributeFound );
2162 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( nameAttributeFound );
2163 }
2164
2165 // Eagle has a brain dead module reference scheme where the module names separated by colons
2166 // are prefixed to the symbol references. This will get blown away in KiCad the first time
2167 // any annotation is performed. It is required for the initial synchronization between the
2168 // schematic and the board.
2169 wxString refPrefix;
2170
2171 for( const EMODULEINST* emoduleInst : m_moduleInstances )
2172 {
2173 wxCHECK2( emoduleInst, continue );
2174
2175 refPrefix += emoduleInst->name + wxS( ":" );
2176 }
2177
2178 symbol->AddHierarchicalReference( m_sheetPath.Path(), refPrefix + reference, unit );
2179
2180 // Cache the lib symbol so pin positions are available for connection-point tracking.
2181 // Use the already-loaded `part` directly rather than re-fetching through the adapter,
2182 // because the .kicad_sym library is still buffered in m_pi and has not yet been saved to
2183 // disk at the time loadInstance runs.
2184 symbol->SetLibSymbol( part->Flatten().release() );
2185
2186 for( const auto& [name, variant] : epart->variants )
2187 {
2188 SCH_SYMBOL_VARIANT symbolVariant( name );
2189
2190 if( variant->populate && !*variant->populate )
2191 symbolVariant.m_DNP = true;
2192
2193 if( variant->value )
2194 symbolVariant.m_Fields[GetCanonicalFieldName( FIELD_T::VALUE )] = *variant->value;
2195
2196 if( variant->technology )
2197 {
2198 auto eLibIt = m_eagleDoc->drawing->schematic->libraries.find( epart->library );
2199
2200 if( eLibIt == m_eagleDoc->drawing->schematic->libraries.end() )
2201 {
2202 Report( wxString::Format( wxS( "Library '%s' not found in schematic." ), epart->library ) );
2203 continue;
2204 }
2205
2206 auto eDeviceSetIt = eLibIt->second->devicesets.find( epart->deviceset );
2207
2208 if( eDeviceSetIt == eLibIt->second->devicesets.end() )
2209 {
2210 Report( wxString::Format( wxS( "Device set '%s' not found in library '%s'." ),
2211 epart->deviceset, epart->library ) );
2212 continue;
2213 }
2214
2215 auto eDeviceIt = eDeviceSetIt->second->devices.find( epart->device );
2216
2217 if( eDeviceIt == eDeviceSetIt->second->devices.end() )
2218 {
2219 Report( wxString::Format( wxS( "Device '%s' not found in device set '%s' in library '%s'." ),
2220 epart->device, epart->deviceset, epart->library ) );
2221 continue;
2222 }
2223
2224 auto eTechnologyIt = eDeviceIt->second->technologies.find( *variant->technology );
2225
2226 if( eTechnologyIt == eDeviceIt->second->technologies.end() )
2227 {
2228 Report( wxString::Format( wxS( "Technology '%s' not found in device '%s' in device set '%s' "
2229 "in library '%s'." ),
2230 *variant->technology, epart->device, epart->deviceset, epart->library ) );
2231 continue;
2232 }
2233
2234 for( const auto& attr : eTechnologyIt->second->attributes )
2235 {
2236 wxString attrValue;
2237
2238 if( attr->value )
2239 attrValue = *attr->value;
2240
2241 symbolVariant.m_Fields[attr->name] = attrValue;
2242 }
2243 }
2244
2245 symbol->AddVariant( m_sheetPath, symbolVariant );
2246 }
2247
2248 for( const SCH_PIN* pin : symbol->GetLibPins() )
2249 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
2250
2251 if( part->IsGlobalPower() )
2252 m_powerPorts[ reference ] = symbol->GetField( FIELD_T::VALUE )->GetText();
2253
2254 symbol->ClearFlags();
2255
2256 screen->Append( symbol.release() );
2257}
2258
2259
2261{
2262 wxCHECK( aLibrary && aEagleLibrary, nullptr );
2264
2265 // Loop through the device sets and load each of them
2266 for( const auto& [name, edeviceset] : aLibrary->devicesets )
2267 {
2268 // Get Device set information
2269 wxString prefix = edeviceset->prefix ? edeviceset->prefix.Get() : wxString( wxT( "" ) );
2270 wxString deviceSetDescr;
2271
2272 if( edeviceset->description )
2273 deviceSetDescr = convertDescription( UnescapeHTML( edeviceset->description->text ) );
2274
2275 // For each device in the device set:
2276 for( const auto& [devname, edevice] : edeviceset->devices )
2277 {
2278 std::vector<std::unique_ptr<LIB_SYMBOL>> derivedSymbols;
2279
2280 // Create symbol name from deviceset and device names.
2281 wxString symbolName = edeviceset->name + edevice->name;
2282 symbolName.Replace( wxT( "*" ), wxEmptyString );
2283 wxASSERT( !symbolName.IsEmpty() );
2284 symbolName = EscapeString( symbolName, CTX_LIBID );
2285
2286 if( edevice->package )
2287 aEagleLibrary->package[symbolName] = edevice->package.Get();
2288
2289 // Create KiCad symbol.
2290 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2291
2292 // Process each gate in the deviceset for this device.
2293 int gate_count = static_cast<int>( edeviceset->gates.size() );
2294
2295 if( gate_count > 1 )
2296 libSymbol->SetUnitCount( gate_count, true );
2297
2298 libSymbol->LockUnits( true );
2299
2300 SCH_FIELD* reference = libSymbol->GetField( FIELD_T::REFERENCE );
2301
2302 if( prefix.length() == 0 )
2303 {
2304 reference->SetVisible( false );
2305 }
2306 else
2307 {
2308 // If there is no footprint assigned, then prepend the reference value
2309 // with a hash character to mute netlist updater complaints
2310 reference->SetText( edevice->package ? prefix : '#' + prefix );
2311 }
2312
2313 libSymbol->GetValueField().SetVisible( true );
2314
2315 int gateindex = 1;
2316 bool ispower = false;
2317
2318 for( const auto& [gateName, egate] : edeviceset->gates )
2319 {
2320 const auto it = aLibrary->symbols.find( egate->symbol );
2321
2322 if( it == aLibrary->symbols.end() )
2323 {
2324 Report( wxString::Format( wxS( "Eagle symbol '%s' not found in library '%s'." ),
2325 egate->symbol, aLibrary->GetName() ) );
2326 continue;
2327 }
2328
2329 wxString gateMapName = edeviceset->name + wxS( "_" ) + edevice->name +
2330 wxS( "_" ) + egate->name;
2331 aEagleLibrary->GateToUnitMap[gateMapName] = gateindex;
2332 ispower = loadSymbol( it->second, libSymbol, edevice, gateindex, egate->name );
2333
2334 gateindex++;
2335 }
2336
2337 std::vector<SCH_FIELD*> fields;
2338 libSymbol->GetFields( fields );
2339
2340 for( SCH_FIELD* field : fields )
2341 field->SetCanAutoplace( canAutoplace );
2342
2343 for( const auto& [techname, technology ] : edevice->technologies )
2344 {
2345 std::unique_ptr<LIB_SYMBOL> derivedSymbol;
2346 VECTOR2I nextFieldPosition = getLastSymbolFieldPosition( libSymbol.get() );
2347
2348 if( !technology->name.IsEmpty() )
2349 {
2350 derivedSymbol = std::make_unique<LIB_SYMBOL>( symbolName + technology->name, libSymbol.get() );
2351
2352 for( SCH_FIELD* parentField : fields )
2353 {
2354 SCH_FIELD* childField = derivedSymbol->GetField( parentField->GetName() );
2355
2356 if( childField )
2357 {
2358 childField->SetAttributes( *parentField );
2359 childField->SetCanAutoplace( canAutoplace );
2360 }
2361 }
2362 }
2363
2364 for( const std::unique_ptr<EATTR>& attr : technology->attributes )
2365 {
2366 if( !attr->value )
2367 continue;
2368
2369 SCH_FIELD* field = nullptr;
2370
2371 if( !derivedSymbol )
2372 field = libSymbol->FindFieldCaseInsensitive( attr->name );
2373 else
2374 field = derivedSymbol->FindFieldCaseInsensitive( attr->name );
2375
2376 if( field )
2377 {
2378 field->SetText( *attr->value );
2379 }
2380 else
2381 {
2382 SCH_FIELD* newField = new SCH_FIELD( derivedSymbol ? derivedSymbol.get() : libSymbol.get(),
2383 FIELD_T::USER, attr->name );
2384
2385 if( derivedSymbol )
2386 {
2387 SCH_FIELD* parentField = libSymbol->FindFieldCaseInsensitive( attr->name );
2388
2389 if( parentField )
2390 newField->SetAttributes( *parentField );
2391 }
2392
2393 nextFieldPosition.y += newField->GetTextHeight() + schIUScale.MilsToIU( 10 );
2394 newField->SetText( *attr->value );
2395 newField->SetVisible( false );
2396 newField->SetPosition( nextFieldPosition );
2397 newField->SetCanAutoplace( canAutoplace );
2398
2399 if( !derivedSymbol )
2400 libSymbol->AddField( newField );
2401 else
2402 derivedSymbol->AddField( newField );
2403 }
2404 }
2405
2406 if( derivedSymbol )
2407 derivedSymbols.push_back( std::move( derivedSymbol ) );
2408 }
2409
2410 if( gate_count > 1 )
2411 libSymbol->SetUnitCount( gate_count, true );
2412
2413 if( gate_count == 1 && ispower )
2414 libSymbol->SetGlobalPower();
2415
2416 // Don't set the footprint field if no package is defined in the Eagle schematic.
2417 if( edevice->package )
2418 {
2419 wxString libName;
2420
2421 if( m_schematic )
2422 {
2423 // assume that footprint library is identical to project name
2424 libName = m_schematic->Project().GetProjectName();
2425 }
2426 else
2427 {
2428 libName = m_libName;
2429 }
2430
2431 wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
2432
2433 libSymbol->GetFootprintField().SetText( packageString );
2434 }
2435
2436 wxString libName = libSymbol->GetName();
2437 libSymbol->SetName( libName );
2438 libSymbol->SetDescription( deviceSetDescr );
2439
2440 if( m_pi )
2441 {
2442 // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
2443 // Eagle symbol library name to the symbol which should ensure that it is unique.
2444 try
2445 {
2446 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
2447 {
2448 libName = aEagleLibrary->name + wxT( "_" ) + libName;
2449 libName = EscapeString( libName, CTX_LIBID );
2450 libSymbol->SetName( libName );
2451 }
2452
2453 // set properties to prevent save file on every symbol save
2454 std::map<std::string, UTF8> properties;
2455 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
2456
2457 LIB_SYMBOL* parentSymbol = new LIB_SYMBOL( *libSymbol.get() );
2458 m_pi->SaveSymbol( getLibFileName().GetFullPath(), parentSymbol, &properties );
2459
2460 for( std::unique_ptr<LIB_SYMBOL>& symbol : derivedSymbols )
2461 {
2462 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), symbol->GetName() ) )
2463 {
2464 wxString tmp = aEagleLibrary->name + wxT( "_" ) + symbol->GetName();
2465 tmp = EscapeString( tmp, CTX_LIBID );
2466 symbol->SetName( tmp );
2467 }
2468
2469 LIB_SYMBOL* derivedSymbol = new LIB_SYMBOL( *symbol.get() );
2470
2471 derivedSymbol->SetParent( parentSymbol );
2472 m_pi->SaveSymbol( getLibFileName().GetFullPath(), derivedSymbol, &properties );
2473 }
2474 }
2475 catch(...)
2476 {
2477 // A library symbol cannot be loaded for some reason.
2478 // Just skip this symbol creating an issue.
2479 // The issue will be reported later by the Reporter
2480 }
2481 }
2482
2483 aEagleLibrary->KiCadSymbols[ libName ] = std::move( libSymbol );
2484
2485 // Store information on whether the value of FIELD_T::VALUE for a part should be
2486 // part/@value or part/@deviceset + part/@device.
2487 m_userValue.emplace( std::make_pair( libName, edeviceset->uservalue == true ) );
2488
2489 for( std::unique_ptr<LIB_SYMBOL>& symbol : derivedSymbols )
2490 {
2491 m_userValue.emplace( std::make_pair( symbol->GetName(), edeviceset->uservalue == true ) );
2492 aEagleLibrary->KiCadSymbols[symbol->GetName()] = std::move( symbol );
2493 }
2494 }
2495 }
2496
2497 return aEagleLibrary;
2498}
2499
2500
2501bool SCH_IO_EAGLE::loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
2502 std::unique_ptr<LIB_SYMBOL>& aSymbol,
2503 const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
2504 const wxString& aGateName )
2505{
2506 wxCHECK( aEsymbol && aSymbol && aDevice, false );
2507
2508 std::vector<SCH_ITEM*> items;
2509
2510 bool showRefDes = false;
2511 bool showValue = false;
2512 bool ispower = false;
2513 int pincount = 0;
2514
2515 for( const std::unique_ptr<ECIRCLE>& ecircle : aEsymbol->circles )
2516 aSymbol->AddDrawItem( loadSymbolCircle( aSymbol, ecircle, aGateNumber ) );
2517
2518 for( const std::unique_ptr<EPIN>& epin : aEsymbol->pins )
2519 {
2520 std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, epin, aGateNumber ) );
2521 pincount++;
2522
2523 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
2524
2525 if( epin->direction )
2526 {
2527 for( const auto& pinDir : pinDirectionsMap )
2528 {
2529 if( epin->direction->Lower() == pinDir.first )
2530 {
2531 pin->SetType( pinDir.second );
2532
2533 if( pinDir.first == wxT( "sup" ) ) // power supply symbol
2534 ispower = true;
2535
2536 break;
2537 }
2538 }
2539
2540 }
2541
2542 if( aDevice->connects.size() != 0 )
2543 {
2544 for( const std::unique_ptr<ECONNECT>& connect : aDevice->connects )
2545 {
2546 // Eagle <connect> references the full pin name including any "@<tag>"
2547 // linking hint, so match against the raw Eagle name rather than the
2548 // stripped display name set on the pin.
2549 if( connect->gate == aGateName && epin->name == connect->pin )
2550 {
2551 wxArrayString pads = wxSplit( wxString( connect->pad ), ' ' );
2552
2553 pin->SetUnit( aGateNumber );
2554 pin->SetName( escapeName( pin->GetName() ) );
2555
2556 if( pads.GetCount() > 1 )
2557 {
2558 pin->SetNumberTextSize( 0 );
2559 }
2560
2561 for( unsigned i = 0; i < pads.GetCount(); i++ )
2562 {
2563 SCH_PIN* apin = new SCH_PIN( *pin );
2564
2565 wxString padname( pads[i] );
2566 apin->SetNumber( padname );
2567 aSymbol->AddDrawItem( apin );
2568 }
2569
2570 break;
2571 }
2572 }
2573 }
2574 else
2575 {
2576 pin->SetUnit( aGateNumber );
2577 pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
2578 aSymbol->AddDrawItem( pin.release() );
2579 }
2580 }
2581
2582 for( const std::unique_ptr<EPOLYGON>& epolygon : aEsymbol->polygons )
2583 if( SCH_SHAPE* shape = loadSymbolPolyLine( aSymbol, epolygon, aGateNumber ) )
2584 aSymbol->AddDrawItem( shape );
2585
2586 for( const std::unique_ptr<ERECT>& erectangle : aEsymbol->rectangles )
2587 aSymbol->AddDrawItem( loadSymbolRectangle( aSymbol, erectangle, aGateNumber ) );
2588
2589 for( const std::unique_ptr<ETEXT>& etext : aEsymbol->texts )
2590 {
2591 std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( aSymbol, etext, aGateNumber ) );
2592
2593 if( libtext->GetText() == wxT( "${REFERENCE}" ) )
2594 {
2595 // Move text & attributes to Reference field and discard LIB_TEXT item
2596 loadFieldAttributes( &aSymbol->GetReferenceField(), libtext.get() );
2597
2598 // Show Reference field if Eagle reference was uppercase
2599 showRefDes = etext->text == wxT( ">NAME" );
2600 }
2601 else if( libtext->GetText() == wxT( "${VALUE}" ) )
2602 {
2603 // Move text & attributes to Value field and discard LIB_TEXT item
2604 loadFieldAttributes( &aSymbol->GetValueField(), libtext.get() );
2605
2606 // Show Value field if Eagle reference was uppercase
2607 showValue = etext->text == wxT( ">VALUE" );
2608 }
2609 else if( etext->text.StartsWith( ">" ) )
2610 {
2611 // Text values that start with '>' are place holders for fields defined later
2612 // in library deviceset objects.
2613 wxString fieldName = etext->text.Mid( 1 );
2614
2615 if( !fieldName.IsEmpty() )
2616 {
2617 SCH_FIELD* field = new SCH_FIELD( aSymbol.get(), FIELD_T::USER, fieldName );
2618
2619 loadFieldAttributes( field, libtext.get() );
2620
2621 // Field visibility is determined by the symbol instance attributes.
2622 field->SetVisible( false );
2623 aSymbol->AddField( field );
2624 }
2625 }
2626 else
2627 {
2628 aSymbol->AddDrawItem( libtext.release() );
2629 }
2630 }
2631
2632 for( const std::unique_ptr<EWIRE>& ewire : aEsymbol->wires )
2633 aSymbol->AddDrawItem( loadSymbolWire( aSymbol, ewire, aGateNumber ) );
2634
2635 for( const std::unique_ptr<EFRAME>& eframe : aEsymbol->frames )
2636 {
2637 std::vector<SCH_ITEM*> frameItems;
2638
2639 loadFrame( eframe, frameItems );
2640
2641 for( SCH_ITEM* item : frameItems )
2642 {
2643 item->SetParent( aSymbol.get() );
2644 item->SetUnit( aGateNumber );
2645 aSymbol->AddDrawItem( item );
2646 }
2647 }
2648
2649 aSymbol->GetReferenceField().SetVisible( showRefDes );
2650 aSymbol->GetValueField().SetVisible( showValue );
2651
2652 return pincount == 1 ? ispower : false;
2653}
2654
2655
2656SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2657 const std::unique_ptr<ECIRCLE>& aCircle,
2658 int aGateNumber )
2659{
2660 wxCHECK( aSymbol && aCircle, nullptr );
2661
2662 // Parse the circle properties
2664 VECTOR2I center( aCircle->x.ToSchUnits(), -aCircle->y.ToSchUnits() );
2665
2666 circle->SetParent( aSymbol.get() );
2667 circle->SetPosition( center );
2668 circle->SetEnd( VECTOR2I( center.x + aCircle->radius.ToSchUnits(), center.y ) );
2669
2670 if( aCircle->width.ToSchUnits() == 0 )
2671 {
2672 circle->SetStroke( STROKE_PARAMS( -1, LINE_STYLE::SOLID ) );
2673 circle->SetFillMode( FILL_T::FILLED_SHAPE );
2674 }
2675 else
2676 {
2677 circle->SetStroke( STROKE_PARAMS( aCircle->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2678 }
2679
2680 circle->SetUnit( aGateNumber );
2681
2682 return circle;
2683}
2684
2685
2686SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2687 const std::unique_ptr<ERECT>& aRectangle,
2688 int aGateNumber )
2689{
2690 wxCHECK( aSymbol && aRectangle, nullptr );
2691
2693
2694 rectangle->SetParent( aSymbol.get() );
2695 rectangle->SetPosition( VECTOR2I( aRectangle->x1.ToSchUnits(), -aRectangle->y1.ToSchUnits() ) );
2696 rectangle->SetEnd( VECTOR2I( aRectangle->x2.ToSchUnits(), -aRectangle->y2.ToSchUnits() ) );
2697
2698 if( aRectangle->rot )
2699 {
2700 VECTOR2I pos( rectangle->GetPosition() );
2701 VECTOR2I end( rectangle->GetEnd() );
2702 VECTOR2I center( rectangle->GetCenter() );
2703
2704 RotatePoint( pos, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2705 RotatePoint( end, center, EDA_ANGLE( aRectangle->rot->degrees, DEGREES_T ) );
2706
2707 rectangle->SetPosition( pos );
2708 rectangle->SetEnd( end );
2709 }
2710
2711 rectangle->SetUnit( aGateNumber );
2712
2713 // Eagle rectangles are filled and have vanishing line width by definition.
2714 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2715 rectangle->SetWidth( -1 );
2716
2717 return rectangle;
2718}
2719
2720
2721SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2722 const std::unique_ptr<EWIRE>& aWire, int aGateNumber )
2723{
2724 wxCHECK( aSymbol && aWire, nullptr );
2725
2726 VECTOR2I begin, end;
2727
2728 begin.x = aWire->x1.ToSchUnits();
2729 begin.y = -aWire->y1.ToSchUnits();
2730 end.x = aWire->x2.ToSchUnits();
2731 end.y = -aWire->y2.ToSchUnits();
2732
2733 if( begin == end )
2734 return nullptr;
2735
2736 // if the wire is an arc
2737 if( aWire->curve )
2738 {
2740 VECTOR2I center = ConvertArcCenter( begin, end, *aWire->curve );
2741 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2742 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2743
2744 arc->SetParent( aSymbol.get() );
2745
2746 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2747 if( aWire->cap == EWIRE::FLAT && aWire->width.ToSchUnits() >= 2 * radius )
2748 {
2749 VECTOR2I centerStartVector = ( begin - center ) *
2750 ( aWire->width.ToSchUnits() / radius );
2751 begin = center + centerStartVector;
2752
2755 }
2756 else
2757 {
2758 arc->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2759 }
2760
2761 arc->SetCenter( center );
2762 arc->SetStart( begin );
2763
2764 // KiCad rotates the other way.
2765 arc->SetArcAngleAndEnd( -EDA_ANGLE( *aWire->curve, DEGREES_T ), true );
2766 arc->SetUnit( aGateNumber );
2767
2768 return arc;
2769 }
2770 else
2771 {
2773
2774 poly->AddPoint( begin );
2775 poly->AddPoint( end );
2776 poly->SetUnit( aGateNumber );
2777 poly->SetStroke( STROKE_PARAMS( aWire->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2778
2779 return poly;
2780 }
2781}
2782
2783
2784SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2785 const std::unique_ptr<EPOLYGON>& aPolygon,
2786 int aGateNumber )
2787{
2788 wxCHECK( aSymbol && aPolygon, nullptr );
2789
2790 if( !aPolygon->IsValidOutline() )
2791 return nullptr;
2792
2794 VECTOR2I pt, prev_pt;
2795 opt_double prev_curve;
2796 std::optional<VECTOR2I> first_pt;
2797
2798 poly->SetParent( aSymbol.get() );
2799
2800 for( const std::unique_ptr<EVERTEX>& evertex : aPolygon->vertices )
2801 {
2802 pt = VECTOR2I( evertex->x.ToSchUnits(), -evertex->y.ToSchUnits() );
2803
2804 if( !first_pt.has_value() )
2805 first_pt = pt;
2806
2807 if( prev_curve )
2808 {
2809 SHAPE_ARC arc;
2810 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2811 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2812 }
2813 else
2814 {
2815 poly->AddPoint( pt );
2816 }
2817
2818 prev_pt = pt;
2819 prev_curve = evertex->curve;
2820 }
2821
2822 if( first_pt.has_value() )
2823 poly->AddPoint( first_pt.value() );
2824
2825 poly->SetStroke( STROKE_PARAMS( aPolygon->width.ToSchUnits(), LINE_STYLE::SOLID ) );
2827 poly->SetUnit( aGateNumber );
2828
2829 return poly;
2830}
2831
2832
2833SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2834 const std::unique_ptr<EPIN>& aPin, int aGateNumber )
2835{
2836 wxCHECK( aSymbol && aPin, nullptr );
2837
2838 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2839 pin->SetPosition( VECTOR2I( aPin->x.ToSchUnits(), -aPin->y.ToSchUnits() ) );
2840
2841 // Eagle pin names may carry a trailing "@<tag>" linking hint that disambiguates
2842 // duplicate names within a symbol. It is metadata, not visible text, so strip it
2843 // from the displayed name. The full Eagle name is still used to match <connect>.
2844 pin->SetName( extractNetName( aPin->name ) );
2845 pin->SetUnit( aGateNumber );
2846
2847 int roti = aPin->rot ? aPin->rot->degrees : 0;
2848
2849 switch( roti )
2850 {
2851 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2852 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2853 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2854 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2855 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2856 }
2857
2858 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2859
2860 if( aPin->length )
2861 {
2862 wxString length = aPin->length.Get();
2863
2864 if( length == wxT( "short" ) )
2865 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2866 else if( length == wxT( "middle" ) )
2867 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2868 else if( length == wxT( "long" ) )
2869 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2870 else if( length == wxT( "point" ) )
2871 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2872 }
2873
2874 // Pin names and numbers are fixed size in Eagle.
2875 pin->SetNumberTextSize( schIUScale.MilsToIU( 60 ) );
2876 pin->SetNameTextSize( schIUScale.MilsToIU( 60 ) );
2877
2878 // emulate the visibility of pin elements
2879 if( aPin->visible )
2880 {
2881 wxString visible = aPin->visible.Get();
2882
2883 if( visible == wxT( "off" ) )
2884 {
2885 pin->SetNameTextSize( 0 );
2886 pin->SetNumberTextSize( 0 );
2887 }
2888 else if( visible == wxT( "pad" ) )
2889 {
2890 pin->SetNameTextSize( 0 );
2891 }
2892 else if( visible == wxT( "pin" ) )
2893 {
2894 pin->SetNumberTextSize( 0 );
2895 }
2896
2897 /*
2898 * else if( visible == wxT( "both" ) )
2899 * {
2900 * }
2901 */
2902 }
2903
2904 if( aPin->function )
2905 {
2906 wxString function = aPin->function.Get();
2907
2908 if( function == wxT( "dot" ) )
2909 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2910 else if( function == wxT( "clk" ) )
2911 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2912 else if( function == wxT( "dotclk" ) )
2914 }
2915
2916 return pin.release();
2917}
2918
2919
2920SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
2921 const std::unique_ptr<ETEXT>& aText, int aGateNumber )
2922{
2923 wxCHECK( aSymbol && aText, nullptr );
2924
2925 std::unique_ptr<SCH_TEXT> libtext = std::make_unique<SCH_TEXT>();
2926
2927 libtext->SetLayer( LAYER_DEVICE );
2928 libtext->SetParent( aSymbol.get() );
2929 libtext->SetUnit( aGateNumber );
2930 libtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2931
2932 const wxString& eagleText = aText->text;
2933 wxString adjustedText;
2934 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2935
2936 // Strip the whitespace from both ends of each line.
2937 while( tokenizer.HasMoreTokens() )
2938 {
2939 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2940
2941 if( tokenizer.HasMoreTokens() )
2942 tmp += wxT( "\n" );
2943
2944 adjustedText += tmp;
2945 }
2946
2947 libtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "~" ) ) : adjustedText );
2948
2949 loadTextAttributes( libtext.get(), aText );
2950
2951 return libtext.release();
2952}
2953
2954
2955SCH_TEXT* SCH_IO_EAGLE::loadPlainText( const std::unique_ptr<ETEXT>& aText )
2956{
2957 wxCHECK( aText, nullptr );
2958
2959 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2960
2961 const wxString& eagleText = aText->text;
2962 wxString adjustedText;
2963 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2964
2965 // Strip the whitespace from both ends of each line.
2966 while( tokenizer.HasMoreTokens() )
2967 {
2968 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2969
2970 if( tokenizer.HasMoreTokens() )
2971 tmp += wxT( "\n" );
2972
2973 adjustedText += tmp;
2974 }
2975
2976 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxS( "\" \"" ) )
2977 : escapeName( adjustedText ) );
2978
2979 schtext->SetPosition( VECTOR2I( aText->x.ToSchUnits(), -aText->y.ToSchUnits() ) );
2980 loadTextAttributes( schtext.get(), aText );
2981 schtext->SetItalic( false );
2982
2983 return schtext.release();
2984}
2985
2986
2988 const std::unique_ptr<ETEXT>& aAttributes ) const
2989{
2990 wxCHECK( aText && aAttributes, /* void */ );
2991
2992 aText->SetTextSize( aAttributes->ConvertSize() );
2993
2994 // Must come after SetTextSize()
2995 if( aAttributes->ratio && aAttributes->ratio.CGet() > 12 )
2996 aText->SetBold( true );
2997
2998 int align = aAttributes->align ? *aAttributes->align : ETEXT::BOTTOM_LEFT;
2999 int degrees = aAttributes->rot ? aAttributes->rot->degrees : 0;
3000 bool mirror = aAttributes->rot ? aAttributes->rot->mirror : false;
3001 bool spin = aAttributes->rot ? aAttributes->rot->spin : false;
3002
3003 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
3004}
3005
3006
3007void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
3008{
3009 wxCHECK( aField && aText, /* void */ );
3010
3011 aField->SetTextPos( aText->GetPosition() );
3012 aField->SetTextSize( aText->GetTextSize() );
3013 aField->SetTextAngle( aText->GetTextAngle() );
3014
3015 // Must come after SetTextSize()
3016 aField->SetBold( aText->IsBold() );
3017 aField->SetItalic( false );
3018
3019 aField->SetVertJustify( aText->GetVertJustify() );
3020 aField->SetHorizJustify( aText->GetHorizJustify() );
3021}
3022
3023
3025{
3026 // Eagle supports detached labels, so a label does not need to be placed on a wire
3027 // to be associated with it. KiCad needs to move them, so the labels actually touch the
3028 // corresponding wires.
3029
3030 // Sort the intersection points to speed up the search process
3031 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
3032
3033 auto onIntersection =
3034 [&]( const VECTOR2I& aPos )
3035 {
3036 return std::binary_search( m_wireIntersections.begin(),
3037 m_wireIntersections.end(), aPos );
3038 };
3039
3040 for( SEG_DESC& segDesc : m_segments )
3041 {
3042 for( SCH_LABEL_BASE* label : segDesc.labels )
3043 {
3044 VECTOR2I labelPos( label->GetPosition() );
3045 const SEG* segAttached = segDesc.LabelAttached( label );
3046
3047 if( segAttached && !onIntersection( labelPos ) )
3048 continue; // label is placed correctly
3049
3050 // Move the label to the nearest wire
3051 if( !segAttached )
3052 {
3053 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
3054 segDesc.segs );
3055
3056 if( !segAttached ) // we cannot do anything
3057 continue;
3058 }
3059
3060 // Create a vector pointing in the direction of the wire, 50 mils long
3061 VECTOR2I wireDirection( segAttached->B - segAttached->A );
3062
3063 if( ( wireDirection.x == 0 ) && (wireDirection.y == 0 ) )
3064 continue;
3065
3066 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
3067 const VECTOR2I origPos( labelPos );
3068
3069 // Flags determining the search direction
3070 bool checkPositive = true;
3071 bool checkNegative = true;
3072 bool move = false;
3073 int trial = 0;
3074
3075 // Be sure the label is not placed on a wire intersection
3076 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
3077 {
3078 move = false;
3079
3080 // Move along the attached wire to find the new label position
3081 if( trial % 2 == 1 )
3082 {
3083 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
3084 move = checkPositive = segAttached->Contains( labelPos );
3085 }
3086 else
3087 {
3088 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
3089 move = checkNegative = segAttached->Contains( labelPos );
3090 }
3091
3092 ++trial;
3093 }
3094
3095 if( move )
3096 {
3097 label->SetPosition( VECTOR2I( labelPos ) );
3098
3099 if( wireDirection.x == 0 ) // Moved vertically
3100 {
3101 if( wireDirection.y < 0 )
3102 label->SetSpinStyle( SPIN_STYLE::UP );
3103 else
3105 }
3106 else if( wireDirection.y == 0 ) // Moved horizontally
3107 {
3108 if( wireDirection.x < 0 )
3110 else
3112 }
3113 }
3114 }
3115 }
3116
3117 m_segments.clear();
3118 m_wireIntersections.clear();
3119}
3120
3121
3122bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
3123{
3124 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
3125 return false;
3126
3127 return checkHeader( aFileName );
3128}
3129
3130
3131bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
3132{
3133 if( !SCH_IO::CanReadLibrary( aFileName ) )
3134 return false;
3135
3136 return checkHeader( aFileName );
3137}
3138
3139
3140bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
3141{
3142 wxFileInputStream input( aFileName );
3143
3144 if( !input.IsOk() )
3145 return false;
3146
3147 wxTextInputStream text( input );
3148
3149 for( int i = 0; i < 8; i++ )
3150 {
3151 if( input.Eof() )
3152 return false;
3153
3154 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
3155 return true;
3156 }
3157
3158 return false;
3159}
3160
3161
3162void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
3163{
3164 wxCHECK( aWire, /* void */ );
3165
3166 SCH_SCREEN* screen = getCurrentScreen();
3167
3168 wxCHECK( screen, /* void */ );
3169
3170 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
3171 {
3172 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
3173 continue;
3174
3175 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
3176 item->SetPosition( aNewEndPoint );
3177 }
3178}
3179
3180
3182{
3183 // Add bus entry symbols
3184 // TODO: Cleanup this function and break into pieces
3185
3186 // for each wire segment, compare each end with all busses.
3187 // If the wire end is found to end on a bus segment, place a bus entry symbol.
3188
3189 std::vector<SCH_LINE*> buses;
3190 std::vector<SCH_LINE*> wires;
3191
3192 SCH_SCREEN* screen = getCurrentScreen();
3193
3194 wxCHECK( screen, /* void */ );
3195
3196 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
3197 {
3198 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
3199
3200 if( line->IsBus() )
3201 buses.push_back( line );
3202 else if( line->IsWire() )
3203 wires.push_back( line );
3204 }
3205
3206 for( SCH_LINE* wire : wires )
3207 {
3208 VECTOR2I wireStart = wire->GetStartPoint();
3209 VECTOR2I wireEnd = wire->GetEndPoint();
3210
3211 for( SCH_LINE* bus : buses )
3212 {
3213 VECTOR2I busStart = bus->GetStartPoint();
3214 VECTOR2I busEnd = bus->GetEndPoint();
3215
3216 auto entrySize =
3217 []( int signX, int signY ) -> VECTOR2I
3218 {
3219 return VECTOR2I( schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signX,
3220 schIUScale.MilsToIU( DEFAULT_SCH_ENTRY_SIZE ) * signY );
3221 };
3222
3223 auto testBusHit =
3224 [&]( const VECTOR2I& aPt ) -> bool
3225 {
3226 return TestSegmentHit( aPt, busStart, busEnd, 0 );
3227 };
3228
3229 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
3230 {
3231 // Horizontal wire and vertical bus
3232
3233 if( testBusHit( wireStart ) )
3234 {
3235 // Wire start is on the vertical bus
3236
3237 if( wireEnd.x < busStart.x )
3238 {
3239 /* the end of the wire is to the left of the bus
3240 * ⎥⎢
3241 * ——————⎥⎢
3242 * ⎥⎢
3243 */
3244 VECTOR2I p = wireStart + entrySize( -1, 0 );
3245
3246 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
3247 {
3248 /* there is room above the wire for the bus entry
3249 * ⎥⎢
3250 * _____/⎥⎢
3251 * ⎥⎢
3252 */
3253 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3254 busEntry->SetFlags( IS_NEW );
3255 screen->Append( busEntry );
3256 moveLabels( wire, p );
3257 wire->SetStartPoint( p );
3258 }
3259 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
3260 {
3261 /* there is room below the wire for the bus entry
3262 * _____ ⎥⎢
3263 * \⎥⎢
3264 * ⎥⎢
3265 */
3266 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3267 busEntry->SetFlags( IS_NEW );
3268 screen->Append( busEntry );
3269 moveLabels( wire, p );
3270 wire->SetStartPoint( p );
3271 }
3272 else
3273 {
3274 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3275 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3276 }
3277 }
3278 else
3279 {
3280 /* the wire end is to the right of the bus
3281 * ⎥⎢
3282 * ⎥⎢——————
3283 * ⎥⎢
3284 */
3285 VECTOR2I p = wireStart + entrySize( 1, 0 );
3286
3287 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
3288 {
3289 /* There is room above the wire for the bus entry
3290 * ⎥⎢
3291 * ⎥⎢\_____
3292 * ⎥⎢
3293 */
3294 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
3295 busEntry->SetFlags( IS_NEW );
3296 screen->Append( busEntry );
3297 moveLabels( wire, p );
3298 wire->SetStartPoint( p );
3299 }
3300 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
3301 {
3302 /* There is room below the wire for the bus entry
3303 * ⎥⎢ _____
3304 * ⎥⎢/
3305 * ⎥⎢
3306 */
3307 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3308 busEntry->SetFlags( IS_NEW );
3309 screen->Append( busEntry );
3310 moveLabels( wire, p );
3311 wire->SetStartPoint( p );
3312 }
3313 else
3314 {
3315 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3316 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3317 }
3318 }
3319
3320 break;
3321 }
3322 else if( testBusHit( wireEnd ) )
3323 {
3324 // Wire end is on the vertical bus
3325
3326 if( wireStart.x < busStart.x )
3327 {
3328 /* start of the wire is to the left of the bus
3329 * ⎥⎢
3330 * ——————⎥⎢
3331 * ⎥⎢
3332 */
3333 VECTOR2I p = wireEnd + entrySize( -1, 0 );
3334
3335 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3336 {
3337 /* there is room above the wire for the bus entry
3338 * ⎥⎢
3339 * _____/⎥⎢
3340 * ⎥⎢
3341 */
3342 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3343 busEntry->SetFlags( IS_NEW );
3344 screen->Append( busEntry );
3345 moveLabels( wire, p );
3346 wire->SetEndPoint( p );
3347 }
3348 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3349 {
3350 /* there is room below the wire for the bus entry
3351 * _____ ⎥⎢
3352 * \⎥⎢
3353 * ⎥⎢
3354 */
3355 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3356 busEntry->SetFlags( IS_NEW );
3357 screen->Append( busEntry );
3358 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
3359 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
3360 }
3361 else
3362 {
3363 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3364 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3365 }
3366 }
3367 else
3368 {
3369 /* the start of the wire is to the right of the bus
3370 * ⎥⎢
3371 * ⎥⎢——————
3372 * ⎥⎢
3373 */
3374 VECTOR2I p = wireEnd + entrySize( 1, 0 );
3375
3376 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3377 {
3378 /* There is room above the wire for the bus entry
3379 * ⎥⎢
3380 * ⎥⎢\_____
3381 * ⎥⎢
3382 */
3383 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3384 busEntry->SetFlags( IS_NEW );
3385 screen->Append( busEntry );
3386 moveLabels( wire, p );
3387 wire->SetEndPoint( p );
3388 }
3389 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
3390 {
3391 /* There is room below the wire for the bus entry
3392 * ⎥⎢ _____
3393 * ⎥⎢/
3394 * ⎥⎢
3395 */
3396 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3397 busEntry->SetFlags( IS_NEW );
3398 screen->Append( busEntry );
3399 moveLabels( wire, p );
3400 wire->SetEndPoint( p );
3401 }
3402 else
3403 {
3404 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3405 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3406 }
3407 }
3408
3409 break;
3410 }
3411 }
3412 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
3413 {
3414 // Vertical wire and horizontal bus
3415
3416 if( testBusHit( wireStart ) )
3417 {
3418 // Wire start is on the bus
3419
3420 if( wireEnd.y < busStart.y )
3421 {
3422 /* the end of the wire is above the bus
3423 * |
3424 * |
3425 * |
3426 * =======
3427 */
3428 VECTOR2I p = wireStart + entrySize( 0, -1 );
3429
3430 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3431 {
3432 /* there is room to the left of the wire for the bus entry
3433 * |
3434 * |
3435 * /
3436 * =======
3437 */
3438 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3439 busEntry->SetFlags( IS_NEW );
3440 screen->Append( busEntry );
3441 moveLabels( wire, p );
3442 wire->SetStartPoint( p );
3443 }
3444 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3445 {
3446 /* there is room to the right of the wire for the bus entry
3447 * |
3448 * |
3449 * \
3450 * =======
3451 */
3452 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3453 busEntry->SetFlags( IS_NEW );
3454 screen->Append( busEntry );
3455 moveLabels( wire, p );
3456 wire->SetStartPoint( p );
3457 }
3458 else
3459 {
3460 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3461 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3462 }
3463 }
3464 else
3465 {
3466 /* wire end is below the bus
3467 * =======
3468 * |
3469 * |
3470 * |
3471 */
3472 VECTOR2I p = wireStart + entrySize( 0, 1 );
3473
3474 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3475 {
3476 /* there is room to the left of the wire for the bus entry
3477 * =======
3478 * \
3479 * |
3480 * |
3481 */
3482 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3483 busEntry->SetFlags( IS_NEW );
3484 screen->Append( busEntry );
3485 moveLabels( wire, p );
3486 wire->SetStartPoint( p );
3487 }
3488 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3489 {
3490 /* there is room to the right of the wire for the bus entry
3491 * =======
3492 * /
3493 * |
3494 * |
3495 */
3496 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3497 busEntry->SetFlags( IS_NEW );
3498 screen->Append( busEntry );
3499 moveLabels( wire, p );
3500 wire->SetStartPoint( p );
3501 }
3502 else
3503 {
3504 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3505 screen->Append( new SCH_MARKER( std::move( ercItem ), wireStart ) );
3506 }
3507 }
3508
3509 break;
3510 }
3511 else if( testBusHit( wireEnd ) )
3512 {
3513 // Wire end is on the bus
3514
3515 if( wireStart.y < busStart.y )
3516 {
3517 /* the start of the wire is above the bus
3518 * |
3519 * |
3520 * |
3521 * =======
3522 */
3523 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3524
3525 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3526 {
3527 /* there is room to the left of the wire for the bus entry
3528 * |
3529 * |
3530 * /
3531 * =======
3532 */
3533 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3534 busEntry->SetFlags( IS_NEW );
3535 screen->Append( busEntry );
3536 moveLabels( wire, p );
3537 wire->SetEndPoint( p );
3538 }
3539 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3540 {
3541 /* there is room to the right of the wire for the bus entry
3542 * |
3543 * |
3544 * \
3545 * =======
3546 */
3547 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3548 busEntry->SetFlags( IS_NEW );
3549 screen->Append( busEntry );
3550 moveLabels( wire, p );
3551 wire->SetEndPoint( p );
3552 }
3553 else
3554 {
3555 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3556 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3557 }
3558 }
3559 else
3560 {
3561 /* wire start is below the bus
3562 * =======
3563 * |
3564 * |
3565 * |
3566 */
3567 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3568
3569 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3570 {
3571 /* there is room to the left of the wire for the bus entry
3572 * =======
3573 * \
3574 * |
3575 * |
3576 */
3577 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3578 busEntry->SetFlags( IS_NEW );
3579 screen->Append( busEntry );
3580 moveLabels( wire, p );
3581 wire->SetEndPoint( p );
3582 }
3583 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3584 {
3585 /* there is room to the right of the wire for the bus entry
3586 * =======
3587 * /
3588 * |
3589 * |
3590 */
3591 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3592 busEntry->SetFlags( IS_NEW );
3593 screen->Append( busEntry );
3594 moveLabels( wire, p );
3595 wire->SetEndPoint( p );
3596 }
3597 else
3598 {
3599 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3600 screen->Append( new SCH_MARKER( std::move( ercItem ), wireEnd ) );
3601 }
3602 }
3603
3604 break;
3605 }
3606 }
3607 else
3608 {
3609 // Wire isn't horizontal or vertical
3610
3611 if( testBusHit( wireStart ) )
3612 {
3613 VECTOR2I wirevector = wireStart - wireEnd;
3614
3615 if( wirevector.x > 0 )
3616 {
3617 if( wirevector.y > 0 )
3618 {
3619 VECTOR2I p = wireStart + entrySize( -1, -1 );
3620 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3621 busEntry->SetFlags( IS_NEW );
3622 screen->Append( busEntry );
3623
3624 moveLabels( wire, p );
3625 wire->SetStartPoint( p );
3626 }
3627 else
3628 {
3629 VECTOR2I p = wireStart + entrySize( -1, 1 );
3630 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3631 busEntry->SetFlags( IS_NEW );
3632 screen->Append( busEntry );
3633
3634 moveLabels( wire, p );
3635 wire->SetStartPoint( p );
3636 }
3637 }
3638 else
3639 {
3640 if( wirevector.y > 0 )
3641 {
3642 VECTOR2I p = wireStart + entrySize( 1, -1 );
3643 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3644 busEntry->SetFlags( IS_NEW );
3645 screen->Append( busEntry );
3646
3647 moveLabels( wire, p );
3648 wire->SetStartPoint( p );
3649 }
3650 else
3651 {
3652 VECTOR2I p = wireStart + entrySize( 1, 1 );
3653 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3654 busEntry->SetFlags( IS_NEW );
3655 screen->Append( busEntry );
3656
3657 moveLabels( wire, p );
3658 wire->SetStartPoint( p );
3659 }
3660 }
3661
3662 break;
3663 }
3664 else if( testBusHit( wireEnd ) )
3665 {
3666 VECTOR2I wirevector = wireStart - wireEnd;
3667
3668 if( wirevector.x > 0 )
3669 {
3670 if( wirevector.y > 0 )
3671 {
3672 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3673 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3674 busEntry->SetFlags( IS_NEW );
3675 screen->Append( busEntry );
3676
3677 moveLabels( wire, p );
3678 wire->SetEndPoint( p );
3679 }
3680 else
3681 {
3682 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3683 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3684 busEntry->SetFlags( IS_NEW );
3685 screen->Append( busEntry );
3686
3687 moveLabels( wire, p );
3688 wire->SetEndPoint( p );
3689 }
3690 }
3691 else
3692 {
3693 if( wirevector.y > 0 )
3694 {
3695 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3696 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3697 busEntry->SetFlags( IS_NEW );
3698 screen->Append( busEntry );
3699
3700 moveLabels( wire, p );
3701 wire->SetEndPoint( p );
3702 }
3703 else
3704 {
3705 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3706 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3707 busEntry->SetFlags( IS_NEW );
3708 screen->Append( busEntry );
3709
3710 moveLabels( wire, p );
3711 wire->SetEndPoint( p );
3712 }
3713 }
3714
3715 break;
3716 }
3717 }
3718 }
3719 }
3720}
3721
3722
3724{
3725 wxCHECK( aLabel, nullptr );
3726
3727 VECTOR2I labelPos( aLabel->GetPosition() );
3728
3729 for( const SEG& seg : segs )
3730 {
3731 if( seg.Contains( labelPos ) )
3732 return &seg;
3733 }
3734
3735 return nullptr;
3736}
3737
3738
3739// TODO could be used to place junctions, instead of IsJunctionNeeded()
3740// (see SCH_EDIT_FRAME::importFile())
3741bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3742{
3743 wxCHECK( aSymbol && aPin, false );
3744
3745 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3746 auto pointIt = m_connPoints.find( pinPosition );
3747
3748 if( pointIt == m_connPoints.end() )
3749 return false;
3750
3751 const auto& items = pointIt->second;
3752
3753 wxCHECK( items.find( aPin ) != items.end(), false );
3754
3755 return items.size() > 1;
3756}
3757
3758
3760 bool aUpdateSet )
3761{
3762 wxCHECK( aSymbol && aScreen && aSymbol->GetLibSymbolRef(), /*void*/ );
3763
3764 // Normally power parts also have power input pins,
3765 // but they already force net names on the attached wires
3766 if( aSymbol->GetLibSymbolRef()->IsGlobalPower() )
3767 return;
3768
3769 int unit = aSymbol->GetUnit();
3770 const wxString reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
3771 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetGraphicalPins( 0, 0 );
3772 std::set<int> missingUnits;
3773
3774 // Search all units for pins creating implicit connections
3775 for( const SCH_PIN* pin : pins )
3776 {
3777 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3778 {
3779 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3780
3781 // Create a global net label only if there are no other wires/pins attached
3782 if( pinInUnit )
3783 {
3784 if( !checkConnections( aSymbol, pin ) )
3785 {
3786 // Create a net label to force the net name on the pin
3787 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3788 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3789 netLabel->SetText( extractNetName( pin->GetName() ) );
3790 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3791 schIUScale.MilsToIU( 40 ) ) );
3792
3793 switch( pin->GetOrientation() )
3794 {
3795 default:
3797 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3798 break;
3800 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3801 break;
3803 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3804 break;
3806 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3807 break;
3808 }
3809
3810 aScreen->Append( netLabel );
3811 }
3812 }
3813 else if( aUpdateSet )
3814 {
3815 // Found a pin creating implicit connection information in another unit.
3816 // Such units will be instantiated if they do not appear in another sheet and
3817 // processed later.
3818 wxASSERT( pin->GetUnit() );
3819 missingUnits.insert( pin->GetUnit() );
3820 }
3821 }
3822 }
3823
3824 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3825 {
3826 auto cmpIt = m_missingCmps.find( reference );
3827
3828 // The first unit found has always already been processed.
3829 if( cmpIt == m_missingCmps.end() )
3830 {
3831 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3832 entry.cmp = aSymbol;
3833 entry.screen = aScreen;
3834 entry.units.emplace( unit, false );
3835 }
3836 else
3837 {
3838 // Set the flag indicating this unit has been processed.
3839 cmpIt->second.units[unit] = false;
3840 }
3841
3842 if( !missingUnits.empty() ) // Save the units that need later processing
3843 {
3844 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3845 entry.cmp = aSymbol;
3846 entry.screen = aScreen;
3847
3848 // Add units that haven't already been processed.
3849 for( int i : missingUnits )
3850 {
3851 if( entry.units.find( i ) != entry.units.end() )
3852 entry.units.emplace( i, true );
3853 }
3854 }
3855 }
3856}
3857
3858
3859wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3860{
3861 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3862 return aEagleName;
3863
3864 wxString ret = wxT( "{" );
3865
3866 wxStringTokenizer tokenizer( aEagleName, "," );
3867
3868 while( tokenizer.HasMoreTokens() )
3869 {
3870 wxString member = tokenizer.GetNextToken();
3871
3872 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3873 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3874 // if there is an odd number of overbar markers in this net name, we need to append one
3875 // to close it out before appending the space.
3876
3877 if( member.Freq( '!' ) % 2 > 0 )
3878 member << wxT( "!" );
3879
3880 ret << member << wxS( " " );
3881 }
3882
3883 ret.Trim( true );
3884 ret << wxT( "}" );
3885
3886 return ret;
3887}
3888
3889
3890const ESYMBOL* SCH_IO_EAGLE::getEagleSymbol( const std::unique_ptr<EINSTANCE>& aInstance )
3891{
3892 wxCHECK( m_eagleDoc && m_eagleDoc->drawing && m_eagleDoc->drawing->schematic && aInstance,
3893 nullptr );
3894
3895 std::unique_ptr<EPART>& epart = m_eagleDoc->drawing->schematic->parts[aInstance->part];
3896
3897 if( !epart || epart->deviceset.IsEmpty() )
3898 return nullptr;
3899
3900 std::unique_ptr<ELIBRARY>& elibrary = m_eagleDoc->drawing->schematic->libraries[epart->library];
3901
3902 if( !elibrary )
3903 return nullptr;
3904
3905 std::unique_ptr<EDEVICE_SET>& edeviceset = elibrary->devicesets[epart->deviceset];
3906
3907 if( !edeviceset )
3908 return nullptr;
3909
3910 std::unique_ptr<EGATE>& egate = edeviceset->gates[aInstance->gate];
3911
3912 if( !egate )
3913 return nullptr;
3914
3915 std::unique_ptr<ESYMBOL>& esymbol = elibrary->symbols[egate->symbol];
3916
3917 if( esymbol )
3918 return esymbol.get();
3919
3920 return nullptr;
3921}
3922
3923
3924void SCH_IO_EAGLE::getEagleSymbolFieldAttributes( const std::unique_ptr<EINSTANCE>& aInstance,
3925 const wxString& aEagleFieldName,
3926 SCH_FIELD* aField )
3927{
3928 wxCHECK( aField && !aEagleFieldName.IsEmpty(), /* void */ );
3929
3930 const ESYMBOL* esymbol = getEagleSymbol( aInstance );
3931
3932 if( esymbol )
3933 {
3934 for( const std::unique_ptr<ETEXT>& text : esymbol->texts )
3935 {
3936 if( text->text == aEagleFieldName )
3937 {
3938 aField->SetVisible( true );
3939 VECTOR2I pos( text->x.ToSchUnits() + aInstance->x.ToSchUnits(),
3940 -text->y.ToSchUnits() - aInstance->y.ToSchUnits() );
3941
3942 bool mirror = text->rot ? text->rot->mirror : false;
3943
3944 if( aInstance->rot && aInstance->rot->mirror )
3945 mirror = !mirror;
3946
3947 if( mirror )
3948 pos.y = -aInstance->y.ToSchUnits() + text->y.ToSchUnits();
3949
3950 aField->SetPosition( pos );
3951 }
3952 }
3953 }
3954}
3955
3956
3958{
3959 VECTOR2I retv;
3960
3961 std::vector<SCH_FIELD*> fields;
3962 aPart->GetFields( fields );
3963
3964 if( fields.size() )
3965 {
3966 retv = fields[0]->GetPosition();
3967
3968 for( size_t i = 1; i < fields.size(); i++ )
3969 {
3970 if( fields[i]->GetPosition().x > retv.x )
3971 retv.x = fields[i]->GetPosition().x;
3972
3973 if( fields[i]->GetPosition().y > retv.y )
3974 retv.y = fields[i]->GetPosition().y;
3975 }
3976 }
3977
3978 return retv;
3979}
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:292
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:205
Define a library symbol object.
Definition lib_symbol.h:80
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, SCH_LAYER_ID aLayer=LAYER_NOTES)
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
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:339
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:810
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.