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