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