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-2020 Kicad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Alejandro GarcĂ­a Montoro <alejandro.garciamontoro@gmail.com>
8  * @author Maciej Suminski <maciej.suminski@cern.ch>
9  * @author Russell Oliver <roliver8143@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 3
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <sch_eagle_plugin.h>
26 
27 #include <kiway.h>
28 #include <properties.h>
29 
30 #include <algorithm>
31 #include <memory>
32 #include <wx/filename.h>
33 #include <wx/tokenzr.h>
34 
35 #include <class_libentry.h>
36 #include <class_library.h>
37 #include <eagle_parser.h>
38 #include <gr_text.h>
39 #include <lib_arc.h>
40 #include <lib_circle.h>
41 #include <lib_id.h>
42 #include <lib_item.h>
43 #include <lib_pin.h>
44 #include <lib_polyline.h>
45 #include <lib_rectangle.h>
46 #include <lib_text.h>
47 #include <macros.h>
48 #include <project.h>
49 #include <sch_bus_entry.h>
50 #include <sch_component.h>
51 #include <sch_connection.h>
52 #include <sch_edit_frame.h>
53 #include <sch_junction.h>
54 #include <sch_legacy_plugin.h>
55 #include <sch_marker.h>
56 #include <sch_screen.h>
57 #include <sch_sheet.h>
58 #include <sch_sheet_path.h>
59 #include <sch_text.h>
60 #include <schematic.h>
61 #include <symbol_lib_table.h>
62 #include <template_fieldnames.h>
64 #include <ws_draw_item.h>
65 
66 
67 // Eagle schematic axes are aligned with x increasing left to right and Y increasing bottom to top
68 // Kicad schematic axes are aligned with x increasing left to right and Y increasing top to bottom.
69 
70 using namespace std;
71 
75 static const std::map<wxString, ELECTRICAL_PINTYPE> pinDirectionsMap = {
80  { "nc", ELECTRICAL_PINTYPE::PT_NC },
85 };
86 
87 
94 static int countChildren( wxXmlNode* aCurrentNode, const wxString& aName )
95 {
96  // Map node_name -> node_pointer
97  int count = 0;
98 
99  // Loop through all children counting them if they match the given name
100  aCurrentNode = aCurrentNode->GetChildren();
101 
102  while( aCurrentNode )
103  {
104  if( aCurrentNode->GetName() == aName )
105  count++;
106 
107  // Get next child
108  aCurrentNode = aCurrentNode->GetNext();
109  }
110 
111  return count;
112 }
113 
114 
116 static EDA_RECT getSheetBbox( SCH_SHEET* aSheet )
117 {
118  EDA_RECT bbox;
119 
120  for( auto item : aSheet->GetScreen()->Items() )
121  bbox.Merge( item->GetBoundingBox() );
122 
123  return bbox;
124 }
125 
126 
128 static inline wxString extractNetName( const wxString& aPinName )
129 {
130  return aPinName.BeforeFirst( '@' );
131 }
132 
133 
135 {
136  if( m_libName.IsEmpty() )
137  {
138  // Try to come up with a meaningful name
139  m_libName = m_schematic->Prj().GetProjectName();
140 
141  if( m_libName.IsEmpty() )
142  {
143  wxFileName fn( m_rootSheet->GetFileName() );
144  m_libName = fn.GetName();
145  }
146 
147  if( m_libName.IsEmpty() )
148  m_libName = "noname";
149 
150  m_libName += "-eagle-import";
151  m_libName = LIB_ID::FixIllegalChars( m_libName, LIB_ID::ID_SCH, true );
152  }
153 
154  return m_libName;
155 }
156 
157 
159 {
160  wxFileName fn( m_schematic->Prj().GetProjectPath(), getLibName(), KiCadSymbolLibFileExtension );
161 
162  return fn;
163 }
164 
165 
166 void SCH_EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
167 {
168  std::vector<ELAYER> eagleLayers;
169 
170  // Get the first layer and iterate
171  wxXmlNode* layerNode = aLayers->GetChildren();
172 
173  while( layerNode )
174  {
175  ELAYER elayer( layerNode );
176  eagleLayers.push_back( elayer );
177 
178  layerNode = layerNode->GetNext();
179  }
180 
181  // match layers based on their names
182  for( const auto& elayer : eagleLayers )
183  {
202  if( elayer.name == "Nets" )
203  {
204  m_layerMap[elayer.number] = LAYER_WIRE;
205  }
206  else if( elayer.name == "Info" || elayer.name == "Guide" )
207  {
208  m_layerMap[elayer.number] = LAYER_NOTES;
209  }
210  else if( elayer.name == "Busses" )
211  {
212  m_layerMap[elayer.number] = LAYER_BUS;
213  }
214  }
215 }
216 
217 
219 {
220  auto it = m_layerMap.find( aEagleLayer );
221  return it == m_layerMap.end() ? LAYER_NOTES : it->second;
222 }
223 
224 
225 // Return the kicad component orientation based on eagle rotation degrees.
227 {
228  int roti = int( eagleDegrees );
229 
230  switch( roti )
231  {
232  default:
233  wxASSERT_MSG( false, wxString::Format( "Unhandled orientation (%d degrees)", roti ) );
235 
236  case 0:
237  return CMP_ORIENT_0;
238 
239  case 90:
240  return CMP_ORIENT_90;
241 
242  case 180:
243  return CMP_ORIENT_180;
244 
245  case 270:
246  return CMP_ORIENT_270;
247  }
248 
249  return CMP_ORIENT_0;
250 }
251 
252 
253 // Calculate text alignment based on the given Eagle text alignment parameters.
254 static void eagleToKicadAlignment( EDA_TEXT* aText, int aEagleAlignment, int aRelDegress,
255  bool aMirror, bool aSpin, int aAbsDegress )
256 {
257  int align = aEagleAlignment;
258 
259  if( aRelDegress == 90 )
260  {
261  aText->SetTextAngle( 900 );
262  }
263  else if( aRelDegress == 180 )
264  align = -align;
265  else if( aRelDegress == 270 )
266  {
267  aText->SetTextAngle( 900 );
268  align = -align;
269  }
270 
271  if( aMirror == true )
272  {
273  if( aAbsDegress == 90 || aAbsDegress == 270 )
274  {
275  if( align == ETEXT::BOTTOM_RIGHT )
276  align = ETEXT::TOP_RIGHT;
277  else if( align == ETEXT::BOTTOM_LEFT )
278  align = ETEXT::TOP_LEFT;
279  else if( align == ETEXT::TOP_LEFT )
280  align = ETEXT::BOTTOM_LEFT;
281  else if( align == ETEXT::TOP_RIGHT )
282  align = ETEXT::BOTTOM_RIGHT;
283  }
284  else if( aAbsDegress == 0 || aAbsDegress == 180 )
285  {
286  if( align == ETEXT::BOTTOM_RIGHT )
287  align = ETEXT::BOTTOM_LEFT;
288  else if( align == ETEXT::BOTTOM_LEFT )
289  align = ETEXT::BOTTOM_RIGHT;
290  else if( align == ETEXT::TOP_LEFT )
291  align = ETEXT::TOP_RIGHT;
292  else if( align == ETEXT::TOP_RIGHT )
293  align = ETEXT::TOP_LEFT;
294  else if( align == ETEXT::CENTER_LEFT )
295  align = ETEXT::CENTER_RIGHT;
296  else if( align == ETEXT::CENTER_RIGHT )
297  align = ETEXT::CENTER_LEFT;
298  }
299  }
300 
301  switch( align )
302  {
303  case ETEXT::CENTER:
306  break;
307 
308  case ETEXT::CENTER_LEFT:
311  break;
312 
313  case ETEXT::CENTER_RIGHT:
316  break;
317 
318  case ETEXT::TOP_CENTER:
321  break;
322 
323  case ETEXT::TOP_LEFT:
326  break;
327 
328  case ETEXT::TOP_RIGHT:
331  break;
332 
336  break;
337 
338  case ETEXT::BOTTOM_LEFT:
341  break;
342 
343  case ETEXT::BOTTOM_RIGHT:
346  break;
347 
348  default:
351  break;
352  }
353 }
354 
355 
357 {
358  m_kiway = nullptr;
359  m_rootSheet = nullptr;
360  m_currentSheet = nullptr;
361  m_schematic = nullptr;
362 }
363 
364 
366 {
367 }
368 
369 
370 const wxString SCH_EAGLE_PLUGIN::GetName() const
371 {
372  return "EAGLE";
373 }
374 
375 
377 {
378  return "sch";
379 }
380 
381 
383 {
384  return "lbr";
385 }
386 
387 
389 {
390  return 0;
391 }
392 
393 
394 SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
395  SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
396 {
397  wxASSERT( !aFileName || aSchematic != nullptr );
398  LOCALE_IO toggle; // toggles on, then off, the C locale.
399 
400  // Load the document
401  wxXmlDocument xmlDocument;
402 
403  m_filename = aFileName;
404  m_schematic = aSchematic;
405 
406  if( !xmlDocument.Load( m_filename.GetFullPath() ) )
408  wxString::Format( _( "Unable to read file \"%s\"" ), m_filename.GetFullPath() ) );
409 
410  // Delete on exception, if I own m_rootSheet, according to aAppendToMe
411  unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
412 
413  if( aAppendToMe )
414  {
415  wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
416  m_rootSheet = &aSchematic->Root();
417  }
418  else
419  {
420  m_rootSheet = new SCH_SHEET( aSchematic );
421  m_rootSheet->SetFileName( aFileName );
422  }
423 
424  if( !m_rootSheet->GetScreen() )
425  {
426  SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
427  screen->SetFileName( aFileName );
428  m_rootSheet->SetScreen( screen );
429  }
430 
431  SYMBOL_LIB_TABLE* libTable = m_schematic->Prj().SchSymbolLibTable();
432 
433  wxCHECK_MSG( libTable, NULL, "Could not load symbol lib table." );
434 
435  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
436  m_properties = std::make_unique<PROPERTIES>();
437  ( *m_properties )[SCH_LEGACY_PLUGIN::PropBuffering] = "";
438 
441  if( !libTable->HasLibrary( getLibName() ) )
442  {
443  // Create a new empty symbol library.
444  m_pi->CreateSymbolLib( getLibFileName().GetFullPath() );
445  wxString libTableUri = "${KIPRJMOD}/" + getLibFileName().GetFullName();
446 
447  // Add the new library to the project symbol library table.
448  libTable->InsertRow(
449  new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri, wxString( "KiCad" ) ) );
450 
451  // Save project symbol library table.
452  wxFileName fn( m_schematic->Prj().GetProjectPath(),
454 
455  // So output formatter goes out of scope and closes the file before reloading.
456  {
457  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
458  libTable->Format( &formatter, 0 );
459  }
460 
461  // Relaod the symbol library table.
462  m_schematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
463  m_schematic->Prj().SchSymbolLibTable();
464  }
465 
466  // Retrieve the root as current node
467  wxXmlNode* currentNode = xmlDocument.GetRoot();
468 
469  // If the attribute is found, store the Eagle version;
470  // otherwise, store the dummy "0.0" version.
471  m_version = currentNode->GetAttribute( "version", "0.0" );
472 
473  // Map all children into a readable dictionary
474  NODE_MAP children = MapChildren( currentNode );
475 
476  // Load drawing
477  loadDrawing( children["drawing"] );
478 
479  m_pi->SaveLibrary( getLibFileName().GetFullPath() );
480 
481  return m_rootSheet;
482 }
483 
484 
485 void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* aDrawingNode )
486 {
487  // Map all children into a readable dictionary
488  NODE_MAP drawingChildren = MapChildren( aDrawingNode );
489 
490  // Board nodes should not appear in .sch files
491  // wxXmlNode* board = drawingChildren["board"]
492 
493  // wxXmlNode* grid = drawingChildren["grid"]
494 
495  auto layers = drawingChildren["layers"];
496 
497  if( layers )
498  loadLayerDefs( layers );
499 
500  // wxXmlNode* library = drawingChildren["library"]
501 
502  // wxXmlNode* settings = drawingChildren["settings"]
503 
504  // Load schematic
505  auto schematic = drawingChildren["schematic"];
506 
507  if( schematic )
508  loadSchematic( schematic );
509 }
510 
511 
512 void SCH_EAGLE_PLUGIN::countNets( wxXmlNode* aSchematicNode )
513 {
514  // Map all children into a readable dictionary
515  NODE_MAP schematicChildren = MapChildren( aSchematicNode );
516  // Loop through all the sheets
517 
518  wxXmlNode* sheetNode = getChildrenNodes( schematicChildren, "sheets" );
519 
520  while( sheetNode )
521  {
522  NODE_MAP sheetChildren = MapChildren( sheetNode );
523  // Loop through all nets
524  // From the DTD: "Net is an electrical connection in a schematic."
525  wxXmlNode* netNode = getChildrenNodes( sheetChildren, "nets" );
526 
527  while( netNode )
528  {
529  wxString netName = netNode->GetAttribute( "name" );
530 
531  if( m_netCounts.count( netName ) )
532  m_netCounts[netName] = m_netCounts[netName] + 1;
533  else
534  m_netCounts[netName] = 1;
535 
536  // Get next net
537  netNode = netNode->GetNext();
538  }
539 
540  sheetNode = sheetNode->GetNext();
541  }
542 }
543 
544 
545 void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
546 {
547  // Map all children into a readable dictionary
548  NODE_MAP schematicChildren = MapChildren( aSchematicNode );
549  auto partNode = getChildrenNodes( schematicChildren, "parts" );
550  auto libraryNode = getChildrenNodes( schematicChildren, "libraries" );
551  auto sheetNode = getChildrenNodes( schematicChildren, "sheets" );
552 
553  if( !partNode || !libraryNode || !sheetNode )
554  return;
555 
556  while( partNode )
557  {
558  std::unique_ptr<EPART> epart( new EPART( partNode ) );
559 
560  // N.B. Eagle parts are case-insensitive in matching but we keep the display case
561  m_partlist[epart->name.Upper()] = std::move( epart );
562  partNode = partNode->GetNext();
563  }
564 
565  // Loop through all the libraries
566  while( libraryNode )
567  {
568  // Read the library name
569  wxString libName = libraryNode->GetAttribute( "name" );
570 
571  EAGLE_LIBRARY* elib = &m_eagleLibs[libName];
572  elib->name = libName;
573 
574  loadLibrary( libraryNode, &m_eagleLibs[libName] );
575 
576  libraryNode = libraryNode->GetNext();
577  }
578 
579  m_pi->SaveLibrary( getLibFileName().GetFullPath() );
580 
581  // find all nets and count how many sheets they appear on.
582  // local labels will be used for nets found only on that sheet.
583  countNets( aSchematicNode );
584 
585  // Loop through all the sheets
586  int sheet_count = countChildren( sheetNode->GetParent(), "sheet" );
587 
588  // If eagle schematic has multiple sheets then create corresponding subsheets on the root sheet
589  if( sheet_count > 1 )
590  {
591  int x, y, i;
592  i = 1;
593  x = 1;
594  y = 1;
595 
596  while( sheetNode )
597  {
598  wxPoint pos = wxPoint( x * Mils2iu( 1000 ), y * Mils2iu( 1000 ) );
599  std::unique_ptr<SCH_SHEET> sheet( new SCH_SHEET( m_rootSheet, pos ) );
600  SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
601 
602  sheet->SetScreen( screen );
603  sheet->GetScreen()->SetFileName( sheet->GetFileName() );
604 
605  m_currentSheet = sheet.get();
606  loadSheet( sheetNode, i );
607  m_rootSheet->GetScreen()->Append( sheet.release() );
608 
609  sheetNode = sheetNode->GetNext();
610  x += 2;
611 
612  if( x > 10 ) // start next row
613  {
614  x = 1;
615  y += 2;
616  }
617 
618  i++;
619  }
620  }
621  else
622  {
623  while( sheetNode )
624  {
625  m_currentSheet = m_rootSheet;
626  loadSheet( sheetNode, 0 );
627  sheetNode = sheetNode->GetNext();
628  }
629  }
630 
631 
632  // Handle the missing component units that need to be instantiated
633  // to create the missing implicit connections
634 
635  // Calculate the already placed items bounding box and the page size to determine
636  // placement for the new components
637  wxSize pageSizeIU = m_rootSheet->GetScreen()->GetPageSettings().GetSizeIU();
638  EDA_RECT sheetBbox = getSheetBbox( m_rootSheet );
639  wxPoint newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() );
640  int maxY = sheetBbox.GetY();
641 
642  SCH_SHEET_PATH sheetpath;
643  m_rootSheet->LocatePathOfScreen( m_rootSheet->GetScreen(), &sheetpath );
644 
645  for( auto& cmp : m_missingCmps )
646  {
647  const SCH_COMPONENT* origCmp = cmp.second.cmp;
648 
649  for( auto unitEntry : cmp.second.units )
650  {
651  if( unitEntry.second == false )
652  continue; // unit has been already processed
653 
654  // Instantiate the missing component unit
655  int unit = unitEntry.first;
656  const wxString reference = origCmp->GetField( REFERENCE )->GetText();
657  std::unique_ptr<SCH_COMPONENT> component( (SCH_COMPONENT*) origCmp->Duplicate() );
658  component->SetUnitSelection( &sheetpath, unit );
659  component->SetUnit( unit );
660  component->SetOrientation( 0 );
661  component->AddHierarchicalReference( sheetpath.Path(), reference, unit );
662 
663  // Calculate the placement position
664  EDA_RECT cmpBbox = component->GetBoundingBox();
665  int posY = newCmpPosition.y + cmpBbox.GetHeight();
666  component->SetPosition( wxPoint( newCmpPosition.x, posY ) );
667  newCmpPosition.x += cmpBbox.GetWidth();
668  maxY = std::max( maxY, posY );
669 
670  if( newCmpPosition.x >= pageSizeIU.GetWidth() ) // reached the page boundary?
671  newCmpPosition = wxPoint( sheetBbox.GetLeft(), maxY ); // then start a new row
672 
673  // Add the global net labels to recreate the implicit connections
674  addImplicitConnections( component.get(), m_rootSheet->GetScreen(), false );
675  m_rootSheet->GetScreen()->Append( component.release() );
676  }
677  }
678 
679  m_missingCmps.clear();
680 }
681 
682 
683 void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
684 {
685  // Map all children into a readable dictionary
686  NODE_MAP sheetChildren = MapChildren( aSheetNode );
687 
688  // Get description node
689  wxXmlNode* descriptionNode = getChildrenNodes( sheetChildren, "description" );
690 
691  wxString des;
692  std::string filename;
693  SCH_FIELD& sheetNameField = m_currentSheet->GetFields()[SHEETNAME];
694  SCH_FIELD& filenameField = m_currentSheet->GetFields()[SHEETFILENAME];
695 
696  if( descriptionNode )
697  {
698  des = descriptionNode->GetContent();
699  des.Replace( "\n", "_", true );
700  sheetNameField.SetText( des );
701  filename = des.ToStdString();
702  }
703  else
704  {
705  filename = wxString::Format( "%s_%d", m_filename.GetName(), aSheetIndex );
706  sheetNameField.SetText( filename );
707  }
708 
709  ReplaceIllegalFileNameChars( &filename );
710  replace( filename.begin(), filename.end(), ' ', '_' );
711 
712  wxString fn = wxString( filename + ".sch" );
713  filenameField.SetText( fn );
714  wxFileName fileName( fn );
715  m_currentSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
716 
717  // Loop through all buses
718  // From the DTD: "Buses receive names which determine which signals they include.
719  // A bus is a drawing object. It does not create any electrical connections.
720  // These are always created by means of the nets and their names."
721  wxXmlNode* busNode = getChildrenNodes( sheetChildren, "busses" );
722 
723  while( busNode )
724  {
725  // Get the bus name
726  wxString busName = translateEagleBusName( busNode->GetAttribute( "name" ) );
727 
728  // Load segments of this bus
729  loadSegments( busNode, busName, wxString() );
730 
731  // Get next bus
732  busNode = busNode->GetNext();
733  }
734 
735  // Loop through all nets
736  // From the DTD: "Net is an electrical connection in a schematic."
737  wxXmlNode* netNode = getChildrenNodes( sheetChildren, "nets" );
738 
739  while( netNode )
740  {
741  // Get the net name and class
742  wxString netName = netNode->GetAttribute( "name" );
743  wxString netClass = netNode->GetAttribute( "class" );
744 
745  // Load segments of this net
746  loadSegments( netNode, netName, netClass );
747 
748  // Get next net
749  netNode = netNode->GetNext();
750  }
751 
752  adjustNetLabels(); // needs to be called before addBusEntries()
753  addBusEntries();
754 
755  // Loop through all instances
756  wxXmlNode* instanceNode = getChildrenNodes( sheetChildren, "instances" );
757 
758  while( instanceNode )
759  {
760  loadInstance( instanceNode );
761  instanceNode = instanceNode->GetNext();
762  }
763 
764  /* moduleinst is a design block definition and is an EagleCad 8 feature,
765  *
766  * // Loop through all moduleinsts
767  * wxXmlNode* moduleinstNode = getChildrenNodes( sheetChildren, "moduleinsts" );
768  *
769  * while( moduleinstNode )
770  * {
771  * loadModuleinst( moduleinstNode );
772  * moduleinstNode = moduleinstNode->GetNext();
773  * }
774  */
775 
776  wxXmlNode* plainNode = getChildrenNodes( sheetChildren, "plain" );
777 
778  while( plainNode )
779  {
780  wxString nodeName = plainNode->GetName();
781 
782  if( nodeName == "text" )
783  {
784  m_currentSheet->GetScreen()->Append( loadPlainText( plainNode ) );
785  }
786  else if( nodeName == "wire" )
787  {
788  m_currentSheet->GetScreen()->Append( loadWire( plainNode ) );
789  }
790 
791  plainNode = plainNode->GetNext();
792  }
793 
794  // Calculate the new sheet size.
795  EDA_RECT sheetBoundingBox = getSheetBbox( m_currentSheet );
796  wxSize targetSheetSize = sheetBoundingBox.GetSize();
797  targetSheetSize.IncBy( Mils2iu( 1500 ), Mils2iu( 1500 ) );
798 
799  // Get current Eeschema sheet size.
800  wxSize pageSizeIU = m_currentSheet->GetScreen()->GetPageSettings().GetSizeIU();
801  PAGE_INFO pageInfo = m_currentSheet->GetScreen()->GetPageSettings();
802 
803  // Increase if necessary
804  if( pageSizeIU.x < targetSheetSize.x )
805  pageInfo.SetWidthMils( Iu2Mils( targetSheetSize.x ) );
806 
807  if( pageSizeIU.y < targetSheetSize.y )
808  pageInfo.SetHeightMils( Iu2Mils( targetSheetSize.y ) );
809 
810  // Set the new sheet size.
811  m_currentSheet->GetScreen()->SetPageSettings( pageInfo );
812 
813  pageSizeIU = m_currentSheet->GetScreen()->GetPageSettings().GetSizeIU();
814  wxPoint sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
815  wxPoint itemsCentre = sheetBoundingBox.Centre();
816 
817  // round the translation to nearest 100mil to place it on the grid.
818  wxPoint translation = sheetcentre - itemsCentre;
819  translation.x = translation.x - translation.x % Mils2iu( 100 );
820  translation.y = translation.y - translation.y % Mils2iu( 100 );
821 
822  // Add global net labels for the named power input pins in this sheet
823  for( auto item : m_currentSheet->GetScreen()->Items().OfType( SCH_COMPONENT_T ) )
824  addImplicitConnections(
825  static_cast<SCH_COMPONENT*>( item ), m_currentSheet->GetScreen(), true );
826 
827  m_connPoints.clear();
828 
829  // Translate the items.
830  std::vector<SCH_ITEM*> allItems;
831 
832  std::copy( m_currentSheet->GetScreen()->Items().begin(),
833  m_currentSheet->GetScreen()->Items().end(), std::back_inserter( allItems ) );
834 
835  for( auto item : allItems )
836  {
837  item->SetPosition( item->GetPosition() + translation );
838  item->ClearFlags();
839  m_currentSheet->GetScreen()->Update( item );
840 
841  }
842 }
843 
844 
846  wxXmlNode* aSegmentsNode, const wxString& netName, const wxString& aNetClass )
847 {
848  // Loop through all segments
849  wxXmlNode* currentSegment = aSegmentsNode->GetChildren();
850  SCH_SCREEN* screen = m_currentSheet->GetScreen();
851 
852  int segmentCount = countChildren( aSegmentsNode, "segment" );
853 
854  // wxCHECK( screen, [>void<] );
855  while( currentSegment )
856  {
857  bool labelled = false; // has a label been added to this continously connected segment
858  NODE_MAP segmentChildren = MapChildren( currentSegment );
859  SCH_LINE* firstWire = nullptr;
860  m_segments.emplace_back();
861  SEG_DESC& segDesc = m_segments.back();
862 
863  // Loop through all segment children
864  wxXmlNode* segmentAttribute = currentSegment->GetChildren();
865 
866  while( segmentAttribute )
867  {
868  if( segmentAttribute->GetName() == "wire" )
869  {
870  SCH_LINE* wire = loadWire( segmentAttribute );
871 
872  if( !firstWire )
873  firstWire = wire;
874 
875  // Test for intersections with other wires
876  SEG thisWire( wire->GetStartPoint(), wire->GetEndPoint() );
877 
878  for( auto& desc : m_segments )
879  {
880  if( !desc.labels.empty() && desc.labels.front()->GetText() == netName )
881  continue; // no point in saving intersections of the same net
882 
883  for( const auto& seg : desc.segs )
884  {
885  auto intersection = thisWire.Intersect( seg, true );
886 
887  if( intersection )
888  m_wireIntersections.push_back( *intersection );
889  }
890  }
891 
892  segDesc.segs.push_back( thisWire );
893  screen->Append( wire );
894  }
895 
896  segmentAttribute = segmentAttribute->GetNext();
897  }
898 
899  segmentAttribute = currentSegment->GetChildren();
900 
901  while( segmentAttribute )
902  {
903  wxString nodeName = segmentAttribute->GetName();
904 
905  if( nodeName == "junction" )
906  {
907  screen->Append( loadJunction( segmentAttribute ) );
908  }
909  else if( nodeName == "label" )
910  {
911  SCH_TEXT* label = loadLabel( segmentAttribute, netName );
912  screen->Append( label );
913  wxASSERT( segDesc.labels.empty()
914  || segDesc.labels.front()->GetText() == label->GetText() );
915  segDesc.labels.push_back( label );
916  labelled = true;
917  }
918  else if( nodeName == "pinref" )
919  {
920  segmentAttribute->GetAttribute( "gate" ); // REQUIRED
921  segmentAttribute->GetAttribute( "part" ); // REQUIRED
922  segmentAttribute->GetAttribute( "pin" ); // REQUIRED
923  }
924  else if( nodeName == "wire" )
925  {
926  // already handled;
927  }
928  else // DEFAULT
929  {
930  // THROW_IO_ERROR( wxString::Format( _( "XML node \"%s\" unknown" ), nodeName ) );
931  }
932 
933  // Get next segment attribute
934  segmentAttribute = segmentAttribute->GetNext();
935  }
936 
937  // Add a small label to the net segment if it hasn't been labelled already
938  // this preserves the named net feature of Eagle schematics.
939  if( !labelled && firstWire )
940  {
941  std::unique_ptr<SCH_TEXT> label;
942 
943  // Add a global label if the net appears on more than one Eagle sheet
944  if( m_netCounts[netName.ToStdString()] > 1 )
945  label.reset( new SCH_GLOBALLABEL );
946  else if( segmentCount > 1 )
947  label.reset( new SCH_LABEL );
948 
949  if( label )
950  {
951  label->SetPosition( firstWire->GetStartPoint() );
952  label->SetText( escapeName( netName ) );
953  label->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) );
954  label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
955  screen->Append( label.release() );
956  }
957  }
958 
959  currentSegment = currentSegment->GetNext();
960  }
961 }
962 
963 
964 SCH_LINE* SCH_EAGLE_PLUGIN::loadWire( wxXmlNode* aWireNode )
965 {
966  std::unique_ptr<SCH_LINE> wire( new SCH_LINE );
967 
968  auto ewire = EWIRE( aWireNode );
969 
970  wire->SetLayer( kiCadLayer( ewire.layer ) );
971 
972  wxPoint begin, end;
973 
974  begin.x = ewire.x1.ToSchUnits();
975  begin.y = -ewire.y1.ToSchUnits();
976  end.x = ewire.x2.ToSchUnits();
977  end.y = -ewire.y2.ToSchUnits();
978 
979  wire->SetStartPoint( begin );
980  wire->SetEndPoint( end );
981 
982  m_connPoints[begin].emplace( wire.get() );
983  m_connPoints[end].emplace( wire.get() );
984 
985  return wire.release();
986 }
987 
988 
990 {
991  std::unique_ptr<SCH_JUNCTION> junction( new SCH_JUNCTION );
992 
993  auto ejunction = EJUNCTION( aJunction );
994  wxPoint pos( ejunction.x.ToSchUnits(), -ejunction.y.ToSchUnits() );
995 
996  junction->SetPosition( pos );
997 
998  return junction.release();
999 }
1000 
1001 
1002 SCH_TEXT* SCH_EAGLE_PLUGIN::loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName )
1003 {
1004  auto elabel = ELABEL( aLabelNode, aNetName );
1005  wxPoint elabelpos( elabel.x.ToSchUnits(), -elabel.y.ToSchUnits() );
1006 
1007  // Determine if the label is local or global depending on
1008  // the number of sheets the net appears in
1009  bool global = m_netCounts[aNetName] > 1;
1010  std::unique_ptr<SCH_TEXT> label;
1011 
1012  if( global )
1013  label.reset( new SCH_GLOBALLABEL );
1014  else
1015  label.reset( new SCH_LABEL );
1016 
1017  label->SetPosition( elabelpos );
1018  label->SetText( escapeName( elabel.netname ) );
1019  label->SetTextSize( wxSize( elabel.size.ToSchUnits(), elabel.size.ToSchUnits() ) );
1020  label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
1021 
1022  if( elabel.rot )
1023  {
1024  label->SetLabelSpinStyle( (LABEL_SPIN_STYLE::SPIN) ( KiROUND( elabel.rot->degrees / 90 ) % 4 ) );
1025 
1026  if( elabel.rot->mirror )
1027  {
1028  label->SetLabelSpinStyle( label->GetLabelSpinStyle().MirrorY() );
1029  }
1030  }
1031 
1032  return label.release();
1033 }
1034 
1035 
1036 std::pair<VECTOR2I, const SEG*> SCH_EAGLE_PLUGIN::findNearestLinePoint(
1037  const wxPoint& aPoint, const std::vector<SEG>& aLines ) const
1038 {
1039  VECTOR2I nearestPoint;
1040  const SEG* nearestLine = nullptr;
1041 
1042  float d, mindistance = std::numeric_limits<float>::max();
1043 
1044  // Find the nearest start, middle or end of a line from the list of lines.
1045  for( const SEG& line : aLines )
1046  {
1047  auto testpoint = line.A;
1048  d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1049 
1050  if( d < mindistance )
1051  {
1052  mindistance = d;
1053  nearestPoint = testpoint;
1054  nearestLine = &line;
1055  }
1056 
1057  testpoint = line.Center();
1058  d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1059 
1060  if( d < mindistance )
1061  {
1062  mindistance = d;
1063  nearestPoint = testpoint;
1064  nearestLine = &line;
1065  }
1066 
1067  testpoint = line.B;
1068  d = sqrt( abs( ( ( aPoint.x - testpoint.x ) ^ 2 ) + ( ( aPoint.y - testpoint.y ) ^ 2 ) ) );
1069 
1070  if( d < mindistance )
1071  {
1072  mindistance = d;
1073  nearestPoint = testpoint;
1074  nearestLine = &line;
1075  }
1076  }
1077 
1078  return std::make_pair( nearestPoint, nearestLine );
1079 }
1080 
1081 
1082 void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode )
1083 {
1084  auto einstance = EINSTANCE( aInstanceNode );
1085 
1086  SCH_SCREEN* screen = m_currentSheet->GetScreen();
1087 
1088  // Find the part in the list for the sheet.
1089  // Assign the component its value from the part entry
1090  // Calculate the unit number from the gate entry of the instance
1091  // Assign the the LIB_ID from deviceset and device names
1092 
1093  auto part_it = m_partlist.find( einstance.part.Upper() );
1094 
1095  if( part_it == m_partlist.end() )
1096  {
1097  wxLogError( _( "Error parsing Eagle file. "
1098  "Could not find \"%s\" instance but it is referenced in the schematic." ),
1099  einstance.part );
1100 
1101  return;
1102  }
1103 
1104  EPART* epart = part_it->second.get();
1105 
1106  wxString libraryname = epart->library;
1107  wxString gatename = epart->deviceset + epart->device + einstance.gate;
1108  wxString symbolname = wxString( epart->deviceset + epart->device );
1109  symbolname.Replace( "*", "" );
1110  wxString kisymbolname = fixSymbolName( symbolname );
1111 
1112  int unit = m_eagleLibs[libraryname].GateUnit[gatename];
1113 
1114  wxString package;
1115  EAGLE_LIBRARY* elib = &m_eagleLibs[libraryname];
1116 
1117  auto p = elib->package.find( kisymbolname );
1118 
1119  if( p != elib->package.end() )
1120  package = p->second;
1121 
1122  LIB_PART* part =
1123  m_pi->LoadSymbol( getLibFileName().GetFullPath(), kisymbolname, m_properties.get() );
1124 
1125  if( !part )
1126  {
1127  wxLogMessage( wxString::Format( _( "Could not find %s in the imported library" ),
1128  kisymbolname ) );
1129  return;
1130  }
1131 
1132  LIB_ID libId( getLibName(), kisymbolname );
1133  std::unique_ptr<SCH_COMPONENT> component( new SCH_COMPONENT() );
1134  component->SetLibId( libId );
1135  component->SetUnit( unit );
1136  component->SetPosition( wxPoint( einstance.x.ToSchUnits(), -einstance.y.ToSchUnits() ) );
1137  component->GetField( FOOTPRINT )->SetText( package );
1138 
1139  if( einstance.rot )
1140  {
1141  component->SetOrientation( kiCadComponentRotation( einstance.rot->degrees ) );
1142 
1143  if( einstance.rot->mirror )
1144  component->MirrorY( einstance.x.ToSchUnits() );
1145  }
1146 
1147  LIB_FIELDS partFields;
1148  part->GetFields( partFields );
1149 
1150  for( auto const& field : partFields )
1151  {
1152  component->GetField( field.GetId() )->ImportValues( field );
1153  component->GetField( field.GetId() )
1154  ->SetTextPos( component->GetPosition() + field.GetTextPos() );
1155  }
1156 
1157  // If there is no footprint assigned, then prepend the reference value
1158  // with a hash character to mute netlist updater complaints
1159  wxString reference = package.IsEmpty() ? '#' + einstance.part : einstance.part;
1160 
1161  // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
1162  // parts to have non-digit + digit annotation. If the reference begins with a number,
1163  // we prepend 'UNK' (unknown) for the symbol designator
1164  if( reference.find_first_not_of( "0123456789" ) == wxString::npos )
1165  reference.Prepend( "UNK" );
1166 
1167  SCH_SHEET_PATH sheetpath;
1168  m_rootSheet->LocatePathOfScreen( screen, &sheetpath );
1169  wxString current_sheetpath = sheetpath.PathAsString() + component->m_Uuid.AsString();
1170 
1171  component->GetField( REFERENCE )->SetText( reference );
1172  component->AddHierarchicalReference( current_sheetpath, reference, unit );
1173 
1174  if( epart->value )
1175  component->GetField( VALUE )->SetText( *epart->value );
1176  else
1177  component->GetField( VALUE )->SetText( kisymbolname );
1178 
1179  // Set the visibility of fields.
1180  component->GetField( REFERENCE )->SetVisible( part->GetField( REFERENCE )->IsVisible() );
1181  component->GetField( VALUE )->SetVisible( part->GetField( VALUE )->IsVisible() );
1182 
1183  for( const auto& a : epart->attribute )
1184  {
1185  auto field = component->AddField( *component->GetField( VALUE ) );
1186  field->SetName( a.first );
1187  field->SetText( a.second );
1188  field->SetVisible( false );
1189  }
1190 
1191  for( const auto& a : epart->variant )
1192  {
1193  auto field = component->AddField( *component->GetField( VALUE ) );
1194  field->SetName( "VARIANT_" + a.first );
1195  field->SetText( a.second );
1196  field->SetVisible( false );
1197  }
1198 
1199  bool valueAttributeFound = false;
1200  bool nameAttributeFound = false;
1201 
1202  wxXmlNode* attributeNode = aInstanceNode->GetChildren();
1203 
1204  // Parse attributes for the instance
1205  while( attributeNode )
1206  {
1207  if( attributeNode->GetName() == "attribute" )
1208  {
1209  auto attr = EATTR( attributeNode );
1210  SCH_FIELD* field = NULL;
1211 
1212  if( attr.name.Lower() == "name" )
1213  {
1214  field = component->GetField( REFERENCE );
1215  nameAttributeFound = true;
1216  }
1217  else if( attr.name.Lower() == "value" )
1218  {
1219  field = component->GetField( VALUE );
1220  valueAttributeFound = true;
1221  }
1222  else
1223  {
1224  field = component->FindField( attr.name );
1225 
1226  if( field )
1227  field->SetVisible( false );
1228  }
1229 
1230  if( field )
1231  {
1232 
1233  field->SetPosition( wxPoint( attr.x->ToSchUnits(), -attr.y->ToSchUnits() ) );
1234  int align = attr.align ? *attr.align : ETEXT::BOTTOM_LEFT;
1235  int absdegrees = attr.rot ? attr.rot->degrees : 0;
1236  bool mirror = attr.rot ? attr.rot->mirror : false;
1237 
1238  if( einstance.rot && einstance.rot->mirror )
1239  mirror = !mirror;
1240 
1241  bool spin = attr.rot ? attr.rot->spin : false;
1242 
1243  if( attr.display == EATTR::Off || attr.display == EATTR::NAME )
1244  field->SetVisible( false );
1245 
1246  int rotation = einstance.rot ? einstance.rot->degrees : 0;
1247  int reldegrees = ( absdegrees - rotation + 360.0 );
1248  reldegrees %= 360;
1249 
1251  (EDA_TEXT*) field, align, reldegrees, mirror, spin, absdegrees );
1252  }
1253  }
1254  else if( attributeNode->GetName() == "variant" )
1255  {
1256  wxString variant, value;
1257 
1258  if( attributeNode->GetAttribute( "name", &variant )
1259  && attributeNode->GetAttribute( "value", &value ) )
1260  {
1261  auto field = component->AddField( *component->GetField( VALUE ) );
1262  field->SetName( "VARIANT_" + variant );
1263  field->SetText( value );
1264  field->SetVisible( false );
1265  }
1266  }
1267 
1268  attributeNode = attributeNode->GetNext();
1269  }
1270 
1271  if( einstance.smashed && einstance.smashed.Get() )
1272  {
1273  if( !valueAttributeFound )
1274  component->GetField( VALUE )->SetVisible( false );
1275 
1276  if( !nameAttributeFound )
1277  component->GetField( REFERENCE )->SetVisible( false );
1278  }
1279 
1280  // Save the pin positions
1281  SYMBOL_LIB_TABLE& schLibTable = *m_schematic->Prj().SchSymbolLibTable();
1282  LIB_PART* libSymbol = schLibTable.LoadSymbol( component->GetLibId() );
1283 
1284  wxCHECK( libSymbol, /*void*/ );
1285 
1286  component->SetLibSymbol( new LIB_PART( *libSymbol ) );
1287 
1288  std::vector<LIB_PIN*> pins;
1289  component->GetPins( pins );
1290 
1291  for( const auto& pin : pins )
1292  m_connPoints[component->GetPinPhysicalPosition( pin )].emplace( pin );
1293 
1294  component->ClearFlags();
1295 
1296  screen->Append( component.release() );
1297 }
1298 
1299 
1301  wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLibrary )
1302 {
1303  NODE_MAP libraryChildren = MapChildren( aLibraryNode );
1304 
1305  // Loop through the symbols and load each of them
1306  wxXmlNode* symbolNode = getChildrenNodes( libraryChildren, "symbols" );
1307 
1308  while( symbolNode )
1309  {
1310  wxString symbolName = symbolNode->GetAttribute( "name" );
1311  aEagleLibrary->SymbolNodes[symbolName] = symbolNode;
1312  symbolNode = symbolNode->GetNext();
1313  }
1314 
1315  // Loop through the devicesets and load each of them
1316  wxXmlNode* devicesetNode = getChildrenNodes( libraryChildren, "devicesets" );
1317 
1318  while( devicesetNode )
1319  {
1320  // Get Device set information
1321  EDEVICE_SET edeviceset = EDEVICE_SET( devicesetNode );
1322 
1323  wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : "";
1324 
1325  NODE_MAP aDeviceSetChildren = MapChildren( devicesetNode );
1326  wxXmlNode* deviceNode = getChildrenNodes( aDeviceSetChildren, "devices" );
1327 
1328  // For each device in the device set:
1329  while( deviceNode )
1330  {
1331  // Get device information
1332  EDEVICE edevice = EDEVICE( deviceNode );
1333 
1334  // Create symbol name from deviceset and device names.
1335  wxString symbolName = edeviceset.name + edevice.name;
1336  symbolName.Replace( "*", "" );
1337  wxASSERT( !symbolName.IsEmpty() );
1338  symbolName = fixSymbolName( symbolName );
1339 
1340  if( edevice.package )
1341  aEagleLibrary->package[symbolName] = edevice.package.Get();
1342 
1343  // Create KiCad symbol.
1344  unique_ptr<LIB_PART> kpart( new LIB_PART( symbolName ) );
1345 
1346  // Process each gate in the deviceset for this device.
1347  wxXmlNode* gateNode = getChildrenNodes( aDeviceSetChildren, "gates" );
1348  int gates_count = countChildren( aDeviceSetChildren["gates"], "gate" );
1349  kpart->SetUnitCount( gates_count );
1350  kpart->LockUnits( true );
1351 
1352  LIB_FIELD* reference = kpart->GetField( REFERENCE );
1353 
1354  if( prefix.length() == 0 )
1355  reference->SetVisible( false );
1356  else
1357  // If there is no footprint assigned, then prepend the reference value
1358  // with a hash character to mute netlist updater complaints
1359  reference->SetText( edevice.package ? prefix : '#' + prefix );
1360 
1361  int gateindex = 1;
1362  bool ispower = false;
1363 
1364  while( gateNode )
1365  {
1366  EGATE egate = EGATE( gateNode );
1367 
1368  aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex;
1369 
1370  ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol], kpart, &edevice,
1371  gateindex, egate.name );
1372 
1373  gateindex++;
1374  gateNode = gateNode->GetNext();
1375  } // gateNode
1376 
1377  kpart->SetUnitCount( gates_count );
1378 
1379  if( gates_count == 1 && ispower )
1380  kpart->SetPower();
1381 
1382  wxString name = fixSymbolName( kpart->GetName() );
1383  kpart->SetName( name );
1384  m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_PART( *kpart.get() ),
1385  m_properties.get() );
1386  aEagleLibrary->KiCadSymbols.insert( name, kpart.release() );
1387 
1388  deviceNode = deviceNode->GetNext();
1389  } // devicenode
1390 
1391  devicesetNode = devicesetNode->GetNext();
1392  } // devicesetNode
1393 
1394  return aEagleLibrary;
1395 }
1396 
1397 
1398 bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart,
1399  EDEVICE* aDevice, int aGateNumber, const wxString& aGateName )
1400 {
1401  wxString symbolName = aSymbolNode->GetAttribute( "name" );
1402  std::vector<LIB_ITEM*> items;
1403 
1404  wxXmlNode* currentNode = aSymbolNode->GetChildren();
1405 
1406  bool foundName = false;
1407  bool foundValue = false;
1408  bool ispower = false;
1409  int pincount = 0;
1410 
1411  while( currentNode )
1412  {
1413  wxString nodeName = currentNode->GetName();
1414 
1415  if( nodeName == "circle" )
1416  {
1417  aPart->AddDrawItem( loadSymbolCircle( aPart, currentNode, aGateNumber ) );
1418  }
1419  else if( nodeName == "pin" )
1420  {
1421  EPIN ePin = EPIN( currentNode );
1422  std::unique_ptr<LIB_PIN> pin( loadPin( aPart, currentNode, &ePin, aGateNumber ) );
1423  pincount++;
1424 
1425  pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
1426 
1427  if( ePin.direction )
1428  {
1429  for( const auto& pinDir : pinDirectionsMap )
1430  {
1431  if( ePin.direction->Lower() == pinDir.first )
1432  {
1433  pin->SetType( pinDir.second );
1434 
1435  if( pinDir.first == "sup" ) // power supply symbol
1436  ispower = true;
1437 
1438  break;
1439  }
1440  }
1441  }
1442 
1443 
1444  if( aDevice->connects.size() != 0 )
1445  {
1446  for( const auto& connect : aDevice->connects )
1447  {
1448  if( connect.gate == aGateName && pin->GetName() == connect.pin )
1449  {
1450  wxArrayString pads = wxSplit( wxString( connect.pad ), ' ' );
1451 
1452  pin->SetPartNumber( aGateNumber );
1453  pin->SetUnit( aGateNumber );
1454  pin->SetName( escapeName( pin->GetName() ) );
1455 
1456  if( pads.GetCount() > 1 )
1457  {
1458  pin->SetNumberTextSize( 0 );
1459  }
1460 
1461  // Eagle does not connect multiple NC pins together when they are stacked.
1462  // KiCad will do this for pins that are coincident. We opt here for correct
1463  // schematic netlist and leave out the multiple NC pins when stacked.
1464  for( unsigned i = 0; i < pads.GetCount(); i++ )
1465  {
1466  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC && i > 0 )
1467  break;
1468 
1469  LIB_PIN* apin = new LIB_PIN( *pin );
1470 
1471  wxString padname( pads[i] );
1472  apin->SetNumber( padname );
1473  aPart->AddDrawItem( apin );
1474  }
1475 
1476  break;
1477  }
1478  }
1479  }
1480  else
1481  {
1482  pin->SetPartNumber( aGateNumber );
1483  pin->SetUnit( aGateNumber );
1484  pin->SetNumber( wxString::Format( "%i", pincount ) );
1485  aPart->AddDrawItem( pin.release() );
1486  }
1487  }
1488  else if( nodeName == "polygon" )
1489  {
1490  aPart->AddDrawItem( loadSymbolPolyLine( aPart, currentNode, aGateNumber ) );
1491  }
1492  else if( nodeName == "rectangle" )
1493  {
1494  aPart->AddDrawItem( loadSymbolRectangle( aPart, currentNode, aGateNumber ) );
1495  }
1496  else if( nodeName == "text" )
1497  {
1498  std::unique_ptr<LIB_TEXT> libtext( loadSymbolText( aPart, currentNode, aGateNumber ) );
1499 
1500  if( libtext->GetText().Upper() == ">NAME" )
1501  {
1502  LIB_FIELD* field = aPart->GetField( REFERENCE );
1503  loadFieldAttributes( field, libtext.get() );
1504  foundName = true;
1505  }
1506  else if( libtext->GetText().Upper() == ">VALUE" )
1507  {
1508  LIB_FIELD* field = aPart->GetField( VALUE );
1509  loadFieldAttributes( field, libtext.get() );
1510  foundValue = true;
1511  }
1512  else
1513  {
1514  aPart->AddDrawItem( libtext.release() );
1515  }
1516  }
1517  else if( nodeName == "wire" )
1518  {
1519  aPart->AddDrawItem( loadSymbolWire( aPart, currentNode, aGateNumber ) );
1520  }
1521 
1522  /*
1523  * else if( nodeName == "description" )
1524  * {
1525  * }
1526  * else if( nodeName == "dimension" )
1527  * {
1528  * }
1529  * else if( nodeName == "frame" )
1530  * {
1531  * }
1532  */
1533 
1534  currentNode = currentNode->GetNext();
1535  }
1536 
1537  if( foundName == false )
1538  aPart->GetField( REFERENCE )->SetVisible( false );
1539 
1540  if( foundValue == false )
1541  aPart->GetField( VALUE )->SetVisible( false );
1542 
1543  return pincount == 1 ? ispower : false;
1544 }
1545 
1546 
1548  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aCircleNode, int aGateNumber )
1549 {
1550  // Parse the circle properties
1551  ECIRCLE c( aCircleNode );
1552 
1553  unique_ptr<LIB_CIRCLE> circle( new LIB_CIRCLE( aPart.get() ) );
1554 
1555  circle->SetPosition( wxPoint( c.x.ToSchUnits(), c.y.ToSchUnits() ) );
1556  circle->SetRadius( c.radius.ToSchUnits() );
1557  circle->SetWidth( c.width.ToSchUnits() );
1558  circle->SetUnit( aGateNumber );
1559 
1560  return circle.release();
1561 }
1562 
1563 
1565  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aRectNode, int aGateNumber )
1566 {
1567  ERECT rect( aRectNode );
1568 
1569  unique_ptr<LIB_RECTANGLE> rectangle( new LIB_RECTANGLE( aPart.get() ) );
1570 
1571  rectangle->SetPosition( wxPoint( rect.x1.ToSchUnits(), rect.y1.ToSchUnits() ) );
1572  rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
1573 
1574  rectangle->SetUnit( aGateNumber );
1575  // Eagle rectangles are filled by definition.
1576  rectangle->SetFillMode( FILLED_SHAPE );
1577 
1578  return rectangle.release();
1579 }
1580 
1581 
1583  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aWireNode, int aGateNumber )
1584 {
1585  auto ewire = EWIRE( aWireNode );
1586 
1587  wxPoint begin, end;
1588 
1589  begin.x = ewire.x1.ToSchUnits();
1590  begin.y = ewire.y1.ToSchUnits();
1591  end.x = ewire.x2.ToSchUnits();
1592  end.y = ewire.y2.ToSchUnits();
1593 
1594  if( begin == end )
1595  return nullptr;
1596 
1597  // if the wire is an arc
1598  if( ewire.curve )
1599  {
1600  std::unique_ptr<LIB_ARC> arc( new LIB_ARC( aPart.get() ) );
1601  wxPoint center = ConvertArcCenter( begin, end, *ewire.curve * -1 );
1602 
1603  double radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1604  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) )
1605  * 2;
1606 
1607  // this emulates the filled semicircles created by a thick arc with flat ends caps.
1608  if( ewire.width.ToSchUnits() * 2 > radius )
1609  {
1610  wxPoint centerStartVector = begin - center;
1611  wxPoint centerEndVector = end - center;
1612 
1613  centerStartVector.x = centerStartVector.x * ewire.width.ToSchUnits() * 2 / radius;
1614  centerStartVector.y = centerStartVector.y * ewire.width.ToSchUnits() * 2 / radius;
1615 
1616  centerEndVector.x = centerEndVector.x * ewire.width.ToSchUnits() * 2 / radius;
1617  centerEndVector.y = centerEndVector.y * ewire.width.ToSchUnits() * 2 / radius;
1618 
1619  begin = center + centerStartVector;
1620  end = center + centerEndVector;
1621 
1622  radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1623  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) )
1624  * 2;
1625 
1626  arc->SetWidth( 1 );
1627  arc->SetFillMode( FILLED_SHAPE );
1628  }
1629  else
1630  {
1631  arc->SetWidth( ewire.width.ToSchUnits() );
1632  }
1633 
1634  arc->SetPosition( center );
1635 
1636  if( *ewire.curve > 0 )
1637  {
1638  arc->SetStart( begin );
1639  arc->SetEnd( end );
1640  }
1641  else
1642  {
1643  arc->SetStart( end );
1644  arc->SetEnd( begin );
1645  }
1646 
1647  arc->SetRadius( radius );
1648  arc->CalcRadiusAngles();
1649  arc->SetUnit( aGateNumber );
1650 
1651  return (LIB_ITEM*) arc.release();
1652  }
1653  else
1654  {
1655  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1656 
1657  polyLine->AddPoint( begin );
1658  polyLine->AddPoint( end );
1659  polyLine->SetUnit( aGateNumber );
1660  polyLine->SetWidth( ewire.width.ToSchUnits() );
1661 
1662  return (LIB_ITEM*) polyLine.release();
1663  }
1664 }
1665 
1666 
1668  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aPolygonNode, int aGateNumber )
1669 {
1670  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1671 
1672  EPOLYGON epoly( aPolygonNode );
1673  wxXmlNode* vertex = aPolygonNode->GetChildren();
1674 
1675 
1676  wxPoint pt;
1677 
1678  while( vertex )
1679  {
1680  if( vertex->GetName() == "vertex" ) // skip <xmlattr> node
1681  {
1682  EVERTEX evertex( vertex );
1683  pt = wxPoint( evertex.x.ToSchUnits(), evertex.y.ToSchUnits() );
1684  polyLine->AddPoint( pt );
1685  }
1686 
1687  vertex = vertex->GetNext();
1688  }
1689 
1690  polyLine->SetFillMode( FILLED_SHAPE );
1691  polyLine->SetUnit( aGateNumber );
1692 
1693  return polyLine.release();
1694 }
1695 
1696 
1698  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aPin, EPIN* aEPin, int aGateNumber )
1699 {
1700  std::unique_ptr<LIB_PIN> pin( new LIB_PIN( aPart.get() ) );
1701  pin->SetPosition( wxPoint( aEPin->x.ToSchUnits(), aEPin->y.ToSchUnits() ) );
1702  pin->SetName( aEPin->name );
1703  pin->SetUnit( aGateNumber );
1704 
1705  int roti = aEPin->rot ? aEPin->rot->degrees : 0;
1706 
1707  switch( roti )
1708  {
1709  default:
1710  wxASSERT_MSG( false, wxString::Format( "Unhandled orientation (%d degrees)", roti ) );
1712 
1713  case 0:
1714  pin->SetOrientation( 'R' );
1715  break;
1716 
1717  case 90:
1718  pin->SetOrientation( 'U' );
1719  break;
1720 
1721  case 180:
1722  pin->SetOrientation( 'L' );
1723  break;
1724 
1725  case 270:
1726  pin->SetOrientation( 'D' );
1727  break;
1728  }
1729 
1730  if( aEPin->length )
1731  {
1732  wxString length = aEPin->length.Get();
1733 
1734  if( length == "short" )
1735  {
1736  pin->SetLength( Mils2iu( 100 ) );
1737  }
1738  else if( length == "middle" )
1739  {
1740  pin->SetLength( Mils2iu( 200 ) );
1741  }
1742  else if( length == "long" )
1743  {
1744  pin->SetLength( Mils2iu( 300 ) );
1745  }
1746  else if( length == "point" )
1747  {
1748  pin->SetLength( Mils2iu( 0 ) );
1749  }
1750  }
1751 
1752  // emulate the visibility of pin elements
1753  if( aEPin->visible )
1754  {
1755  wxString visible = aEPin->visible.Get();
1756 
1757  if( visible == "off" )
1758  {
1759  pin->SetNameTextSize( 0 );
1760  pin->SetNumberTextSize( 0 );
1761  }
1762  else if( visible == "pad" )
1763  {
1764  pin->SetNameTextSize( 0 );
1765  }
1766  else if( visible == "pin" )
1767  {
1768  pin->SetNumberTextSize( 0 );
1769  }
1770 
1771  /*
1772  * else if( visible == "both" )
1773  * {
1774  * }
1775  */
1776  }
1777 
1778  if( aEPin->function )
1779  {
1780  wxString function = aEPin->function.Get();
1781 
1782  if( function == "dot" )
1783  {
1784  pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
1785  }
1786  else if( function == "clk" )
1787  {
1788  pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
1789  }
1790  else if( function == "dotclk" )
1791  {
1792  pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
1793  }
1794  }
1795 
1796  return pin.release();
1797 }
1798 
1799 
1801  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText, int aGateNumber )
1802 {
1803  std::unique_ptr<LIB_TEXT> libtext( new LIB_TEXT( aPart.get() ) );
1804  ETEXT etext( aLibText );
1805 
1806  libtext->SetUnit( aGateNumber );
1807  libtext->SetPosition( wxPoint( etext.x.ToSchUnits(), etext.y.ToSchUnits() ) );
1808 
1809  // Eagle supports multiple line text in library symbols. Legacy library symbol text cannot
1810  // contain CRs or LFs.
1811  //
1812  // @todo Split this into multiple text objects and offset the Y position so that it looks
1813  // more like the original Eagle schematic.
1814  wxString text = aLibText->GetNodeContent();
1815  std::replace( text.begin(), text.end(), '\n', '_' );
1816  std::replace( text.begin(), text.end(), '\r', '_' );
1817 
1818  libtext->SetText( text.IsEmpty() ? "~~" : text );
1819  loadTextAttributes( libtext.get(), etext );
1820 
1821  return libtext.release();
1822 }
1823 
1824 
1826 {
1827  std::unique_ptr<SCH_TEXT> schtext( new SCH_TEXT() );
1828  ETEXT etext = ETEXT( aSchText );
1829 
1830  const wxString& thetext = aSchText->GetNodeContent();
1831  schtext->SetText( thetext.IsEmpty() ? "\" \"" : escapeName( thetext ) );
1832  schtext->SetPosition( wxPoint( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
1833  loadTextAttributes( schtext.get(), etext );
1834  schtext->SetItalic( false );
1835 
1836  return schtext.release();
1837 }
1838 
1839 
1840 void SCH_EAGLE_PLUGIN::loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const
1841 {
1842  aText->SetTextSize( aAttribs.ConvertSize() );
1843 
1844  if( aAttribs.ratio )
1845  {
1846  if( aAttribs.ratio.CGet() > 12 )
1847  {
1848  aText->SetBold( true );
1849  aText->SetTextThickness( GetPenSizeForBold( aText->GetTextWidth() ) );
1850  }
1851  }
1852 
1853  int align = aAttribs.align ? *aAttribs.align : ETEXT::BOTTOM_LEFT;
1854  int degrees = aAttribs.rot ? aAttribs.rot->degrees : 0;
1855  bool mirror = aAttribs.rot ? aAttribs.rot->mirror : false;
1856  bool spin = aAttribs.rot ? aAttribs.rot->spin : false;
1857 
1858  eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
1859 }
1860 
1861 
1862 void SCH_EAGLE_PLUGIN::loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const
1863 {
1864  aField->SetTextPos( aText->GetPosition() );
1865  aField->SetTextSize( aText->GetTextSize() );
1866  aField->SetTextAngle( aText->GetTextAngle() );
1867  aField->SetBold( aText->IsBold() );
1868  aField->SetVertJustify( aText->GetVertJustify() );
1869  aField->SetHorizJustify( aText->GetHorizJustify() );
1870  aField->SetVisible( true );
1871 }
1872 
1873 
1875 {
1876  // Eagle supports detached labels, so a label does not need to be placed on a wire
1877  // to be associated with it. KiCad needs to move them, so the labels actually touch the
1878  // corresponding wires.
1879 
1880  // Sort the intersection points to speed up the search process
1881  std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
1882 
1883  auto onIntersection = [&]( const VECTOR2I& aPos ) {
1884  return std::binary_search( m_wireIntersections.begin(), m_wireIntersections.end(), aPos );
1885  };
1886 
1887  for( auto& segDesc : m_segments )
1888  {
1889  for( SCH_TEXT* label : segDesc.labels )
1890  {
1891  VECTOR2I labelPos( label->GetPosition() );
1892  const SEG* segAttached = segDesc.LabelAttached( label );
1893 
1894  if( segAttached && !onIntersection( labelPos ) )
1895  continue; // label is placed correctly
1896 
1897 
1898  // Move the label to the nearest wire
1899  if( !segAttached )
1900  {
1901  std::tie( labelPos, segAttached ) =
1902  findNearestLinePoint( label->GetPosition(), segDesc.segs );
1903 
1904  if( !segAttached ) // we cannot do anything
1905  continue;
1906  }
1907 
1908 
1909  // Create a vector pointing in the direction of the wire, 50 mils long
1910  VECTOR2I wireDirection( segAttached->B - segAttached->A );
1911  wireDirection = wireDirection.Resize( Mils2iu( 50 ) );
1912  const VECTOR2I origPos( labelPos );
1913 
1914  // Flags determining the search direction
1915  bool checkPositive = true, checkNegative = true, move = false;
1916  int trial = 0;
1917 
1918  // Be sure the label is not placed on a wire intersection
1919  while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
1920  {
1921  move = false;
1922 
1923  // Move along the attached wire to find the new label position
1924  if( trial % 2 == 1 )
1925  {
1926  labelPos = wxPoint( origPos + wireDirection * trial / 2 );
1927  move = checkPositive = segAttached->Contains( labelPos );
1928  }
1929  else
1930  {
1931  labelPos = wxPoint( origPos - wireDirection * trial / 2 );
1932  move = checkNegative = segAttached->Contains( labelPos );
1933  }
1934 
1935  ++trial;
1936  }
1937 
1938  if( move )
1939  label->SetPosition( wxPoint( labelPos ) );
1940  }
1941  }
1942 
1943  m_segments.clear();
1944  m_wireIntersections.clear();
1945 }
1946 
1947 
1948 bool SCH_EAGLE_PLUGIN::CheckHeader( const wxString& aFileName )
1949 {
1950  // Open file and check first line
1951  wxTextFile tempFile;
1952 
1953  tempFile.Open( aFileName );
1954  wxString firstline;
1955  // read the first line
1956  firstline = tempFile.GetFirstLine();
1957  wxString secondline = tempFile.GetNextLine();
1958  wxString thirdline = tempFile.GetNextLine();
1959  tempFile.Close();
1960 
1961  return firstline.StartsWith( "<?xml" ) && secondline.StartsWith( "<!DOCTYPE eagle SYSTEM" )
1962  && thirdline.StartsWith( "<eagle version" );
1963 }
1964 
1965 
1966 void SCH_EAGLE_PLUGIN::moveLabels( SCH_ITEM* aWire, const wxPoint& aNewEndPoint )
1967 {
1968  for( auto item : m_currentSheet->GetScreen()->Items().Overlapping( aWire->GetBoundingBox() ) )
1969  {
1970  if( item->Type() == SCH_LABEL_T || item->Type() == SCH_GLOBAL_LABEL_T )
1971  {
1972  if( TestSegmentHit( item->GetPosition(), ( (SCH_LINE*) aWire )->GetStartPoint(),
1973  ( (SCH_LINE*) aWire )->GetEndPoint(), 0 ) )
1974  {
1975  item->SetPosition( aNewEndPoint );
1976  }
1977  }
1978  }
1979 }
1980 
1981 
1983 {
1984  // Add bus entry symbols
1985  // TODO: Cleanup this function and break into pieces
1986 
1987  // for each wire segment, compare each end with all busess.
1988  // If the wire end is found to end on a bus segment, place a bus entry symbol.
1989 
1990  for( auto it1 = m_currentSheet->GetScreen()->Items().OfType( SCH_LINE_T ).begin();
1991  it1 != m_currentSheet->GetScreen()->Items().end(); ++it1 )
1992  {
1993  SCH_LINE* bus = static_cast<SCH_LINE*>( *it1 );
1994 
1995  // Check line type for wire
1996  if( bus->GetLayer() != LAYER_BUS )
1997  continue;
1998 
1999 
2000  wxPoint busstart = bus->GetStartPoint();
2001  wxPoint busend = bus->GetEndPoint();
2002 
2003  auto it2 = it1;
2004  ++it2;
2005  for( ; it2 != m_currentSheet->GetScreen()->Items().end(); ++it2 )
2006  {
2007  SCH_LINE* line = static_cast<SCH_LINE*>( *it2 );
2008 
2009  // Check line type for bus
2010  if( ( (SCH_LINE*) *it2 )->GetLayer() == LAYER_WIRE )
2011  {
2012  // Get points of both segments.
2013  wxPoint linestart = line->GetStartPoint();
2014  wxPoint lineend = line->GetEndPoint();
2015 
2016  // Test for horizontal wire and vertical bus
2017  if( linestart.y == lineend.y && busstart.x == busend.x )
2018  {
2019  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2020  {
2021  // Wire start is on a bus.
2022  // Wire start is on the vertical bus
2023 
2024  // if the end of the wire is to the left of the bus
2025  if( lineend.x < busstart.x )
2026  {
2027  // |
2028  // ---|
2029  // |
2030  if( TestSegmentHit(
2031  linestart + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2032  {
2033  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2034  linestart + wxPoint( -100, 0 ), true );
2035  busEntry->SetFlags( IS_NEW );
2036  m_currentSheet->GetScreen()->Append( busEntry );
2037  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2038  line->SetStartPoint( linestart + wxPoint( -100, 0 ) );
2039  }
2040  else if( TestSegmentHit(
2041  linestart + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2042  {
2043  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2044  linestart + wxPoint( -100, 0 ), false );
2045  busEntry->SetFlags( IS_NEW );
2046  m_currentSheet->GetScreen()->Append( busEntry );
2047  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2048  line->SetStartPoint( linestart + wxPoint( -100, 0 ) );
2049  }
2050  else
2051  {
2052  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2053  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2054 
2055  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2056  m_currentSheet->GetScreen()->Append( marker );
2057  }
2058  }
2059  // else the wire end is to the right of the bus
2060  // Wire is to the right of the bus
2061  // |
2062  // |----
2063  // |
2064  else
2065  {
2066  // test is bus exists above the wire
2067  if( TestSegmentHit(
2068  linestart + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2069  {
2070  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2071  linestart + wxPoint( 0, -100 ), false );
2072  busEntry->SetFlags( IS_NEW );
2073  m_currentSheet->GetScreen()->Append( busEntry );
2074  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2075  line->SetStartPoint( linestart + wxPoint( 100, 0 ) );
2076  }
2077  // test is bus exists below the wire
2078  else if( TestSegmentHit(
2079  linestart + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2080  {
2081  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2082  linestart + wxPoint( 0, 100 ), true );
2083  busEntry->SetFlags( IS_NEW );
2084  m_currentSheet->GetScreen()->Append( busEntry );
2085  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2086  line->SetStartPoint( linestart + wxPoint( 100, 0 ) );
2087  }
2088  else
2089  {
2090  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2091  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2092 
2093  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2094  m_currentSheet->GetScreen()->Append( marker );
2095  }
2096  }
2097  }
2098 
2099  // Same thing but test end of the wire instead.
2100  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2101  {
2102  // Wire end is on the vertical bus
2103 
2104  // if the start of the wire is to the left of the bus
2105  if( linestart.x < busstart.x )
2106  {
2107  // Test if bus exists above the wire
2108  if( TestSegmentHit( lineend + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2109  {
2110  // |
2111  // ___/|
2112  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2113  lineend + wxPoint( -100, 0 ), false );
2114  busEntry->SetFlags( IS_NEW );
2115  m_currentSheet->GetScreen()->Append( busEntry );
2116  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2117  line->SetEndPoint( lineend + wxPoint( -100, 0 ) );
2118  }
2119  // Test if bus exists below the wire
2120  else if( TestSegmentHit(
2121  lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2122  {
2123  SCH_BUS_WIRE_ENTRY* busEntry =
2124  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true );
2125  busEntry->SetFlags( IS_NEW );
2126  m_currentSheet->GetScreen()->Append( busEntry );
2127  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2128  line->SetEndPoint( lineend + wxPoint( -100, 0 ) );
2129  }
2130  else
2131  {
2132  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2133  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2134 
2135  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2136  m_currentSheet->GetScreen()->Append( marker );
2137  }
2138  }
2139  // else the start of the wire is to the right of the bus
2140  // |
2141  // |----
2142  // |
2143  else
2144  {
2145  // test if bus existed above the wire
2146  if( TestSegmentHit(
2147  lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2148  {
2149  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2150  lineend + wxPoint( 0, -100 ), false );
2151  busEntry->SetFlags( IS_NEW );
2152  m_currentSheet->GetScreen()->Append( busEntry );
2153  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2154  line->SetEndPoint( lineend + wxPoint( 100, 0 ) );
2155  }
2156  // test if bus existed below the wire
2157  else if( TestSegmentHit(
2158  lineend + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2159  {
2160  SCH_BUS_WIRE_ENTRY* busEntry =
2161  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( 0, 100 ), true );
2162  busEntry->SetFlags( IS_NEW );
2163  m_currentSheet->GetScreen()->Append( busEntry );
2164  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2165  line->SetEndPoint( lineend + wxPoint( 100, 0 ) );
2166  }
2167  else
2168  {
2169  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2170  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2171 
2172  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2173  m_currentSheet->GetScreen()->Append( marker );
2174  }
2175  }
2176  }
2177  } // if( linestart.y == lineend.y && busstart.x == busend.x)
2178 
2179  // Test for horizontal wire and vertical bus
2180  if( linestart.x == lineend.x && busstart.y == busend.y )
2181  {
2182  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2183  {
2184  // Wire start is on the bus
2185  // If wire end is above the bus,
2186  if( lineend.y < busstart.y )
2187  {
2188  // Test for bus existance to the left of the wire
2189  if( TestSegmentHit(
2190  linestart + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2191  {
2192  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2193  linestart + wxPoint( -100, 0 ), true );
2194  busEntry->SetFlags( IS_NEW );
2195  m_currentSheet->GetScreen()->Append( busEntry );
2196  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2197  line->SetStartPoint( linestart + wxPoint( 0, -100 ) );
2198  }
2199  else if( TestSegmentHit(
2200  linestart + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2201  {
2202  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2203  linestart + wxPoint( 0, 100 ), false );
2204  busEntry->SetFlags( IS_NEW );
2205  m_currentSheet->GetScreen()->Append( busEntry );
2206  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2207  line->SetStartPoint( linestart + wxPoint( 0, -100 ) );
2208  }
2209  else
2210  {
2211  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2212  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2213 
2214  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2215  m_currentSheet->GetScreen()->Append( marker );
2216  }
2217  }
2218  else // wire end is below the bus.
2219  {
2220  // Test for bus existance to the left of the wire
2221  if( TestSegmentHit(
2222  linestart + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2223  {
2224  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2225  linestart + wxPoint( -100, 0 ), false );
2226  busEntry->SetFlags( IS_NEW );
2227  m_currentSheet->GetScreen()->Append( busEntry );
2228  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2229  line->SetStartPoint( linestart + wxPoint( 0, 100 ) );
2230  }
2231  else if( TestSegmentHit(
2232  linestart + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2233  {
2234  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2235  linestart + wxPoint( 100, 0 ), true );
2236  busEntry->SetFlags( IS_NEW );
2237  m_currentSheet->GetScreen()->Append( busEntry );
2238  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2239  line->SetStartPoint( linestart + wxPoint( 0, 100 ) );
2240  }
2241  else
2242  {
2243  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2244  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2245 
2246  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2247  m_currentSheet->GetScreen()->Append( marker );
2248  }
2249  }
2250  }
2251 
2252  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2253  {
2254  // Wire end is on the bus
2255  // If wire start is above the bus,
2256 
2257  if( linestart.y < busstart.y )
2258  {
2259  // Test for bus existance to the left of the wire
2260  if( TestSegmentHit(
2261  lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2262  {
2263  SCH_BUS_WIRE_ENTRY* busEntry =
2264  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true );
2265  busEntry->SetFlags( IS_NEW );
2266  m_currentSheet->GetScreen()->Append( busEntry );
2267  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2268  line->SetEndPoint( lineend + wxPoint( 0, -100 ) );
2269  }
2270  else if( TestSegmentHit(
2271  lineend + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2272  {
2273  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2274  lineend + wxPoint( 0, -100 ), false );
2275  busEntry->SetFlags( IS_NEW );
2276  m_currentSheet->GetScreen()->Append( busEntry );
2277  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2278  line->SetEndPoint( lineend + wxPoint( 0, -100 ) );
2279  }
2280  else
2281  {
2282  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2283  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2284 
2285  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2286  m_currentSheet->GetScreen()->Append( marker );
2287  }
2288  }
2289  else // wire end is below the bus.
2290  {
2291  // Test for bus existance to the left of the wire
2292  if( TestSegmentHit(
2293  lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2294  {
2295  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2296  lineend + wxPoint( -100, 0 ), false );
2297  busEntry->SetFlags( IS_NEW );
2298  m_currentSheet->GetScreen()->Append( busEntry );
2299  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2300  line->SetEndPoint( lineend + wxPoint( 0, 100 ) );
2301  }
2302  else if( TestSegmentHit(
2303  lineend + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2304  {
2305  SCH_BUS_WIRE_ENTRY* busEntry =
2306  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( 0, 100 ), true );
2307  busEntry->SetFlags( IS_NEW );
2308  m_currentSheet->GetScreen()->Append( busEntry );
2309  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2310  line->SetEndPoint( lineend + wxPoint( 0, 100 ) );
2311  }
2312  else
2313  {
2314  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2315  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2316 
2317  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2318  m_currentSheet->GetScreen()->Append( marker );
2319  }
2320  }
2321  }
2322  }
2323 
2324  linestart = line->GetStartPoint();
2325  lineend = line->GetEndPoint();
2326  busstart = bus->GetStartPoint();
2327  busend = bus->GetEndPoint();
2328 
2329  // bus entry wire isn't horizontal or vertical
2330  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2331  {
2332  wxPoint wirevector = linestart - lineend;
2333 
2334  if( wirevector.x > 0 )
2335  {
2336  if( wirevector.y > 0 )
2337  {
2338  wxPoint p = linestart + wxPoint( -100, -100 );
2339  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, false );
2340  busEntry->SetFlags( IS_NEW );
2341  m_currentSheet->GetScreen()->Append( busEntry );
2342  moveLabels( line, p );
2343 
2344  if( p == lineend ) // wire is overlapped by bus entry symbol
2345  {
2346  m_currentSheet->GetScreen()->DeleteItem( line );
2347  line = nullptr;
2348  }
2349  else
2350  {
2351  line->SetStartPoint( p );
2352  }
2353  }
2354  else
2355  {
2356  wxPoint p = linestart + wxPoint( -100, 100 );
2357  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, true );
2358  busEntry->SetFlags( IS_NEW );
2359  m_currentSheet->GetScreen()->Append( busEntry );
2360 
2361  moveLabels( line, p );
2362 
2363  if( p == lineend ) // wire is overlapped by bus entry symbol
2364  {
2365  m_currentSheet->GetScreen()->DeleteItem( line );
2366  line = nullptr;
2367  }
2368  else
2369  {
2370  line->SetStartPoint( p );
2371  }
2372  }
2373  }
2374  else
2375  {
2376  if( wirevector.y > 0 )
2377  {
2378  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart, true );
2379  busEntry->SetFlags( IS_NEW );
2380  m_currentSheet->GetScreen()->Append( busEntry );
2381 
2382  moveLabels( line, linestart + wxPoint( 100, -100 ) );
2383 
2384  if( linestart + wxPoint( 100, -100 )
2385  == lineend ) // wire is overlapped by bus entry symbol
2386  {
2387  m_currentSheet->GetScreen()->DeleteItem( line );
2388  line = nullptr;
2389  }
2390  else
2391  {
2392  line->SetStartPoint( linestart + wxPoint( 100, -100 ) );
2393  }
2394  }
2395  else
2396  {
2397  SCH_BUS_WIRE_ENTRY* busEntry =
2398  new SCH_BUS_WIRE_ENTRY( linestart, false );
2399  busEntry->SetFlags( IS_NEW );
2400  m_currentSheet->GetScreen()->Append( busEntry );
2401  moveLabels( line, linestart + wxPoint( 100, 100 ) );
2402 
2403  if( linestart + wxPoint( 100, 100 )
2404  == lineend ) // wire is overlapped by bus entry symbol
2405  {
2406  m_currentSheet->GetScreen()->DeleteItem( line );
2407  line = nullptr;
2408  }
2409  else
2410  {
2411  line->SetStartPoint( linestart + wxPoint( 100, 100 ) );
2412  }
2413  }
2414  }
2415  }
2416 
2417  if( line && TestSegmentHit( lineend, busstart, busend, 0 ) )
2418  {
2419  wxPoint wirevector = linestart - lineend;
2420 
2421  if( wirevector.x > 0 )
2422  {
2423  if( wirevector.y > 0 )
2424  {
2425  wxPoint p = lineend + wxPoint( 100, 100 );
2426  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend, false );
2427  busEntry->SetFlags( IS_NEW );
2428  m_currentSheet->GetScreen()->Append( busEntry );
2429 
2430  moveLabels( line, p );
2431 
2432  if( p == linestart ) // wire is overlapped by bus entry symbol
2433  {
2434  m_currentSheet->GetScreen()->DeleteItem( line );
2435  }
2436  else
2437  {
2438  line->SetEndPoint( p );
2439  }
2440  }
2441  else
2442  {
2443  wxPoint p = lineend + wxPoint( 100, -100 );
2444  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend, true );
2445  busEntry->SetFlags( IS_NEW );
2446  m_currentSheet->GetScreen()->Append( busEntry );
2447 
2448  moveLabels( line, p );
2449 
2450  if( p == linestart ) // wire is overlapped by bus entry symbol
2451  {
2452  m_currentSheet->GetScreen()->DeleteItem( line );
2453  }
2454  else
2455  {
2456  line->SetEndPoint( p );
2457  }
2458  }
2459  }
2460  else
2461  {
2462  if( wirevector.y > 0 )
2463  {
2464  wxPoint p = lineend + wxPoint( -100, 100 );
2465  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, true );
2466  busEntry->SetFlags( IS_NEW );
2467  m_currentSheet->GetScreen()->Append( busEntry );
2468  moveLabels( line, p );
2469 
2470  if( p == linestart ) // wire is overlapped by bus entry symbol
2471  {
2472  m_currentSheet->GetScreen()->DeleteItem( line );
2473  }
2474  else
2475  {
2476  line->SetEndPoint( p );
2477  }
2478  }
2479  else
2480  {
2481  wxPoint p = lineend + wxPoint( -100, -100 );
2482  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, false );
2483  busEntry->SetFlags( IS_NEW );
2484  m_currentSheet->GetScreen()->Append( busEntry );
2485  moveLabels( line, p );
2486 
2487  if( p == linestart ) // wire is overlapped by bus entry symbol
2488  {
2489  m_currentSheet->GetScreen()->DeleteItem( line );
2490  }
2491  else
2492  {
2493  line->SetEndPoint( p );
2494  }
2495  }
2496  }
2497  }
2498  }
2499  }
2500  } // for ( bus ..
2501 }
2502 
2503 
2505 {
2506  VECTOR2I labelPos( aLabel->GetPosition() );
2507 
2508  for( const auto& seg : segs )
2509  {
2510  if( seg.Contains( labelPos ) )
2511  return &seg;
2512  }
2513 
2514  return nullptr;
2515 }
2516 
2517 
2518 // TODO could be used to place junctions, instead of IsJunctionNeeded() (see SCH_EDIT_FRAME::importFile())
2520  const SCH_COMPONENT* aComponent, const LIB_PIN* aPin ) const
2521 {
2522  wxPoint pinPosition = aComponent->GetPinPhysicalPosition( aPin );
2523  auto pointIt = m_connPoints.find( pinPosition );
2524 
2525  if( pointIt == m_connPoints.end() )
2526  return false;
2527 
2528  const auto& items = pointIt->second;
2529  wxASSERT( items.find( aPin ) != items.end() );
2530  return items.size() > 1;
2531 }
2532 
2533 
2535  SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet )
2536 {
2537  wxCHECK( aComponent->GetPartRef(), /*void*/ );
2538 
2539  // Normally power parts also have power input pins,
2540  // but they already force net names on the attached wires
2541  if( aComponent->GetPartRef()->IsPower() )
2542  return;
2543 
2544  int unit = aComponent->GetUnit();
2545  const wxString reference = aComponent->GetField( REFERENCE )->GetText();
2546  std::vector<LIB_PIN*> pins;
2547  aComponent->GetPartRef()->GetPins( pins );
2548  std::set<int> missingUnits;
2549 
2550  // Search all units for pins creating implicit connections
2551  for( const auto& pin : pins )
2552  {
2553  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
2554  {
2555  bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
2556 
2557  // Create a global net label only if there are no other wires/pins attached
2558  if( pinInUnit && !checkConnections( aComponent, pin ) )
2559  {
2560  // Create a net label to force the net name on the pin
2561  SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
2562  netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
2563  netLabel->SetText( extractNetName( pin->GetName() ) );
2564  netLabel->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) );
2566  aScreen->Append( netLabel );
2567  }
2568 
2569  else if( !pinInUnit && aUpdateSet )
2570  {
2571  // Found a pin creating implicit connection information in another unit.
2572  // Such units will be instantiated if they do not appear in another sheet and
2573  // processed later.
2574  wxASSERT( pin->GetUnit() );
2575  missingUnits.insert( pin->GetUnit() );
2576  }
2577  }
2578  }
2579 
2580  if( aUpdateSet )
2581  {
2582  auto cmpIt = m_missingCmps.find( reference );
2583 
2584  // Set the flag indicating this unit has been processed
2585  if( cmpIt != m_missingCmps.end() )
2586  cmpIt->second.units[unit] = false;
2587 
2588  // Save the units that need later processing
2589  else if( !missingUnits.empty() )
2590  {
2591  EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
2592  entry.cmp = aComponent;
2593 
2594  for( int i : missingUnits )
2595  entry.units.emplace( i, true );
2596  }
2597  }
2598 }
2599 
2600 
2601 wxString SCH_EAGLE_PLUGIN::fixSymbolName( const wxString& aName )
2602 {
2603  wxString ret = LIB_ID::FixIllegalChars( aName, LIB_ID::ID_SCH );
2604 
2605  return ret;
2606 }
2607 
2608 
2609 wxString SCH_EAGLE_PLUGIN::translateEagleBusName( const wxString& aEagleName ) const
2610 {
2611  if( SCH_CONNECTION::ParseBusVector( aEagleName, nullptr, nullptr ) )
2612  return aEagleName;
2613 
2614  wxString ret = "{";
2615 
2616  wxStringTokenizer tokenizer( aEagleName, "," );
2617 
2618  while( tokenizer.HasMoreTokens() )
2619  {
2620  wxString member = tokenizer.GetNextToken();
2621 
2622  // In Eagle, overbar text is automatically stopped at the end of the net name, even when
2623  // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
2624  // if there is an odd number of overbar markers in this net name, we need to append one
2625  // to close it out before appending the space.
2626 
2627  if( member.Freq( '!' ) % 2 > 0 )
2628  member << "!";
2629 
2630  ret << member << " ";
2631  }
2632 
2633  ret.Trim( true );
2634  ret << "}";
2635 
2636  return ret;
2637 }
wxString name
Eagle vertex.
Definition: eagle_parser.h:746
power input (GND, VCC for ICs). Must be connected to a power output.
wxString deviceset
Definition: eagle_parser.h:912
static const wxString & GetSymbolLibTableFileName()
bool IsBold() const
Definition: eda_text.h:182
Eagle Junction.
Definition: eagle_parser.h:530
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
bool mirror
Definition: eagle_parser.h:480
std::pair< VECTOR2I, const SEG * > findNearestLinePoint(const wxPoint &aPoint, const std::vector< SEG > &aLines) const
ECOORD x
Definition: eagle_parser.h:731
const wxString GetLibraryFileExtension() const override
Return the library file extension for the SCH_PLUGIN object.
std::unordered_map< wxString, wxXmlNode * > SymbolNodes
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
#define KI_FALLTHROUGH
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:199
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect.
int ToSchUnits() const
Definition: eagle_parser.h:437
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
wxPoint GetStartPoint() const
Definition: sch_line.h:94
void loadSchematic(wxXmlNode *aSchematicNode)
EAGLE_LIBRARY * loadLibrary(wxXmlNode *aLibraryNode, EAGLE_LIBRARY *aEagleLib)
int GetPenSizeForBold(int aTextSize)
Function GetPensizeForBold.
Definition: gr_text.cpp:51
COMPONENT_ORIENTATION_T
enum used in RotationMiroir()
Holds all the data relating to one schematic A schematic may consist of one or more sheets (and one r...
Definition: schematic.h:42
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:911
opt_wxString direction
Definition: eagle_parser.h:736
SCH_LINE * loadWire(wxXmlNode *aWireNode)
Define a symbol library graphical text item.
Definition: lib_text.h:40
std::unordered_map< wxString, wxString > package
const T & CGet() const
Function CGet returns a constant reference to the value of the attribute assuming it is available.
Definition: eagle_parser.h:311
bool checkConnections(const SCH_COMPONENT *aComponent, const LIB_PIN *aPin) const
Checks if there are other wires or pins at the position of the tested pin
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Function Intersect()
Definition: seg.cpp:93
const wxPoint GetPosition() const override
Definition: lib_text.h:84
T & Get()
Function Get returns a reference to the value of the attribute assuming it is available.
Definition: eagle_parser.h:300
int GetLeft() const
Definition: eda_rect.h:122
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
ECOORD y
Definition: eagle_parser.h:749
const SEG * LabelAttached(const SCH_TEXT *aLabel) const
Tests if a particular label is attached to any of the stored segments
Field object used in symbol libraries.
Definition: lib_field.h:59
ECOORD x2
Definition: eagle_parser.h:587
int GetModifyHash() const override
Return the modification hash from the library cache.
pin for passive components: 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:111
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:246
void SetVisible(bool aVisible)
Definition: eda_text.h:184
int GetWidth() const
Definition: eda_rect.h:119
opt_double ratio
Definition: eagle_parser.h:653
double GetTextAngle() const
Definition: eda_text.h:173
LIB_PART * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_PART having aName from the library given by aNickname.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
Definition: string.cpp:714
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:56
std::map< std::string, std::string > variant
Definition: eagle_parser.h:917
wxString PathAsString() const
Function PathAsString the path uses the time stamps which do not changes even when editing sheet para...
double degrees
Definition: eagle_parser.h:482
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
VECTOR2I Center() const
Returns the center point of the line
Definition: seg.h:350
static int countChildren(wxXmlNode *aCurrentNode, const wxString &aName)
Provides an easy access to the children of an XML node via their names.
ECOORD y
Definition: eagle_parser.h:573
static void eagleToKicadAlignment(EDA_TEXT *aText, int aEagleAlignment, int aRelDegress, bool aMirror, bool aSpin, int aAbsDegress)
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
SCH_TEXT * loadPlainText(wxXmlNode *aSchText)
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:282
LIB_RECTANGLE * loadSymbolRectangle(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aRectNode, int aGateNumber)
Eagle text element.
Definition: eagle_parser.h:645
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
NODE_MAP MapChildren(wxXmlNode *aCurrentNode)
Function MapChildren provides an easy access to the children of an XML node via their names.
ECOORD width
Definition: eagle_parser.h:575
ECOORD x
Definition: eagle_parser.h:572
Eagle pin element.
Definition: eagle_parser.h:728
The base class for drawable items used by schematic library components.
Definition: lib_item.h:61
Eagle label.
Definition: eagle_parser.h:540
opt_wxString value
Definition: eagle_parser.h:915
This file contains miscellaneous commonly used macros and functions.
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:98
int GetBottom() const
Definition: eda_rect.h:124
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parses a bus vector (e.g.
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
SCH_JUNCTION * loadJunction(wxXmlNode *aJunction)
#define IS_NEW
New item, just created.
Definition: base_struct.h:117
void SetNumber(const wxString &aNumber)
Set the pin number.
Definition: lib_pin.cpp:249
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:112
wxString name
LIB_PIN * loadPin(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *, EPIN *epin, int aGateNumber)
static wxString fixSymbolName(const wxString &aName)
Fixes invalid characters in Eagle symbol names.
SCH_LAYER_ID kiCadLayer(int aEagleLayer)
Return the matching layer or return LAYER_NOTES.
#define VALUE
int GetUnit() const
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
bool CheckHeader(const wxString &aFileName) override
Return true if the first line in aFileName begins with the expected header.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:232
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:198
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:116
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:78
#define NULL
void adjustNetLabels()
Moves net labels that are detached from any wire to the nearest wire
LIB_CIRCLE * loadSymbolCircle(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aCircleNode, int aGateNumber)
const wxPoint GetPosition() const override
Definition: sch_text.h:313
void addImplicitConnections(SCH_COMPONENT *aComponent, SCH_SCREEN *aScreen, bool aUpdateSet)
Creates net labels to emulate implicit connections in Eagle.
PAGE_INFO describes the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
Class LIB_PIN definition.
ECOORD y1
Definition: eagle_parser.h:586
const wxSize & GetTextSize() const
Definition: eda_text.h:238
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:202
void SetStartPoint(const wxPoint &aPosition)
Definition: sch_line.h:95
SCH_SHEET * Load(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=NULL, const PROPERTIES *aProperties=NULL) override
Load information from some input file format that this SCH_PLUGIN implementation knows about,...
Eagle circle.
Definition: eagle_parser.h:570
opt_wxString function
Definition: eagle_parser.h:737
wxString symbol
Definition: eagle_parser.h:963
SCH_TEXT * loadLabel(wxXmlNode *aLabelNode, const wxString &aNetName)
bool loadSymbol(wxXmlNode *aSymbolNode, std::unique_ptr< LIB_PART > &aPart, EDEVICE *aDevice, int aGateNumber, const wxString &aGateName)
Define a library symbol object.
Definition of file extensions used in Kicad.
ECOORD x
Definition: eagle_parser.h:648
void loadSegments(wxXmlNode *aSegmentsNode, const wxString &aNetName, const wxString &aNetClass)
wxFileName getLibFileName()
std::map< std::string, std::string > attribute
Definition: eagle_parser.h:916
#define THROW_IO_ERROR(msg)
wxSize ConvertSize() const
Calculate text size based on font type and size.
SCH_LAYER_ID
Eeschema drawing layers.
SCH_SHEET_PATH.
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indention level of aIndentLevel.
std::unique_ptr< LIB_PART > & GetPartRef()
LIB_ITEM * loadSymbolWire(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aWireNode, int aGateNumber)
wxString name
Definition: eagle_parser.h:962
Eagle XML rectangle in binary.
Definition: eagle_parser.h:583
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
opt_int align
Definition: eagle_parser.h:670
int GetHeight() const
Definition: eda_rect.h:120
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:216
void addBusEntries()
This function finds best way to place a bus entry symbol for when an Eagle wire segment ends on an Ea...
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:271
std::unordered_map< wxString, int > GateUnit
void loadLayerDefs(wxXmlNode *aLayers)
static EDA_RECT getSheetBbox(SCH_SHEET *aSheet)
Computes a bounding box for all items in a schematic sheet
void loadInstance(wxXmlNode *aInstanceNode)
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
Definition: seg.h:39
const SCH_COMPONENT * cmp
Link to the parent component
opt_wxString prefix
EATTR parses an Eagle "attribute" XML element.
Definition: eagle_parser.h:602
VECTOR2< T > Resize(T aNewLength) const
Function Resize returns a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:392
static COMPONENT_ORIENTATION_T kiCadComponentRotation(float eagleDegrees)
ECOORD x1
Definition: eagle_parser.h:585
static ERC_ITEM * Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:144
void loadFieldAttributes(LIB_FIELD *aField, const LIB_TEXT *aText) const
SCH_SHEET & Root() const
Definition: schematic.h:97
opt_erot rot
Definition: eagle_parser.h:654
void loadTextAttributes(EDA_TEXT *aText, const ETEXT &aAttribs) const
void loadDrawing(wxXmlNode *aDrawingNode)
int GetTextWidth() const
Definition: eda_text.h:241
wxString translateEagleBusName(const wxString &aEagleName) const
Translates an Eagle-style bus name into one that is KiCad-compatible.
const char * name
Definition: DXF_plotter.cpp:60
ECOORD x
Definition: eagle_parser.h:748
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
bool Replace(wxFindReplaceData &aSearchData, void *aAuxData=NULL) override
Function Replace performs a text replace using the find and replace criteria in aSearchData on items ...
Definition: sch_field.cpp:360
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:133
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:201
#define _(s)
Definition: 3d_actions.cpp:33
usual pin input: must be connected
wxPoint ConvertArcCenter(const wxPoint &aStart, const wxPoint &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC
const wxString GetName() const override
Returns a brief hard coded name for this SCH_PLUGIN.
std::vector< LIB_FIELD > LIB_FIELDS
Definition: lib_field.h:218
ECOORD radius
Definition: eagle_parser.h:574
EE_RTREE & Items()
Definition: sch_screen.h:162
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
std::vector< ECONNECT > connects
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
Schematic symbol object.
Definition: sch_component.h:88
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:68
int GetY() const
Definition: eda_rect.h:112
void moveLabels(SCH_ITEM *aWire, const wxPoint &aNewEndPoint)
Moves any labels on the wire to the new end point of the wire.
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
static const std::map< wxString, ELECTRICAL_PINTYPE > pinDirectionsMap
Map of EAGLE pin type values to KiCad pin type values.
wxPoint Centre() const
Definition: eda_rect.h:62
static wxString extractNetName(const wxString &aPinName)
Extracts the net name part from a pin name (e.g. return 'GND' for pin named 'GND@2')
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:352
std::vector< SCH_TEXT * > labels
LIB_TEXT * loadSymbolText(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aLibText, int aGateNumber)
FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
static bool GetLayer(MODEL_VRML &aModel, LAYER_NUM layer, VRML_LAYER **vlayer)
Eagle wire.
Definition: eagle_parser.h:499
Class for a wire to bus entry.
Wires and labels of a single connection (segment in Eagle nomenclature)
ECOORD y
Definition: eagle_parser.h:732
wxString name
Definition: eagle_parser.h:730
void SetErrorMessage(const wxString &aMessage)
Definition: rc_item.h:117
opt_wxString package
input or output (like port for a microprocessor)
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:157
bool spin
Definition: eagle_parser.h:481
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:166
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:898
ECOORD y2
Definition: eagle_parser.h:588
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:187
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: base_struct.cpp:95
Definition for part library class.
ECOORD y
Definition: eagle_parser.h:649
Eagle polygon, without vertices which are parsed as needed.
Definition: eagle_parser.h:757
void countNets(wxXmlNode *aSchematicNode)
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
not connected (must be left open)
const wxString GetFileExtension() const override
Returns the file extension for the SCH_PLUGIN.
void loadSheet(wxXmlNode *aSheetNode, int sheetcount)
wxString device
Definition: eagle_parser.h:913
void SetPosition(const wxPoint &aPosition) override
Set the schematic item position to aPosition.
Definition: sch_text.h:314
boost::ptr_map< wxString, LIB_PART > KiCadSymbols
wxPoint GetPinPhysicalPosition(const LIB_PIN *Pin) const
void SetBold(bool aBold)
Definition: eda_text.h:181
void SetPosition(const wxPoint &aPosition) override
Set the schematic item position to aPosition.
Definition: sch_field.cpp:558
opt_wxString visible
Definition: eagle_parser.h:734
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:186
opt_wxString length
Definition: eagle_parser.h:735
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:48
static wxXmlNode * getChildrenNodes(NODE_MAP &aMap, const wxString &aName)
Definition: eagle_parser.h:58
LIB_POLYLINE * loadSymbolPolyLine(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aPolygonNode, int aGateNumber)
const wxSize GetSize() const
Definition: eda_rect.h:103
const std::string KiCadSymbolLibFileExtension
opt_erot rot
Definition: eagle_parser.h:739
VECTOR2I B
Definition: seg.h:48
wxPoint GetEndPoint() const
Definition: sch_line.h:97