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 <project.h>
43#include <project_sch.h>
44#include <sch_bus_entry.h>
45#include <sch_symbol.h>
47#include <sch_edit_frame.h>
48#include <sch_junction.h>
50#include <sch_marker.h>
51#include <sch_screen.h>
52#include <sch_pin.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 for( const SCH_PIN* pin : symbol->GetLibPins() )
1971 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
1972
1973 if( part->IsPower() )
1974 m_powerPorts[ reference ] = symbol->GetField( VALUE_FIELD )->GetText();
1975
1976 symbol->ClearFlags();
1977
1978 screen->Append( symbol.release() );
1979}
1980
1981
1982EAGLE_LIBRARY* SCH_IO_EAGLE::loadLibrary( wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLibrary )
1983{
1984 NODE_MAP libraryChildren = MapChildren( aLibraryNode );
1985
1986 // Loop through the symbols and load each of them
1987 wxXmlNode* symbolNode = getChildrenNodes( libraryChildren, wxT( "symbols" ) );
1988
1989 while( symbolNode )
1990 {
1991 wxString symbolName = symbolNode->GetAttribute( wxT( "name" ) );
1992 aEagleLibrary->SymbolNodes[symbolName] = symbolNode;
1993 symbolNode = symbolNode->GetNext();
1994 }
1995
1996 // Loop through the device sets and load each of them
1997 wxXmlNode* devicesetNode = getChildrenNodes( libraryChildren, wxT( "devicesets" ) );
1998
1999 while( devicesetNode )
2000 {
2001 // Get Device set information
2002 EDEVICE_SET edeviceset = EDEVICE_SET( devicesetNode );
2003
2004 wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : wxString( wxT( "" ) );
2005 wxString deviceSetDescr;
2006
2007 NODE_MAP deviceSetChildren = MapChildren( devicesetNode );
2008 wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, wxT( "devices" ) );
2009 wxXmlNode* deviceSetDescrNode = getChildrenNodes( deviceSetChildren, wxT( "description" ) );
2010
2011 if( deviceSetDescrNode )
2012 deviceSetDescr = convertDescription( UnescapeHTML( deviceSetDescrNode->GetContent() ) );
2013
2014 // For each device in the device set:
2015 while( deviceNode )
2016 {
2017 // Get device information
2018 EDEVICE edevice = EDEVICE( deviceNode );
2019
2020 // Create symbol name from deviceset and device names.
2021 wxString symbolName = edeviceset.name + edevice.name;
2022 symbolName.Replace( wxT( "*" ), wxEmptyString );
2023 wxASSERT( !symbolName.IsEmpty() );
2024 symbolName = EscapeString( symbolName, CTX_LIBID );
2025
2026 if( edevice.package )
2027 aEagleLibrary->package[symbolName] = edevice.package.Get();
2028
2029 // Create KiCad symbol.
2030 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2031
2032 // Process each gate in the deviceset for this device.
2033 wxXmlNode* gateNode = getChildrenNodes( deviceSetChildren, wxT( "gates" ) );
2034 int gates_count = countChildren( deviceSetChildren["gates"], wxT( "gate" ) );
2035 libSymbol->SetUnitCount( gates_count );
2036 libSymbol->LockUnits( true );
2037
2038 SCH_FIELD* reference = libSymbol->GetFieldById( REFERENCE_FIELD );
2039
2040 if( prefix.length() == 0 )
2041 {
2042 reference->SetVisible( false );
2043 }
2044 else
2045 {
2046 // If there is no footprint assigned, then prepend the reference value
2047 // with a hash character to mute netlist updater complaints
2048 reference->SetText( edevice.package ? prefix : '#' + prefix );
2049 }
2050
2051 int gateindex = 1;
2052 bool ispower = false;
2053
2054 while( gateNode )
2055 {
2056 checkpoint();
2057
2058 EGATE egate = EGATE( gateNode );
2059
2060 aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex;
2061 ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol], libSymbol, &edevice,
2062 gateindex, egate.name );
2063
2064 gateindex++;
2065 gateNode = gateNode->GetNext();
2066 } // gateNode
2067
2068 libSymbol->SetUnitCount( gates_count );
2069
2070 if( gates_count == 1 && ispower )
2071 libSymbol->SetPower();
2072
2073 // Don't set the footprint field if no package is defined in the Eagle schematic.
2074 if( edevice.package )
2075 {
2076 wxString libName;
2077
2078 if( m_schematic )
2079 {
2080 // assume that footprint library is identical to project name
2081 libName = m_schematic->Prj().GetProjectName();
2082 }
2083 else
2084 {
2085 libName = m_libName;
2086 }
2087
2088 wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
2089
2090 libSymbol->GetFootprintField().SetText( packageString );
2091 }
2092
2093 wxString libName = libSymbol->GetName();
2094 libSymbol->SetName( libName );
2095 libSymbol->SetDescription( deviceSetDescr );
2096
2097 if( m_pi )
2098 {
2099 // If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
2100 // Eagle symbol library name to the symbol which should ensure that it is unique.
2101 if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
2102 {
2103 libName = aEagleLibrary->name + wxT( "_" ) + libName;
2104 libName = EscapeString( libName, CTX_LIBID );
2105 libSymbol->SetName( libName );
2106 }
2107
2108 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
2109 new LIB_SYMBOL( *libSymbol.get() ), m_properties.get() );
2110 }
2111
2112 aEagleLibrary->KiCadSymbols.insert( libName, libSymbol.release() );
2113
2114 // Store information on whether the value of VALUE_FIELD for a part should be
2115 // part/@value or part/@deviceset + part/@device.
2116 m_userValue.emplace( std::make_pair( libName,
2117 edeviceset.uservalue == true ) );
2118
2119 deviceNode = deviceNode->GetNext();
2120 } // devicenode
2121
2122 devicesetNode = devicesetNode->GetNext();
2123 } // devicesetNode
2124
2125 return aEagleLibrary;
2126}
2127
2128
2129bool SCH_IO_EAGLE::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol,
2130 EDEVICE* aDevice, int aGateNumber, const wxString& aGateName )
2131{
2132 wxString symbolName = aSymbolNode->GetAttribute( wxT( "name" ) );
2133 std::vector<SCH_ITEM*> items;
2134
2135 wxXmlNode* currentNode = aSymbolNode->GetChildren();
2136
2137 bool showRefDes = false;
2138 bool showValue = false;
2139 bool ispower = false;
2140 int pincount = 0;
2141
2142 while( currentNode )
2143 {
2144 wxString nodeName = currentNode->GetName();
2145
2146 if( nodeName == wxT( "circle" ) )
2147 {
2148 aSymbol->AddDrawItem( loadSymbolCircle( currentNode, aGateNumber ) );
2149 }
2150 else if( nodeName == wxT( "pin" ) )
2151 {
2152 EPIN ePin = EPIN( currentNode );
2153 std::unique_ptr<SCH_PIN> pin( loadPin( aSymbol, currentNode, &ePin, aGateNumber ) );
2154 pincount++;
2155
2156 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
2157
2158 if( ePin.direction )
2159 {
2160 for( const auto& pinDir : pinDirectionsMap )
2161 {
2162 if( ePin.direction->Lower() == pinDir.first )
2163 {
2164 pin->SetType( pinDir.second );
2165
2166 if( pinDir.first == wxT( "sup" ) ) // power supply symbol
2167 ispower = true;
2168
2169 break;
2170 }
2171 }
2172 }
2173
2174 if( aDevice->connects.size() != 0 )
2175 {
2176 for( const ECONNECT& connect : aDevice->connects )
2177 {
2178 if( connect.gate == aGateName && pin->GetName() == connect.pin )
2179 {
2180 wxArrayString pads = wxSplit( wxString( connect.pad ), ' ' );
2181
2182 pin->SetUnit( aGateNumber );
2183 pin->SetName( escapeName( pin->GetName() ) );
2184
2185 if( pads.GetCount() > 1 )
2186 {
2187 pin->SetNumberTextSize( 0 );
2188 }
2189
2190 for( unsigned i = 0; i < pads.GetCount(); i++ )
2191 {
2192 SCH_PIN* apin = new SCH_PIN( *pin );
2193
2194 wxString padname( pads[i] );
2195 apin->SetNumber( padname );
2196 aSymbol->AddDrawItem( apin );
2197 }
2198
2199 break;
2200 }
2201 }
2202 }
2203 else
2204 {
2205 pin->SetUnit( aGateNumber );
2206 pin->SetNumber( wxString::Format( wxT( "%i" ), pincount ) );
2207 aSymbol->AddDrawItem( pin.release() );
2208 }
2209 }
2210 else if( nodeName == wxT( "polygon" ) )
2211 {
2212 aSymbol->AddDrawItem( loadSymbolPolyLine( currentNode, aGateNumber ) );
2213 }
2214 else if( nodeName == wxT( "rectangle" ) )
2215 {
2216 aSymbol->AddDrawItem( loadSymbolRectangle( currentNode, aGateNumber ) );
2217 }
2218 else if( nodeName == wxT( "text" ) )
2219 {
2220 std::unique_ptr<SCH_TEXT> libtext( loadSymbolText( currentNode, aGateNumber ) );
2221
2222 if( libtext->GetText() == wxT( "${REFERENCE}" ) )
2223 {
2224 // Move text & attributes to Reference field and discard LIB_TEXT item
2225 SCH_FIELD* field = aSymbol->GetFieldById( REFERENCE_FIELD );
2226 loadFieldAttributes( field, libtext.get() );
2227
2228 // Show Reference field if Eagle reference was uppercase
2229 showRefDes = currentNode->GetNodeContent() == wxT( ">NAME" );
2230 }
2231 else if( libtext->GetText() == wxT( "${VALUE}" ) )
2232 {
2233 // Move text & attributes to Value field and discard LIB_TEXT item
2234 SCH_FIELD* field = aSymbol->GetFieldById( VALUE_FIELD );
2235 loadFieldAttributes( field, libtext.get() );
2236
2237 // Show Value field if Eagle reference was uppercase
2238 showValue = currentNode->GetNodeContent() == wxT( ">VALUE" );
2239 }
2240 else
2241 {
2242 aSymbol->AddDrawItem( libtext.release() );
2243 }
2244 }
2245 else if( nodeName == wxT( "wire" ) )
2246 {
2247 aSymbol->AddDrawItem( loadSymbolWire( currentNode, aGateNumber ) );
2248 }
2249 else if( nodeName == wxT( "frame" ) )
2250 {
2251 std::vector<SCH_ITEM*> frameItems;
2252
2253 loadSymbolFrame( currentNode, frameItems );
2254
2255 for( SCH_ITEM* item : frameItems )
2256 {
2257 item->SetParent( aSymbol.get() );
2258 item->SetUnit( aGateNumber );
2259 aSymbol->AddDrawItem( item );
2260 }
2261 }
2262
2263 /*
2264 * else if( nodeName == "description" )
2265 * {
2266 * }
2267 * else if( nodeName == "dimension" )
2268 * {
2269 * }
2270 */
2271
2272 currentNode = currentNode->GetNext();
2273 }
2274
2275 if( !showRefDes )
2276 aSymbol->GetFieldById( REFERENCE_FIELD )->SetVisible( false );
2277
2278 if( !showValue )
2279 aSymbol->GetFieldById( VALUE_FIELD )->SetVisible( false );
2280
2281 return pincount == 1 ? ispower : false;
2282}
2283
2284
2285SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( wxXmlNode* aCircleNode, int aGateNumber )
2286{
2287 // Parse the circle properties
2288 ECIRCLE c( aCircleNode );
2289 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2290 VECTOR2I center( c.x.ToSchUnits(), c.y.ToSchUnits() );
2291
2292 circle->SetPosition( center );
2293 circle->SetEnd( VECTOR2I( center.x + c.radius.ToSchUnits(), center.y ) );
2294 circle->SetStroke( STROKE_PARAMS( c.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2295 circle->SetUnit( aGateNumber );
2296
2297 return circle;
2298}
2299
2300
2301SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( wxXmlNode* aRectNode, int aGateNumber )
2302{
2303 ERECT rect( aRectNode );
2304 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
2305
2306 rectangle->SetPosition( VECTOR2I( rect.x1.ToSchUnits(), rect.y1.ToSchUnits() ) );
2307 rectangle->SetEnd( VECTOR2I( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
2308
2309 if( rect.rot )
2310 {
2311 VECTOR2I pos( rectangle->GetPosition() );
2312 VECTOR2I end( rectangle->GetEnd() );
2313 VECTOR2I center( rectangle->GetCenter() );
2314
2315 RotatePoint( pos, center, EDA_ANGLE( rect.rot->degrees, DEGREES_T ) );
2316 RotatePoint( end, center, EDA_ANGLE( rect.rot->degrees, DEGREES_T ) );
2317
2318 rectangle->SetPosition( pos );
2319 rectangle->SetEnd( end );
2320 }
2321
2322 rectangle->SetUnit( aGateNumber );
2323
2324 // Eagle rectangles are filled by definition.
2325 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2326
2327 return rectangle;
2328}
2329
2330
2331SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( wxXmlNode* aWireNode, int aGateNumber )
2332{
2333 EWIRE ewire = EWIRE( aWireNode );
2334
2335 VECTOR2I begin, end;
2336
2337 begin.x = ewire.x1.ToSchUnits();
2338 begin.y = ewire.y1.ToSchUnits();
2339 end.x = ewire.x2.ToSchUnits();
2340 end.y = ewire.y2.ToSchUnits();
2341
2342 if( begin == end )
2343 return nullptr;
2344
2345 // if the wire is an arc
2346 if( ewire.curve )
2347 {
2348 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2349 VECTOR2I center = ConvertArcCenter( begin, end, *ewire.curve * -1 );
2350 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2351 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2352
2353 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2354 if( ewire.cap == EWIRE::FLAT && ewire.width.ToSchUnits() >= 2 * radius )
2355 {
2356 VECTOR2I centerStartVector = ( begin - center ) * ( ewire.width.ToSchUnits() / radius );
2357 begin = center + centerStartVector;
2358
2359 arc->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2360 arc->SetFillMode( FILL_T::FILLED_SHAPE );
2361 }
2362 else
2363 {
2364 arc->SetStroke( STROKE_PARAMS( ewire.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2365 }
2366
2367 arc->SetCenter( center );
2368 arc->SetStart( begin );
2369 arc->SetArcAngleAndEnd( EDA_ANGLE( *ewire.curve, DEGREES_T ), true );
2370 arc->SetUnit( aGateNumber );
2371
2372 return arc;
2373 }
2374 else
2375 {
2376 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2377
2378 poly->AddPoint( begin );
2379 poly->AddPoint( end );
2380 poly->SetUnit( aGateNumber );
2381 poly->SetStroke( STROKE_PARAMS( ewire.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2382
2383 return poly;
2384 }
2385}
2386
2387
2388SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( wxXmlNode* aPolygonNode, int aGateNumber )
2389{
2390 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2391 EPOLYGON epoly( aPolygonNode );
2392 wxXmlNode* vertex = aPolygonNode->GetChildren();
2393 VECTOR2I pt, prev_pt;
2394 opt_double prev_curve;
2395
2396 while( vertex )
2397 {
2398 if( vertex->GetName() == wxT( "vertex" ) ) // skip <xmlattr> node
2399 {
2400 EVERTEX evertex( vertex );
2401 pt = VECTOR2I( evertex.x.ToSchUnits(), evertex.y.ToSchUnits() );
2402
2403 if( prev_curve )
2404 {
2405 SHAPE_ARC arc;
2406 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2407 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2408 }
2409 else
2410 {
2411 poly->AddPoint( pt );
2412 }
2413
2414 prev_pt = pt;
2415 prev_curve = evertex.curve;
2416 }
2417
2418 vertex = vertex->GetNext();
2419 }
2420
2421 poly->SetStroke( STROKE_PARAMS( epoly.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2422 poly->SetFillMode( FILL_T::FILLED_SHAPE );
2423 poly->SetUnit( aGateNumber );
2424
2425 return poly;
2426}
2427
2428
2429SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, wxXmlNode* aPin,
2430 EPIN* aEPin, int aGateNumber )
2431{
2432 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2433 pin->SetPosition( VECTOR2I( aEPin->x.ToSchUnits(), aEPin->y.ToSchUnits() ) );
2434 pin->SetName( aEPin->name );
2435 pin->SetUnit( aGateNumber );
2436
2437 int roti = aEPin->rot ? aEPin->rot->degrees : 0;
2438
2439 switch( roti )
2440 {
2441 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2442 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2443 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2444 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2445 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2446 }
2447
2448 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2449
2450 if( aEPin->length )
2451 {
2452 wxString length = aEPin->length.Get();
2453
2454 if( length == wxT( "short" ) )
2455 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2456 else if( length == wxT( "middle" ) )
2457 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2458 else if( length == wxT( "long" ) )
2459 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2460 else if( length == wxT( "point" ) )
2461 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2462 }
2463
2464 // emulate the visibility of pin elements
2465 if( aEPin->visible )
2466 {
2467 wxString visible = aEPin->visible.Get();
2468
2469 if( visible == wxT( "off" ) )
2470 {
2471 pin->SetNameTextSize( 0 );
2472 pin->SetNumberTextSize( 0 );
2473 }
2474 else if( visible == wxT( "pad" ) )
2475 {
2476 pin->SetNameTextSize( 0 );
2477 }
2478 else if( visible == wxT( "pin" ) )
2479 {
2480 pin->SetNumberTextSize( 0 );
2481 }
2482
2483 /*
2484 * else if( visible == wxT( "both" ) )
2485 * {
2486 * }
2487 */
2488 }
2489
2490 if( aEPin->function )
2491 {
2492 wxString function = aEPin->function.Get();
2493
2494 if( function == wxT( "dot" ) )
2495 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2496 else if( function == wxT( "clk" ) )
2497 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2498 else if( function == wxT( "dotclk" ) )
2499 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
2500 }
2501
2502 return pin.release();
2503}
2504
2505
2506SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( wxXmlNode* aLibText, int aGateNumber )
2507{
2508 ETEXT etext( aLibText );
2509 VECTOR2I pos( etext.x.ToSchUnits(), etext.y.ToSchUnits() );
2510 const wxString& eagleText = aLibText->GetNodeContent();
2511 wxString adjustedText;
2512 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2513
2514 // Strip the whitespace from both ends of each line.
2515 while( tokenizer.HasMoreTokens() )
2516 {
2517 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2518
2519 if( tokenizer.HasMoreTokens() )
2520 tmp += wxT( "\n" );
2521
2522 adjustedText += tmp;
2523 }
2524
2525 if( adjustedText.IsEmpty() )
2526 adjustedText = wxT( "~" );
2527
2528 auto libtext = std::make_unique<SCH_TEXT>( pos, adjustedText, LAYER_DEVICE );
2529
2530 libtext->SetUnit( aGateNumber );
2531 loadTextAttributes( libtext.get(), etext );
2532
2533 return libtext.release();
2534}
2535
2536
2537void SCH_IO_EAGLE::loadSymbolFrame( wxXmlNode* aFrameNode, std::vector<SCH_ITEM*>& aItems )
2538{
2539 EFRAME eframe( aFrameNode );
2540
2541 int xMin = eframe.x1.ToSchUnits();
2542 int xMax = eframe.x2.ToSchUnits();
2543 int yMin = eframe.y1.ToSchUnits();
2544 int yMax = eframe.y2.ToSchUnits();
2545
2546 if( xMin > xMax )
2547 std::swap( xMin, xMax );
2548
2549 if( yMin > yMax )
2550 std::swap( yMin, yMax );
2551
2552 SCH_SHAPE* lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2553 lines->AddPoint( VECTOR2I( xMin, yMin ) );
2554 lines->AddPoint( VECTOR2I( xMax, yMin ) );
2555 lines->AddPoint( VECTOR2I( xMax, yMax ) );
2556 lines->AddPoint( VECTOR2I( xMin, yMax ) );
2557 lines->AddPoint( VECTOR2I( xMin, yMin ) );
2558 aItems.push_back( lines );
2559
2560 if( !( eframe.border_left == false ) )
2561 {
2562 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2563 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2564 yMin + schIUScale.MilsToIU( 150 ) ) );
2565 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2566 yMax - schIUScale.MilsToIU( 150 ) ) );
2567 aItems.push_back( lines );
2568
2569 int i;
2570 int height = yMax - yMin;
2571 int x1 = xMin;
2572 int x2 = x1 + schIUScale.MilsToIU( 150 );
2573 int legendPosX = xMin + schIUScale.MilsToIU( 75 );
2574 double rowSpacing = height / double( eframe.rows );
2575 double legendPosY = yMax - ( rowSpacing / 2 );
2576
2577 for( i = 1; i < eframe.rows; i++ )
2578 {
2579 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
2580 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2581 lines->AddPoint( VECTOR2I( x1, newY ) );
2582 lines->AddPoint( VECTOR2I( x2, newY ) );
2583 aItems.push_back( lines );
2584 }
2585
2586 char legendChar = 'A';
2587
2588 for( i = 0; i < eframe.rows; i++ )
2589 {
2590 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( legendPosX, KiROUND( legendPosY ) ),
2591 wxString( legendChar ), LAYER_DEVICE );
2592 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2593 schIUScale.MilsToIU( 100 ) ) );
2594 aItems.push_back( legendText );
2595 legendChar++;
2596 legendPosY -= rowSpacing;
2597 }
2598 }
2599
2600 if( !( eframe.border_right == false ) )
2601 {
2602 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2603 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2604 yMin + schIUScale.MilsToIU( 150 ) ) );
2605 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2606 yMax - schIUScale.MilsToIU( 150 ) ) );
2607 aItems.push_back( lines );
2608
2609 int i;
2610 int height = yMax - yMin;
2611 int x1 = xMax - schIUScale.MilsToIU( 150 );
2612 int x2 = xMax;
2613 int legendPosX = xMax - schIUScale.MilsToIU( 75 );
2614 double rowSpacing = height / double( eframe.rows );
2615 double legendPosY = yMax - ( rowSpacing / 2 );
2616
2617 for( i = 1; i < eframe.rows; i++ )
2618 {
2619 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
2620 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2621 lines->AddPoint( VECTOR2I( x1, newY ) );
2622 lines->AddPoint( VECTOR2I( x2, newY ) );
2623 aItems.push_back( lines );
2624 }
2625
2626 char legendChar = 'A';
2627
2628 for( i = 0; i < eframe.rows; i++ )
2629 {
2630 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( legendPosX, KiROUND( legendPosY ) ),
2631 wxString( legendChar ), LAYER_DEVICE );
2632 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2633 schIUScale.MilsToIU( 100 ) ) );
2634 aItems.push_back( legendText );
2635 legendChar++;
2636 legendPosY -= rowSpacing;
2637 }
2638 }
2639
2640 if( !( eframe.border_top == false ) )
2641 {
2642 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2643 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2644 yMax - schIUScale.MilsToIU( 150 ) ) );
2645 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2646 yMax - schIUScale.MilsToIU( 150 ) ) );
2647 aItems.push_back( lines );
2648
2649 int i;
2650 int width = xMax - xMin;
2651 int y1 = yMin;
2652 int y2 = yMin + schIUScale.MilsToIU( 150 );
2653 int legendPosY = yMax - schIUScale.MilsToIU( 75 );
2654 double columnSpacing = width / double( eframe.columns );
2655 double legendPosX = xMin + ( columnSpacing / 2 );
2656
2657 for( i = 1; i < eframe.columns; i++ )
2658 {
2659 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
2660 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2661 lines->AddPoint( VECTOR2I( newX, y1 ) );
2662 lines->AddPoint( VECTOR2I( newX, y2 ) );
2663 aItems.push_back( lines );
2664 }
2665
2666 char legendChar = '1';
2667
2668 for( i = 0; i < eframe.columns; i++ )
2669 {
2670 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( KiROUND( legendPosX ), legendPosY ),
2671 wxString( legendChar ), LAYER_DEVICE );
2672 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2673 schIUScale.MilsToIU( 100 ) ) );
2674 aItems.push_back( legendText );
2675 legendChar++;
2676 legendPosX += columnSpacing;
2677 }
2678 }
2679
2680 if( !( eframe.border_bottom == false ) )
2681 {
2682 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2683 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2684 yMin + schIUScale.MilsToIU( 150 ) ) );
2685 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2686 yMin + schIUScale.MilsToIU( 150 ) ) );
2687 aItems.push_back( lines );
2688
2689 int i;
2690 int width = xMax - xMin;
2691 int y1 = yMax - schIUScale.MilsToIU( 150 );
2692 int y2 = yMax;
2693 int legendPosY = yMin + schIUScale.MilsToIU( 75 );
2694 double columnSpacing = width / double( eframe.columns );
2695 double legendPosX = xMin + ( columnSpacing / 2 );
2696
2697 for( i = 1; i < eframe.columns; i++ )
2698 {
2699 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
2700 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2701 lines->AddPoint( VECTOR2I( newX, y1 ) );
2702 lines->AddPoint( VECTOR2I( newX, y2 ) );
2703 aItems.push_back( lines );
2704 }
2705
2706 char legendChar = '1';
2707
2708 for( i = 0; i < eframe.columns; i++ )
2709 {
2710 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( KiROUND( legendPosX ), legendPosY ),
2711 wxString( legendChar ), LAYER_DEVICE );
2712 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2713 schIUScale.MilsToIU( 100 ) ) );
2714 aItems.push_back( legendText );
2715 legendChar++;
2716 legendPosX += columnSpacing;
2717 }
2718 }
2719}
2720
2721
2723{
2724 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2725 ETEXT etext = ETEXT( aSchText );
2726
2727 const wxString& eagleText = aSchText->GetNodeContent();
2728 wxString adjustedText;
2729 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2730
2731 // Strip the whitespace from both ends of each line.
2732 while( tokenizer.HasMoreTokens() )
2733 {
2734 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2735
2736 if( tokenizer.HasMoreTokens() )
2737 tmp += wxT( "\n" );
2738
2739 adjustedText += tmp;
2740 }
2741
2742 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxT( "\" \"" ) ) : escapeName( adjustedText ) );
2743 schtext->SetPosition( VECTOR2I( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
2744 loadTextAttributes( schtext.get(), etext );
2745 schtext->SetItalic( false );
2746
2747 return schtext.release();
2748}
2749
2750
2751void SCH_IO_EAGLE::loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const
2752{
2753 aText->SetTextSize( aAttribs.ConvertSize() );
2754
2755 // Must come after SetTextSize()
2756 if( aAttribs.ratio && aAttribs.ratio.CGet() > 12 )
2757 aText->SetBold( true );
2758
2759 int align = aAttribs.align ? *aAttribs.align : ETEXT::BOTTOM_LEFT;
2760 int degrees = aAttribs.rot ? aAttribs.rot->degrees : 0;
2761 bool mirror = aAttribs.rot ? aAttribs.rot->mirror : false;
2762 bool spin = aAttribs.rot ? aAttribs.rot->spin : false;
2763
2764 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
2765}
2766
2767
2768void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
2769{
2770 aField->SetTextPos( aText->GetPosition() );
2771 aField->SetTextSize( aText->GetTextSize() );
2772 aField->SetTextAngle( aText->GetTextAngle() );
2773
2774 // Must come after SetTextSize()
2775 aField->SetBold( aText->IsBold() );
2776 aField->SetItalic( false );
2777
2778 aField->SetVertJustify( aText->GetVertJustify() );
2779 aField->SetHorizJustify( aText->GetHorizJustify() );
2780}
2781
2782
2784{
2785 // Eagle supports detached labels, so a label does not need to be placed on a wire
2786 // to be associated with it. KiCad needs to move them, so the labels actually touch the
2787 // corresponding wires.
2788
2789 // Sort the intersection points to speed up the search process
2790 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
2791
2792 auto onIntersection =
2793 [&]( const VECTOR2I& aPos )
2794 {
2795 return std::binary_search( m_wireIntersections.begin(),
2796 m_wireIntersections.end(), aPos );
2797 };
2798
2799 for( SEG_DESC& segDesc : m_segments )
2800 {
2801 for( SCH_TEXT* label : segDesc.labels )
2802 {
2803 VECTOR2I labelPos( label->GetPosition() );
2804 const SEG* segAttached = segDesc.LabelAttached( label );
2805
2806 if( segAttached && !onIntersection( labelPos ) )
2807 continue; // label is placed correctly
2808
2809 // Move the label to the nearest wire
2810 if( !segAttached )
2811 {
2812 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
2813 segDesc.segs );
2814
2815 if( !segAttached ) // we cannot do anything
2816 continue;
2817 }
2818
2819 // Create a vector pointing in the direction of the wire, 50 mils long
2820 VECTOR2I wireDirection( segAttached->B - segAttached->A );
2821 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
2822 const VECTOR2I origPos( labelPos );
2823
2824 // Flags determining the search direction
2825 bool checkPositive = true, checkNegative = true, move = false;
2826 int trial = 0;
2827
2828 // Be sure the label is not placed on a wire intersection
2829 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
2830 {
2831 move = false;
2832
2833 // Move along the attached wire to find the new label position
2834 if( trial % 2 == 1 )
2835 {
2836 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
2837 move = checkPositive = segAttached->Contains( labelPos );
2838 }
2839 else
2840 {
2841 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
2842 move = checkNegative = segAttached->Contains( labelPos );
2843 }
2844
2845 ++trial;
2846 }
2847
2848 if( move )
2849 label->SetPosition( VECTOR2I( labelPos ) );
2850 }
2851 }
2852
2853 m_segments.clear();
2854 m_wireIntersections.clear();
2855}
2856
2857
2858bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
2859{
2860 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
2861 return false;
2862
2863 return checkHeader( aFileName );
2864}
2865
2866
2867bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
2868{
2869 if( !SCH_IO::CanReadLibrary( aFileName ) )
2870 return false;
2871
2872 return checkHeader( aFileName );
2873}
2874
2875
2876bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
2877{
2878 wxFileInputStream input( aFileName );
2879
2880 if( !input.IsOk() )
2881 return false;
2882
2883 wxTextInputStream text( input );
2884
2885 for( int i = 0; i < 4; i++ )
2886 {
2887 if( input.Eof() )
2888 return false;
2889
2890 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
2891 return true;
2892 }
2893
2894 return false;
2895}
2896
2897
2898void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
2899{
2900 SCH_SCREEN* screen = getCurrentScreen();
2901
2902 wxCHECK( screen, /* void */ );
2903
2904 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
2905 {
2906 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
2907 continue;
2908
2909 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
2910 item->SetPosition( aNewEndPoint );
2911 }
2912}
2913
2914
2916{
2917 // Add bus entry symbols
2918 // TODO: Cleanup this function and break into pieces
2919
2920 // for each wire segment, compare each end with all busses.
2921 // If the wire end is found to end on a bus segment, place a bus entry symbol.
2922
2923 std::vector<SCH_LINE*> buses;
2924 std::vector<SCH_LINE*> wires;
2925
2926 SCH_SCREEN* screen = getCurrentScreen();
2927
2928 wxCHECK( screen, /* void */ );
2929
2930 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
2931 {
2932 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
2933
2934 if( line->IsBus() )
2935 buses.push_back( line );
2936 else if( line->IsWire() )
2937 wires.push_back( line );
2938 }
2939
2940 for( SCH_LINE* wire : wires )
2941 {
2942 VECTOR2I wireStart = wire->GetStartPoint();
2943 VECTOR2I wireEnd = wire->GetEndPoint();
2944
2945 for( SCH_LINE* bus : buses )
2946 {
2947 VECTOR2I busStart = bus->GetStartPoint();
2948 VECTOR2I busEnd = bus->GetEndPoint();
2949
2950 auto entrySize =
2951 []( int signX, int signY ) -> VECTOR2I
2952 {
2955 };
2956
2957 auto testBusHit =
2958 [&]( const VECTOR2I& aPt ) -> bool
2959 {
2960 return TestSegmentHit( aPt, busStart, busEnd, 0 );
2961 };
2962
2963 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
2964 {
2965 // Horizontal wire and vertical bus
2966
2967 if( testBusHit( wireStart ) )
2968 {
2969 // Wire start is on the vertical bus
2970
2971 if( wireEnd.x < busStart.x )
2972 {
2973 /* the end of the wire is to the left of the bus
2974 * ⎥⎢
2975 * ——————⎥⎢
2976 * ⎥⎢
2977 */
2978 VECTOR2I p = wireStart + entrySize( -1, 0 );
2979
2980 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2981 {
2982 /* there is room above the wire for the bus entry
2983 * ⎥⎢
2984 * _____/⎥⎢
2985 * ⎥⎢
2986 */
2987 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2988 busEntry->SetFlags( IS_NEW );
2989 screen->Append( busEntry );
2990 moveLabels( wire, p );
2991 wire->SetStartPoint( p );
2992 }
2993 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2994 {
2995 /* there is room below the wire for the bus entry
2996 * _____ ⎥⎢
2997 * \⎥⎢
2998 * ⎥⎢
2999 */
3000 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3001 busEntry->SetFlags( IS_NEW );
3002 screen->Append( busEntry );
3003 moveLabels( wire, p );
3004 wire->SetStartPoint( p );
3005 }
3006 else
3007 {
3008 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3009 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3010 screen->Append( marker );
3011 }
3012 }
3013 else
3014 {
3015 /* the wire end is to the right of the bus
3016 * ⎥⎢
3017 * ⎥⎢——————
3018 * ⎥⎢
3019 */
3020 VECTOR2I p = wireStart + entrySize( 1, 0 );
3021
3022 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
3023 {
3024 /* There is room above the wire for the bus entry
3025 * ⎥⎢
3026 * ⎥⎢\_____
3027 * ⎥⎢
3028 */
3029 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
3030 busEntry->SetFlags( IS_NEW );
3031 screen->Append( busEntry );
3032 moveLabels( wire, p );
3033 wire->SetStartPoint( p );
3034 }
3035 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
3036 {
3037 /* There is room below the wire for the bus entry
3038 * ⎥⎢ _____
3039 * ⎥⎢/
3040 * ⎥⎢
3041 */
3042 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3043 busEntry->SetFlags( IS_NEW );
3044 screen->Append( busEntry );
3045 moveLabels( wire, p );
3046 wire->SetStartPoint( p );
3047 }
3048 else
3049 {
3050 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3051 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3052 screen->Append( marker );
3053 }
3054 }
3055
3056 break;
3057 }
3058 else if( testBusHit( wireEnd ) )
3059 {
3060 // Wire end is on the vertical bus
3061
3062 if( wireStart.x < busStart.x )
3063 {
3064 /* start of the wire is to the left of the bus
3065 * ⎥⎢
3066 * ——————⎥⎢
3067 * ⎥⎢
3068 */
3069 VECTOR2I p = wireEnd + entrySize( -1, 0 );
3070
3071 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3072 {
3073 /* there is room above the wire for the bus entry
3074 * ⎥⎢
3075 * _____/⎥⎢
3076 * ⎥⎢
3077 */
3078 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3079 busEntry->SetFlags( IS_NEW );
3080 screen->Append( busEntry );
3081 moveLabels( wire, p );
3082 wire->SetEndPoint( p );
3083 }
3084 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3085 {
3086 /* there is room below the wire for the bus entry
3087 * _____ ⎥⎢
3088 * \⎥⎢
3089 * ⎥⎢
3090 */
3091 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3092 busEntry->SetFlags( IS_NEW );
3093 screen->Append( busEntry );
3094 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
3095 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
3096 }
3097 else
3098 {
3099 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3100 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3101 screen->Append( marker );
3102 }
3103 }
3104 else
3105 {
3106 /* the start of the wire is to the right of the bus
3107 * ⎥⎢
3108 * ⎥⎢——————
3109 * ⎥⎢
3110 */
3111 VECTOR2I p = wireEnd + entrySize( 1, 0 );
3112
3113 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3114 {
3115 /* There is room above the wire for the bus entry
3116 * ⎥⎢
3117 * ⎥⎢\_____
3118 * ⎥⎢
3119 */
3120 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3121 busEntry->SetFlags( IS_NEW );
3122 screen->Append( busEntry );
3123 moveLabels( wire, p );
3124 wire->SetEndPoint( p );
3125 }
3126 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
3127 {
3128 /* There is room below the wire for the bus entry
3129 * ⎥⎢ _____
3130 * ⎥⎢/
3131 * ⎥⎢
3132 */
3133 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3134 busEntry->SetFlags( IS_NEW );
3135 screen->Append( busEntry );
3136 moveLabels( wire, p );
3137 wire->SetEndPoint( p );
3138 }
3139 else
3140 {
3141 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3142 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3143 screen->Append( marker );
3144 }
3145 }
3146
3147 break;
3148 }
3149 }
3150 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
3151 {
3152 // Vertical wire and horizontal bus
3153
3154 if( testBusHit( wireStart ) )
3155 {
3156 // Wire start is on the bus
3157
3158 if( wireEnd.y < busStart.y )
3159 {
3160 /* the end of the wire is above the bus
3161 * |
3162 * |
3163 * |
3164 * =======
3165 */
3166 VECTOR2I p = wireStart + entrySize( 0, -1 );
3167
3168 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3169 {
3170 /* there is room to the left of the wire for the bus entry
3171 * |
3172 * |
3173 * /
3174 * =======
3175 */
3176 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3177 busEntry->SetFlags( IS_NEW );
3178 screen->Append( busEntry );
3179 moveLabels( wire, p );
3180 wire->SetStartPoint( p );
3181 }
3182 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3183 {
3184 /* there is room to the right of the wire for the bus entry
3185 * |
3186 * |
3187 * \
3188 * =======
3189 */
3190 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3191 busEntry->SetFlags( IS_NEW );
3192 screen->Append( busEntry );
3193 moveLabels( wire, p );
3194 wire->SetStartPoint( p );
3195 }
3196 else
3197 {
3198 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3199 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3200 screen->Append( marker );
3201 }
3202 }
3203 else
3204 {
3205 /* wire end is below the bus
3206 * =======
3207 * |
3208 * |
3209 * |
3210 */
3211 VECTOR2I p = wireStart + entrySize( 0, 1 );
3212
3213 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3214 {
3215 /* there is room to the left of the wire for the bus entry
3216 * =======
3217 * \
3218 * |
3219 * |
3220 */
3221 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3222 busEntry->SetFlags( IS_NEW );
3223 screen->Append( busEntry );
3224 moveLabels( wire, p );
3225 wire->SetStartPoint( p );
3226 }
3227 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3228 {
3229 /* there is room to the right of the wire for the bus entry
3230 * =======
3231 * /
3232 * |
3233 * |
3234 */
3235 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3236 busEntry->SetFlags( IS_NEW );
3237 screen->Append( busEntry );
3238 moveLabels( wire, p );
3239 wire->SetStartPoint( p );
3240 }
3241 else
3242 {
3243 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3244 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3245 screen->Append( marker );
3246 }
3247 }
3248
3249 break;
3250 }
3251 else if( testBusHit( wireEnd ) )
3252 {
3253 // Wire end is on the bus
3254
3255 if( wireStart.y < busStart.y )
3256 {
3257 /* the start of the wire is above the bus
3258 * |
3259 * |
3260 * |
3261 * =======
3262 */
3263 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3264
3265 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3266 {
3267 /* there is room to the left of the wire for the bus entry
3268 * |
3269 * |
3270 * /
3271 * =======
3272 */
3273 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3274 busEntry->SetFlags( IS_NEW );
3275 screen->Append( busEntry );
3276 moveLabels( wire, p );
3277 wire->SetEndPoint( p );
3278 }
3279 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3280 {
3281 /* there is room to the right of the wire for the bus entry
3282 * |
3283 * |
3284 * \
3285 * =======
3286 */
3287 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3288 busEntry->SetFlags( IS_NEW );
3289 screen->Append( busEntry );
3290 moveLabels( wire, p );
3291 wire->SetEndPoint( p );
3292 }
3293 else
3294 {
3295 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3296 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3297 screen->Append( marker );
3298 }
3299 }
3300 else
3301 {
3302 /* wire start is below the bus
3303 * =======
3304 * |
3305 * |
3306 * |
3307 */
3308 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3309
3310 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3311 {
3312 /* there is room to the left of the wire for the bus entry
3313 * =======
3314 * \
3315 * |
3316 * |
3317 */
3318 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3319 busEntry->SetFlags( IS_NEW );
3320 screen->Append( busEntry );
3321 moveLabels( wire, p );
3322 wire->SetEndPoint( p );
3323 }
3324 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3325 {
3326 /* there is room to the right of the wire for the bus entry
3327 * =======
3328 * /
3329 * |
3330 * |
3331 */
3332 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3333 busEntry->SetFlags( IS_NEW );
3334 screen->Append( busEntry );
3335 moveLabels( wire, p );
3336 wire->SetEndPoint( p );
3337 }
3338 else
3339 {
3340 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3341 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3342 screen->Append( marker );
3343 }
3344 }
3345
3346 break;
3347 }
3348 }
3349 else
3350 {
3351 // Wire isn't horizontal or vertical
3352
3353 if( testBusHit( wireStart ) )
3354 {
3355 VECTOR2I wirevector = wireStart - wireEnd;
3356
3357 if( wirevector.x > 0 )
3358 {
3359 if( wirevector.y > 0 )
3360 {
3361 VECTOR2I p = wireStart + entrySize( -1, -1 );
3362 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3363 busEntry->SetFlags( IS_NEW );
3364 screen->Append( busEntry );
3365
3366 moveLabels( wire, p );
3367 wire->SetStartPoint( p );
3368 }
3369 else
3370 {
3371 VECTOR2I p = wireStart + entrySize( -1, 1 );
3372 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3373 busEntry->SetFlags( IS_NEW );
3374 screen->Append( busEntry );
3375
3376 moveLabels( wire, p );
3377 wire->SetStartPoint( p );
3378 }
3379 }
3380 else
3381 {
3382 if( wirevector.y > 0 )
3383 {
3384 VECTOR2I p = wireStart + entrySize( 1, -1 );
3385 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3386 busEntry->SetFlags( IS_NEW );
3387 screen->Append( busEntry );
3388
3389 moveLabels( wire, p );
3390 wire->SetStartPoint( p );
3391 }
3392 else
3393 {
3394 VECTOR2I p = wireStart + entrySize( 1, 1 );
3395 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3396 busEntry->SetFlags( IS_NEW );
3397 screen->Append( busEntry );
3398
3399 moveLabels( wire, p );
3400 wire->SetStartPoint( p );
3401 }
3402 }
3403
3404 break;
3405 }
3406 else if( testBusHit( wireEnd ) )
3407 {
3408 VECTOR2I wirevector = wireStart - wireEnd;
3409
3410 if( wirevector.x > 0 )
3411 {
3412 if( wirevector.y > 0 )
3413 {
3414 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3415 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3416 busEntry->SetFlags( IS_NEW );
3417 screen->Append( busEntry );
3418
3419 moveLabels( wire, p );
3420 wire->SetEndPoint( p );
3421 }
3422 else
3423 {
3424 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3425 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3426 busEntry->SetFlags( IS_NEW );
3427 screen->Append( busEntry );
3428
3429 moveLabels( wire, p );
3430 wire->SetEndPoint( p );
3431 }
3432 }
3433 else
3434 {
3435 if( wirevector.y > 0 )
3436 {
3437 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3438 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3439 busEntry->SetFlags( IS_NEW );
3440 screen->Append( busEntry );
3441
3442 moveLabels( wire, p );
3443 wire->SetEndPoint( p );
3444 }
3445 else
3446 {
3447 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3448 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3449 busEntry->SetFlags( IS_NEW );
3450 screen->Append( busEntry );
3451
3452 moveLabels( wire, p );
3453 wire->SetEndPoint( p );
3454 }
3455 }
3456
3457 break;
3458 }
3459 }
3460 }
3461 }
3462}
3463
3464
3466{
3467 VECTOR2I labelPos( aLabel->GetPosition() );
3468
3469 for( const SEG& seg : segs )
3470 {
3471 if( seg.Contains( labelPos ) )
3472 return &seg;
3473 }
3474
3475 return nullptr;
3476}
3477
3478
3479// TODO could be used to place junctions, instead of IsJunctionNeeded()
3480// (see SCH_EDIT_FRAME::importFile())
3481bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3482{
3483 wxCHECK( aSymbol && aPin, false );
3484
3485 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3486 auto pointIt = m_connPoints.find( pinPosition );
3487
3488 if( pointIt == m_connPoints.end() )
3489 return false;
3490
3491 const auto& items = pointIt->second;
3492
3493 wxCHECK( items.find( aPin ) != items.end(), false );
3494
3495 return items.size() > 1;
3496}
3497
3498
3500 bool aUpdateSet )
3501{
3502 wxCHECK( aSymbol->GetLibSymbolRef(), /*void*/ );
3503
3504 // Normally power parts also have power input pins,
3505 // but they already force net names on the attached wires
3506 if( aSymbol->GetLibSymbolRef()->IsPower() )
3507 return;
3508
3509 int unit = aSymbol->GetUnit();
3510 const wxString reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
3511 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetAllLibPins();
3512 std::set<int> missingUnits;
3513
3514 // Search all units for pins creating implicit connections
3515 for( const SCH_PIN* pin : pins )
3516 {
3517 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3518 {
3519 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3520
3521 // Create a global net label only if there are no other wires/pins attached
3522 if( pinInUnit )
3523 {
3524 if( !checkConnections( aSymbol, pin ) )
3525 {
3526 // Create a net label to force the net name on the pin
3527 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3528 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3529 netLabel->SetText( extractNetName( pin->GetName() ) );
3530 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3531 schIUScale.MilsToIU( 40 ) ) );
3532
3533 switch( pin->GetOrientation() )
3534 {
3535 default:
3536 case PIN_ORIENTATION::PIN_RIGHT:
3537 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3538 break;
3539 case PIN_ORIENTATION::PIN_LEFT:
3540 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3541 break;
3542 case PIN_ORIENTATION::PIN_UP:
3543 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3544 break;
3545 case PIN_ORIENTATION::PIN_DOWN:
3546 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3547 break;
3548 }
3549
3550 aScreen->Append( netLabel );
3551 }
3552 }
3553 else if( aUpdateSet )
3554 {
3555 // Found a pin creating implicit connection information in another unit.
3556 // Such units will be instantiated if they do not appear in another sheet and
3557 // processed later.
3558 wxASSERT( pin->GetUnit() );
3559 missingUnits.insert( pin->GetUnit() );
3560 }
3561 }
3562 }
3563
3564 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3565 {
3566 auto cmpIt = m_missingCmps.find( reference );
3567
3568 // The first unit found has always already been processed.
3569 if( cmpIt == m_missingCmps.end() )
3570 {
3571 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3572 entry.cmp = aSymbol;
3573 entry.units.emplace( unit, false );
3574 }
3575 else
3576 {
3577 // Set the flag indicating this unit has been processed.
3578 cmpIt->second.units[unit] = false;
3579 }
3580
3581 if( !missingUnits.empty() ) // Save the units that need later processing
3582 {
3583 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3584 entry.cmp = aSymbol;
3585
3586 // Add units that haven't already been processed.
3587 for( int i : missingUnits )
3588 {
3589 if( entry.units.find( i ) != entry.units.end() )
3590 entry.units.emplace( i, true );
3591 }
3592 }
3593 }
3594}
3595
3596
3597wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3598{
3599 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3600 return aEagleName;
3601
3602 wxString ret = wxT( "{" );
3603
3604 wxStringTokenizer tokenizer( aEagleName, wxT( "," ) );
3605
3606 while( tokenizer.HasMoreTokens() )
3607 {
3608 wxString member = tokenizer.GetNextToken();
3609
3610 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3611 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3612 // if there is an odd number of overbar markers in this net name, we need to append one
3613 // to close it out before appending the space.
3614
3615 if( member.Freq( '!' ) % 2 > 0 )
3616 member << wxT( "!" );
3617
3618 ret << member << wxS( " " );
3619 }
3620
3621 ret.Trim( true );
3622 ret << wxT( "}" );
3623
3624 return ret;
3625}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
const SizeVec & GetSize() const
Definition: box2.h:196
size_type GetHeight() const
Definition: box2.h:205
size_type GetWidth() const
Definition: box2.h:204
coord_type GetY() const
Definition: box2.h:198
Vec Centre() const
Definition: box2.h:87
coord_type GetLeft() const
Definition: box2.h:218
coord_type GetBottom() const
Definition: box2.h:212
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:623
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:252
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:210
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:213
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
Define a library symbol object.
Definition: lib_symbol.h:77
bool IsPower() const override
Definition: lib_symbol.cpp:663
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:1407
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1387
void SetName(const wxString &aName)
Definition: sch_field.cpp:1128
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1138
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1903
SCH_SHAPE * loadSymbolRectangle(wxXmlNode *aRectNode, int aGateNumber)
SCH_PIN * loadPin(std::unique_ptr< LIB_SYMBOL > &aSymbol, wxXmlNode *, EPIN *epin, 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
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
bool checkConnections(const SCH_SYMBOL *aSymbol, const SCH_PIN *aPin) const
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()
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:174
int GetUnit() const
Definition: sch_item.h:237
virtual void SetUnit(int aUnit)
Definition: sch_item.h:236
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
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:465
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:910
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:216
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
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:194
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:84
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:370
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_NOTES
Definition: layer_ids.h:371
@ 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:172
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:118
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.