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 <project/net_settings.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->SetUnit( aGateNumber );
1453  pin->SetName( escapeName( pin->GetName() ) );
1454 
1455  if( pads.GetCount() > 1 )
1456  {
1457  pin->SetNumberTextSize( 0 );
1458  }
1459 
1460  // Eagle does not connect multiple NC pins together when they are stacked.
1461  // KiCad will do this for pins that are coincident. We opt here for correct
1462  // schematic netlist and leave out the multiple NC pins when stacked.
1463  for( unsigned i = 0; i < pads.GetCount(); i++ )
1464  {
1465  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC && i > 0 )
1466  break;
1467 
1468  LIB_PIN* apin = new LIB_PIN( *pin );
1469 
1470  wxString padname( pads[i] );
1471  apin->SetNumber( padname );
1472  aPart->AddDrawItem( apin );
1473  }
1474 
1475  break;
1476  }
1477  }
1478  }
1479  else
1480  {
1481  pin->SetUnit( aGateNumber );
1482  pin->SetNumber( wxString::Format( "%i", pincount ) );
1483  aPart->AddDrawItem( pin.release() );
1484  }
1485  }
1486  else if( nodeName == "polygon" )
1487  {
1488  aPart->AddDrawItem( loadSymbolPolyLine( aPart, currentNode, aGateNumber ) );
1489  }
1490  else if( nodeName == "rectangle" )
1491  {
1492  aPart->AddDrawItem( loadSymbolRectangle( aPart, currentNode, aGateNumber ) );
1493  }
1494  else if( nodeName == "text" )
1495  {
1496  std::unique_ptr<LIB_TEXT> libtext( loadSymbolText( aPart, currentNode, aGateNumber ) );
1497 
1498  if( libtext->GetText().Upper() == ">NAME" )
1499  {
1500  LIB_FIELD* field = aPart->GetField( REFERENCE );
1501  loadFieldAttributes( field, libtext.get() );
1502  foundName = true;
1503  }
1504  else if( libtext->GetText().Upper() == ">VALUE" )
1505  {
1506  LIB_FIELD* field = aPart->GetField( VALUE );
1507  loadFieldAttributes( field, libtext.get() );
1508  foundValue = true;
1509  }
1510  else
1511  {
1512  aPart->AddDrawItem( libtext.release() );
1513  }
1514  }
1515  else if( nodeName == "wire" )
1516  {
1517  aPart->AddDrawItem( loadSymbolWire( aPart, currentNode, aGateNumber ) );
1518  }
1519 
1520  /*
1521  * else if( nodeName == "description" )
1522  * {
1523  * }
1524  * else if( nodeName == "dimension" )
1525  * {
1526  * }
1527  * else if( nodeName == "frame" )
1528  * {
1529  * }
1530  */
1531 
1532  currentNode = currentNode->GetNext();
1533  }
1534 
1535  if( foundName == false )
1536  aPart->GetField( REFERENCE )->SetVisible( false );
1537 
1538  if( foundValue == false )
1539  aPart->GetField( VALUE )->SetVisible( false );
1540 
1541  return pincount == 1 ? ispower : false;
1542 }
1543 
1544 
1546  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aCircleNode, int aGateNumber )
1547 {
1548  // Parse the circle properties
1549  ECIRCLE c( aCircleNode );
1550 
1551  unique_ptr<LIB_CIRCLE> circle( new LIB_CIRCLE( aPart.get() ) );
1552 
1553  circle->SetPosition( wxPoint( c.x.ToSchUnits(), c.y.ToSchUnits() ) );
1554  circle->SetRadius( c.radius.ToSchUnits() );
1555  circle->SetWidth( c.width.ToSchUnits() );
1556  circle->SetUnit( aGateNumber );
1557 
1558  return circle.release();
1559 }
1560 
1561 
1563  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aRectNode, int aGateNumber )
1564 {
1565  ERECT rect( aRectNode );
1566 
1567  unique_ptr<LIB_RECTANGLE> rectangle( new LIB_RECTANGLE( aPart.get() ) );
1568 
1569  rectangle->SetPosition( wxPoint( rect.x1.ToSchUnits(), rect.y1.ToSchUnits() ) );
1570  rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
1571 
1572  rectangle->SetUnit( aGateNumber );
1573  // Eagle rectangles are filled by definition.
1574  rectangle->SetFillMode( FILLED_SHAPE );
1575 
1576  return rectangle.release();
1577 }
1578 
1579 
1581  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aWireNode, int aGateNumber )
1582 {
1583  auto ewire = EWIRE( aWireNode );
1584 
1585  wxPoint begin, end;
1586 
1587  begin.x = ewire.x1.ToSchUnits();
1588  begin.y = ewire.y1.ToSchUnits();
1589  end.x = ewire.x2.ToSchUnits();
1590  end.y = ewire.y2.ToSchUnits();
1591 
1592  if( begin == end )
1593  return nullptr;
1594 
1595  // if the wire is an arc
1596  if( ewire.curve )
1597  {
1598  std::unique_ptr<LIB_ARC> arc( new LIB_ARC( aPart.get() ) );
1599  wxPoint center = ConvertArcCenter( begin, end, *ewire.curve * -1 );
1600 
1601  double radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1602  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) )
1603  * 2;
1604 
1605  // this emulates the filled semicircles created by a thick arc with flat ends caps.
1606  if( ewire.width.ToSchUnits() * 2 > radius )
1607  {
1608  wxPoint centerStartVector = begin - center;
1609  wxPoint centerEndVector = end - center;
1610 
1611  centerStartVector.x = centerStartVector.x * ewire.width.ToSchUnits() * 2 / radius;
1612  centerStartVector.y = centerStartVector.y * ewire.width.ToSchUnits() * 2 / radius;
1613 
1614  centerEndVector.x = centerEndVector.x * ewire.width.ToSchUnits() * 2 / radius;
1615  centerEndVector.y = centerEndVector.y * ewire.width.ToSchUnits() * 2 / radius;
1616 
1617  begin = center + centerStartVector;
1618  end = center + centerEndVector;
1619 
1620  radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1621  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) )
1622  * 2;
1623 
1624  arc->SetWidth( 1 );
1625  arc->SetFillMode( FILLED_SHAPE );
1626  }
1627  else
1628  {
1629  arc->SetWidth( ewire.width.ToSchUnits() );
1630  }
1631 
1632  arc->SetPosition( center );
1633 
1634  if( *ewire.curve > 0 )
1635  {
1636  arc->SetStart( begin );
1637  arc->SetEnd( end );
1638  }
1639  else
1640  {
1641  arc->SetStart( end );
1642  arc->SetEnd( begin );
1643  }
1644 
1645  arc->SetRadius( radius );
1646  arc->CalcRadiusAngles();
1647  arc->SetUnit( aGateNumber );
1648 
1649  return (LIB_ITEM*) arc.release();
1650  }
1651  else
1652  {
1653  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1654 
1655  polyLine->AddPoint( begin );
1656  polyLine->AddPoint( end );
1657  polyLine->SetUnit( aGateNumber );
1658  polyLine->SetWidth( ewire.width.ToSchUnits() );
1659 
1660  return (LIB_ITEM*) polyLine.release();
1661  }
1662 }
1663 
1664 
1666  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aPolygonNode, int aGateNumber )
1667 {
1668  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1669 
1670  EPOLYGON epoly( aPolygonNode );
1671  wxXmlNode* vertex = aPolygonNode->GetChildren();
1672 
1673 
1674  wxPoint pt;
1675 
1676  while( vertex )
1677  {
1678  if( vertex->GetName() == "vertex" ) // skip <xmlattr> node
1679  {
1680  EVERTEX evertex( vertex );
1681  pt = wxPoint( evertex.x.ToSchUnits(), evertex.y.ToSchUnits() );
1682  polyLine->AddPoint( pt );
1683  }
1684 
1685  vertex = vertex->GetNext();
1686  }
1687 
1688  polyLine->SetFillMode( FILLED_SHAPE );
1689  polyLine->SetUnit( aGateNumber );
1690 
1691  return polyLine.release();
1692 }
1693 
1694 
1696  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aPin, EPIN* aEPin, int aGateNumber )
1697 {
1698  std::unique_ptr<LIB_PIN> pin( new LIB_PIN( aPart.get() ) );
1699  pin->SetPosition( wxPoint( aEPin->x.ToSchUnits(), aEPin->y.ToSchUnits() ) );
1700  pin->SetName( aEPin->name );
1701  pin->SetUnit( aGateNumber );
1702 
1703  int roti = aEPin->rot ? aEPin->rot->degrees : 0;
1704 
1705  switch( roti )
1706  {
1707  default:
1708  wxASSERT_MSG( false, wxString::Format( "Unhandled orientation (%d degrees)", roti ) );
1710 
1711  case 0:
1712  pin->SetOrientation( 'R' );
1713  break;
1714 
1715  case 90:
1716  pin->SetOrientation( 'U' );
1717  break;
1718 
1719  case 180:
1720  pin->SetOrientation( 'L' );
1721  break;
1722 
1723  case 270:
1724  pin->SetOrientation( 'D' );
1725  break;
1726  }
1727 
1728  if( aEPin->length )
1729  {
1730  wxString length = aEPin->length.Get();
1731 
1732  if( length == "short" )
1733  {
1734  pin->SetLength( Mils2iu( 100 ) );
1735  }
1736  else if( length == "middle" )
1737  {
1738  pin->SetLength( Mils2iu( 200 ) );
1739  }
1740  else if( length == "long" )
1741  {
1742  pin->SetLength( Mils2iu( 300 ) );
1743  }
1744  else if( length == "point" )
1745  {
1746  pin->SetLength( Mils2iu( 0 ) );
1747  }
1748  }
1749 
1750  // emulate the visibility of pin elements
1751  if( aEPin->visible )
1752  {
1753  wxString visible = aEPin->visible.Get();
1754 
1755  if( visible == "off" )
1756  {
1757  pin->SetNameTextSize( 0 );
1758  pin->SetNumberTextSize( 0 );
1759  }
1760  else if( visible == "pad" )
1761  {
1762  pin->SetNameTextSize( 0 );
1763  }
1764  else if( visible == "pin" )
1765  {
1766  pin->SetNumberTextSize( 0 );
1767  }
1768 
1769  /*
1770  * else if( visible == "both" )
1771  * {
1772  * }
1773  */
1774  }
1775 
1776  if( aEPin->function )
1777  {
1778  wxString function = aEPin->function.Get();
1779 
1780  if( function == "dot" )
1781  {
1782  pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
1783  }
1784  else if( function == "clk" )
1785  {
1786  pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
1787  }
1788  else if( function == "dotclk" )
1789  {
1790  pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
1791  }
1792  }
1793 
1794  return pin.release();
1795 }
1796 
1797 
1799  std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText, int aGateNumber )
1800 {
1801  std::unique_ptr<LIB_TEXT> libtext( new LIB_TEXT( aPart.get() ) );
1802  ETEXT etext( aLibText );
1803 
1804  libtext->SetUnit( aGateNumber );
1805  libtext->SetPosition( wxPoint( etext.x.ToSchUnits(), etext.y.ToSchUnits() ) );
1806 
1807  // Eagle supports multiple line text in library symbols. Legacy library symbol text cannot
1808  // contain CRs or LFs.
1809  //
1810  // @todo Split this into multiple text objects and offset the Y position so that it looks
1811  // more like the original Eagle schematic.
1812  wxString text = aLibText->GetNodeContent();
1813  std::replace( text.begin(), text.end(), '\n', '_' );
1814  std::replace( text.begin(), text.end(), '\r', '_' );
1815 
1816  libtext->SetText( text.IsEmpty() ? "~~" : text );
1817  loadTextAttributes( libtext.get(), etext );
1818 
1819  return libtext.release();
1820 }
1821 
1822 
1824 {
1825  std::unique_ptr<SCH_TEXT> schtext( new SCH_TEXT() );
1826  ETEXT etext = ETEXT( aSchText );
1827 
1828  const wxString& thetext = aSchText->GetNodeContent();
1829  schtext->SetText( thetext.IsEmpty() ? "\" \"" : escapeName( thetext ) );
1830  schtext->SetPosition( wxPoint( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
1831  loadTextAttributes( schtext.get(), etext );
1832  schtext->SetItalic( false );
1833 
1834  return schtext.release();
1835 }
1836 
1837 
1838 void SCH_EAGLE_PLUGIN::loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const
1839 {
1840  aText->SetTextSize( aAttribs.ConvertSize() );
1841 
1842  if( aAttribs.ratio )
1843  {
1844  if( aAttribs.ratio.CGet() > 12 )
1845  {
1846  aText->SetBold( true );
1847  aText->SetTextThickness( GetPenSizeForBold( aText->GetTextWidth() ) );
1848  }
1849  }
1850 
1851  int align = aAttribs.align ? *aAttribs.align : ETEXT::BOTTOM_LEFT;
1852  int degrees = aAttribs.rot ? aAttribs.rot->degrees : 0;
1853  bool mirror = aAttribs.rot ? aAttribs.rot->mirror : false;
1854  bool spin = aAttribs.rot ? aAttribs.rot->spin : false;
1855 
1856  eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
1857 }
1858 
1859 
1860 void SCH_EAGLE_PLUGIN::loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const
1861 {
1862  aField->SetTextPos( aText->GetPosition() );
1863  aField->SetTextSize( aText->GetTextSize() );
1864  aField->SetTextAngle( aText->GetTextAngle() );
1865  aField->SetBold( aText->IsBold() );
1866  aField->SetVertJustify( aText->GetVertJustify() );
1867  aField->SetHorizJustify( aText->GetHorizJustify() );
1868  aField->SetVisible( true );
1869 }
1870 
1871 
1873 {
1874  // Eagle supports detached labels, so a label does not need to be placed on a wire
1875  // to be associated with it. KiCad needs to move them, so the labels actually touch the
1876  // corresponding wires.
1877 
1878  // Sort the intersection points to speed up the search process
1879  std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
1880 
1881  auto onIntersection = [&]( const VECTOR2I& aPos ) {
1882  return std::binary_search( m_wireIntersections.begin(), m_wireIntersections.end(), aPos );
1883  };
1884 
1885  for( auto& segDesc : m_segments )
1886  {
1887  for( SCH_TEXT* label : segDesc.labels )
1888  {
1889  VECTOR2I labelPos( label->GetPosition() );
1890  const SEG* segAttached = segDesc.LabelAttached( label );
1891 
1892  if( segAttached && !onIntersection( labelPos ) )
1893  continue; // label is placed correctly
1894 
1895 
1896  // Move the label to the nearest wire
1897  if( !segAttached )
1898  {
1899  std::tie( labelPos, segAttached ) =
1900  findNearestLinePoint( label->GetPosition(), segDesc.segs );
1901 
1902  if( !segAttached ) // we cannot do anything
1903  continue;
1904  }
1905 
1906 
1907  // Create a vector pointing in the direction of the wire, 50 mils long
1908  VECTOR2I wireDirection( segAttached->B - segAttached->A );
1909  wireDirection = wireDirection.Resize( Mils2iu( 50 ) );
1910  const VECTOR2I origPos( labelPos );
1911 
1912  // Flags determining the search direction
1913  bool checkPositive = true, checkNegative = true, move = false;
1914  int trial = 0;
1915 
1916  // Be sure the label is not placed on a wire intersection
1917  while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
1918  {
1919  move = false;
1920 
1921  // Move along the attached wire to find the new label position
1922  if( trial % 2 == 1 )
1923  {
1924  labelPos = wxPoint( origPos + wireDirection * trial / 2 );
1925  move = checkPositive = segAttached->Contains( labelPos );
1926  }
1927  else
1928  {
1929  labelPos = wxPoint( origPos - wireDirection * trial / 2 );
1930  move = checkNegative = segAttached->Contains( labelPos );
1931  }
1932 
1933  ++trial;
1934  }
1935 
1936  if( move )
1937  label->SetPosition( wxPoint( labelPos ) );
1938  }
1939  }
1940 
1941  m_segments.clear();
1942  m_wireIntersections.clear();
1943 }
1944 
1945 
1946 bool SCH_EAGLE_PLUGIN::CheckHeader( const wxString& aFileName )
1947 {
1948  // Open file and check first line
1949  wxTextFile tempFile;
1950 
1951  tempFile.Open( aFileName );
1952  wxString firstline;
1953  // read the first line
1954  firstline = tempFile.GetFirstLine();
1955  wxString secondline = tempFile.GetNextLine();
1956  wxString thirdline = tempFile.GetNextLine();
1957  tempFile.Close();
1958 
1959  return firstline.StartsWith( "<?xml" ) && secondline.StartsWith( "<!DOCTYPE eagle SYSTEM" )
1960  && thirdline.StartsWith( "<eagle version" );
1961 }
1962 
1963 
1964 void SCH_EAGLE_PLUGIN::moveLabels( SCH_ITEM* aWire, const wxPoint& aNewEndPoint )
1965 {
1966  for( auto item : m_currentSheet->GetScreen()->Items().Overlapping( aWire->GetBoundingBox() ) )
1967  {
1968  if( item->Type() == SCH_LABEL_T || item->Type() == SCH_GLOBAL_LABEL_T )
1969  {
1970  if( TestSegmentHit( item->GetPosition(), ( (SCH_LINE*) aWire )->GetStartPoint(),
1971  ( (SCH_LINE*) aWire )->GetEndPoint(), 0 ) )
1972  {
1973  item->SetPosition( aNewEndPoint );
1974  }
1975  }
1976  }
1977 }
1978 
1979 
1981 {
1982  // Add bus entry symbols
1983  // TODO: Cleanup this function and break into pieces
1984 
1985  // for each wire segment, compare each end with all busess.
1986  // If the wire end is found to end on a bus segment, place a bus entry symbol.
1987 
1988  for( auto it1 = m_currentSheet->GetScreen()->Items().OfType( SCH_LINE_T ).begin();
1989  it1 != m_currentSheet->GetScreen()->Items().end(); ++it1 )
1990  {
1991  SCH_LINE* bus = static_cast<SCH_LINE*>( *it1 );
1992 
1993  // Check line type for wire
1994  if( bus->GetLayer() != LAYER_BUS )
1995  continue;
1996 
1997 
1998  wxPoint busstart = bus->GetStartPoint();
1999  wxPoint busend = bus->GetEndPoint();
2000 
2001  auto it2 = it1;
2002  ++it2;
2003  for( ; it2 != m_currentSheet->GetScreen()->Items().end(); ++it2 )
2004  {
2005  SCH_LINE* line = static_cast<SCH_LINE*>( *it2 );
2006 
2007  // Check line type for bus
2008  if( ( (SCH_LINE*) *it2 )->GetLayer() == LAYER_WIRE )
2009  {
2010  // Get points of both segments.
2011  wxPoint linestart = line->GetStartPoint();
2012  wxPoint lineend = line->GetEndPoint();
2013 
2014  // Test for horizontal wire and vertical bus
2015  if( linestart.y == lineend.y && busstart.x == busend.x )
2016  {
2017  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2018  {
2019  // Wire start is on a bus.
2020  // Wire start is on the vertical bus
2021 
2022  // if the end of the wire is to the left of the bus
2023  if( lineend.x < busstart.x )
2024  {
2025  // |
2026  // ---|
2027  // |
2028  if( TestSegmentHit(
2029  linestart + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2030  {
2031  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2032  linestart + wxPoint( -100, 0 ), true );
2033  busEntry->SetFlags( IS_NEW );
2034  m_currentSheet->GetScreen()->Append( busEntry );
2035  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2036  line->SetStartPoint( linestart + wxPoint( -100, 0 ) );
2037  }
2038  else if( TestSegmentHit(
2039  linestart + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2040  {
2041  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2042  linestart + wxPoint( -100, 0 ), false );
2043  busEntry->SetFlags( IS_NEW );
2044  m_currentSheet->GetScreen()->Append( busEntry );
2045  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2046  line->SetStartPoint( linestart + wxPoint( -100, 0 ) );
2047  }
2048  else
2049  {
2050  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2051  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2052 
2053  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2054  m_currentSheet->GetScreen()->Append( marker );
2055  }
2056  }
2057  // else the wire end is to the right of the bus
2058  // Wire is to the right of the bus
2059  // |
2060  // |----
2061  // |
2062  else
2063  {
2064  // test is bus exists above the wire
2065  if( TestSegmentHit(
2066  linestart + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2067  {
2068  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2069  linestart + wxPoint( 0, -100 ), false );
2070  busEntry->SetFlags( IS_NEW );
2071  m_currentSheet->GetScreen()->Append( busEntry );
2072  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2073  line->SetStartPoint( linestart + wxPoint( 100, 0 ) );
2074  }
2075  // test is bus exists below the wire
2076  else if( TestSegmentHit(
2077  linestart + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2078  {
2079  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2080  linestart + wxPoint( 0, 100 ), true );
2081  busEntry->SetFlags( IS_NEW );
2082  m_currentSheet->GetScreen()->Append( busEntry );
2083  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2084  line->SetStartPoint( linestart + wxPoint( 100, 0 ) );
2085  }
2086  else
2087  {
2088  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2089  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2090 
2091  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2092  m_currentSheet->GetScreen()->Append( marker );
2093  }
2094  }
2095  }
2096 
2097  // Same thing but test end of the wire instead.
2098  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2099  {
2100  // Wire end is on the vertical bus
2101 
2102  // if the start of the wire is to the left of the bus
2103  if( linestart.x < busstart.x )
2104  {
2105  // Test if bus exists above the wire
2106  if( TestSegmentHit( lineend + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2107  {
2108  // |
2109  // ___/|
2110  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2111  lineend + wxPoint( -100, 0 ), false );
2112  busEntry->SetFlags( IS_NEW );
2113  m_currentSheet->GetScreen()->Append( busEntry );
2114  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2115  line->SetEndPoint( lineend + wxPoint( -100, 0 ) );
2116  }
2117  // Test if bus exists below the wire
2118  else if( TestSegmentHit(
2119  lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2120  {
2121  SCH_BUS_WIRE_ENTRY* busEntry =
2122  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true );
2123  busEntry->SetFlags( IS_NEW );
2124  m_currentSheet->GetScreen()->Append( busEntry );
2125  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2126  line->SetEndPoint( lineend + wxPoint( -100, 0 ) );
2127  }
2128  else
2129  {
2130  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2131  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2132 
2133  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2134  m_currentSheet->GetScreen()->Append( marker );
2135  }
2136  }
2137  // else the start of the wire is to the right of the bus
2138  // |
2139  // |----
2140  // |
2141  else
2142  {
2143  // test if bus existed above the wire
2144  if( TestSegmentHit(
2145  lineend + wxPoint( 0, -100 ), busstart, busend, 0 ) )
2146  {
2147  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2148  lineend + wxPoint( 0, -100 ), false );
2149  busEntry->SetFlags( IS_NEW );
2150  m_currentSheet->GetScreen()->Append( busEntry );
2151  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2152  line->SetEndPoint( lineend + wxPoint( 100, 0 ) );
2153  }
2154  // test if bus existed below the wire
2155  else if( TestSegmentHit(
2156  lineend + wxPoint( 0, 100 ), busstart, busend, 0 ) )
2157  {
2158  SCH_BUS_WIRE_ENTRY* busEntry =
2159  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( 0, 100 ), true );
2160  busEntry->SetFlags( IS_NEW );
2161  m_currentSheet->GetScreen()->Append( busEntry );
2162  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2163  line->SetEndPoint( lineend + wxPoint( 100, 0 ) );
2164  }
2165  else
2166  {
2167  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2168  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2169 
2170  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2171  m_currentSheet->GetScreen()->Append( marker );
2172  }
2173  }
2174  }
2175  } // if( linestart.y == lineend.y && busstart.x == busend.x)
2176 
2177  // Test for horizontal wire and vertical bus
2178  if( linestart.x == lineend.x && busstart.y == busend.y )
2179  {
2180  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2181  {
2182  // Wire start is on the bus
2183  // If wire end is above the bus,
2184  if( lineend.y < busstart.y )
2185  {
2186  // Test for bus existance to the left of the wire
2187  if( TestSegmentHit(
2188  linestart + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2189  {
2190  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2191  linestart + wxPoint( -100, 0 ), true );
2192  busEntry->SetFlags( IS_NEW );
2193  m_currentSheet->GetScreen()->Append( busEntry );
2194  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2195  line->SetStartPoint( linestart + wxPoint( 0, -100 ) );
2196  }
2197  else if( TestSegmentHit(
2198  linestart + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2199  {
2200  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2201  linestart + wxPoint( 0, 100 ), false );
2202  busEntry->SetFlags( IS_NEW );
2203  m_currentSheet->GetScreen()->Append( busEntry );
2204  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2205  line->SetStartPoint( linestart + wxPoint( 0, -100 ) );
2206  }
2207  else
2208  {
2209  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2210  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2211 
2212  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2213  m_currentSheet->GetScreen()->Append( marker );
2214  }
2215  }
2216  else // wire end is below the bus.
2217  {
2218  // Test for bus existance to the left of the wire
2219  if( TestSegmentHit(
2220  linestart + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2221  {
2222  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2223  linestart + wxPoint( -100, 0 ), false );
2224  busEntry->SetFlags( IS_NEW );
2225  m_currentSheet->GetScreen()->Append( busEntry );
2226  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2227  line->SetStartPoint( linestart + wxPoint( 0, 100 ) );
2228  }
2229  else if( TestSegmentHit(
2230  linestart + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2231  {
2232  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2233  linestart + wxPoint( 100, 0 ), true );
2234  busEntry->SetFlags( IS_NEW );
2235  m_currentSheet->GetScreen()->Append( busEntry );
2236  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2237  line->SetStartPoint( linestart + wxPoint( 0, 100 ) );
2238  }
2239  else
2240  {
2241  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2242  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2243 
2244  SCH_MARKER* marker = new SCH_MARKER( ercItem, linestart );
2245  m_currentSheet->GetScreen()->Append( marker );
2246  }
2247  }
2248  }
2249 
2250  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2251  {
2252  // Wire end is on the bus
2253  // If wire start is above the bus,
2254 
2255  if( linestart.y < busstart.y )
2256  {
2257  // Test for bus existance to the left of the wire
2258  if( TestSegmentHit(
2259  lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2260  {
2261  SCH_BUS_WIRE_ENTRY* busEntry =
2262  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( -100, 0 ), true );
2263  busEntry->SetFlags( IS_NEW );
2264  m_currentSheet->GetScreen()->Append( busEntry );
2265  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2266  line->SetEndPoint( lineend + wxPoint( 0, -100 ) );
2267  }
2268  else if( TestSegmentHit(
2269  lineend + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2270  {
2271  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2272  lineend + wxPoint( 0, -100 ), false );
2273  busEntry->SetFlags( IS_NEW );
2274  m_currentSheet->GetScreen()->Append( busEntry );
2275  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2276  line->SetEndPoint( lineend + wxPoint( 0, -100 ) );
2277  }
2278  else
2279  {
2280  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2281  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2282 
2283  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2284  m_currentSheet->GetScreen()->Append( marker );
2285  }
2286  }
2287  else // wire end is below the bus.
2288  {
2289  // Test for bus existance to the left of the wire
2290  if( TestSegmentHit(
2291  lineend + wxPoint( -100, 0 ), busstart, busend, 0 ) )
2292  {
2293  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY(
2294  lineend + wxPoint( -100, 0 ), false );
2295  busEntry->SetFlags( IS_NEW );
2296  m_currentSheet->GetScreen()->Append( busEntry );
2297  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2298  line->SetEndPoint( lineend + wxPoint( 0, 100 ) );
2299  }
2300  else if( TestSegmentHit(
2301  lineend + wxPoint( 100, 0 ), busstart, busend, 0 ) )
2302  {
2303  SCH_BUS_WIRE_ENTRY* busEntry =
2304  new SCH_BUS_WIRE_ENTRY( lineend + wxPoint( 0, 100 ), true );
2305  busEntry->SetFlags( IS_NEW );
2306  m_currentSheet->GetScreen()->Append( busEntry );
2307  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2308  line->SetEndPoint( lineend + wxPoint( 0, 100 ) );
2309  }
2310  else
2311  {
2312  ERC_ITEM* ercItem = ERC_ITEM::Create( 0 );
2313  ercItem->SetErrorMessage( _( "Bus Entry needed" ) );
2314 
2315  SCH_MARKER* marker = new SCH_MARKER( ercItem, lineend );
2316  m_currentSheet->GetScreen()->Append( marker );
2317  }
2318  }
2319  }
2320  }
2321 
2322  linestart = line->GetStartPoint();
2323  lineend = line->GetEndPoint();
2324  busstart = bus->GetStartPoint();
2325  busend = bus->GetEndPoint();
2326 
2327  // bus entry wire isn't horizontal or vertical
2328  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2329  {
2330  wxPoint wirevector = linestart - lineend;
2331 
2332  if( wirevector.x > 0 )
2333  {
2334  if( wirevector.y > 0 )
2335  {
2336  wxPoint p = linestart + wxPoint( -100, -100 );
2337  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, false );
2338  busEntry->SetFlags( IS_NEW );
2339  m_currentSheet->GetScreen()->Append( busEntry );
2340  moveLabels( line, p );
2341 
2342  if( p == lineend ) // wire is overlapped by bus entry symbol
2343  {
2344  m_currentSheet->GetScreen()->DeleteItem( line );
2345  line = nullptr;
2346  }
2347  else
2348  {
2349  line->SetStartPoint( p );
2350  }
2351  }
2352  else
2353  {
2354  wxPoint p = linestart + wxPoint( -100, 100 );
2355  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, true );
2356  busEntry->SetFlags( IS_NEW );
2357  m_currentSheet->GetScreen()->Append( busEntry );
2358 
2359  moveLabels( line, p );
2360 
2361  if( p == lineend ) // wire is overlapped by bus entry symbol
2362  {
2363  m_currentSheet->GetScreen()->DeleteItem( line );
2364  line = nullptr;
2365  }
2366  else
2367  {
2368  line->SetStartPoint( p );
2369  }
2370  }
2371  }
2372  else
2373  {
2374  if( wirevector.y > 0 )
2375  {
2376  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart, true );
2377  busEntry->SetFlags( IS_NEW );
2378  m_currentSheet->GetScreen()->Append( busEntry );
2379 
2380  moveLabels( line, linestart + wxPoint( 100, -100 ) );
2381 
2382  if( linestart + wxPoint( 100, -100 )
2383  == lineend ) // wire is overlapped by bus entry symbol
2384  {
2385  m_currentSheet->GetScreen()->DeleteItem( line );
2386  line = nullptr;
2387  }
2388  else
2389  {
2390  line->SetStartPoint( linestart + wxPoint( 100, -100 ) );
2391  }
2392  }
2393  else
2394  {
2395  SCH_BUS_WIRE_ENTRY* busEntry =
2396  new SCH_BUS_WIRE_ENTRY( linestart, false );
2397  busEntry->SetFlags( IS_NEW );
2398  m_currentSheet->GetScreen()->Append( busEntry );
2399  moveLabels( line, linestart + wxPoint( 100, 100 ) );
2400 
2401  if( linestart + wxPoint( 100, 100 )
2402  == lineend ) // wire is overlapped by bus entry symbol
2403  {
2404  m_currentSheet->GetScreen()->DeleteItem( line );
2405  line = nullptr;
2406  }
2407  else
2408  {
2409  line->SetStartPoint( linestart + wxPoint( 100, 100 ) );
2410  }
2411  }
2412  }
2413  }
2414 
2415  if( line && TestSegmentHit( lineend, busstart, busend, 0 ) )
2416  {
2417  wxPoint wirevector = linestart - lineend;
2418 
2419  if( wirevector.x > 0 )
2420  {
2421  if( wirevector.y > 0 )
2422  {
2423  wxPoint p = lineend + wxPoint( 100, 100 );
2424  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend, false );
2425  busEntry->SetFlags( IS_NEW );
2426  m_currentSheet->GetScreen()->Append( busEntry );
2427 
2428  moveLabels( line, p );
2429 
2430  if( p == linestart ) // wire is overlapped by bus entry symbol
2431  {
2432  m_currentSheet->GetScreen()->DeleteItem( line );
2433  }
2434  else
2435  {
2436  line->SetEndPoint( p );
2437  }
2438  }
2439  else
2440  {
2441  wxPoint p = lineend + wxPoint( 100, -100 );
2442  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend, true );
2443  busEntry->SetFlags( IS_NEW );
2444  m_currentSheet->GetScreen()->Append( busEntry );
2445 
2446  moveLabels( line, p );
2447 
2448  if( p == linestart ) // wire is overlapped by bus entry symbol
2449  {
2450  m_currentSheet->GetScreen()->DeleteItem( line );
2451  }
2452  else
2453  {
2454  line->SetEndPoint( p );
2455  }
2456  }
2457  }
2458  else
2459  {
2460  if( wirevector.y > 0 )
2461  {
2462  wxPoint p = lineend + wxPoint( -100, 100 );
2463  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, true );
2464  busEntry->SetFlags( IS_NEW );
2465  m_currentSheet->GetScreen()->Append( busEntry );
2466  moveLabels( line, p );
2467 
2468  if( p == linestart ) // wire is overlapped by bus entry symbol
2469  {
2470  m_currentSheet->GetScreen()->DeleteItem( line );
2471  }
2472  else
2473  {
2474  line->SetEndPoint( p );
2475  }
2476  }
2477  else
2478  {
2479  wxPoint p = lineend + wxPoint( -100, -100 );
2480  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, false );
2481  busEntry->SetFlags( IS_NEW );
2482  m_currentSheet->GetScreen()->Append( busEntry );
2483  moveLabels( line, p );
2484 
2485  if( p == linestart ) // wire is overlapped by bus entry symbol
2486  {
2487  m_currentSheet->GetScreen()->DeleteItem( line );
2488  }
2489  else
2490  {
2491  line->SetEndPoint( p );
2492  }
2493  }
2494  }
2495  }
2496  }
2497  }
2498  } // for ( bus ..
2499 }
2500 
2501 
2503 {
2504  VECTOR2I labelPos( aLabel->GetPosition() );
2505 
2506  for( const auto& seg : segs )
2507  {
2508  if( seg.Contains( labelPos ) )
2509  return &seg;
2510  }
2511 
2512  return nullptr;
2513 }
2514 
2515 
2516 // TODO could be used to place junctions, instead of IsJunctionNeeded() (see SCH_EDIT_FRAME::importFile())
2518  const SCH_COMPONENT* aComponent, const LIB_PIN* aPin ) const
2519 {
2520  wxPoint pinPosition = aComponent->GetPinPhysicalPosition( aPin );
2521  auto pointIt = m_connPoints.find( pinPosition );
2522 
2523  if( pointIt == m_connPoints.end() )
2524  return false;
2525 
2526  const auto& items = pointIt->second;
2527  wxASSERT( items.find( aPin ) != items.end() );
2528  return items.size() > 1;
2529 }
2530 
2531 
2533  SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet )
2534 {
2535  wxCHECK( aComponent->GetPartRef(), /*void*/ );
2536 
2537  // Normally power parts also have power input pins,
2538  // but they already force net names on the attached wires
2539  if( aComponent->GetPartRef()->IsPower() )
2540  return;
2541 
2542  int unit = aComponent->GetUnit();
2543  const wxString reference = aComponent->GetField( REFERENCE )->GetText();
2544  std::vector<LIB_PIN*> pins;
2545  aComponent->GetPartRef()->GetPins( pins );
2546  std::set<int> missingUnits;
2547 
2548  // Search all units for pins creating implicit connections
2549  for( const auto& pin : pins )
2550  {
2551  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
2552  {
2553  bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
2554 
2555  // Create a global net label only if there are no other wires/pins attached
2556  if( pinInUnit && !checkConnections( aComponent, pin ) )
2557  {
2558  // Create a net label to force the net name on the pin
2559  SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
2560  netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
2561  netLabel->SetText( extractNetName( pin->GetName() ) );
2562  netLabel->SetTextSize( wxSize( Mils2iu( 10 ), Mils2iu( 10 ) ) );
2564  aScreen->Append( netLabel );
2565  }
2566 
2567  else if( !pinInUnit && aUpdateSet )
2568  {
2569  // Found a pin creating implicit connection information in another unit.
2570  // Such units will be instantiated if they do not appear in another sheet and
2571  // processed later.
2572  wxASSERT( pin->GetUnit() );
2573  missingUnits.insert( pin->GetUnit() );
2574  }
2575  }
2576  }
2577 
2578  if( aUpdateSet )
2579  {
2580  auto cmpIt = m_missingCmps.find( reference );
2581 
2582  // Set the flag indicating this unit has been processed
2583  if( cmpIt != m_missingCmps.end() )
2584  cmpIt->second.units[unit] = false;
2585 
2586  // Save the units that need later processing
2587  else if( !missingUnits.empty() )
2588  {
2589  EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
2590  entry.cmp = aComponent;
2591 
2592  for( int i : missingUnits )
2593  entry.units.emplace( i, true );
2594  }
2595  }
2596 }
2597 
2598 
2599 wxString SCH_EAGLE_PLUGIN::fixSymbolName( const wxString& aName )
2600 {
2601  wxString ret = LIB_ID::FixIllegalChars( aName, LIB_ID::ID_SCH );
2602 
2603  return ret;
2604 }
2605 
2606 
2607 wxString SCH_EAGLE_PLUGIN::translateEagleBusName( const wxString& aEagleName ) const
2608 {
2609  if( NET_SETTINGS::ParseBusVector( aEagleName, nullptr, nullptr ) )
2610  return aEagleName;
2611 
2612  wxString ret = "{";
2613 
2614  wxStringTokenizer tokenizer( aEagleName, "," );
2615 
2616  while( tokenizer.HasMoreTokens() )
2617  {
2618  wxString member = tokenizer.GetNextToken();
2619 
2620  // In Eagle, overbar text is automatically stopped at the end of the net name, even when
2621  // that net name is part of a bus definition. In KiCad, we don't (currently) do that, so
2622  // if there is an odd number of overbar markers in this net name, we need to append one
2623  // to close it out before appending the space.
2624 
2625  if( member.Freq( '!' ) % 2 > 0 )
2626  member << "!";
2627 
2628  ret << member << " ";
2629  }
2630 
2631  ret.Trim( true );
2632  ret << "}";
2633 
2634  return ret;
2635 }
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:183
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:200
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
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
wxPoint GetPosition() const override
Definition: lib_text.h:84
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:247
void SetVisible(bool aVisible)
Definition: eda_text.h:185
int GetWidth() const
Definition: eda_rect.h:119
opt_double ratio
Definition: eagle_parser.h:653
double GetTextAngle() const
Definition: eda_text.h:174
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:708
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:238
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
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)
Definition: lib_pin.h:193
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:113
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.
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:199
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:81
#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)
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
ECOORD y1
Definition: eagle_parser.h:586
const wxSize & GetTextSize() const
Definition: eda_text.h:239
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:203
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()
wxPoint GetPosition() const override
Definition: sch_text.h:313
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:257
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:272
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
Field Value of part, i.e. "3.3K".
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:242
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:378
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:132
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:202
#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:158
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parses a bus vector (e.g.
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:243
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:113
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:158
bool spin
Definition: eagle_parser.h:481
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:167
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:881
ECOORD y2
Definition: eagle_parser.h:588
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:183
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: base_struct.cpp:97
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:182
void SetPosition(const wxPoint &aPosition) override
Set the schematic item position to aPosition.
Definition: sch_field.cpp:576
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:187
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:127
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