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 if( epart->value )
1840 {
1841 valueField->SetText( *epart->value );
1842 }
1843 else
1844 {
1845 valueField->SetText( kisymbolname );
1846
1847 if( userValue )
1848 valueField->SetVisible( false );
1849 }
1850
1851 for( const auto& [ attrName, attrValue ] : epart->attribute )
1852 {
1853 VECTOR2I newFieldPosition( 0, 0 );
1854 SCH_FIELD* lastField = symbol->GetFieldById( symbol->GetFieldCount() - 1 );
1855
1856 if( lastField )
1857 newFieldPosition = lastField->GetPosition();
1858
1859 SCH_FIELD newField( newFieldPosition, symbol->GetFieldCount(), symbol.get() );
1860
1861 newField.SetName( attrName );
1862 newField.SetText( attrValue );
1863 newField.SetVisible( false );
1864
1865 symbol->AddField( newField );
1866 }
1867
1868 for( const auto& a : epart->variant )
1869 {
1870 SCH_FIELD* field = symbol->AddField( *symbol->GetField( VALUE_FIELD ) );
1871 field->SetName( wxT( "VARIANT_" ) + wxString( a.first ) );
1872 field->SetText( a.second );
1873 field->SetVisible( false );
1874 }
1875
1876 bool valueAttributeFound = false;
1877 bool nameAttributeFound = false;
1878
1879 wxXmlNode* attributeNode = aInstanceNode->GetChildren();
1880
1881 // Parse attributes for the instance
1882 while( attributeNode )
1883 {
1884 if( attributeNode->GetName() == wxT( "attribute" ) )
1885 {
1886 EATTR attr = EATTR( attributeNode );
1887 SCH_FIELD* field = nullptr;
1888
1889 if( attr.name.Lower() == wxT( "name" ) )
1890 {
1891 field = symbol->GetField( REFERENCE_FIELD );
1892 nameAttributeFound = true;
1893 }
1894 else if( attr.name.Lower() == wxT( "value" ) )
1895 {
1896 field = symbol->GetField( VALUE_FIELD );
1897 valueAttributeFound = true;
1898 }
1899 else
1900 {
1901 field = symbol->FindField( attr.name );
1902
1903 if( field )
1904 field->SetVisible( false );
1905 }
1906
1907 if( field )
1908 {
1909 field->SetPosition( VECTOR2I( attr.x->ToSchUnits(), -attr.y->ToSchUnits() ) );
1910 int align = attr.align ? *attr.align : ETEXT::BOTTOM_LEFT;
1911 int absdegrees = attr.rot ? attr.rot->degrees : 0;
1912 bool mirror = attr.rot ? attr.rot->mirror : false;
1913
1914 if( einstance.rot && einstance.rot->mirror )
1915 mirror = !mirror;
1916
1917 bool spin = attr.rot ? attr.rot->spin : false;
1918
1919 if( attr.display == EATTR::Off || attr.display == EATTR::NAME )
1920 field->SetVisible( false );
1921
1922 int rotation = einstance.rot ? einstance.rot->degrees : 0;
1923 int reldegrees = ( absdegrees - rotation + 360.0 );
1924 reldegrees %= 360;
1925
1926 eagleToKicadAlignment( (EDA_TEXT*) field, align, reldegrees, mirror, spin,
1927 absdegrees );
1928 }
1929 }
1930 else if( attributeNode->GetName() == wxT( "variant" ) )
1931 {
1932 wxString variantName, fieldValue;
1933
1934 if( attributeNode->GetAttribute( wxT( "name" ), &variantName )
1935 && attributeNode->GetAttribute( wxT( "value" ), &fieldValue ) )
1936 {
1937 SCH_FIELD field( VECTOR2I( 0, 0 ), -1, symbol.get() );
1938 field.SetName( wxT( "VARIANT_" ) + variantName );
1939 field.SetText( fieldValue );
1940 field.SetVisible( false );
1941 symbol->AddField( field );
1942 }
1943 }
1944
1945 attributeNode = attributeNode->GetNext();
1946 }
1947
1948 // Use the instance attribute to determine the reference and value field visibility.
1949 if( einstance.smashed && einstance.smashed.Get() )
1950 {
1951 if( !valueAttributeFound )
1952 symbol->GetField( VALUE_FIELD )->SetVisible( false );
1953
1954 if( !nameAttributeFound )
1955 symbol->GetField( REFERENCE_FIELD )->SetVisible( false );
1956 }
1957
1958 symbol->AddHierarchicalReference( m_sheetPath.Path(), reference, unit );
1959
1960 // Save the pin positions
1961 SYMBOL_LIB_TABLE& schLibTable = *PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() );
1962 LIB_SYMBOL* libSymbol = schLibTable.LoadSymbol( symbol->GetLibId() );
1963
1964 wxCHECK( libSymbol, /*void*/ );
1965
1966 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
1967
1968 for( const SCH_PIN* pin : symbol->GetLibPins() )
1969 m_connPoints[symbol->GetPinPhysicalPosition( pin )].emplace( pin );
1970
1971 if( part->IsPower() )
1972 m_powerPorts[ reference ] = symbol->GetField( VALUE_FIELD )->GetText();
1973
1974 symbol->ClearFlags();
1975
1976 screen->Append( symbol.release() );
1977}
1978
1979
1980EAGLE_LIBRARY* SCH_IO_EAGLE::loadLibrary( wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLibrary )
1981{
1982 NODE_MAP libraryChildren = MapChildren( aLibraryNode );
1983
1984 // Loop through the symbols and load each of them
1985 wxXmlNode* symbolNode = getChildrenNodes( libraryChildren, wxT( "symbols" ) );
1986
1987 while( symbolNode )
1988 {
1989 wxString symbolName = symbolNode->GetAttribute( wxT( "name" ) );
1990 aEagleLibrary->SymbolNodes[symbolName] = symbolNode;
1991 symbolNode = symbolNode->GetNext();
1992 }
1993
1994 // Loop through the device sets and load each of them
1995 wxXmlNode* devicesetNode = getChildrenNodes( libraryChildren, wxT( "devicesets" ) );
1996
1997 while( devicesetNode )
1998 {
1999 // Get Device set information
2000 EDEVICE_SET edeviceset = EDEVICE_SET( devicesetNode );
2001
2002 wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : wxString( wxT( "" ) );
2003 wxString deviceSetDescr;
2004
2005 NODE_MAP deviceSetChildren = MapChildren( devicesetNode );
2006 wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, wxT( "devices" ) );
2007 wxXmlNode* deviceSetDescrNode = getChildrenNodes( deviceSetChildren, wxT( "description" ) );
2008
2009 if( deviceSetDescrNode )
2010 deviceSetDescr = convertDescription( UnescapeHTML( deviceSetDescrNode->GetContent() ) );
2011
2012 // For each device in the device set:
2013 while( deviceNode )
2014 {
2015 // Get device information
2016 EDEVICE edevice = EDEVICE( deviceNode );
2017
2018 // Create symbol name from deviceset and device names.
2019 wxString symbolName = edeviceset.name + edevice.name;
2020 symbolName.Replace( wxT( "*" ), wxEmptyString );
2021 wxASSERT( !symbolName.IsEmpty() );
2022 symbolName = EscapeString( symbolName, CTX_LIBID );
2023
2024 if( edevice.package )
2025 aEagleLibrary->package[symbolName] = edevice.package.Get();
2026
2027 // Create KiCad symbol.
2028 std::unique_ptr<LIB_SYMBOL> libSymbol = std::make_unique<LIB_SYMBOL>( symbolName );
2029
2030 // Process each gate in the deviceset for this device.
2031 wxXmlNode* gateNode = getChildrenNodes( deviceSetChildren, wxT( "gates" ) );
2032 int gates_count = countChildren( deviceSetChildren["gates"], wxT( "gate" ) );
2033 libSymbol->SetUnitCount( gates_count );
2034 libSymbol->LockUnits( true );
2035
2036 SCH_FIELD* reference = libSymbol->GetFieldById( REFERENCE_FIELD );
2037
2038 if( prefix.length() == 0 )
2039 {
2040 reference->SetVisible( false );
2041 }
2042 else
2043 {
2044 // If there is no footprint assigned, then prepend the reference value
2045 // with a hash character to mute netlist updater complaints
2046 reference->SetText( edevice.package ? prefix : '#' + prefix );
2047 }
2048
2049 libSymbol->GetFieldById( VALUE_FIELD )->SetVisible( true );
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 aSymbol->GetFieldById( REFERENCE_FIELD )->SetVisible( showRefDes );
2276 aSymbol->GetFieldById( VALUE_FIELD )->SetVisible( showValue );
2277
2278 return pincount == 1 ? ispower : false;
2279}
2280
2281
2282SCH_SHAPE* SCH_IO_EAGLE::loadSymbolCircle( wxXmlNode* aCircleNode, int aGateNumber )
2283{
2284 // Parse the circle properties
2285 ECIRCLE c( aCircleNode );
2286 SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
2287 VECTOR2I center( c.x.ToSchUnits(), -c.y.ToSchUnits() );
2288
2289 circle->SetPosition( center );
2290 circle->SetEnd( VECTOR2I( center.x + c.radius.ToSchUnits(), center.y ) );
2291 circle->SetStroke( STROKE_PARAMS( c.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2292 circle->SetUnit( aGateNumber );
2293
2294 return circle;
2295}
2296
2297
2298SCH_SHAPE* SCH_IO_EAGLE::loadSymbolRectangle( wxXmlNode* aRectNode, int aGateNumber )
2299{
2300 ERECT rect( aRectNode );
2301 SCH_SHAPE* rectangle = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
2302
2303 rectangle->SetPosition( VECTOR2I( rect.x1.ToSchUnits(), -rect.y1.ToSchUnits() ) );
2304 rectangle->SetEnd( VECTOR2I( rect.x2.ToSchUnits(), -rect.y2.ToSchUnits() ) );
2305
2306 if( rect.rot )
2307 {
2308 VECTOR2I pos( rectangle->GetPosition() );
2309 VECTOR2I end( rectangle->GetEnd() );
2310 VECTOR2I center( rectangle->GetCenter() );
2311
2312 RotatePoint( pos, center, EDA_ANGLE( rect.rot->degrees, DEGREES_T ) );
2313 RotatePoint( end, center, EDA_ANGLE( rect.rot->degrees, DEGREES_T ) );
2314
2315 rectangle->SetPosition( pos );
2316 rectangle->SetEnd( end );
2317 }
2318
2319 rectangle->SetUnit( aGateNumber );
2320
2321 // Eagle rectangles are filled by definition.
2322 rectangle->SetFillMode( FILL_T::FILLED_SHAPE );
2323
2324 return rectangle;
2325}
2326
2327
2328SCH_ITEM* SCH_IO_EAGLE::loadSymbolWire( wxXmlNode* aWireNode, int aGateNumber )
2329{
2330 EWIRE ewire = EWIRE( aWireNode );
2331
2332 VECTOR2I begin, end;
2333
2334 begin.x = ewire.x1.ToSchUnits();
2335 begin.y = -ewire.y1.ToSchUnits();
2336 end.x = ewire.x2.ToSchUnits();
2337 end.y = -ewire.y2.ToSchUnits();
2338
2339 if( begin == end )
2340 return nullptr;
2341
2342 // if the wire is an arc
2343 if( ewire.curve )
2344 {
2345 SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2346 VECTOR2I center = ConvertArcCenter( begin, end, *ewire.curve * - 1 );
2347 double radius = sqrt( ( ( center.x - begin.x ) * ( center.x - begin.x ) ) +
2348 ( ( center.y - begin.y ) * ( center.y - begin.y ) ) );
2349
2350 // this emulates the filled semicircles created by a thick arc with flat ends caps.
2351 if( ewire.cap == EWIRE::FLAT && ewire.width.ToSchUnits() >= 2 * radius )
2352 {
2353 VECTOR2I centerStartVector = ( begin - center ) * ( ewire.width.ToSchUnits() / radius );
2354 begin = center + centerStartVector;
2355
2356 arc->SetStroke( STROKE_PARAMS( 1, LINE_STYLE::SOLID ) );
2357 arc->SetFillMode( FILL_T::FILLED_SHAPE );
2358 }
2359 else
2360 {
2361 arc->SetStroke( STROKE_PARAMS( ewire.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2362 }
2363
2364 arc->SetCenter( center );
2365 arc->SetStart( begin );
2366 arc->SetArcAngleAndEnd( EDA_ANGLE( *ewire.curve * - 1, DEGREES_T ), true );
2367 arc->SetUnit( aGateNumber );
2368
2369 return arc;
2370 }
2371 else
2372 {
2373 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2374
2375 poly->AddPoint( begin );
2376 poly->AddPoint( end );
2377 poly->SetUnit( aGateNumber );
2378 poly->SetStroke( STROKE_PARAMS( ewire.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2379
2380 return poly;
2381 }
2382}
2383
2384
2385SCH_SHAPE* SCH_IO_EAGLE::loadSymbolPolyLine( wxXmlNode* aPolygonNode, int aGateNumber )
2386{
2387 SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2388 EPOLYGON epoly( aPolygonNode );
2389 wxXmlNode* vertex = aPolygonNode->GetChildren();
2390 VECTOR2I pt, prev_pt;
2391 opt_double prev_curve;
2392
2393 while( vertex )
2394 {
2395 if( vertex->GetName() == wxT( "vertex" ) ) // skip <xmlattr> node
2396 {
2397 EVERTEX evertex( vertex );
2398 pt = VECTOR2I( evertex.x.ToSchUnits(), -evertex.y.ToSchUnits() );
2399
2400 if( prev_curve )
2401 {
2402 SHAPE_ARC arc;
2403 arc.ConstructFromStartEndAngle( prev_pt, pt, -EDA_ANGLE( *prev_curve, DEGREES_T ) );
2404 poly->GetPolyShape().Append( arc, -1, -1, ARC_ACCURACY );
2405 }
2406 else
2407 {
2408 poly->AddPoint( pt );
2409 }
2410
2411 prev_pt = pt;
2412 prev_curve = evertex.curve;
2413 }
2414
2415 vertex = vertex->GetNext();
2416 }
2417
2418 poly->SetStroke( STROKE_PARAMS( epoly.width.ToSchUnits(), LINE_STYLE::SOLID ) );
2419 poly->SetFillMode( FILL_T::FILLED_SHAPE );
2420 poly->SetUnit( aGateNumber );
2421
2422 return poly;
2423}
2424
2425
2426SCH_PIN* SCH_IO_EAGLE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, wxXmlNode* aPin,
2427 EPIN* aEPin, int aGateNumber )
2428{
2429 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( aSymbol.get() );
2430 pin->SetPosition( VECTOR2I( aEPin->x.ToSchUnits(), -aEPin->y.ToSchUnits() ) );
2431 pin->SetName( aEPin->name );
2432 pin->SetUnit( aGateNumber );
2433
2434 int roti = aEPin->rot ? aEPin->rot->degrees : 0;
2435
2436 switch( roti )
2437 {
2438 case 0: pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); break;
2439 case 90: pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); break;
2440 case 180: pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); break;
2441 case 270: pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); break;
2442 default: wxFAIL_MSG( wxString::Format( wxT( "Unhandled orientation (%d degrees)." ), roti ) );
2443 }
2444
2445 pin->SetLength( schIUScale.MilsToIU( 300 ) ); // Default pin length when not defined.
2446
2447 if( aEPin->length )
2448 {
2449 wxString length = aEPin->length.Get();
2450
2451 if( length == wxT( "short" ) )
2452 pin->SetLength( schIUScale.MilsToIU( 100 ) );
2453 else if( length == wxT( "middle" ) )
2454 pin->SetLength( schIUScale.MilsToIU( 200 ) );
2455 else if( length == wxT( "long" ) )
2456 pin->SetLength( schIUScale.MilsToIU( 300 ) );
2457 else if( length == wxT( "point" ) )
2458 pin->SetLength( schIUScale.MilsToIU( 0 ) );
2459 }
2460
2461 // emulate the visibility of pin elements
2462 if( aEPin->visible )
2463 {
2464 wxString visible = aEPin->visible.Get();
2465
2466 if( visible == wxT( "off" ) )
2467 {
2468 pin->SetNameTextSize( 0 );
2469 pin->SetNumberTextSize( 0 );
2470 }
2471 else if( visible == wxT( "pad" ) )
2472 {
2473 pin->SetNameTextSize( 0 );
2474 }
2475 else if( visible == wxT( "pin" ) )
2476 {
2477 pin->SetNumberTextSize( 0 );
2478 }
2479
2480 /*
2481 * else if( visible == wxT( "both" ) )
2482 * {
2483 * }
2484 */
2485 }
2486
2487 if( aEPin->function )
2488 {
2489 wxString function = aEPin->function.Get();
2490
2491 if( function == wxT( "dot" ) )
2492 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
2493 else if( function == wxT( "clk" ) )
2494 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
2495 else if( function == wxT( "dotclk" ) )
2496 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
2497 }
2498
2499 return pin.release();
2500}
2501
2502
2503SCH_TEXT* SCH_IO_EAGLE::loadSymbolText( wxXmlNode* aLibText, int aGateNumber )
2504{
2505 ETEXT etext( aLibText );
2506 VECTOR2I pos( etext.x.ToSchUnits(), -etext.y.ToSchUnits() );
2507 const wxString& eagleText = aLibText->GetNodeContent();
2508 wxString adjustedText;
2509 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2510
2511 // Strip the whitespace from both ends of each line.
2512 while( tokenizer.HasMoreTokens() )
2513 {
2514 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2515
2516 if( tokenizer.HasMoreTokens() )
2517 tmp += wxT( "\n" );
2518
2519 adjustedText += tmp;
2520 }
2521
2522 if( adjustedText.IsEmpty() )
2523 adjustedText = wxT( "~" );
2524
2525 auto libtext = std::make_unique<SCH_TEXT>( pos, adjustedText, LAYER_DEVICE );
2526
2527 libtext->SetUnit( aGateNumber );
2528 loadTextAttributes( libtext.get(), etext );
2529
2530 return libtext.release();
2531}
2532
2533
2534void SCH_IO_EAGLE::loadSymbolFrame( wxXmlNode* aFrameNode, std::vector<SCH_ITEM*>& aItems )
2535{
2536 EFRAME eframe( aFrameNode );
2537
2538 int xMin = eframe.x1.ToSchUnits();
2539 int xMax = eframe.x2.ToSchUnits();
2540 int yMin = -eframe.y1.ToSchUnits();
2541 int yMax = -eframe.y2.ToSchUnits();
2542
2543 if( xMin > xMax )
2544 std::swap( xMin, xMax );
2545
2546 if( yMin > yMax )
2547 std::swap( yMin, yMax );
2548
2549 SCH_SHAPE* lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2550 lines->AddPoint( VECTOR2I( xMin, yMin ) );
2551 lines->AddPoint( VECTOR2I( xMax, yMin ) );
2552 lines->AddPoint( VECTOR2I( xMax, yMax ) );
2553 lines->AddPoint( VECTOR2I( xMin, yMax ) );
2554 lines->AddPoint( VECTOR2I( xMin, yMin ) );
2555 aItems.push_back( lines );
2556
2557 if( !( eframe.border_left == false ) )
2558 {
2559 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2560 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2561 yMin + schIUScale.MilsToIU( 150 ) ) );
2562 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2563 yMax - schIUScale.MilsToIU( 150 ) ) );
2564 aItems.push_back( lines );
2565
2566 int i;
2567 int height = yMax - yMin;
2568 int x1 = xMin;
2569 int x2 = x1 + schIUScale.MilsToIU( 150 );
2570 int legendPosX = xMin + schIUScale.MilsToIU( 75 );
2571 double rowSpacing = height / double( eframe.rows );
2572 double legendPosY = yMax - ( rowSpacing / 2 );
2573
2574 for( i = 1; i < eframe.rows; i++ )
2575 {
2576 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
2577 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2578 lines->AddPoint( VECTOR2I( x1, newY ) );
2579 lines->AddPoint( VECTOR2I( x2, newY ) );
2580 aItems.push_back( lines );
2581 }
2582
2583 char legendChar = 'A';
2584
2585 for( i = 0; i < eframe.rows; i++ )
2586 {
2587 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( legendPosX, KiROUND( legendPosY ) ),
2588 wxString( legendChar ), LAYER_DEVICE );
2589 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2590 schIUScale.MilsToIU( 100 ) ) );
2591 aItems.push_back( legendText );
2592 legendChar++;
2593 legendPosY -= rowSpacing;
2594 }
2595 }
2596
2597 if( !( eframe.border_right == false ) )
2598 {
2599 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2600 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2601 yMin + schIUScale.MilsToIU( 150 ) ) );
2602 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2603 yMax - schIUScale.MilsToIU( 150 ) ) );
2604 aItems.push_back( lines );
2605
2606 int i;
2607 int height = yMax - yMin;
2608 int x1 = xMax - schIUScale.MilsToIU( 150 );
2609 int x2 = xMax;
2610 int legendPosX = xMax - schIUScale.MilsToIU( 75 );
2611 double rowSpacing = height / double( eframe.rows );
2612 double legendPosY = yMax - ( rowSpacing / 2 );
2613
2614 for( i = 1; i < eframe.rows; i++ )
2615 {
2616 int newY = KiROUND( yMin + ( rowSpacing * (double) i ) );
2617 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2618 lines->AddPoint( VECTOR2I( x1, newY ) );
2619 lines->AddPoint( VECTOR2I( x2, newY ) );
2620 aItems.push_back( lines );
2621 }
2622
2623 char legendChar = 'A';
2624
2625 for( i = 0; i < eframe.rows; i++ )
2626 {
2627 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( legendPosX, KiROUND( legendPosY ) ),
2628 wxString( legendChar ), LAYER_DEVICE );
2629 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2630 schIUScale.MilsToIU( 100 ) ) );
2631 aItems.push_back( legendText );
2632 legendChar++;
2633 legendPosY -= rowSpacing;
2634 }
2635 }
2636
2637 if( !( eframe.border_top == false ) )
2638 {
2639 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2640 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2641 yMax - schIUScale.MilsToIU( 150 ) ) );
2642 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2643 yMax - schIUScale.MilsToIU( 150 ) ) );
2644 aItems.push_back( lines );
2645
2646 int i;
2647 int width = xMax - xMin;
2648 int y1 = yMin;
2649 int y2 = yMin + schIUScale.MilsToIU( 150 );
2650 int legendPosY = yMax - schIUScale.MilsToIU( 75 );
2651 double columnSpacing = width / double( eframe.columns );
2652 double legendPosX = xMin + ( columnSpacing / 2 );
2653
2654 for( i = 1; i < eframe.columns; i++ )
2655 {
2656 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
2657 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2658 lines->AddPoint( VECTOR2I( newX, y1 ) );
2659 lines->AddPoint( VECTOR2I( newX, y2 ) );
2660 aItems.push_back( lines );
2661 }
2662
2663 char legendChar = '1';
2664
2665 for( i = 0; i < eframe.columns; i++ )
2666 {
2667 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( KiROUND( legendPosX ), legendPosY ),
2668 wxString( legendChar ), LAYER_DEVICE );
2669 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2670 schIUScale.MilsToIU( 100 ) ) );
2671 aItems.push_back( legendText );
2672 legendChar++;
2673 legendPosX += columnSpacing;
2674 }
2675 }
2676
2677 if( !( eframe.border_bottom == false ) )
2678 {
2679 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2680 lines->AddPoint( VECTOR2I( xMax - schIUScale.MilsToIU( 150 ),
2681 yMin + schIUScale.MilsToIU( 150 ) ) );
2682 lines->AddPoint( VECTOR2I( xMin + schIUScale.MilsToIU( 150 ),
2683 yMin + schIUScale.MilsToIU( 150 ) ) );
2684 aItems.push_back( lines );
2685
2686 int i;
2687 int width = xMax - xMin;
2688 int y1 = yMax - schIUScale.MilsToIU( 150 );
2689 int y2 = yMax;
2690 int legendPosY = yMin + schIUScale.MilsToIU( 75 );
2691 double columnSpacing = width / double( eframe.columns );
2692 double legendPosX = xMin + ( columnSpacing / 2 );
2693
2694 for( i = 1; i < eframe.columns; i++ )
2695 {
2696 int newX = KiROUND( xMin + ( columnSpacing * (double) i ) );
2697 lines = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2698 lines->AddPoint( VECTOR2I( newX, y1 ) );
2699 lines->AddPoint( VECTOR2I( newX, y2 ) );
2700 aItems.push_back( lines );
2701 }
2702
2703 char legendChar = '1';
2704
2705 for( i = 0; i < eframe.columns; i++ )
2706 {
2707 SCH_TEXT* legendText = new SCH_TEXT( VECTOR2I( KiROUND( legendPosX ), legendPosY ),
2708 wxString( legendChar ), LAYER_DEVICE );
2709 legendText->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 90 ),
2710 schIUScale.MilsToIU( 100 ) ) );
2711 aItems.push_back( legendText );
2712 legendChar++;
2713 legendPosX += columnSpacing;
2714 }
2715 }
2716}
2717
2718
2720{
2721 std::unique_ptr<SCH_TEXT> schtext = std::make_unique<SCH_TEXT>();
2722 ETEXT etext = ETEXT( aSchText );
2723
2724 const wxString& eagleText = aSchText->GetNodeContent();
2725 wxString adjustedText;
2726 wxStringTokenizer tokenizer( eagleText, "\r\n" );
2727
2728 // Strip the whitespace from both ends of each line.
2729 while( tokenizer.HasMoreTokens() )
2730 {
2731 wxString tmp = interpretText( tokenizer.GetNextToken().Trim( true ).Trim( false ) );
2732
2733 if( tokenizer.HasMoreTokens() )
2734 tmp += wxT( "\n" );
2735
2736 adjustedText += tmp;
2737 }
2738
2739 schtext->SetText( adjustedText.IsEmpty() ? wxString( wxT( "\" \"" ) ) : escapeName( adjustedText ) );
2740 schtext->SetPosition( VECTOR2I( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
2741 loadTextAttributes( schtext.get(), etext );
2742 schtext->SetItalic( false );
2743
2744 return schtext.release();
2745}
2746
2747
2748void SCH_IO_EAGLE::loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const
2749{
2750 aText->SetTextSize( aAttribs.ConvertSize() );
2751
2752 // Must come after SetTextSize()
2753 if( aAttribs.ratio && aAttribs.ratio.CGet() > 12 )
2754 aText->SetBold( true );
2755
2756 int align = aAttribs.align ? *aAttribs.align : ETEXT::BOTTOM_LEFT;
2757 int degrees = aAttribs.rot ? aAttribs.rot->degrees : 0;
2758 bool mirror = aAttribs.rot ? aAttribs.rot->mirror : false;
2759 bool spin = aAttribs.rot ? aAttribs.rot->spin : false;
2760
2761 eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
2762}
2763
2764
2765void SCH_IO_EAGLE::loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const
2766{
2767 aField->SetTextPos( aText->GetPosition() );
2768 aField->SetTextSize( aText->GetTextSize() );
2769 aField->SetTextAngle( aText->GetTextAngle() );
2770
2771 // Must come after SetTextSize()
2772 aField->SetBold( aText->IsBold() );
2773 aField->SetItalic( false );
2774
2775 aField->SetVertJustify( aText->GetVertJustify() );
2776 aField->SetHorizJustify( aText->GetHorizJustify() );
2777}
2778
2779
2781{
2782 // Eagle supports detached labels, so a label does not need to be placed on a wire
2783 // to be associated with it. KiCad needs to move them, so the labels actually touch the
2784 // corresponding wires.
2785
2786 // Sort the intersection points to speed up the search process
2787 std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
2788
2789 auto onIntersection =
2790 [&]( const VECTOR2I& aPos )
2791 {
2792 return std::binary_search( m_wireIntersections.begin(),
2793 m_wireIntersections.end(), aPos );
2794 };
2795
2796 for( SEG_DESC& segDesc : m_segments )
2797 {
2798 for( SCH_TEXT* label : segDesc.labels )
2799 {
2800 VECTOR2I labelPos( label->GetPosition() );
2801 const SEG* segAttached = segDesc.LabelAttached( label );
2802
2803 if( segAttached && !onIntersection( labelPos ) )
2804 continue; // label is placed correctly
2805
2806 // Move the label to the nearest wire
2807 if( !segAttached )
2808 {
2809 std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(),
2810 segDesc.segs );
2811
2812 if( !segAttached ) // we cannot do anything
2813 continue;
2814 }
2815
2816 // Create a vector pointing in the direction of the wire, 50 mils long
2817 VECTOR2I wireDirection( segAttached->B - segAttached->A );
2818 wireDirection = wireDirection.Resize( schIUScale.MilsToIU( 50 ) );
2819 const VECTOR2I origPos( labelPos );
2820
2821 // Flags determining the search direction
2822 bool checkPositive = true, checkNegative = true, move = false;
2823 int trial = 0;
2824
2825 // Be sure the label is not placed on a wire intersection
2826 while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
2827 {
2828 move = false;
2829
2830 // Move along the attached wire to find the new label position
2831 if( trial % 2 == 1 )
2832 {
2833 labelPos = VECTOR2I( origPos + wireDirection * trial / 2 );
2834 move = checkPositive = segAttached->Contains( labelPos );
2835 }
2836 else
2837 {
2838 labelPos = VECTOR2I( origPos - wireDirection * trial / 2 );
2839 move = checkNegative = segAttached->Contains( labelPos );
2840 }
2841
2842 ++trial;
2843 }
2844
2845 if( move )
2846 label->SetPosition( VECTOR2I( labelPos ) );
2847 }
2848 }
2849
2850 m_segments.clear();
2851 m_wireIntersections.clear();
2852}
2853
2854
2855bool SCH_IO_EAGLE::CanReadSchematicFile( const wxString& aFileName ) const
2856{
2857 if( !SCH_IO::CanReadSchematicFile( aFileName ) )
2858 return false;
2859
2860 return checkHeader( aFileName );
2861}
2862
2863
2864bool SCH_IO_EAGLE::CanReadLibrary( const wxString& aFileName ) const
2865{
2866 if( !SCH_IO::CanReadLibrary( aFileName ) )
2867 return false;
2868
2869 return checkHeader( aFileName );
2870}
2871
2872
2873bool SCH_IO_EAGLE::checkHeader( const wxString& aFileName ) const
2874{
2875 wxFileInputStream input( aFileName );
2876
2877 if( !input.IsOk() )
2878 return false;
2879
2880 wxTextInputStream text( input );
2881
2882 for( int i = 0; i < 4; i++ )
2883 {
2884 if( input.Eof() )
2885 return false;
2886
2887 if( text.ReadLine().Contains( wxS( "<eagle" ) ) )
2888 return true;
2889 }
2890
2891 return false;
2892}
2893
2894
2895void SCH_IO_EAGLE::moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint )
2896{
2897 SCH_SCREEN* screen = getCurrentScreen();
2898
2899 wxCHECK( screen, /* void */ );
2900
2901 for( SCH_ITEM* item : screen->Items().Overlapping( aWire->GetBoundingBox() ) )
2902 {
2903 if( !item->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
2904 continue;
2905
2906 if( TestSegmentHit( item->GetPosition(), aWire->GetStartPoint(), aWire->GetEndPoint(), 0 ) )
2907 item->SetPosition( aNewEndPoint );
2908 }
2909}
2910
2911
2913{
2914 // Add bus entry symbols
2915 // TODO: Cleanup this function and break into pieces
2916
2917 // for each wire segment, compare each end with all busses.
2918 // If the wire end is found to end on a bus segment, place a bus entry symbol.
2919
2920 std::vector<SCH_LINE*> buses;
2921 std::vector<SCH_LINE*> wires;
2922
2923 SCH_SCREEN* screen = getCurrentScreen();
2924
2925 wxCHECK( screen, /* void */ );
2926
2927 for( SCH_ITEM* ii : screen->Items().OfType( SCH_LINE_T ) )
2928 {
2929 SCH_LINE* line = static_cast<SCH_LINE*>( ii );
2930
2931 if( line->IsBus() )
2932 buses.push_back( line );
2933 else if( line->IsWire() )
2934 wires.push_back( line );
2935 }
2936
2937 for( SCH_LINE* wire : wires )
2938 {
2939 VECTOR2I wireStart = wire->GetStartPoint();
2940 VECTOR2I wireEnd = wire->GetEndPoint();
2941
2942 for( SCH_LINE* bus : buses )
2943 {
2944 VECTOR2I busStart = bus->GetStartPoint();
2945 VECTOR2I busEnd = bus->GetEndPoint();
2946
2947 auto entrySize =
2948 []( int signX, int signY ) -> VECTOR2I
2949 {
2952 };
2953
2954 auto testBusHit =
2955 [&]( const VECTOR2I& aPt ) -> bool
2956 {
2957 return TestSegmentHit( aPt, busStart, busEnd, 0 );
2958 };
2959
2960 if( wireStart.y == wireEnd.y && busStart.x == busEnd.x )
2961 {
2962 // Horizontal wire and vertical bus
2963
2964 if( testBusHit( wireStart ) )
2965 {
2966 // Wire start is on the vertical bus
2967
2968 if( wireEnd.x < busStart.x )
2969 {
2970 /* the end of the wire is to the left of the bus
2971 * ⎥⎢
2972 * ——————⎥⎢
2973 * ⎥⎢
2974 */
2975 VECTOR2I p = wireStart + entrySize( -1, 0 );
2976
2977 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
2978 {
2979 /* there is room above the wire for the bus entry
2980 * ⎥⎢
2981 * _____/⎥⎢
2982 * ⎥⎢
2983 */
2984 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
2985 busEntry->SetFlags( IS_NEW );
2986 screen->Append( busEntry );
2987 moveLabels( wire, p );
2988 wire->SetStartPoint( p );
2989 }
2990 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
2991 {
2992 /* there is room below the wire for the bus entry
2993 * _____ ⎥⎢
2994 * \⎥⎢
2995 * ⎥⎢
2996 */
2997 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
2998 busEntry->SetFlags( IS_NEW );
2999 screen->Append( busEntry );
3000 moveLabels( wire, p );
3001 wire->SetStartPoint( p );
3002 }
3003 else
3004 {
3005 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3006 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3007 screen->Append( marker );
3008 }
3009 }
3010 else
3011 {
3012 /* the wire end is to the right of the bus
3013 * ⎥⎢
3014 * ⎥⎢——————
3015 * ⎥⎢
3016 */
3017 VECTOR2I p = wireStart + entrySize( 1, 0 );
3018
3019 if( testBusHit( wireStart + entrySize( 0, -1 ) ) )
3020 {
3021 /* There is room above the wire for the bus entry
3022 * ⎥⎢
3023 * ⎥⎢\_____
3024 * ⎥⎢
3025 */
3026 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p , 4 );
3027 busEntry->SetFlags( IS_NEW );
3028 screen->Append( busEntry );
3029 moveLabels( wire, p );
3030 wire->SetStartPoint( p );
3031 }
3032 else if( testBusHit( wireStart + entrySize( 0, 1 ) ) )
3033 {
3034 /* There is room below the wire for the bus entry
3035 * ⎥⎢ _____
3036 * ⎥⎢/
3037 * ⎥⎢
3038 */
3039 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3040 busEntry->SetFlags( IS_NEW );
3041 screen->Append( busEntry );
3042 moveLabels( wire, p );
3043 wire->SetStartPoint( p );
3044 }
3045 else
3046 {
3047 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3048 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3049 screen->Append( marker );
3050 }
3051 }
3052
3053 break;
3054 }
3055 else if( testBusHit( wireEnd ) )
3056 {
3057 // Wire end is on the vertical bus
3058
3059 if( wireStart.x < busStart.x )
3060 {
3061 /* start of the wire is to the left of the bus
3062 * ⎥⎢
3063 * ——————⎥⎢
3064 * ⎥⎢
3065 */
3066 VECTOR2I p = wireEnd + entrySize( -1, 0 );
3067
3068 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3069 {
3070 /* there is room above the wire for the bus entry
3071 * ⎥⎢
3072 * _____/⎥⎢
3073 * ⎥⎢
3074 */
3075 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3076 busEntry->SetFlags( IS_NEW );
3077 screen->Append( busEntry );
3078 moveLabels( wire, p );
3079 wire->SetEndPoint( p );
3080 }
3081 else if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3082 {
3083 /* there is room below the wire for the bus entry
3084 * _____ ⎥⎢
3085 * \⎥⎢
3086 * ⎥⎢
3087 */
3088 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3089 busEntry->SetFlags( IS_NEW );
3090 screen->Append( busEntry );
3091 moveLabels( wire, wireEnd + entrySize( -1, 0 ) );
3092 wire->SetEndPoint( wireEnd + entrySize( -1, 0 ) );
3093 }
3094 else
3095 {
3096 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3097 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3098 screen->Append( marker );
3099 }
3100 }
3101 else
3102 {
3103 /* the start of the wire is to the right of the bus
3104 * ⎥⎢
3105 * ⎥⎢——————
3106 * ⎥⎢
3107 */
3108 VECTOR2I p = wireEnd + entrySize( 1, 0 );
3109
3110 if( testBusHit( wireEnd + entrySize( 0, -1 ) ) )
3111 {
3112 /* There is room above the wire for the bus entry
3113 * ⎥⎢
3114 * ⎥⎢\_____
3115 * ⎥⎢
3116 */
3117 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3118 busEntry->SetFlags( IS_NEW );
3119 screen->Append( busEntry );
3120 moveLabels( wire, p );
3121 wire->SetEndPoint( p );
3122 }
3123 else if( testBusHit( wireEnd + entrySize( 0, 1 ) ) )
3124 {
3125 /* There is room below the wire for the bus entry
3126 * ⎥⎢ _____
3127 * ⎥⎢/
3128 * ⎥⎢
3129 */
3130 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3131 busEntry->SetFlags( IS_NEW );
3132 screen->Append( busEntry );
3133 moveLabels( wire, p );
3134 wire->SetEndPoint( p );
3135 }
3136 else
3137 {
3138 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3139 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3140 screen->Append( marker );
3141 }
3142 }
3143
3144 break;
3145 }
3146 }
3147 else if( wireStart.x == wireEnd.x && busStart.y == busEnd.y )
3148 {
3149 // Vertical wire and horizontal bus
3150
3151 if( testBusHit( wireStart ) )
3152 {
3153 // Wire start is on the bus
3154
3155 if( wireEnd.y < busStart.y )
3156 {
3157 /* the end of the wire is above the bus
3158 * |
3159 * |
3160 * |
3161 * =======
3162 */
3163 VECTOR2I p = wireStart + entrySize( 0, -1 );
3164
3165 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3166 {
3167 /* there is room to the left of the wire for the bus entry
3168 * |
3169 * |
3170 * /
3171 * =======
3172 */
3173 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3174 busEntry->SetFlags( IS_NEW );
3175 screen->Append( busEntry );
3176 moveLabels( wire, p );
3177 wire->SetStartPoint( p );
3178 }
3179 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3180 {
3181 /* there is room to the right of the wire for the bus entry
3182 * |
3183 * |
3184 * \
3185 * =======
3186 */
3187 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3188 busEntry->SetFlags( IS_NEW );
3189 screen->Append( busEntry );
3190 moveLabels( wire, p );
3191 wire->SetStartPoint( p );
3192 }
3193 else
3194 {
3195 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3196 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3197 screen->Append( marker );
3198 }
3199 }
3200 else
3201 {
3202 /* wire end is below the bus
3203 * =======
3204 * |
3205 * |
3206 * |
3207 */
3208 VECTOR2I p = wireStart + entrySize( 0, 1 );
3209
3210 if( testBusHit( wireStart + entrySize( -1, 0 ) ) )
3211 {
3212 /* there is room to the left of the wire for the bus entry
3213 * =======
3214 * \
3215 * |
3216 * |
3217 */
3218 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3219 busEntry->SetFlags( IS_NEW );
3220 screen->Append( busEntry );
3221 moveLabels( wire, p );
3222 wire->SetStartPoint( p );
3223 }
3224 else if( testBusHit( wireStart + entrySize( 1, 0 ) ) )
3225 {
3226 /* there is room to the right of the wire for the bus entry
3227 * =======
3228 * /
3229 * |
3230 * |
3231 */
3232 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3233 busEntry->SetFlags( IS_NEW );
3234 screen->Append( busEntry );
3235 moveLabels( wire, p );
3236 wire->SetStartPoint( p );
3237 }
3238 else
3239 {
3240 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3241 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireStart );
3242 screen->Append( marker );
3243 }
3244 }
3245
3246 break;
3247 }
3248 else if( testBusHit( wireEnd ) )
3249 {
3250 // Wire end is on the bus
3251
3252 if( wireStart.y < busStart.y )
3253 {
3254 /* the start of the wire is above the bus
3255 * |
3256 * |
3257 * |
3258 * =======
3259 */
3260 VECTOR2I p = wireEnd + entrySize( 0, -1 );
3261
3262 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3263 {
3264 /* there is room to the left of the wire for the bus entry
3265 * |
3266 * |
3267 * /
3268 * =======
3269 */
3270 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3271 busEntry->SetFlags( IS_NEW );
3272 screen->Append( busEntry );
3273 moveLabels( wire, p );
3274 wire->SetEndPoint( p );
3275 }
3276 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3277 {
3278 /* there is room to the right of the wire for the bus entry
3279 * |
3280 * |
3281 * \
3282 * =======
3283 */
3284 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3285 busEntry->SetFlags( IS_NEW );
3286 screen->Append( busEntry );
3287 moveLabels( wire, p );
3288 wire->SetEndPoint( p );
3289 }
3290 else
3291 {
3292 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3293 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3294 screen->Append( marker );
3295 }
3296 }
3297 else
3298 {
3299 /* wire start is below the bus
3300 * =======
3301 * |
3302 * |
3303 * |
3304 */
3305 VECTOR2I p = wireEnd + entrySize( 0, 1 );
3306
3307 if( testBusHit( wireEnd + entrySize( -1, 0 ) ) )
3308 {
3309 /* there is room to the left of the wire for the bus entry
3310 * =======
3311 * \
3312 * |
3313 * |
3314 */
3315 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3316 busEntry->SetFlags( IS_NEW );
3317 screen->Append( busEntry );
3318 moveLabels( wire, p );
3319 wire->SetEndPoint( p );
3320 }
3321 else if( testBusHit( wireEnd + entrySize( 1, 0 ) ) )
3322 {
3323 /* there is room to the right of the wire for the bus entry
3324 * =======
3325 * /
3326 * |
3327 * |
3328 */
3329 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3330 busEntry->SetFlags( IS_NEW );
3331 screen->Append( busEntry );
3332 moveLabels( wire, p );
3333 wire->SetEndPoint( p );
3334 }
3335 else
3336 {
3337 auto ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_NEEDED );
3338 SCH_MARKER* marker = new SCH_MARKER( ercItem, wireEnd );
3339 screen->Append( marker );
3340 }
3341 }
3342
3343 break;
3344 }
3345 }
3346 else
3347 {
3348 // Wire isn't horizontal or vertical
3349
3350 if( testBusHit( wireStart ) )
3351 {
3352 VECTOR2I wirevector = wireStart - wireEnd;
3353
3354 if( wirevector.x > 0 )
3355 {
3356 if( wirevector.y > 0 )
3357 {
3358 VECTOR2I p = wireStart + entrySize( -1, -1 );
3359 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3360 busEntry->SetFlags( IS_NEW );
3361 screen->Append( busEntry );
3362
3363 moveLabels( wire, p );
3364 wire->SetStartPoint( p );
3365 }
3366 else
3367 {
3368 VECTOR2I p = wireStart + entrySize( -1, 1 );
3369 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3370 busEntry->SetFlags( IS_NEW );
3371 screen->Append( busEntry );
3372
3373 moveLabels( wire, p );
3374 wire->SetStartPoint( p );
3375 }
3376 }
3377 else
3378 {
3379 if( wirevector.y > 0 )
3380 {
3381 VECTOR2I p = wireStart + entrySize( 1, -1 );
3382 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3383 busEntry->SetFlags( IS_NEW );
3384 screen->Append( busEntry );
3385
3386 moveLabels( wire, p );
3387 wire->SetStartPoint( p );
3388 }
3389 else
3390 {
3391 VECTOR2I p = wireStart + entrySize( 1, 1 );
3392 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3393 busEntry->SetFlags( IS_NEW );
3394 screen->Append( busEntry );
3395
3396 moveLabels( wire, p );
3397 wire->SetStartPoint( p );
3398 }
3399 }
3400
3401 break;
3402 }
3403 else if( testBusHit( wireEnd ) )
3404 {
3405 VECTOR2I wirevector = wireStart - wireEnd;
3406
3407 if( wirevector.x > 0 )
3408 {
3409 if( wirevector.y > 0 )
3410 {
3411 VECTOR2I p = wireEnd + entrySize( 1, 1 );
3412 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 4 );
3413 busEntry->SetFlags( IS_NEW );
3414 screen->Append( busEntry );
3415
3416 moveLabels( wire, p );
3417 wire->SetEndPoint( p );
3418 }
3419 else
3420 {
3421 VECTOR2I p = wireEnd + entrySize( 1, -1 );
3422 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 3 );
3423 busEntry->SetFlags( IS_NEW );
3424 screen->Append( busEntry );
3425
3426 moveLabels( wire, p );
3427 wire->SetEndPoint( p );
3428 }
3429 }
3430 else
3431 {
3432 if( wirevector.y > 0 )
3433 {
3434 VECTOR2I p = wireEnd + entrySize( -1, 1 );
3435 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 1 );
3436 busEntry->SetFlags( IS_NEW );
3437 screen->Append( busEntry );
3438
3439 moveLabels( wire, p );
3440 wire->SetEndPoint( p );
3441 }
3442 else
3443 {
3444 VECTOR2I p = wireEnd + entrySize( -1, -1 );
3445 SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, 2 );
3446 busEntry->SetFlags( IS_NEW );
3447 screen->Append( busEntry );
3448
3449 moveLabels( wire, p );
3450 wire->SetEndPoint( p );
3451 }
3452 }
3453
3454 break;
3455 }
3456 }
3457 }
3458 }
3459}
3460
3461
3463{
3464 VECTOR2I labelPos( aLabel->GetPosition() );
3465
3466 for( const SEG& seg : segs )
3467 {
3468 if( seg.Contains( labelPos ) )
3469 return &seg;
3470 }
3471
3472 return nullptr;
3473}
3474
3475
3476// TODO could be used to place junctions, instead of IsJunctionNeeded()
3477// (see SCH_EDIT_FRAME::importFile())
3478bool SCH_IO_EAGLE::checkConnections( const SCH_SYMBOL* aSymbol, const SCH_PIN* aPin ) const
3479{
3480 wxCHECK( aSymbol && aPin, false );
3481
3482 VECTOR2I pinPosition = aSymbol->GetPinPhysicalPosition( aPin );
3483 auto pointIt = m_connPoints.find( pinPosition );
3484
3485 if( pointIt == m_connPoints.end() )
3486 return false;
3487
3488 const auto& items = pointIt->second;
3489
3490 wxCHECK( items.find( aPin ) != items.end(), false );
3491
3492 return items.size() > 1;
3493}
3494
3495
3497 bool aUpdateSet )
3498{
3499 wxCHECK( aSymbol->GetLibSymbolRef(), /*void*/ );
3500
3501 // Normally power parts also have power input pins,
3502 // but they already force net names on the attached wires
3503 if( aSymbol->GetLibSymbolRef()->IsPower() )
3504 return;
3505
3506 int unit = aSymbol->GetUnit();
3507 const wxString reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
3508 std::vector<SCH_PIN*> pins = aSymbol->GetLibSymbolRef()->GetAllLibPins();
3509 std::set<int> missingUnits;
3510
3511 // Search all units for pins creating implicit connections
3512 for( const SCH_PIN* pin : pins )
3513 {
3514 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
3515 {
3516 bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
3517
3518 // Create a global net label only if there are no other wires/pins attached
3519 if( pinInUnit )
3520 {
3521 if( !checkConnections( aSymbol, pin ) )
3522 {
3523 // Create a net label to force the net name on the pin
3524 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
3525 netLabel->SetPosition( aSymbol->GetPinPhysicalPosition( pin ) );
3526 netLabel->SetText( extractNetName( pin->GetName() ) );
3527 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 40 ),
3528 schIUScale.MilsToIU( 40 ) ) );
3529
3530 switch( pin->GetOrientation() )
3531 {
3532 default:
3533 case PIN_ORIENTATION::PIN_RIGHT:
3534 netLabel->SetSpinStyle( SPIN_STYLE::LEFT );
3535 break;
3536 case PIN_ORIENTATION::PIN_LEFT:
3537 netLabel->SetSpinStyle( SPIN_STYLE::RIGHT );
3538 break;
3539 case PIN_ORIENTATION::PIN_UP:
3540 netLabel->SetSpinStyle( SPIN_STYLE::UP );
3541 break;
3542 case PIN_ORIENTATION::PIN_DOWN:
3543 netLabel->SetSpinStyle( SPIN_STYLE::BOTTOM );
3544 break;
3545 }
3546
3547 aScreen->Append( netLabel );
3548 }
3549 }
3550 else if( aUpdateSet )
3551 {
3552 // Found a pin creating implicit connection information in another unit.
3553 // Such units will be instantiated if they do not appear in another sheet and
3554 // processed later.
3555 wxASSERT( pin->GetUnit() );
3556 missingUnits.insert( pin->GetUnit() );
3557 }
3558 }
3559 }
3560
3561 if( aUpdateSet && aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
3562 {
3563 auto cmpIt = m_missingCmps.find( reference );
3564
3565 // The first unit found has always already been processed.
3566 if( cmpIt == m_missingCmps.end() )
3567 {
3568 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3569 entry.cmp = aSymbol;
3570 entry.units.emplace( unit, false );
3571 }
3572 else
3573 {
3574 // Set the flag indicating this unit has been processed.
3575 cmpIt->second.units[unit] = false;
3576 }
3577
3578 if( !missingUnits.empty() ) // Save the units that need later processing
3579 {
3580 EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
3581 entry.cmp = aSymbol;
3582
3583 // Add units that haven't already been processed.
3584 for( int i : missingUnits )
3585 {
3586 if( entry.units.find( i ) != entry.units.end() )
3587 entry.units.emplace( i, true );
3588 }
3589 }
3590 }
3591}
3592
3593
3594wxString SCH_IO_EAGLE::translateEagleBusName( const wxString& aEagleName ) const
3595{
3596 if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
3597 return aEagleName;
3598
3599 wxString ret = wxT( "{" );
3600
3601 wxStringTokenizer tokenizer( aEagleName, wxT( "," ) );
3602
3603 while( tokenizer.HasMoreTokens() )
3604 {
3605 wxString member = tokenizer.GetNextToken();
3606
3607 // In Eagle, overbar text is automatically stopped at the end of the net name, even when
3608 // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
3609 // if there is an odd number of overbar markers in this net name, we need to append one
3610 // to close it out before appending the space.
3611
3612 if( member.Freq( '!' ) % 2 > 0 )
3613 member << wxT( "!" );
3614
3615 ret << member << wxS( " " );
3616 }
3617
3618 ret.Trim( true );
3619 ret << wxT( "}" );
3620
3621 return ret;
3622}
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:545
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:274
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:162
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:129
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:166
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:691
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:372
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:417
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:274
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:164
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:243
void SetBold(bool aBold)
Definition: eda_text.cpp:219
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:181
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:203
void SetItalic(bool aItalic)
Definition: eda_text.cpp:211
VECTOR2I GetTextSize() const
Definition: eda_text.h:222
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:266
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:257
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:186
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:126
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:976
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_line.cpp:226
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:982
void SetNumber(const wxString &aNumber)
Definition: sch_pin.cpp:467
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:703
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:130
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:151
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: sch_screen.h:131
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
const KIID & GetUuid() const
Definition: sch_screen.h:524
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:116
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
Definition: sch_screen.cpp:314
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:576
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:105
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:911
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:213
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:354
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:77
@ SYM_ORIENT_270
Definition: sch_symbol.h:84
@ SYM_ORIENT_180
Definition: sch_symbol.h:83
@ SYM_ORIENT_90
Definition: sch_symbol.h:82
@ SYM_ORIENT_0
Definition: sch_symbol.h:81
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:602
Definition of file extensions used in Kicad.