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