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