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