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