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