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