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