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