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