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