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