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