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  component->UpdatePinCache();
1251  std::vector<LIB_PIN*> pins;
1252  component->GetPins( pins );
1253 
1254  for( const auto& pin : pins )
1255  m_connPoints[component->GetPinPhysicalPosition( pin )].emplace( pin );
1256 
1257 
1258  component->ClearFlags();
1259 
1260  screen->Append( component.release() );
1261 }
1262 
1263 
1265  EAGLE_LIBRARY* aEagleLibrary )
1266 {
1267  NODE_MAP libraryChildren = MapChildren( aLibraryNode );
1268 
1269  // Loop through the symbols and load each of them
1270  wxXmlNode* symbolNode = getChildrenNodes( libraryChildren, "symbols" );
1271 
1272  while( symbolNode )
1273  {
1274  wxString symbolName = symbolNode->GetAttribute( "name" );
1275  aEagleLibrary->SymbolNodes[symbolName] = symbolNode;
1276  symbolNode = symbolNode->GetNext();
1277  }
1278 
1279  // Loop through the devicesets and load each of them
1280  wxXmlNode* devicesetNode = getChildrenNodes( libraryChildren, "devicesets" );
1281 
1282  while( devicesetNode )
1283  {
1284  // Get Device set information
1285  EDEVICE_SET edeviceset = EDEVICE_SET( devicesetNode );
1286 
1287  wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : "";
1288 
1289  NODE_MAP aDeviceSetChildren = MapChildren( devicesetNode );
1290  wxXmlNode* deviceNode = getChildrenNodes( aDeviceSetChildren, "devices" );
1291 
1292  // For each device in the device set:
1293  while( deviceNode )
1294  {
1295  // Get device information
1296  EDEVICE edevice = EDEVICE( deviceNode );
1297 
1298  // Create symbol name from deviceset and device names.
1299  wxString symbolName = edeviceset.name + edevice.name;
1300  symbolName.Replace( "*", "" );
1301  wxASSERT( !symbolName.IsEmpty() );
1302  symbolName = fixSymbolName( symbolName );
1303 
1304  if( edevice.package )
1305  aEagleLibrary->package[symbolName] = edevice.package.Get();
1306 
1307  // Create KiCad symbol.
1308  unique_ptr<LIB_PART> kpart( new LIB_PART( symbolName ) );
1309 
1310  // Process each gate in the deviceset for this device.
1311  wxXmlNode* gateNode = getChildrenNodes( aDeviceSetChildren, "gates" );
1312  int gates_count = countChildren( aDeviceSetChildren["gates"], "gate" );
1313  kpart->SetUnitCount( gates_count );
1314  kpart->LockUnits( true );
1315 
1316  LIB_FIELD* reference = kpart->GetField( REFERENCE );
1317 
1318  if( prefix.length() == 0 )
1319  reference->SetVisible( false );
1320  else
1321  // If there is no footprint assigned, then prepend the reference value
1322  // with a hash character to mute netlist updater complaints
1323  reference->SetText( edevice.package ? prefix : '#' + prefix );
1324 
1325  int gateindex = 1;
1326  bool ispower = false;
1327 
1328  while( gateNode )
1329  {
1330  EGATE egate = EGATE( gateNode );
1331 
1332  aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex;
1333 
1334  ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol],
1335  kpart, &edevice, gateindex, egate.name );
1336 
1337  gateindex++;
1338  gateNode = gateNode->GetNext();
1339  } // gateNode
1340 
1341  kpart->SetUnitCount( gates_count );
1342 
1343  if( gates_count == 1 && ispower )
1344  kpart->SetPower();
1345 
1346  wxString name = fixSymbolName( kpart->GetName() );
1347  kpart->SetName( name );
1348  m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_PART( *kpart.get() ),
1349  m_properties.get() );
1350  aEagleLibrary->KiCadSymbols.insert( name, kpart.release() );
1351 
1352  deviceNode = deviceNode->GetNext();
1353  } // devicenode
1354 
1355  devicesetNode = devicesetNode->GetNext();
1356  } // devicesetNode
1357 
1358  return aEagleLibrary;
1359 }
1360 
1361 
1362 bool SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart,
1363  EDEVICE* aDevice, int aGateNumber, const wxString& aGateName )
1364 {
1365  wxString symbolName = aSymbolNode->GetAttribute( "name" );
1366  std::vector<LIB_ITEM*> items;
1367 
1368  wxXmlNode* currentNode = aSymbolNode->GetChildren();
1369 
1370  bool foundName = false;
1371  bool foundValue = false;
1372  bool ispower = false;
1373  int pincount = 0;
1374 
1375  while( currentNode )
1376  {
1377  wxString nodeName = currentNode->GetName();
1378 
1379  if( nodeName == "circle" )
1380  {
1381  aPart->AddDrawItem( loadSymbolCircle( aPart, currentNode, aGateNumber ) );
1382  }
1383  else if( nodeName == "pin" )
1384  {
1385  EPIN ePin = EPIN( currentNode );
1386  std::unique_ptr<LIB_PIN> pin( loadPin( aPart, currentNode, &ePin, aGateNumber ) );
1387  pincount++;
1388 
1389  if( ePin.direction )
1390  {
1391  const std::map<wxString, ELECTRICAL_PINTYPE> pinDirectionsMap =
1392  {
1393  { "sup", PIN_POWER_IN }, { "pas", PIN_PASSIVE },
1394  { "out", PIN_OUTPUT }, { "in", PIN_INPUT },
1395  { "nc", PIN_NC }, { "io", PIN_BIDI },
1396  { "oc", PIN_OPENCOLLECTOR }, { "hiz", PIN_TRISTATE },
1397  { "pwr", PIN_POWER_IN },
1398  };
1399 
1400  pin->SetType( PIN_UNSPECIFIED );
1401 
1402  for( const auto& pinDir : pinDirectionsMap )
1403  {
1404  if( ePin.direction->Lower() == pinDir.first )
1405  {
1406  pin->SetType( pinDir.second );
1407 
1408  if( pinDir.first == "sup" ) // power supply symbol
1409  ispower = true;
1410 
1411  break;
1412  }
1413  }
1414  }
1415 
1416 
1417  if( aDevice->connects.size() != 0 )
1418  {
1419  for( auto connect : aDevice->connects )
1420  {
1421  if( connect.gate == aGateName && pin->GetName() == connect.pin )
1422  {
1423  wxArrayString pads = wxSplit( wxString( connect.pad ), ' ');
1424 
1425  pin->SetPartNumber( aGateNumber );
1426  pin->SetUnit( aGateNumber );
1427  pin->SetName( escapeName( pin->GetName() ) );
1428 
1429  if( pads.GetCount() > 1)
1430  {
1431  pin->SetNumberTextSize( 0 );
1432  }
1433 
1434  for( unsigned i = 0; i < pads.GetCount(); i++)
1435  {
1436  LIB_PIN* apin = new LIB_PIN( *pin );
1437 
1438  wxString padname( pads[i] );
1439  apin->SetNumber( padname );
1440  aPart->AddDrawItem( apin );
1441  }
1442  break;
1443  }
1444  }
1445  }
1446  else
1447  {
1448  pin->SetPartNumber( aGateNumber );
1449  pin->SetUnit( aGateNumber );
1450  pin->SetNumber( wxString::Format( "%i", pincount ) );
1451  aPart->AddDrawItem( pin.release() );
1452  }
1453  }
1454  else if( nodeName == "polygon" )
1455  {
1456  aPart->AddDrawItem( loadSymbolPolyLine( aPart, currentNode, aGateNumber ) );
1457  }
1458  else if( nodeName == "rectangle" )
1459  {
1460  aPart->AddDrawItem( loadSymbolRectangle( aPart, currentNode, aGateNumber ) );
1461  }
1462  else if( nodeName == "text" )
1463  {
1464  std::unique_ptr<LIB_TEXT> libtext( loadSymbolText( aPart, currentNode, aGateNumber ) );
1465 
1466  if( libtext->GetText().Upper() ==">NAME" )
1467  {
1468  LIB_FIELD* field = aPart->GetField( REFERENCE );
1469  loadFieldAttributes( field, libtext.get() );
1470  foundName = true;
1471  }
1472  else if( libtext->GetText().Upper() ==">VALUE" )
1473  {
1474  LIB_FIELD* field = aPart->GetField( VALUE );
1475  loadFieldAttributes( field, libtext.get() );
1476  foundValue = true;
1477  }
1478  else
1479  {
1480  aPart->AddDrawItem( libtext.release() );
1481  }
1482  }
1483  else if( nodeName == "wire" )
1484  {
1485  aPart->AddDrawItem( loadSymbolWire( aPart, currentNode, aGateNumber ) );
1486  }
1487 
1488  /*
1489  * else if( nodeName == "description" )
1490  * {
1491  * }
1492  * else if( nodeName == "dimension" )
1493  * {
1494  * }
1495  * else if( nodeName == "frame" )
1496  * {
1497  * }
1498  */
1499 
1500  currentNode = currentNode->GetNext();
1501  }
1502 
1503  if( foundName == false )
1504  aPart->GetField( REFERENCE )->SetVisible( false );
1505 
1506  if( foundValue == false )
1507  aPart->GetField( VALUE )->SetVisible( false );
1508 
1509  return pincount == 1 ? ispower : false;
1510 }
1511 
1512 
1513 LIB_CIRCLE* SCH_EAGLE_PLUGIN::loadSymbolCircle( std::unique_ptr<LIB_PART>& aPart,
1514  wxXmlNode* aCircleNode,
1515  int aGateNumber )
1516 {
1517  // Parse the circle properties
1518  ECIRCLE c( aCircleNode );
1519 
1520  unique_ptr<LIB_CIRCLE> circle( new LIB_CIRCLE( aPart.get() ) );
1521 
1522  circle->SetPosition( wxPoint( c.x.ToSchUnits(), c.y.ToSchUnits() ) );
1523  circle->SetRadius( c.radius.ToSchUnits() );
1524  circle->SetWidth( c.width.ToSchUnits() );
1525  circle->SetUnit( aGateNumber );
1526 
1527  return circle.release();
1528 }
1529 
1530 
1531 LIB_RECTANGLE* SCH_EAGLE_PLUGIN::loadSymbolRectangle( std::unique_ptr<LIB_PART>& aPart,
1532  wxXmlNode* aRectNode,
1533  int aGateNumber )
1534 {
1535  ERECT rect( aRectNode );
1536 
1537  unique_ptr<LIB_RECTANGLE> rectangle( new LIB_RECTANGLE( aPart.get() ) );
1538 
1539  rectangle->SetPosition( wxPoint( rect.x1.ToSchUnits(), rect.y1.ToSchUnits() ) );
1540  rectangle->SetEnd( wxPoint( rect.x2.ToSchUnits(), rect.y2.ToSchUnits() ) );
1541 
1542  rectangle->SetUnit( aGateNumber );
1543  // Eagle rectangles are filled by definition.
1544  rectangle->SetFillMode( FILLED_SHAPE );
1545 
1546  return rectangle.release();
1547 }
1548 
1549 
1550 LIB_ITEM* SCH_EAGLE_PLUGIN::loadSymbolWire( std::unique_ptr<LIB_PART>& aPart,
1551  wxXmlNode* aWireNode,
1552  int aGateNumber )
1553 {
1554  auto ewire = EWIRE( aWireNode );
1555 
1556  wxPoint begin, end;
1557 
1558  begin.x = ewire.x1.ToSchUnits();
1559  begin.y = ewire.y1.ToSchUnits();
1560  end.x = ewire.x2.ToSchUnits();
1561  end.y = ewire.y2.ToSchUnits();
1562 
1563  // if the wire is an arc
1564  if( ewire.curve )
1565  {
1566  std::unique_ptr<LIB_ARC> arc( new LIB_ARC( aPart.get() ) );
1567  wxPoint center = ConvertArcCenter( begin, end, *ewire.curve * -1 );
1568 
1569  double radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1570  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) ) * 2;
1571 
1572  // this emulates the filled semicircles created by a thick arc with flat ends caps.
1573  if( ewire.width.ToSchUnits() * 2 > radius )
1574  {
1575  wxPoint centerStartVector = begin - center;
1576  wxPoint centerEndVector = end - center;
1577 
1578  centerStartVector.x = centerStartVector.x * ewire.width.ToSchUnits() * 2 / radius;
1579  centerStartVector.y = centerStartVector.y * ewire.width.ToSchUnits() * 2 / radius;
1580 
1581  centerEndVector.x = centerEndVector.x * ewire.width.ToSchUnits() * 2 / radius;
1582  centerEndVector.y = centerEndVector.y * ewire.width.ToSchUnits() * 2 / radius;
1583 
1584  begin = center + centerStartVector;
1585  end = center + centerEndVector;
1586 
1587  radius = sqrt( abs( ( ( center.x - begin.x ) * ( center.x - begin.x ) )
1588  + ( ( center.y - begin.y ) * ( center.y - begin.y ) ) ) ) * 2;
1589 
1590  arc->SetWidth( 1 );
1591  arc->SetFillMode( FILLED_SHAPE );
1592  }
1593  else
1594  {
1595  arc->SetWidth( ewire.width.ToSchUnits() );
1596  }
1597 
1598  arc->SetPosition( center );
1599 
1600  if( *ewire.curve > 0 )
1601  {
1602  arc->SetStart( begin );
1603  arc->SetEnd( end );
1604  }
1605  else
1606  {
1607  arc->SetStart( end );
1608  arc->SetEnd( begin );
1609  }
1610 
1611  arc->SetRadius( radius );
1612  arc->CalcRadiusAngles();
1613  arc->SetUnit( aGateNumber );
1614 
1615  return (LIB_ITEM*) arc.release();
1616  }
1617  else
1618  {
1619  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1620 
1621  polyLine->AddPoint( begin );
1622  polyLine->AddPoint( end );
1623  polyLine->SetUnit( aGateNumber );
1624 
1625  return (LIB_ITEM*) polyLine.release();
1626  }
1627 }
1628 
1629 
1630 LIB_POLYLINE* SCH_EAGLE_PLUGIN::loadSymbolPolyLine( std::unique_ptr<LIB_PART>& aPart,
1631  wxXmlNode* aPolygonNode, int aGateNumber )
1632 {
1633  std::unique_ptr<LIB_POLYLINE> polyLine( new LIB_POLYLINE( aPart.get() ) );
1634 
1635  EPOLYGON epoly( aPolygonNode );
1636  wxXmlNode* vertex = aPolygonNode->GetChildren();
1637 
1638 
1639  wxPoint pt;
1640 
1641  while( vertex )
1642  {
1643  if( vertex->GetName() == "vertex" ) // skip <xmlattr> node
1644  {
1645  EVERTEX evertex( vertex );
1646  pt = wxPoint( evertex.x.ToSchUnits(), evertex.y.ToSchUnits() );
1647  polyLine->AddPoint( pt );
1648  }
1649 
1650  vertex = vertex->GetNext();
1651  }
1652 
1653  polyLine->SetFillMode( FILLED_SHAPE );
1654  polyLine->SetUnit( aGateNumber );
1655 
1656  return polyLine.release();
1657 }
1658 
1659 
1660 LIB_PIN* SCH_EAGLE_PLUGIN::loadPin( std::unique_ptr<LIB_PART>& aPart,
1661  wxXmlNode* aPin,
1662  EPIN* aEPin,
1663  int aGateNumber )
1664 {
1665  std::unique_ptr<LIB_PIN> pin( new LIB_PIN( aPart.get() ) );
1666  pin->SetPosition( wxPoint( aEPin->x.ToSchUnits(), aEPin->y.ToSchUnits() ) );
1667  pin->SetName( aEPin->name );
1668  pin->SetUnit( aGateNumber );
1669 
1670  int roti = aEPin->rot ? aEPin->rot->degrees : 0;
1671 
1672  switch( roti )
1673  {
1674  default:
1675  wxASSERT_MSG( false, wxString::Format( "Unhandled orientation (%d degrees)", roti ) );
1676 
1677  // fall through
1678  case 0:
1679  pin->SetOrientation( 'R' );
1680  break;
1681 
1682  case 90:
1683  pin->SetOrientation( 'U' );
1684  break;
1685 
1686  case 180:
1687  pin->SetOrientation( 'L' );
1688  break;
1689 
1690  case 270:
1691  pin->SetOrientation( 'D' );
1692  break;
1693  }
1694 
1695  if( aEPin->length )
1696  {
1697  wxString length = aEPin->length.Get();
1698 
1699  if( length =="short" )
1700  {
1701  pin->SetLength( 100 );
1702  }
1703  else if( length =="middle" )
1704  {
1705  pin->SetLength( 200 );
1706  }
1707  else if( length == "long" )
1708  {
1709  pin->SetLength( 300 );
1710  }
1711  else if( length == "point" )
1712  {
1713  pin->SetLength( 0 );
1714  }
1715  }
1716 
1717  // emulate the visibility of pin elements
1718  if( aEPin->visible )
1719  {
1720  wxString visible = aEPin->visible.Get();
1721 
1722  if( visible == "off" )
1723  {
1724  pin->SetNameTextSize( 0 );
1725  pin->SetNumberTextSize( 0 );
1726  }
1727  else if( visible == "pad" )
1728  {
1729  pin->SetNameTextSize( 0 );
1730  }
1731  else if( visible == "pin" )
1732  {
1733  pin->SetNumberTextSize( 0 );
1734  }
1735 
1736  /*
1737  * else if( visible == "both" )
1738  * {
1739  * }
1740  */
1741  }
1742 
1743  if( aEPin->function )
1744  {
1745  wxString function = aEPin->function.Get();
1746 
1747  if( function == "dot" )
1748  {
1749  pin->SetShape( PINSHAPE_INVERTED );
1750  }
1751  else if( function == "clk" )
1752  {
1753  pin->SetShape( PINSHAPE_CLOCK );
1754  }
1755  else if( function == "dotclk" )
1756  {
1757  pin->SetShape( PINSHAPE_INVERTED_CLOCK );
1758  }
1759  }
1760 
1761  return pin.release();
1762 }
1763 
1764 
1765 LIB_TEXT* SCH_EAGLE_PLUGIN::loadSymbolText( std::unique_ptr<LIB_PART>& aPart,
1766  wxXmlNode* aLibText, int aGateNumber )
1767 {
1768  std::unique_ptr<LIB_TEXT> libtext( new LIB_TEXT( aPart.get() ) );
1769  ETEXT etext( aLibText );
1770 
1771  libtext->SetUnit( aGateNumber );
1772  libtext->SetPosition( wxPoint( etext.x.ToSchUnits(), etext.y.ToSchUnits() ) );
1773 
1774  // Eagle supports multiple line text in library symbols. Legacy library symbol text cannot
1775  // contain CRs or LFs.
1776  //
1777  // @todo Split this into multiple text objects and offset the Y position so that it looks
1778  // more like the original Eagle schematic.
1779  wxString text = aLibText->GetNodeContent();
1780  std::replace( text.begin(), text.end(), '\n', '_' );
1781  std::replace( text.begin(), text.end(), '\r', '_' );
1782 
1783  libtext->SetText( text.IsEmpty() ? "~~" : text );
1784  loadTextAttributes( libtext.get(), etext );
1785 
1786  return libtext.release();
1787 }
1788 
1789 
1791 {
1792  std::unique_ptr<SCH_TEXT> schtext( new SCH_TEXT() );
1793  ETEXT etext = ETEXT( aSchText );
1794 
1795  const wxString& thetext = aSchText->GetNodeContent();
1796  schtext->SetText( thetext.IsEmpty() ? "\" \"" : escapeName( thetext ) );
1797  schtext->SetPosition( wxPoint( etext.x.ToSchUnits(), -etext.y.ToSchUnits() ) );
1798  loadTextAttributes( schtext.get(), etext );
1799  schtext->SetItalic( false );
1800 
1801  return schtext.release();
1802 }
1803 
1804 
1805 void SCH_EAGLE_PLUGIN::loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const
1806 {
1807  aText->SetTextSize( aAttribs.ConvertSize() );
1808 
1809  if( aAttribs.ratio )
1810  {
1811  if( aAttribs.ratio.CGet() > 12 )
1812  {
1813  aText->SetBold( true );
1814  aText->SetThickness( GetPenSizeForBold( aText->GetTextWidth() ) );
1815  }
1816  }
1817 
1818  int align = aAttribs.align ? *aAttribs.align : ETEXT::BOTTOM_LEFT;
1819  int degrees = aAttribs.rot ? aAttribs.rot->degrees : 0;
1820  bool mirror = aAttribs.rot ? aAttribs.rot->mirror : false;
1821  bool spin = aAttribs.rot ? aAttribs.rot->spin : false;
1822 
1823  eagleToKicadAlignment( aText, align, degrees, mirror, spin, 0 );
1824 }
1825 
1826 
1827 void SCH_EAGLE_PLUGIN::loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const
1828 {
1829  aField->SetTextPos( aText->GetPosition() );
1830  aField->SetTextSize( aText->GetTextSize() );
1831  aField->SetTextAngle( aText->GetTextAngle() );
1832  aField->SetBold( aText->IsBold() );
1833  aField->SetVertJustify( aText->GetVertJustify() );
1834  aField->SetHorizJustify( aText->GetHorizJustify() );
1835  aField->SetVisible( true );
1836 }
1837 
1838 
1840 {
1841  // Eagle supports detached labels, so a label does not need to be placed on a wire
1842  // to be associated with it. KiCad needs to move them, so the labels actually touch the
1843  // corresponding wires.
1844 
1845  // Sort the intersection points to speed up the search process
1846  std::sort( m_wireIntersections.begin(), m_wireIntersections.end() );
1847 
1848  auto onIntersection = [&]( const VECTOR2I& aPos )
1849  {
1850  return std::binary_search( m_wireIntersections.begin(), m_wireIntersections.end(), aPos );
1851  };
1852 
1853  for( auto& segDesc : m_segments )
1854  {
1855  for( SCH_TEXT* label : segDesc.labels )
1856  {
1857  VECTOR2I labelPos( label->GetPosition() );
1858  const SEG* segAttached = segDesc.LabelAttached( label );
1859 
1860  if( segAttached && !onIntersection( labelPos ) )
1861  continue; // label is placed correctly
1862 
1863 
1864  // Move the label to the nearest wire
1865  if( !segAttached )
1866  {
1867  std::tie( labelPos, segAttached ) = findNearestLinePoint( label->GetPosition(), segDesc.segs );
1868 
1869  if( !segAttached ) // we cannot do anything
1870  continue;
1871  }
1872 
1873 
1874  // Create a vector pointing in the direction of the wire, 50 mils long
1875  VECTOR2I wireDirection( segAttached->B - segAttached->A );
1876  wireDirection = wireDirection.Resize( 50 );
1877  const VECTOR2I origPos( labelPos );
1878 
1879  // Flags determining the search direction
1880  bool checkPositive = true, checkNegative = true, move = false;
1881  int trial = 0;
1882 
1883  // Be sure the label is not placed on a wire intersection
1884  while( ( !move || onIntersection( labelPos ) ) && ( checkPositive || checkNegative ) )
1885  {
1886  move = false;
1887 
1888  // Move along the attached wire to find the new label position
1889  if( trial % 2 == 1 )
1890  {
1891  labelPos = wxPoint( origPos + wireDirection * trial / 2 );
1892  move = checkPositive = segAttached->Contains( labelPos );
1893  }
1894  else
1895  {
1896  labelPos = wxPoint( origPos - wireDirection * trial / 2 );
1897  move = checkNegative = segAttached->Contains( labelPos );
1898  }
1899 
1900  ++trial;
1901  }
1902 
1903  if( move )
1904  label->SetPosition( wxPoint( labelPos ) );
1905  }
1906  }
1907 
1908  m_segments.clear();
1909  m_wireIntersections.clear();
1910 }
1911 
1912 
1913 bool SCH_EAGLE_PLUGIN::CheckHeader( const wxString& aFileName )
1914 {
1915  // Open file and check first line
1916  wxTextFile tempFile;
1917 
1918  tempFile.Open( aFileName );
1919  wxString firstline;
1920  // read the first line
1921  firstline = tempFile.GetFirstLine();
1922  wxString secondline = tempFile.GetNextLine();
1923  wxString thirdline = tempFile.GetNextLine();
1924  tempFile.Close();
1925 
1926  return firstline.StartsWith( "<?xml" ) && secondline.StartsWith( "<!DOCTYPE eagle SYSTEM" )
1927  && thirdline.StartsWith( "<eagle version" );
1928 }
1929 
1930 
1931 void SCH_EAGLE_PLUGIN::moveLabels( SCH_ITEM* aWire, const wxPoint& aNewEndPoint )
1932 {
1933  for( SCH_ITEM* item = m_currentSheet->GetScreen()->GetDrawItems(); item; item = item->Next() )
1934  {
1935  if( item->Type() == SCH_LABEL_T || item->Type() == SCH_GLOBAL_LABEL_T )
1936  {
1937  if( TestSegmentHit( item->GetPosition(), ( (SCH_LINE*) aWire )->GetStartPoint(),
1938  ( (SCH_LINE*) aWire )->GetEndPoint(), 0 ) )
1939  {
1940  item->SetPosition( aNewEndPoint );
1941  }
1942  }
1943  }
1944 }
1945 
1946 
1948 {
1949  // Add bus entry symbols
1950 
1951  // for each wire segment, compare each end with all busess.
1952  // If the wire end is found to end on a bus segment, place a bus entry symbol.
1953 
1954  for( SCH_ITEM* bus = m_currentSheet->GetScreen()->GetDrawItems(); bus; bus = bus->Next() )
1955  {
1956  // Check line type for line
1957  if( bus->Type() != SCH_LINE_T )
1958  continue;
1959 
1960  // Check line type for wire
1961  if( ( (SCH_LINE*) bus )->GetLayer() != LAYER_BUS )
1962  continue;
1963 
1964 
1965  wxPoint busstart = ( (SCH_LINE*) bus )->GetStartPoint();
1966  wxPoint busend = ( (SCH_LINE*) bus )->GetEndPoint();
1967 
1968  SCH_ITEM* nextline;
1969 
1970  for( SCH_ITEM* line = m_currentSheet->GetScreen()->GetDrawItems(); line; line = nextline )
1971  {
1972  nextline = line->Next();
1973 
1974  // Check line type for line
1975  if( line->Type() == SCH_LINE_T )
1976  {
1977  // Check line type for bus
1978  if( ( (SCH_LINE*) line )->GetLayer() == LAYER_WIRE )
1979  {
1980  // Get points of both segments.
1981 
1982  wxPoint linestart = ( (SCH_LINE*) line )->GetStartPoint();
1983  wxPoint lineend = ( (SCH_LINE*) line )->GetEndPoint();
1984 
1985 
1986  // Test for horizontal wire and vertical bus
1987  if( linestart.y == lineend.y && busstart.x == busend.x )
1988  {
1989  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
1990  {
1991  // Wire start is on a bus.
1992  // Wire start is on the vertical bus
1993 
1994  // if the end of the wire is to the left of the bus
1995  if( lineend.x < busstart.x )
1996  {
1997  // |
1998  // ---|
1999  // |
2000  if( TestSegmentHit( linestart + wxPoint( 0, -100 ), busstart,
2001  busend, 0 ) )
2002  {
2003  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2004  -100,
2005  0 ),
2006  '/' );
2007  busEntry->SetFlags( IS_NEW );
2008  m_currentSheet->GetScreen()->Append( busEntry );
2009  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2010  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2011  wxPoint( -100, 0 ) );
2012  }
2013  else if( TestSegmentHit( linestart + wxPoint( 0, 100 ), busstart,
2014  busend, 0 ) )
2015  {
2016  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2017  -100,
2018  0 ),
2019  '\\' );
2020  busEntry->SetFlags( IS_NEW );
2021  m_currentSheet->GetScreen()->Append( busEntry );
2022  moveLabels( line, linestart + wxPoint( -100, 0 ) );
2023  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2024  wxPoint( -100, 0 ) );
2025  }
2026  else
2027  {
2028  SCH_MARKER* marker = new SCH_MARKER( linestart,
2029  "Bus Entry needed" );
2030 
2031  m_currentSheet->GetScreen()->Append( marker );
2032  }
2033  }
2034  // else the wire end is to the right of the bus
2035  // Wire is to the right of the bus
2036  // |
2037  // |----
2038  // |
2039  else
2040  {
2041  // test is bus exists above the wire
2042  if( TestSegmentHit( linestart + wxPoint( 0, -100 ), busstart,
2043  busend, 0 ) )
2044  {
2045  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2046  0,
2047  -100 ),
2048  '\\' );
2049  busEntry->SetFlags( IS_NEW );
2050  m_currentSheet->GetScreen()->Append( busEntry );
2051  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2052  ( (SCH_LINE*) line )->SetStartPoint( linestart + wxPoint( 100,
2053  0 ) );
2054  }
2055  // test is bus exists below the wire
2056  else if( TestSegmentHit( linestart + wxPoint( 0, 100 ), busstart,
2057  busend, 0 ) )
2058  {
2059  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2060  0,
2061  100 ),
2062  '/' );
2063  busEntry->SetFlags( IS_NEW );
2064  m_currentSheet->GetScreen()->Append( busEntry );
2065  moveLabels( line, linestart + wxPoint( 100, 0 ) );
2066  ( (SCH_LINE*) line )->SetStartPoint( linestart + wxPoint( 100,
2067  0 ) );
2068  }
2069  else
2070  {
2071  SCH_MARKER* marker = new SCH_MARKER( linestart,
2072  "Bus Entry needed" );
2073 
2074  m_currentSheet->GetScreen()->Append( marker );
2075  }
2076  }
2077  }
2078 
2079  // Same thing but test end of the wire instead.
2080  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2081  {
2082  // Wire end is on the vertical bus
2083 
2084  // if the start of the wire is to the left of the bus
2085  if( linestart.x < busstart.x )
2086  {
2087  // Test if bus exists above the wire
2088  if( TestSegmentHit( lineend + wxPoint( 0, 100 ), busstart, busend,
2089  0 ) )
2090  {
2091  // |
2092  // ___/|
2093  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2094  -100,
2095  0 ),
2096  '\\' );
2097  busEntry->SetFlags( IS_NEW );
2098  m_currentSheet->GetScreen()->Append( busEntry );
2099  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2100  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2101  wxPoint( -100, 0 ) );
2102  }
2103  // Test if bus exists below the wire
2104  else if( TestSegmentHit( lineend + wxPoint( 0, -100 ), busstart,
2105  busend, 0 ) )
2106  {
2107  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2108  -100,
2109  0 ),
2110  '/' );
2111  busEntry->SetFlags( IS_NEW );
2112  m_currentSheet->GetScreen()->Append( busEntry );
2113  moveLabels( line, lineend + wxPoint( -100, 0 ) );
2114  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2115  wxPoint( -100, 0 ) );
2116  }
2117  else
2118  {
2119  SCH_MARKER* marker = new SCH_MARKER( lineend,
2120  "Bus Entry needed" );
2121 
2122  m_currentSheet->GetScreen()->Append( marker );
2123  }
2124  }
2125  // else the start of the wire is to the right of the bus
2126  // |
2127  // |----
2128  // |
2129  else
2130  {
2131  // test if bus existed above the wire
2132  if( TestSegmentHit( lineend + wxPoint( 0, -100 ), busstart,
2133  busend, 0 ) )
2134  {
2135  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2136  0,
2137  -100 ),
2138  '\\' );
2139  busEntry->SetFlags( IS_NEW );
2140  m_currentSheet->GetScreen()->Append( busEntry );
2141  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2142  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2143  wxPoint( 100, 0 ) );
2144  }
2145  // test if bus existed below the wire
2146  else if( TestSegmentHit( lineend + wxPoint( 0, 100 ), busstart,
2147  busend, 0 ) )
2148  {
2149  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2150  0,
2151  100 ),
2152  '/' );
2153  busEntry->SetFlags( IS_NEW );
2154  m_currentSheet->GetScreen()->Append( busEntry );
2155  moveLabels( line, lineend + wxPoint( 100, 0 ) );
2156  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2157  wxPoint( 100, 0 ) );
2158  }
2159  else
2160  {
2161  SCH_MARKER* marker = new SCH_MARKER( lineend,
2162  "Bus Entry needed" );
2163 
2164  m_currentSheet->GetScreen()->Append( marker );
2165  }
2166  }
2167  }
2168  } // if( linestart.y == lineend.y && busstart.x == busend.x)
2169 
2170  // Test for horizontal wire and vertical bus
2171  if( linestart.x == lineend.x && busstart.y == busend.y )
2172  {
2173  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2174  {
2175  // Wire start is on the bus
2176  // If wire end is above the bus,
2177  if( lineend.y < busstart.y )
2178  {
2179  // Test for bus existance to the left of the wire
2180  if( TestSegmentHit( linestart + wxPoint( -100, 0 ), busstart,
2181  busend, 0 ) )
2182  {
2183  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2184  -100,
2185  0 ),
2186  '/' );
2187  busEntry->SetFlags( IS_NEW );
2188  m_currentSheet->GetScreen()->Append( busEntry );
2189  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2190  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2191  wxPoint( 0, -100 ) );
2192  }
2193  else if( TestSegmentHit( linestart + wxPoint( 100, 0 ), busstart,
2194  busend, 0 ) )
2195  {
2196  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2197  0,
2198  100 ),
2199  '\\' );
2200  busEntry->SetFlags( IS_NEW );
2201  m_currentSheet->GetScreen()->Append( busEntry );
2202  moveLabels( line, linestart + wxPoint( 0, -100 ) );
2203  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2204  wxPoint( 0, -100 ) );
2205  }
2206  else
2207  {
2208  SCH_MARKER* marker = new SCH_MARKER( linestart,
2209  "Bus Entry needed" );
2210 
2211  m_currentSheet->GetScreen()->Append( marker );
2212  }
2213  }
2214  else // wire end is below the bus.
2215  {
2216  // Test for bus existance to the left of the wire
2217  if( TestSegmentHit( linestart + wxPoint( -100, 0 ), busstart,
2218  busend, 0 ) )
2219  {
2220  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2221  -100,
2222  0 ),
2223  '\\' );
2224  busEntry->SetFlags( IS_NEW );
2225  m_currentSheet->GetScreen()->Append( busEntry );
2226  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2227  ( (SCH_LINE*) line )->SetStartPoint( linestart + wxPoint( 0,
2228  100 ) );
2229  }
2230  else if( TestSegmentHit( linestart + wxPoint( 100, 0 ), busstart,
2231  busend, 0 ) )
2232  {
2233  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart + wxPoint(
2234  100,
2235  0 ),
2236  '/' );
2237  busEntry->SetFlags( IS_NEW );
2238  m_currentSheet->GetScreen()->Append( busEntry );
2239  moveLabels( line, linestart + wxPoint( 0, 100 ) );
2240  ( (SCH_LINE*) line )->SetStartPoint( linestart + wxPoint( 0,
2241  100 ) );
2242  }
2243  else
2244  {
2245  SCH_MARKER* marker = new SCH_MARKER( linestart,
2246  "Bus Entry needed" );
2247 
2248  m_currentSheet->GetScreen()->Append( marker );
2249  }
2250  }
2251  }
2252 
2253  if( TestSegmentHit( lineend, busstart, busend, 0 ) )
2254  {
2255  // Wire end is on the bus
2256  // If wire start is above the bus,
2257 
2258  if( linestart.y < busstart.y )
2259  {
2260  // Test for bus existance to the left of the wire
2261  if( TestSegmentHit( lineend + wxPoint( -100, 0 ), busstart,
2262  busend, 0 ) )
2263  {
2264  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2265  -100,
2266  0 ),
2267  '/' );
2268  busEntry->SetFlags( IS_NEW );
2269  m_currentSheet->GetScreen()->Append( busEntry );
2270  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2271  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2272  wxPoint( 0, -100 ) );
2273  }
2274  else if( TestSegmentHit( lineend + wxPoint( 100, 0 ), busstart,
2275  busend, 0 ) )
2276  {
2277  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2278  0,
2279  -100 ),
2280  '\\' );
2281  busEntry->SetFlags( IS_NEW );
2282  m_currentSheet->GetScreen()->Append( busEntry );
2283  moveLabels( line, lineend + wxPoint( 0, -100 ) );
2284  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2285  wxPoint( 0, -100 ) );
2286  }
2287  else
2288  {
2289  SCH_MARKER* marker = new SCH_MARKER( lineend,
2290  "Bus Entry needed" );
2291 
2292  m_currentSheet->GetScreen()->Append( marker );
2293  }
2294  }
2295  else // wire end is below the bus.
2296  {
2297  // Test for bus existance to the left of the wire
2298  if( TestSegmentHit( lineend + wxPoint( -100, 0 ), busstart,
2299  busend, 0 ) )
2300  {
2301  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2302  -100,
2303  0 ),
2304  '\\' );
2305  busEntry->SetFlags( IS_NEW );
2306  m_currentSheet->GetScreen()->Append( busEntry );
2307  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2308  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2309  wxPoint( 0, 100 ) );
2310  }
2311  else if( TestSegmentHit( lineend + wxPoint( 100, 0 ), busstart,
2312  busend, 0 ) )
2313  {
2314  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( lineend + wxPoint(
2315  0,
2316  100 ),
2317  '/' );
2318  busEntry->SetFlags( IS_NEW );
2319  m_currentSheet->GetScreen()->Append( busEntry );
2320  moveLabels( line, lineend + wxPoint( 0, 100 ) );
2321  ( (SCH_LINE*) line )->SetEndPoint( lineend +
2322  wxPoint( 0, 100 ) );
2323  }
2324  else
2325  {
2326  SCH_MARKER* marker = new SCH_MARKER( lineend,
2327  "Bus Entry needed" );
2328 
2329  m_currentSheet->GetScreen()->Append( marker );
2330  }
2331  }
2332  }
2333  }
2334 
2335  linestart = ( (SCH_LINE*) line )->GetStartPoint();
2336  lineend = ( (SCH_LINE*) line )->GetEndPoint();
2337  busstart = ( (SCH_LINE*) bus )->GetStartPoint();
2338  busend = ( (SCH_LINE*) bus )->GetEndPoint();
2339 
2340 
2341  // bus entry wire isn't horizontal or vertical
2342  if( TestSegmentHit( linestart, busstart, busend, 0 ) )
2343  {
2344  wxPoint wirevector = linestart - lineend;
2345 
2346  if( wirevector.x > 0 )
2347  {
2348  if( wirevector.y > 0 )
2349  {
2350  wxPoint p = linestart + wxPoint( -100, -100 );
2351  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, '\\' );
2352  busEntry->SetFlags( IS_NEW );
2353  m_currentSheet->GetScreen()->Append( busEntry );
2354  moveLabels( line, p );
2355 
2356  if( p == lineend ) // wire is overlapped by bus entry symbol
2357  {
2358  m_currentSheet->GetScreen()->DeleteItem( line );
2359  line = nullptr;
2360  }
2361  else
2362  {
2363  ( (SCH_LINE*) line )->SetStartPoint( p );
2364  }
2365  }
2366  else
2367  {
2368  wxPoint p = linestart + wxPoint( -100, 100 );
2369  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( p, '/' );
2370  busEntry->SetFlags( IS_NEW );
2371  m_currentSheet->GetScreen()->Append( busEntry );
2372 
2373  moveLabels( line, p );
2374 
2375  if( p == lineend ) // wire is overlapped by bus entry symbol
2376  {
2377  m_currentSheet->GetScreen()->DeleteItem( line );
2378  line = nullptr;
2379  }
2380  else
2381  {
2382  ( (SCH_LINE*) line )->SetStartPoint( p );
2383  }
2384  }
2385  }
2386  else
2387  {
2388  if( wirevector.y > 0 )
2389  {
2390  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart,
2391  '/' );
2392  busEntry->SetFlags( IS_NEW );
2393  m_currentSheet->GetScreen()->Append( busEntry );
2394 
2395  moveLabels( line, linestart + wxPoint( 100, -100 ) );
2396 
2397  if( linestart + wxPoint( 100, -100 )== lineend ) // wire is overlapped by bus entry symbol
2398  {
2399  m_currentSheet->GetScreen()->DeleteItem( line );
2400  line = nullptr;
2401  }
2402  else
2403  {
2404  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2405  wxPoint( 100, -100 ) );
2406  }
2407  }
2408  else
2409  {
2410  SCH_BUS_WIRE_ENTRY* busEntry = new SCH_BUS_WIRE_ENTRY( linestart,
2411  '\\' );
2412  busEntry->SetFlags( IS_NEW );
2413  m_currentSheet->GetScreen()->Append( busEntry );
2414  moveLabels( line, linestart + wxPoint( 100, 100 ) );
2415 
2416  if( linestart + wxPoint( 100, 100 )== lineend ) // wire is overlapped by bus entry symbol
2417  {
2418  m_currentSheet->GetScreen()->DeleteItem( line );
2419  line = nullptr;
2420  }
2421  else
2422  {
2423  ( (SCH_LINE*) line )->SetStartPoint( linestart +
2424  wxPoint( 100, 100 ) );
2425  }
2426  }
2427  }
2428  }
2429 
2430  if( line && TestSegmentHit( lineend, busstart, busend, 0 ) )
2431  {
2432  wxPoint wirevector = linestart - lineend;
2433 
2434  if( wirevector.x > 0 )
2435  {
2436  if( wirevector.y > 0 )
2437  {
2438  wxPoint p = lineend + wxPoint( 100, 100 );
2439  SCH_BUS_WIRE_ENTRY* busEntry =
2440  new SCH_BUS_WIRE_ENTRY( lineend, '\\' );
2441  busEntry->SetFlags( IS_NEW );
2442  m_currentSheet->GetScreen()->Append( busEntry );
2443 
2444  moveLabels( line, p );
2445 
2446  if( p == linestart ) // wire is overlapped by bus entry symbol
2447  {
2448  m_currentSheet->GetScreen()->DeleteItem( line );
2449  }
2450  else
2451  {
2452  ( (SCH_LINE*) line )->SetEndPoint( p );
2453  }
2454  }
2455  else
2456  {
2457  wxPoint p = lineend + wxPoint( 100, -100 );
2458  SCH_BUS_WIRE_ENTRY* busEntry =
2459  new SCH_BUS_WIRE_ENTRY( lineend, '/' );
2460  busEntry->SetFlags( IS_NEW );
2461  m_currentSheet->GetScreen()->Append( busEntry );
2462 
2463  moveLabels( line, p );
2464 
2465  if( p== linestart ) // wire is overlapped by bus entry symbol
2466  {
2467  m_currentSheet->GetScreen()->DeleteItem( line );
2468  }
2469  else
2470  {
2471  ( (SCH_LINE*) line )->SetEndPoint( p );
2472  }
2473  }
2474  }
2475  else
2476  {
2477  if( wirevector.y > 0 )
2478  {
2479  wxPoint p = lineend + wxPoint( -100, 100 );
2480  SCH_BUS_WIRE_ENTRY* busEntry =
2481  new SCH_BUS_WIRE_ENTRY( p, '/' );
2482  busEntry->SetFlags( IS_NEW );
2483  m_currentSheet->GetScreen()->Append( busEntry );
2484  moveLabels( line, p );
2485 
2486  if( p == linestart ) // wire is overlapped by bus entry symbol
2487  {
2488  m_currentSheet->GetScreen()->DeleteItem( line );
2489  }
2490  else
2491  {
2492  ( (SCH_LINE*) line )->SetEndPoint( p );
2493  }
2494  }
2495  else
2496  {
2497  wxPoint p = lineend + wxPoint( -100, -100 );
2498  SCH_BUS_WIRE_ENTRY* busEntry =
2499  new SCH_BUS_WIRE_ENTRY( p, '\\' );
2500  busEntry->SetFlags( IS_NEW );
2501  m_currentSheet->GetScreen()->Append( busEntry );
2502  moveLabels( line, p );
2503 
2504  if( p == linestart ) // wire is overlapped by bus entry symbol
2505  {
2506  m_currentSheet->GetScreen()->DeleteItem( line );
2507  }
2508  else
2509  {
2510  ( (SCH_LINE*) line )->SetEndPoint( p );
2511  }
2512  }
2513  }
2514  }
2515  }
2516  }
2517  } // for ( line ..
2518  } // for ( bus ..
2519 }
2520 
2521 
2523 {
2524  VECTOR2I labelPos( aLabel->GetPosition() );
2525 
2526  for( const auto& seg : segs )
2527  {
2528  if( seg.Contains( labelPos ) )
2529  return &seg;
2530  }
2531 
2532  return nullptr;
2533 }
2534 
2535 
2536 // TODO could be used to place junctions, instead of IsJunctionNeeded() (see SCH_EDIT_FRAME::importFile())
2537 bool SCH_EAGLE_PLUGIN::checkConnections( const SCH_COMPONENT* aComponent, const LIB_PIN* aPin ) const
2538 {
2539  wxPoint pinPosition = aComponent->GetPinPhysicalPosition( aPin );
2540  auto pointIt = m_connPoints.find( pinPosition );
2541 
2542  if( pointIt == m_connPoints.end() )
2543  return false;
2544 
2545  const auto& items = pointIt->second;
2546  wxASSERT( items.find( aPin ) != items.end() );
2547  return items.size() > 1;
2548 }
2549 
2550 
2552  SCH_SCREEN* aScreen, bool aUpdateSet )
2553 {
2554  aComponent->UpdatePinCache();
2555  auto partRef = aComponent->GetPartRef().lock();
2556  wxCHECK( partRef, /*void*/ );
2557 
2558  // Normally power parts also have power input pins,
2559  // but they already force net names on the attached wires
2560  if( partRef->IsPower() )
2561  return;
2562 
2563  int unit = aComponent->GetUnit();
2564  const wxString& reference = aComponent->GetField( REFERENCE )->GetText();
2565  std::vector<LIB_PIN*> pins;
2566  partRef->GetPins( pins );
2567  std::set<int> missingUnits;
2568 
2569  // Search all units for pins creating implicit connections
2570  for( const auto& pin : pins )
2571  {
2572  if( pin->GetType() == PIN_POWER_IN )
2573  {
2574  bool pinInUnit = !unit || pin->GetUnit() == unit; // pin belongs to the tested unit
2575 
2576  // Create a global net label only if there are no other wires/pins attached
2577  if( pinInUnit && !checkConnections( aComponent, pin ) )
2578  {
2579  // Create a net label to force the net name on the pin
2580  SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
2581  netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) );
2582  netLabel->SetText( extractNetName( pin->GetName() ) );
2583  netLabel->SetTextSize( wxSize( 10, 10 ) );
2584  netLabel->SetLabelSpinStyle( 0 );
2585  aScreen->Append( netLabel );
2586  }
2587 
2588  else if( !pinInUnit && aUpdateSet )
2589  {
2590  // Found a pin creating implicit connection information in another unit.
2591  // Such units will be instantiated if they do not appear in another sheet and
2592  // processed later.
2593  wxASSERT( pin->GetUnit() );
2594  missingUnits.insert( pin->GetUnit() );
2595  }
2596  }
2597  }
2598 
2599  if( aUpdateSet )
2600  {
2601  auto cmpIt = m_missingCmps.find( reference );
2602 
2603  // Set the flag indicating this unit has been processed
2604  if( cmpIt != m_missingCmps.end() )
2605  cmpIt->second.units[unit] = false;
2606 
2607  // Save the units that need later processing
2608  else if( !missingUnits.empty() )
2609  {
2610  EAGLE_MISSING_CMP& entry = m_missingCmps[reference];
2611  entry.cmp = aComponent;
2612 
2613  for( int i : missingUnits )
2614  entry.units.emplace( i, true );
2615  }
2616  }
2617 }
2618 
2619 
2620 wxString SCH_EAGLE_PLUGIN::fixSymbolName( const wxString& aName )
2621 {
2622  wxString ret = LIB_ID::FixIllegalChars( aName, LIB_ID::ID_SCH );
2623 
2624  return ret;
2625 }
void SetTextAngle(double aAngle)
Definition: eda_text.h:169
wxString name
Definition of the SCH_SHEET class for Eeschema.
Eagle vertex.
Definition: eagle_parser.h:746
wxString deviceset
Definition: eagle_parser.h:912
static const wxString & GetSymbolLibTableFileName()
Eagle Junction.
Definition: eagle_parser.h:531
Class SCH_FIELD instances are attached to a component and provide a place for the component&#39;s value...
Definition: sch_field.h:56
LIB_FIELD * GetField(int aId)
Return pointer to the requested field.
bool mirror
Definition: eagle_parser.h:481
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
ECOORD x
Definition: eagle_parser.h:731
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...
PART_REF & GetPartRef()
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect...
int GetPenSizeForBold(int aTextSize)
Function GetPensizeForBold.
int GetLeft() const
Definition: eda_rect.h:120
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:179
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:911
opt_wxString direction
Definition: eagle_parser.h:736
SCH_LINE * loadWire(wxXmlNode *aWireNode)
Define a symbol library graphical text item.
Definition: lib_text.h:44
const wxSize GetSize() const
Definition: eda_rect.h:101
VECTOR2< T > Resize(T aNewLength) const
Function Resize returns a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
virtual void SetPosition(const wxPoint &aPosition) override
Function SetPosition set the schematic item position to aPosition.
Definition: sch_text.h:196
std::unordered_map< wxString, wxString > package
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
T & Get()
Function Get returns a reference to the value of the attribute assuming it is available.
Definition: eagle_parser.h:300
wxPoint GetPosition() const override
Return the current draw object position.
Definition: lib_text.h:117
ECOORD y
Definition: eagle_parser.h:749
Field object used in symbol libraries.
Definition: lib_field.h:59
int GetTextWidth() const
Definition: eda_text.h:231
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:236
void SetVisible(bool aVisible)
Definition: eda_text.h:188
opt_double ratio
Definition: eagle_parser.h:654
int GetHeight() const
Definition: eda_rect.h:118
SCH_SHEET * GetRootSheet()
Return the root sheet of this SCH_SHEET object.
Definition: sch_sheet.cpp:136
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:650
Template specialization to enable wxStrings for certain containers (e.g. unordered_map) ...
Definition: bitmap.cpp:55
std::map< std::string, std::string > variant
Definition: eagle_parser.h:917
wxPoint GetEndPoint() const
Definition: sch_line.h:80
double degrees
Definition: eagle_parser.h:483
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:227
void loadTextAttributes(EDA_TEXT *aText, const ETEXT &aAttribs) const
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)
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Function Intersect()
Definition: seg.cpp:99
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:279
Eagle text element.
Definition: eagle_parser.h:646
#define abs(a)
Definition: auxiliary.h:84
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:203
SCH_ITEM * Next() const
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:728
bool IsBold() const
Definition: eda_text.h:186
double GetTextAngle() const
Definition: eda_text.h:177
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:915
wxString Path() const
Function Path the path uses the time stamps which do not changes even when editing sheet parameters a...
wxPoint GetStartPoint() const
Definition: sch_line.h:76
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:222
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:127
wxString name
void loadFieldAttributes(LIB_FIELD *aField, const LIB_TEXT *aText) const
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:212
void UpdatePinCache()
Updates the local cache of pin positions.
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.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
void SetText(const wxString &aText) override
Sets the field text to aText.
Definition: lib_field.cpp:510
VECTOR2I Center() const
Returns the center point of the line
Definition: seg.h:325
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.
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:143
ECOORD y1
Definition: eagle_parser.h:587
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:207
Eagle circle.
Definition: eagle_parser.h:571
opt_wxString function
Definition: eagle_parser.h:737
wxString symbol
Definition: eagle_parser.h:963
SCH_TEXT * loadLabel(wxXmlNode *aLabelNode, const wxString &aNetName)
bool loadSymbol(wxXmlNode *aSymbolNode, std::unique_ptr< LIB_PART > &aPart, EDEVICE *aDevice, int aGateNumber, const wxString &aGateName)
Define a library symbol object.
The common library.
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:916
#define THROW_IO_ERROR(msg)
SCH_LAYER_ID
Eeschema drawing layers.
int GetBottom() const
Definition: eda_rect.h:122
int GetUnit() const
Class SCH_SHEET_PATH.
wxPoint Centre() const
Definition: eda_rect.h:60
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indention level of aIndentLevel.
LIB_ITEM * loadSymbolWire(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aWireNode, int aGateNumber)
wxString name
Definition: eagle_parser.h:962
Eagle XML rectangle in binary.
Definition: eagle_parser.h:584
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
opt_int align
Definition: eagle_parser.h:671
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:209
virtual wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:194
LIB_PART * GetPart() const
Get the shared LIB_PART.
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
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:204
Class EATTR parses an Eagle "attribute" XML element.
Definition: eagle_parser.h:603
static COMPONENT_ORIENTATION_T kiCadComponentRotation(float eagleDegrees)
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:160
Definition the SCH_COMPONENT class for Eeschema.
ECOORD x1
Definition: eagle_parser.h:586
opt_erot rot
Definition: eagle_parser.h:655
void loadDrawing(wxXmlNode *aDrawingNode)
const char * name
Definition: DXF_plotter.cpp:61
ECOORD x
Definition: eagle_parser.h:748
Segment description base class to describe items which have 2 end points (track, wire, draw line ...)
Definition: sch_line.h:41
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:162
bool IsVisible() const
Definition: lib_field.h:166
#define max(a, b)
Definition: auxiliary.h:86
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:206
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:259
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:69
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
int GetWidth() const
Definition: eda_rect.h:117
static wxString extractNetName(const wxString &aPinName)
Extracts the net name part from a pin name (e.g. return &#39;GND&#39; for pin named &#39;GND@2&#39;) ...
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores &#39;_&#39;.
Definition: lib_id.cpp:352
std::vector< SCH_TEXT * > labels
LIB_TEXT * loadSymbolText(std::unique_ptr< LIB_PART > &aPart, wxXmlNode *aLibText, int aGateNumber)
int GetY() const
Definition: eda_rect.h:110
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:732
wxString name
Definition: eagle_parser.h:730
opt_wxString package
classes and function to generate graphics to plt or draw titles blocks and frame references ...
std::pair< VECTOR2I, const SEG * > findNearestLinePoint(const wxPoint &aPoint, const std::vector< SEG > &aLines) const
bool spin
Definition: eagle_parser.h:482
const wxSize & GetTextSize() const
Definition: eda_text.h:228
ECOORD y2
Definition: eagle_parser.h:589
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:129
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:757
const SEG * LabelAttached(const SCH_TEXT *aLabel) const
Tests if a particular label is attached to any of the stored segments
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
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
wxSize ConvertSize() const
Calculate text size based on font type and size.
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:913
boost::ptr_map< wxString, LIB_PART > KiCadSymbols
#define VALUE
void SetBold(bool aBold)
Definition: eda_text.h:185
void SetPosition(const wxPoint &aPosition) override
Function SetPosition set the schematic item position to aPosition.
Definition: sch_field.cpp:543
opt_wxString visible
Definition: eagle_parser.h:734
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Implementation of the label properties dialog.
opt_wxString length
Definition: eagle_parser.h:735
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:756
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:48
int ToSchUnits() const
Definition: eagle_parser.h:438
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:161
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.
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
wxPoint GetPinPhysicalPosition(const LIB_PIN *Pin) const
opt_erot rot
Definition: eagle_parser.h:739
VECTOR2I B
Definition: seg.h:47