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