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