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