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_draw_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:178
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:98
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:217
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:208
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:268
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_draw_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:107
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:252
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 SetText(const wxString &aText) override
Sets the field text to aText.
Definition: lib_field.cpp:410
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:209
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:190
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:201
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:212
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:235
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:191
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:479
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:787
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