KiCad PCB EDA Suite
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) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 /*
27 
28 Pcbnew PLUGIN for Eagle 6.x XML *.brd and footprint format.
29 
30 XML parsing and converting:
31 Getting line numbers and byte offsets from the source XML file is not
32 possible using currently available XML libraries within KiCad project:
33 wxXmlDocument and boost::property_tree.
34 
35 property_tree will give line numbers but no byte offsets, and only during
36 document loading. This means that if we have a problem after the document is
37 successfully loaded, there is no way to correlate back to line number and byte
38 offset of the problem. So a different approach is taken, one which relies on the
39 XML elements themselves using an XPATH type of reporting mechanism. The path to
40 the problem is reported in the error messages. This means keeping track of that
41 path as we traverse the XML document for the sole purpose of accurate error
42 reporting.
43 
44 User can load the source XML file into firefox or other xml browser and follow
45 our error message.
46 
47 Load() TODO's
48 
49 *) verify zone fill clearances are correct
50 
51 */
52 
53 #include <errno.h>
54 
55 #include <wx/string.h>
56 #include <wx/xml/xml.h>
57 
58 #include <common.h>
59 #include <macros.h>
60 #include <fctsys.h>
61 #include <trigo.h>
62 #include <macros.h>
63 #include <kicad_string.h>
64 #include <properties.h>
65 #include <wx/filename.h>
66 
67 #include <class_board.h>
68 #include <class_module.h>
69 #include <class_track.h>
70 #include <class_edge_mod.h>
71 #include <class_zone.h>
72 #include <class_pcb_text.h>
73 #include <class_dimension.h>
74 
75 #include <eagle_plugin.h>
76 
77 using namespace std;
78 
79 
80 typedef MODULE_MAP::iterator MODULE_ITER;
81 typedef MODULE_MAP::const_iterator MODULE_CITER;
82 
83 
86 static double parseEagle( const wxString& aDistance )
87 {
88  double ret = strtod( aDistance.c_str(), NULL );
89  if( aDistance.npos != aDistance.find( "mil" ) )
90  ret = IU_PER_MILS * ret;
91  else
92  ret = IU_PER_MM * ret;
93 
94  return ret;
95 }
96 
97 
98 void ERULES::parse( wxXmlNode* aRules )
99 {
100  wxXmlNode* child = aRules->GetChildren();
101 
102  while( child )
103  {
104  if( child->GetName() == "param" )
105  {
106  const wxString& name = child->GetAttribute( "name" );
107  const wxString& value = child->GetAttribute( "value" );
108 
109  if( name == "psElongationLong" )
110  psElongationLong = wxAtoi( value );
111  else if( name == "psElongationOffset" )
112  psElongationOffset = wxAtoi( value );
113  else if( name == "rvPadTop" )
114  value.ToDouble( &rvPadTop );
115  else if( name == "rlMinPadTop" )
116  rlMinPadTop = parseEagle( value );
117  else if( name == "rlMaxPadTop" )
118  rlMaxPadTop = parseEagle( value );
119  else if( name == "rvViaOuter" )
120  value.ToDouble( &rvViaOuter );
121  else if( name == "rlMinViaOuter" )
122  rlMinViaOuter = parseEagle( value );
123  else if( name == "rlMaxViaOuter" )
124  rlMaxViaOuter = parseEagle( value );
125  else if( name == "mdWireWire" )
126  mdWireWire = parseEagle( value );
127  }
128 
129  child = child->GetNext();
130  }
131 }
132 
133 
135  m_rules( new ERULES() ),
136  m_xpath( new XPATH() ),
137  m_mod_time( wxDateTime::Now() )
138 {
139  init( NULL );
140 
141  clear_cu_map();
142 }
143 
144 
146 {
147  delete m_rules;
148  delete m_xpath;
149 }
150 
151 
152 const wxString EAGLE_PLUGIN::PluginName() const
153 {
154  return wxT( "Eagle" );
155 }
156 
157 
158 const wxString EAGLE_PLUGIN::GetFileExtension() const
159 {
160  return wxT( "brd" );
161 }
162 
163 
164 int inline EAGLE_PLUGIN::kicad( double d ) const
165 {
166  return KiROUND( biu_per_mm * d );
167 }
168 
169 
170 wxSize inline EAGLE_PLUGIN::kicad_fontz( double d ) const
171 {
172  // texts seem to better match eagle when scaled down by 0.95
173  int kz = kicad( d ) * 95 / 100;
174  return wxSize( kz, kz );
175 }
176 
177 
178 BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
179 {
180  LOCALE_IO toggle; // toggles on, then off, the C locale.
181  wxXmlNode* doc;
182 
183  init( aProperties );
184 
185  m_board = aAppendToMe ? aAppendToMe : new BOARD();
186 
187  // Give the filename to the board if it's new
188  if( !aAppendToMe )
189  m_board->SetFileName( aFileName );
190 
191  // delete on exception, if I own m_board, according to aAppendToMe
192  unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
193 
194  try
195  {
196  // Load the document
197  wxXmlDocument xmlDocument;
198  wxFileName fn = aFileName;
199 
200  if( !xmlDocument.Load( fn.GetFullPath() ) )
201  THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
202  fn.GetFullPath() ) );
203 
204  doc = xmlDocument.GetRoot();
205 
206  m_min_trace = INT_MAX;
207  m_min_via = INT_MAX;
208  m_min_via_hole = INT_MAX;
209 
210  loadAllSections( doc );
211 
212  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
213 
214  if( m_min_trace < designSettings.m_TrackMinWidth )
215  designSettings.m_TrackMinWidth = m_min_trace;
216 
217  if( m_min_via < designSettings.m_ViasMinSize )
218  designSettings.m_ViasMinSize = m_min_via;
219 
220  if( m_min_via_hole < designSettings.m_ViasMinDrill )
221  designSettings.m_ViasMinDrill = m_min_via_hole;
222 
223  if( m_rules->mdWireWire )
224  {
225  NETCLASSPTR defaultNetclass = designSettings.GetDefault();
226  int clearance = KiROUND( m_rules->mdWireWire );
227 
228  if( clearance < defaultNetclass->GetClearance() )
229  defaultNetclass->SetClearance( clearance );
230  }
231 
232  // should be empty, else missing m_xpath->pop()
233  wxASSERT( m_xpath->Contents().size() == 0 );
234  }
235  // Catch all exceptions thrown from the parser.
236  catch( const XML_PARSER_ERROR &exc )
237  {
238  string errmsg = exc.what();
239 
240  errmsg += "\n@ ";
241  errmsg += m_xpath->Contents();
242 
243  THROW_IO_ERROR( errmsg );
244  }
245 
246  // IO_ERROR exceptions are left uncaught, they pass upwards from here.
247 
248  // Ensure the copper layers count is a multiple of 2
249  // Pcbnew does not like boards with odd layers count
250  // (these boards cannot exist. they actually have a even layers count)
251  int lyrcnt = m_board->GetCopperLayerCount();
252 
253  if( (lyrcnt % 2) != 0 )
254  {
255  lyrcnt++;
256  m_board->SetCopperLayerCount( lyrcnt );
257  }
258 
259  centerBoard();
260 
261  deleter.release();
262  return m_board;
263 }
264 
265 
266 void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
267 {
268  m_hole_count = 0;
269  m_min_trace = 0;
270  m_min_via = 0;
271  m_min_via_hole = 0;
272  m_xpath->clear();
273  m_pads_to_nets.clear();
274 
275  // m_templates.clear(); this is the FOOTPRINT cache too
276 
277  m_board = NULL;
278  m_props = aProperties;
279 
280  mm_per_biu = 1/IU_PER_MM;
281  biu_per_mm = IU_PER_MM;
282 
283  delete m_rules;
284  m_rules = new ERULES();
285 }
286 
287 
289 {
290  // All cu layers are invalid until we see them in the <layers> section while
291  // loading either a board or library. See loadLayerDefs().
292  for( unsigned i = 0; i < DIM(m_cu_map); ++i )
293  m_cu_map[i] = -1;
294 }
295 
296 
297 void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
298 {
299  wxXmlNode* drawing = MapChildren( aDoc )["drawing"];
300  NODE_MAP drawingChildren = MapChildren( drawing );
301 
302  wxXmlNode* board = drawingChildren["board"];
303  NODE_MAP boardChildren = MapChildren( board );
304 
305  m_xpath->push( "eagle.drawing" );
306 
307  {
308  m_xpath->push( "board" );
309 
310  wxXmlNode* designrules = boardChildren["designrules"];
311  loadDesignRules( designrules );
312 
313  m_xpath->pop();
314  }
315 
316  {
317  m_xpath->push( "layers" );
318 
319  wxXmlNode* layers = drawingChildren["layers"];
320  loadLayerDefs( layers );
321 
322  m_xpath->pop();
323  }
324 
325  {
326  m_xpath->push( "board" );
327 
328  wxXmlNode* plain = boardChildren["plain"];
329  loadPlain( plain );
330 
331  wxXmlNode* signals = boardChildren["signals"];
332  loadSignals( signals );
333 
334  wxXmlNode* libs = boardChildren["libraries"];
335  loadLibraries( libs );
336 
337  wxXmlNode* elems = boardChildren["elements"];
338  loadElements( elems );
339 
340  m_xpath->pop(); // "board"
341  }
342 
343  m_xpath->pop(); // "eagle.drawing"
344 }
345 
346 
347 void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
348 {
349  m_xpath->push( "designrules" );
350  m_rules->parse( aDesignRules );
351  m_xpath->pop(); // "designrules"
352 }
353 
354 
355 void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
356 {
357  typedef std::vector<ELAYER> ELAYERS;
358  typedef ELAYERS::const_iterator EITER;
359 
360  ELAYERS cu; // copper layers
361 
362  // Get the first layer and iterate
363  wxXmlNode* layerNode = aLayers->GetChildren();
364 
365  // find the subset of layers that are copper, and active
366  while( layerNode )
367  {
368  ELAYER elayer( layerNode );
369 
370  if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
371  {
372  cu.push_back( elayer );
373  }
374 
375  layerNode = layerNode->GetNext();
376  }
377 
378  // establish cu layer map:
379  int ki_layer_count = 0;
380 
381  for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
382  {
383  if( ki_layer_count == 0 )
384  m_cu_map[it->number] = F_Cu;
385  else if( ki_layer_count == int( cu.size()-1 ) )
386  m_cu_map[it->number] = B_Cu;
387  else
388  {
389  // some eagle boards do not have contiguous layer number sequences.
390 
391 #if 0 // pre PCB_LAYER_ID & LSET:
392  m_cu_map[it->number] = cu.size() - 1 - ki_layer_count;
393 #else
394  m_cu_map[it->number] = ki_layer_count;
395 #endif
396  }
397  }
398 
399 #if 0 && defined(DEBUG)
400  printf( "m_cu_map:\n" );
401  for( unsigned i=0; i<DIM(m_cu_map); ++i )
402  {
403  printf( "\t[%d]:%d\n", i, m_cu_map[i] );
404  }
405 #endif
406 
407  // Set the layer names and cu count iff we're loading a board.
408  if( m_board )
409  {
410  m_board->SetCopperLayerCount( cu.size() );
411 
412  for( EITER it = cu.begin(); it != cu.end(); ++it )
413  {
414  PCB_LAYER_ID layer = kicad_layer( it->number );
415 
416  // these function provide their own protection against UNDEFINED_LAYER:
417  m_board->SetLayerName( layer, FROM_UTF8( it->name.c_str() ) );
418  m_board->SetLayerType( layer, LT_SIGNAL );
419 
420  // could map the colors here
421  }
422  }
423 }
424 
425 
426 void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
427 {
428  m_xpath->push( "plain" );
429 
430  // Get the first graphic and iterate
431  wxXmlNode* gr = aGraphics->GetChildren();
432 
433  // (polygon | wire | text | circle | rectangle | frame | hole)*
434  while( gr )
435  {
436  wxString grName = gr->GetName();
437 
438  if( grName == "wire" )
439  {
440  m_xpath->push( "wire" );
441 
442  EWIRE w( gr );
443  PCB_LAYER_ID layer = kicad_layer( w.layer );
444 
445  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
446  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
447 
448  if( layer != UNDEFINED_LAYER )
449  {
450  DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
451  m_board->Add( dseg, ADD_APPEND );
452 
453  if( !w.curve )
454  {
455  dseg->SetStart( start );
456  dseg->SetEnd( end );
457  }
458  else
459  {
460  wxPoint center = kicad_arc_center( start, end, *w.curve);
461 
462  dseg->SetShape( S_ARC );
463  dseg->SetStart( center );
464  dseg->SetEnd( start );
465  dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
466  }
467 
468  dseg->SetTimeStamp( timeStamp( gr ) );
469  dseg->SetLayer( layer );
470  dseg->SetWidth( Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ) );
471  }
472  m_xpath->pop();
473  }
474  else if( grName == "text" )
475  {
476  m_xpath->push( "text" );
477 
478  ETEXT t( gr );
479  PCB_LAYER_ID layer = kicad_layer( t.layer );
480 
481  if( layer != UNDEFINED_LAYER )
482  {
483  TEXTE_PCB* pcbtxt = new TEXTE_PCB( m_board );
484  m_board->Add( pcbtxt, ADD_APPEND );
485 
486  pcbtxt->SetLayer( layer );
487  pcbtxt->SetTimeStamp( timeStamp( gr ) );
488  pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
489  pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
490 
491  pcbtxt->SetTextSize( kicad_fontz( t.size ) );
492 
493  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
494 
495  pcbtxt->SetThickness( kicad( t.size * ratio / 100 ) );
496 
497  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
498 
499  if( t.rot )
500  {
501  int sign = t.rot->mirror ? -1 : 1;
502  pcbtxt->SetMirrored( t.rot->mirror );
503 
504  double degrees = t.rot->degrees;
505 
506  if( degrees == 90 || t.rot->spin )
507  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
508  else if( degrees == 180 )
509  align = ETEXT::TOP_RIGHT;
510  else if( degrees == 270 )
511  {
512  pcbtxt->SetTextAngle( sign * 90 * 10 );
513  align = ETEXT::TOP_RIGHT;
514  }
515  else // Ok so text is not at 90,180 or 270 so do some funny stuf to get placement right
516  {
517  if( ( degrees > 0 ) && ( degrees < 90 ) )
518  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
519  else if( ( degrees > 90 ) && ( degrees < 180 ) )
520  {
521  pcbtxt->SetTextAngle( sign * ( t.rot->degrees + 180 ) * 10 );
522  align = ETEXT::TOP_RIGHT;
523  }
524  else if( ( degrees > 180 ) && ( degrees < 270 ) )
525  {
526  pcbtxt->SetTextAngle( sign * ( t.rot->degrees - 180 ) * 10 );
527  align = ETEXT::TOP_RIGHT;
528  }
529  else if( ( degrees > 270 ) && ( degrees < 360 ) )
530  {
531  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
532  align = ETEXT::BOTTOM_LEFT;
533  }
534  }
535  }
536 
537  switch( align )
538  {
539  case ETEXT::CENTER:
540  // this was the default in pcbtxt's constructor
541  break;
542 
543  case ETEXT::CENTER_LEFT:
545  break;
546 
547  case ETEXT::CENTER_RIGHT:
549  break;
550 
551  case ETEXT::TOP_CENTER:
553  break;
554 
555  case ETEXT::TOP_LEFT:
558  break;
559 
560  case ETEXT::TOP_RIGHT:
563  break;
564 
567  break;
568 
569  case ETEXT::BOTTOM_LEFT:
572  break;
573 
574  case ETEXT::BOTTOM_RIGHT:
577  break;
578  }
579  }
580  m_xpath->pop();
581  }
582  else if( grName == "circle" )
583  {
584  m_xpath->push( "circle" );
585 
586  ECIRCLE c( gr );
587  PCB_LAYER_ID layer = kicad_layer( c.layer );
588 
589  if( layer != UNDEFINED_LAYER ) // unsupported layer
590  {
591  DRAWSEGMENT* dseg = new DRAWSEGMENT( m_board );
592  m_board->Add( dseg, ADD_APPEND );
593 
594  dseg->SetShape( S_CIRCLE );
595  dseg->SetTimeStamp( timeStamp( gr ) );
596  dseg->SetLayer( layer );
597  dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
598  dseg->SetEnd( wxPoint( kicad_x( c.x + c.radius ), kicad_y( c.y ) ) );
599  dseg->SetWidth( kicad( c.width ) );
600  }
601  m_xpath->pop();
602  }
603  else if( grName == "rectangle" )
604  {
605  // This seems to be a simplified rectangular [copper] zone, cannot find any
606  // net related info on it from the DTD.
607  m_xpath->push( "rectangle" );
608 
609  ERECT r( gr );
610  PCB_LAYER_ID layer = kicad_layer( r.layer );
611 
612  if( IsCopperLayer( layer ) )
613  {
614  // use a "netcode = 0" type ZONE:
615  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
616  m_board->Add( zone, ADD_APPEND );
617 
618  zone->SetTimeStamp( timeStamp( gr ) );
619  zone->SetLayer( layer );
621 
623 
624  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
625  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
626  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
627  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
628 
629  // this is not my fault:
630  zone->SetHatch( outline_hatch, Mils2iu( zone->GetDefaultHatchPitchMils() ), true );
631  }
632 
633  m_xpath->pop();
634  }
635  else if( grName == "hole" )
636  {
637  m_xpath->push( "hole" );
638  EHOLE e( gr );
639 
640  // Fabricate a MODULE with a single PAD_ATTRIB_HOLE_NOT_PLATED pad.
641  // Use m_hole_count to gen up a unique name.
642 
643  MODULE* module = new MODULE( m_board );
644  m_board->Add( module, ADD_APPEND );
645 
646  char temp[40];
647  sprintf( temp, "@HOLE%d", m_hole_count++ );
648  module->SetReference( FROM_UTF8( temp ) );
649  module->Reference().SetVisible( false );
650 
651  wxPoint pos( kicad_x( e.x ), kicad_y( e.y ) );
652 
653  module->SetPosition( pos );
654 
655  // Add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
656  D_PAD* pad = new D_PAD( module );
657  module->Pads().PushBack( pad );
658 
659  pad->SetShape( PAD_SHAPE_CIRCLE );
661 
662  /* pad's position is already centered on module at relative (0, 0)
663  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
664 
665  pad->SetPos0( padpos );
666  pad->SetPosition( padpos + module->GetPosition() );
667  */
668 
669  wxSize sz( kicad( e.drill ), kicad( e.drill ) );
670 
671  pad->SetDrillSize( sz );
672  pad->SetSize( sz );
673 
674  pad->SetLayerSet( LSET::AllCuMask() );
675  m_xpath->pop();
676  }
677  else if( grName == "frame" )
678  {
679  // picture this
680  }
681  else if( grName == "polygon" )
682  {
683  // could be on a copper layer, could be on another layer.
684  // copper layer would be done using netCode=0 type of ZONE_CONTAINER.
685  }
686  else if( grName == "dimension" )
687  {
688  EDIMENSION d( gr );
689  PCB_LAYER_ID layer = kicad_layer( d.layer );
690 
691  if( layer != UNDEFINED_LAYER )
692  {
693  DIMENSION* dimension = new DIMENSION( m_board );
694  m_board->Add( dimension, ADD_APPEND );
695 
696  dimension->SetLayer( layer );
697  // The origin and end are assumed to always be in this order from eagle
698  dimension->SetOrigin( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ) );
699  dimension->SetEnd( wxPoint( kicad_x( d.x2 ), kicad_y( d.y2 ) ) );
701 
703  int maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetTextSize() );
704 
705  if( width > maxThickness )
706  width = maxThickness;
707 
708  dimension->Text().SetThickness( width );
709  dimension->SetWidth( width );
710 
711  // check which axis the dimension runs in
712  // because the "height" of the dimension is perpendicular to that axis
713  // Note the check is just if two axes are close enough to each other
714  // Eagle appears to have some rounding errors
715  if( fabs( d.x1 - d.x2 ) < 0.05 )
716  dimension->SetHeight( kicad_x( d.x1 - d.x3 ) );
717  else
718  dimension->SetHeight( kicad_y( d.y3 - d.y1 ) );
719 
720  dimension->AdjustDimensionDetails();
721  }
722  }
723 
724  // Get next graphic
725  gr = gr->GetNext();
726  }
727  m_xpath->pop();
728 }
729 
730 
731 void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const string* aLibName )
732 {
733  m_xpath->push( "packages" );
734 
735  // library will have <xmlattr> node, skip that and get the single packages node
736  wxXmlNode* packages = MapChildren( aLib )["packages"];
737 
738 
739  // Create a MODULE for all the eagle packages, for use later via a copy constructor
740  // to instantiate needed MODULES in our BOARD. Save the MODULE templates in
741  // a MODULE_MAP using a single lookup key consisting of libname+pkgname.
742 
743  // Get the first package and iterate
744  wxXmlNode* package = packages->GetChildren();
745 
746  while( package )
747  {
748  m_xpath->push( "package", "name" );
749 
750  const wxString& pack_ref = package->GetAttribute( "name" );
751 
752  string pack_name( pack_ref.ToStdString() );
753 
754  ReplaceIllegalFileNameChars( &pack_name );
755 
756  m_xpath->Value( pack_name.c_str() );
757 
758  string key = aLibName ? makeKey( *aLibName, pack_name ) : pack_name;
759 
760  MODULE* m = makeModule( package, pack_name );
761 
762  // add the templating MODULE to the MODULE template factory "m_templates"
763  std::pair<MODULE_ITER, bool> r = m_templates.insert( {key, m} );
764 
765  if( !r.second
766  // && !( m_props && m_props->Value( "ignore_duplicates" ) )
767  )
768  {
769  wxString lib = aLibName ? FROM_UTF8( aLibName->c_str() ) : m_lib_path;
770  wxString pkg = FROM_UTF8( pack_name.c_str() );
771 
772  wxString emsg = wxString::Format(
773  _( "<package> name: '%s' duplicated in eagle <library>: '%s'" ),
774  GetChars( pkg ),
775  GetChars( lib )
776  );
777  THROW_IO_ERROR( emsg );
778  }
779 
780  m_xpath->pop();
781 
782  package = package->GetNext();
783  }
784 
785  m_xpath->pop(); // "packages"
786 }
787 
788 
789 void EAGLE_PLUGIN::loadLibraries( wxXmlNode* aLibs )
790 {
791  m_xpath->push( "libraries.library", "name" );
792 
793  // Get the first library and iterate
794  wxXmlNode* library = aLibs->GetChildren();
795 
796  while( library )
797  {
798  const string& lib_name = library->GetAttribute( "name" ).ToStdString();
799 
800  m_xpath->Value( lib_name.c_str() );
801 
802  loadLibrary( library, &lib_name );
803 
804  library = library->GetNext();
805  }
806 
807  m_xpath->pop();
808 }
809 
810 
811 void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
812 {
813  m_xpath->push( "elements.element", "name" );
814 
815  EATTR name;
816  EATTR value;
817  bool refanceNamePresetInPackageLayout;
818  bool valueNamePresetInPackageLayout;
819 
820  // Get the first element and iterate
821  wxXmlNode* element = aElements->GetChildren();
822 
823  while( element )
824  {
825  if( element->GetName() != "element" )
826  continue;
827 
828  EELEMENT e( element );
829 
830  // use "NULL-ness" as an indication of presence of the attribute:
831  EATTR* nameAttr = 0;
832  EATTR* valueAttr = 0;
833 
834  m_xpath->Value( e.name.c_str() );
835 
836  string pkg_key = makeKey( e.library, e.package );
837 
838  MODULE_CITER mi = m_templates.find( pkg_key );
839 
840  if( mi == m_templates.end() )
841  {
842  wxString emsg = wxString::Format( _( "No '%s' package in library '%s'" ),
843  GetChars( FROM_UTF8( e.package.c_str() ) ),
844  GetChars( FROM_UTF8( e.library.c_str() ) ) );
845  THROW_IO_ERROR( emsg );
846  }
847 
848  // copy constructor to clone the template
849  MODULE* m = new MODULE( *mi->second );
850  m_board->Add( m, ADD_APPEND );
851 
852  // update the nets within the pads of the clone
853  for( D_PAD* pad = m->Pads(); pad; pad = pad->Next() )
854  {
855  string pn_key = makeKey( e.name, TO_UTF8( pad->GetPadName() ) );
856 
857  NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
858  if( ni != m_pads_to_nets.end() )
859  {
860  const ENET* enet = &ni->second;
861  pad->SetNetCode( enet->netcode );
862  }
863  }
864 
865  refanceNamePresetInPackageLayout = true;
866  valueNamePresetInPackageLayout = true;
867  m->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
868  // Is >NAME field set in package layout ?
869  if( m->GetReference().size() == 0 )
870  {
871  m->Reference().SetVisible( false ); // No so no show
872  refanceNamePresetInPackageLayout = false;
873  }
874  // Is >VALUE field set in package layout
875  if( m->GetValue().size() == 0 )
876  {
877  m->Value().SetVisible( false ); // No so no show
878  valueNamePresetInPackageLayout = false;
879  }
880  m->SetReference( FROM_UTF8( e.name.c_str() ) );
881  m->SetValue( FROM_UTF8( e.value.c_str() ) );
882 
883  if( !e.smashed )
884  { // Not smashed so show NAME & VALUE
885  if( valueNamePresetInPackageLayout )
886  m->Value().SetVisible( true ); // Only if place holder in package layout
887  if( refanceNamePresetInPackageLayout )
888  m->Reference().SetVisible( true ); // Only if place holder in package layout
889  }
890  else if( *e.smashed == true )
891  { // Smasted so set default to no show for NAME and VALUE
892  m->Value().SetVisible( false );
893  m->Reference().SetVisible( false );
894 
895  // initalize these to default values incase the <attribute> elements are not present.
896  m_xpath->push( "attribute", "name" );
897 
898  // VALUE and NAME can have something like our text "effects" overrides
899  // in SWEET and new schematic. Eagle calls these XML elements "attribute".
900  // There can be one for NAME and/or VALUE both. Features present in the
901  // EATTR override the ones established in the package only if they are
902  // present here (except for rot, which if not present means angle zero).
903  // So the logic is a bit different than in packageText() and in plain text.
904 
905  // Get the first attribute and iterate
906  wxXmlNode* attribute = element->GetChildren();
907 
908  while( attribute )
909  {
910  if( attribute->GetName() != "attribute" )
911  continue;
912 
913  EATTR a( attribute );
914 
915  if( a.name == "NAME" )
916  {
917  name = a;
918  nameAttr = &name;
919 
920  // do we have a display attribute ?
921  if( a.display )
922  {
923  // Yes!
924  switch( *a.display )
925  {
926  case EATTR::VALUE :
927  nameAttr->name = e.name;
928  m->SetReference( e.name );
929  if( refanceNamePresetInPackageLayout )
930  m->Reference().SetVisible( true );
931  break;
932 
933  case EATTR::NAME :
934  if( refanceNamePresetInPackageLayout )
935  {
936  m->SetReference( "NAME" );
937  m->Reference().SetVisible( true );
938  }
939  break;
940 
941  case EATTR::BOTH :
942  if( refanceNamePresetInPackageLayout )
943  m->Reference().SetVisible( true );
944  nameAttr->name = nameAttr->name + " = " + e.name;
945  m->SetReference( "NAME = " + e.name );
946  break;
947 
948  case EATTR::Off :
949  m->Reference().SetVisible( false );
950  break;
951 
952  default:
953  nameAttr->name = e.name;
954  if( refanceNamePresetInPackageLayout )
955  m->Reference().SetVisible( true );
956  }
957  }
958  else
959  // No display, so default is visable, and show value of NAME
960  m->Reference().SetVisible( true );
961  }
962  else if( a.name == "VALUE" )
963  {
964  value = a;
965  valueAttr = &value;
966 
967  if( a.display )
968  {
969  // Yes!
970  switch( *a.display )
971  {
972  case EATTR::VALUE :
973  valueAttr->value = e.value;
974  m->SetValue( e.value );
975  if( valueNamePresetInPackageLayout )
976  m->Value().SetVisible( true );
977  break;
978 
979  case EATTR::NAME :
980  if( valueNamePresetInPackageLayout )
981  m->Value().SetVisible( true );
982  m->SetValue( "VALUE" );
983  break;
984 
985  case EATTR::BOTH :
986  if( valueNamePresetInPackageLayout )
987  m->Value().SetVisible( true );
988  valueAttr->value = "VALUE = " + e.value;
989  m->SetValue( "VALUE = " + e.value );
990  break;
991 
992  case EATTR::Off :
993  m->Value().SetVisible( false );
994  break;
995 
996  default:
997  valueAttr->value = e.value;
998  if( valueNamePresetInPackageLayout )
999  m->Value().SetVisible( true );
1000  }
1001  }
1002  else
1003  // No display, so default is visible, and show value of NAME
1004  m->Value().SetVisible( true );
1005 
1006  }
1007 
1008  attribute = attribute->GetNext();
1009  }
1010 
1011  m_xpath->pop(); // "attribute"
1012  }
1013 
1014  orientModuleAndText( m, e, nameAttr, valueAttr );
1015 
1016  // Get next element
1017  element = element->GetNext();
1018  }
1019 
1020  m_xpath->pop(); // "elements.element"
1021 }
1022 
1023 
1025  const EATTR* nameAttr, const EATTR* valueAttr )
1026 {
1027  if( e.rot )
1028  {
1029  if( e.rot->mirror )
1030  {
1031  double orientation = e.rot->degrees + 180.0;
1032  m->SetOrientation( orientation * 10 );
1033  m->Flip( m->GetPosition() );
1034  }
1035  else
1036  m->SetOrientation( e.rot->degrees * 10 );
1037  }
1038 
1039  orientModuleText( m, e, &m->Reference(), nameAttr );
1040  orientModuleText( m, e, &m->Value(), valueAttr );
1041 }
1042 
1043 
1045  TEXTE_MODULE* txt, const EATTR* aAttr )
1046 {
1047  // Smashed part ?
1048  if( aAttr )
1049  { // Yes
1050  const EATTR& a = *aAttr;
1051 
1052  if( a.value )
1053  {
1054  txt->SetText( FROM_UTF8( a.value->c_str() ) );
1055  }
1056 
1057  if( a.x && a.y ) // boost::optional
1058  {
1059  wxPoint pos( kicad_x( *a.x ), kicad_y( *a.y ) );
1060  txt->SetTextPos( pos );
1061  }
1062 
1063  // Even though size and ratio are both optional, I am not seeing
1064  // a case where ratio is present but size is not.
1065  double ratio = 8;
1066  wxSize fontz = txt->GetTextSize();
1067 
1068  if( a.size )
1069  {
1070  fontz = kicad_fontz( *a.size );
1071  txt->SetTextSize( fontz );
1072 
1073  if( a.ratio )
1074  ratio = *a.ratio;
1075  }
1076 
1077  int lw = int( fontz.y * ratio / 100.0 );
1078  txt->SetThickness( lw );
1079 
1080  int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
1081 
1082  // The "rot" in a EATTR seems to be assumed to be zero if it is not
1083  // present, and this zero rotation becomes an override to the
1084  // package's text field. If they did not want zero, they specify
1085  // what they want explicitly.
1086  double degrees = a.rot ? a.rot->degrees : 0;
1087  double orient; // relative to parent
1088 
1089  int sign = 1;
1090  bool spin = false;
1091 
1092  if( a.rot )
1093  {
1094  spin = a.rot->spin;
1095  sign = a.rot->mirror ? -1 : 1;
1096  txt->SetMirrored( a.rot->mirror );
1097  }
1098 
1099  if( degrees == 90 || degrees == 0 || spin )
1100  {
1101  orient = degrees - m->GetOrientation() / 10;
1102  txt->SetTextAngle( sign * orient * 10 );
1103  }
1104  else if( degrees == 180 )
1105  {
1106  orient = 0 - m->GetOrientation() / 10;
1107  txt->SetTextAngle( sign * orient * 10 );
1108  align = ETEXT::TOP_RIGHT;
1109  }
1110  else if( degrees == 270 )
1111  {
1112  orient = 90 - m->GetOrientation() / 10;
1113  align = ETEXT::TOP_RIGHT;
1114  txt->SetTextAngle( sign * orient * 10 );
1115  }
1116  else
1117  {
1118  orient = 90 - degrees - m->GetOrientation() / 10;
1119  txt->SetTextAngle( sign * orient * 10 );
1120  }
1121 
1122  switch( align )
1123  {
1124  case ETEXT::TOP_RIGHT:
1127  break;
1128 
1129  case ETEXT::BOTTOM_LEFT:
1132  break;
1133 
1134  default:
1135  ;
1136  }
1137  }
1138  else // Part is not smash so use Lib default for NAME/VALUE // the text is per the original package, sans <attribute>
1139  {
1140  double degrees = ( txt->GetTextAngle() + m->GetOrientation() ) / 10;
1141 
1142  // @todo there are a few more cases than these to contend with:
1143  if( (!txt->IsMirrored() && ( abs( degrees ) == 180 || abs( degrees ) == 270 ))
1144  || ( txt->IsMirrored() && ( degrees == 360 ) ) )
1145  {
1146  // ETEXT::TOP_RIGHT:
1149  }
1150  }
1151 }
1152 
1153 
1154 MODULE* EAGLE_PLUGIN::makeModule( wxXmlNode* aPackage, const string& aPkgName ) const
1155 {
1156  std::unique_ptr<MODULE> m( new MODULE( m_board ) );
1157 
1158  m->SetFPID( LIB_ID( aPkgName ) );
1159 
1160  // Get the first package item and iterate
1161  wxXmlNode* packageItem = aPackage->GetChildren();
1162 
1163  while( packageItem )
1164  {
1165  const wxString& itemName = packageItem->GetName();
1166 
1167  if( itemName == "description" )
1168  m->SetDescription( FROM_UTF8( packageItem->GetNodeContent().c_str() ) );
1169 
1170  else if( itemName == "wire" )
1171  packageWire( m.get(), packageItem );
1172 
1173  else if( itemName == "pad" )
1174  packagePad( m.get(), packageItem );
1175 
1176  else if( itemName == "text" )
1177  packageText( m.get(), packageItem );
1178 
1179  else if( itemName == "rectangle" )
1180  packageRectangle( m.get(), packageItem );
1181 
1182  else if( itemName == "polygon" )
1183  packagePolygon( m.get(), packageItem );
1184 
1185  else if( itemName == "circle" )
1186  packageCircle( m.get(), packageItem );
1187 
1188  else if( itemName == "hole" )
1189  packageHole( m.get(), packageItem );
1190 
1191  else if( itemName == "smd" )
1192  packageSMD( m.get(), packageItem );
1193 
1194  packageItem = packageItem->GetNext();
1195  }
1196 
1197  return m.release();
1198 }
1199 
1200 
1201 void EAGLE_PLUGIN::packageWire( MODULE* aModule, wxXmlNode* aTree ) const
1202 {
1203  EWIRE w( aTree );
1204  PCB_LAYER_ID layer = kicad_layer( w.layer );
1205 
1206  if( IsNonCopperLayer( layer ) ) // only valid non-copper wires, skip copper package wires
1207  {
1208  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
1209  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
1210  int width = kicad( w.width );
1211 
1212  // FIXME: the cap attribute is ignored because kicad can't create lines
1213  // with flat ends.
1214  EDGE_MODULE* dwg;
1215  if( !w.curve )
1216  {
1217  dwg = new EDGE_MODULE( aModule, S_SEGMENT );
1218 
1219  dwg->SetStart0( start );
1220  dwg->SetEnd0( end );
1221  }
1222  else
1223  {
1224  dwg = new EDGE_MODULE( aModule, S_ARC );
1225  wxPoint center = kicad_arc_center( start, end, *w.curve);
1226 
1227  dwg->SetStart0( center );
1228  dwg->SetEnd0( start );
1229  dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
1230  }
1231 
1232  dwg->SetLayer( layer );
1233  dwg->SetWidth( width );
1234 
1235  aModule->GraphicalItems().PushBack( dwg );
1236  }
1237 }
1238 
1239 
1240 void EAGLE_PLUGIN::packagePad( MODULE* aModule, wxXmlNode* aTree ) const
1241 {
1242  // this is thru hole technology here, no SMDs
1243  EPAD e( aTree );
1244 
1245  D_PAD* pad = new D_PAD( aModule );
1246  aModule->Pads().PushBack( pad );
1247 
1248  pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
1249 
1250  // pad's "Position" is not relative to the module's,
1251  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
1252 
1253  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1254 
1255  pad->SetPos0( padpos );
1256 
1257  RotatePoint( &padpos, aModule->GetOrientation() );
1258 
1259  pad->SetPosition( padpos + aModule->GetPosition() );
1260 
1261  pad->SetDrillSize( wxSize( kicad( e.drill ), kicad( e.drill ) ) );
1262 
1263  pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
1264 
1265  if( e.shape )
1266  {
1267  switch( *e.shape )
1268  {
1269  case EPAD::ROUND:
1270  wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
1271  break;
1272 
1273  case EPAD::OCTAGON:
1274  // no KiCad octagonal pad shape, use PAD_CIRCLE for now.
1275  // pad->SetShape( PAD_OCTAGON );
1276  wxASSERT( pad->GetShape()==PAD_SHAPE_CIRCLE ); // verify set in D_PAD constructor
1277  break;
1278 
1279  case EPAD::LONG:
1280  pad->SetShape( PAD_SHAPE_OVAL );
1281  break;
1282 
1283  case EPAD::SQUARE:
1284  pad->SetShape( PAD_SHAPE_RECT );
1285  break;
1286 
1287  case EPAD::OFFSET:
1288  ; // don't know what to do here.
1289  }
1290  }
1291  else
1292  {
1293  // if shape is not present, our default is circle and that matches their default "round"
1294  }
1295 
1296  if( e.diameter )
1297  {
1298  int diameter = kicad( *e.diameter );
1299  pad->SetSize( wxSize( diameter, diameter ) );
1300  }
1301  else
1302  {
1303  double drillz = pad->GetDrillSize().x;
1304  double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
1305  annulus = Clamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
1306  int diameter = KiROUND( drillz + 2 * annulus );
1307  pad->SetSize( wxSize( KiROUND( diameter ), KiROUND( diameter ) ) );
1308  }
1309 
1310  if( pad->GetShape() == PAD_SHAPE_OVAL )
1311  {
1312  // The Eagle "long" pad is wider than it is tall,
1313  // m_elongation is percent elongation
1314  wxSize sz = pad->GetSize();
1315  sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
1316  pad->SetSize( sz );
1317  }
1318 
1319  if( e.rot )
1320  {
1321  pad->SetOrientation( e.rot->degrees * 10 );
1322  }
1323 
1324  // @todo: handle stop and thermal
1325 }
1326 
1327 
1328 void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
1329 {
1330  ETEXT t( aTree );
1331  PCB_LAYER_ID layer = kicad_layer( t.layer );
1332 
1333  if( layer == UNDEFINED_LAYER )
1334  {
1335  layer = Cmts_User;
1336  }
1337 
1338  TEXTE_MODULE* txt;
1339 
1340  if( t.text == ">NAME" || t.text == ">name" )
1341  txt = &aModule->Reference();
1342  else if( t.text == ">VALUE" || t.text == ">value" )
1343  txt = &aModule->Value();
1344  else
1345  {
1346  // FIXME: graphical text items are rotated for some reason.
1347  txt = new TEXTE_MODULE( aModule );
1348  aModule->GraphicalItems().PushBack( txt );
1349  }
1350 
1351  txt->SetTimeStamp( timeStamp( aTree ) );
1352  txt->SetText( FROM_UTF8( t.text.c_str() ) );
1353 
1354  wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
1355 
1356  txt->SetTextPos( pos );
1357  txt->SetPos0( pos - aModule->GetPosition() );
1358 
1359  txt->SetLayer( layer );
1360  txt->SetTextSize( kicad_fontz( t.size ) );
1361 
1362  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
1363 
1364  txt->SetThickness( kicad( t.size * ratio / 100 ) );
1365 
1366  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
1367 
1368  // An eagle package is never rotated, the DTD does not allow it.
1369  // angle -= aModule->GetOrienation();
1370 
1371  if( t.rot )
1372  {
1373  int sign = t.rot->mirror ? -1 : 1;
1374  txt->SetMirrored( t.rot->mirror );
1375 
1376  double degrees = t.rot->degrees;
1377 
1378  if( degrees == 90 || t.rot->spin )
1379  txt->SetTextAngle( sign * degrees * 10 );
1380  else if( degrees == 180 )
1381  align = ETEXT::TOP_RIGHT;
1382  else if( degrees == 270 )
1383  {
1384  align = ETEXT::TOP_RIGHT;
1385  txt->SetTextAngle( sign * 90 * 10 );
1386  }
1387  }
1388 
1389  switch( align )
1390  {
1391  case ETEXT::CENTER:
1392  // this was the default in pcbtxt's constructor
1393  break;
1394 
1395  case ETEXT::CENTER_LEFT:
1397  break;
1398 
1399  case ETEXT::CENTER_RIGHT:
1401  break;
1402 
1403  case ETEXT::TOP_CENTER:
1405  break;
1406 
1407  case ETEXT::TOP_LEFT:
1410  break;
1411 
1412  case ETEXT::TOP_RIGHT:
1415  break;
1416 
1417  case ETEXT::BOTTOM_CENTER:
1419  break;
1420 
1421  case ETEXT::BOTTOM_LEFT:
1424  break;
1425 
1426  case ETEXT::BOTTOM_RIGHT:
1429  break;
1430  }
1431 }
1432 
1433 
1434 void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const
1435 {
1436  ERECT r( aTree );
1437  PCB_LAYER_ID layer = kicad_layer( r.layer );
1438 
1439  if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
1440  {
1441  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
1442  aModule->GraphicalItems().PushBack( dwg );
1443 
1444  dwg->SetLayer( layer );
1445  dwg->SetWidth( 0 );
1446 
1447  dwg->SetTimeStamp( timeStamp( aTree ) );
1448 
1449  std::vector<wxPoint> pts;
1450 
1451  wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
1452  wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
1453 
1454  pts.push_back( start );
1455  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
1456  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
1457  pts.push_back( end );
1458 
1459  dwg->SetPolyPoints( pts );
1460 
1461  dwg->SetStart0( start );
1462  dwg->SetEnd0( end );
1463  }
1464 }
1465 
1466 
1467 void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
1468 {
1469  EPOLYGON p( aTree );
1470  PCB_LAYER_ID layer = kicad_layer( p.layer );
1471 
1472  if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
1473  {
1474  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
1475  aModule->GraphicalItems().PushBack( dwg );
1476 
1477  dwg->SetWidth( 0 ); // it's filled, no need for boundary width
1478 
1479  /*
1480  switch( layer )
1481  {
1482  case Eco1_User: layer = F_SilkS; break;
1483  case Eco2_User: layer = B_SilkS; break;
1484 
1485  // all MODULE templates (created from eagle packages) are on front layer
1486  // until cloned.
1487  case Cmts_User: layer = F_SilkS; break;
1488  }
1489  */
1490 
1491  dwg->SetLayer( layer );
1492 
1493  dwg->SetTimeStamp( timeStamp( aTree ) );
1494 
1495  std::vector<wxPoint> pts;
1496  // TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
1497  // pts.reserve( aTree.size() );
1498 
1499  // Get the first vertex and iterate
1500  wxXmlNode* vertex = aTree->GetChildren();
1501 
1502  while( vertex )
1503  {
1504  if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
1505  continue;
1506 
1507  EVERTEX v( vertex );
1508 
1509  pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
1510 
1511  vertex = vertex->GetNext();
1512  }
1513 
1514  dwg->SetPolyPoints( pts );
1515 
1516  dwg->SetStart0( *pts.begin() );
1517  dwg->SetEnd0( pts.back() );
1518  }
1519 }
1520 
1521 
1522 void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
1523 {
1524  ECIRCLE e( aTree );
1525  PCB_LAYER_ID layer = kicad_layer( e.layer );
1526  EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
1527 
1528  aModule->GraphicalItems().PushBack( gr );
1529 
1530  gr->SetWidth( kicad( e.width ) );
1531 
1532  switch( (int) layer )
1533  {
1534  case UNDEFINED_LAYER: layer = Cmts_User; break;
1535  /*
1536  case Eco1_User: layer = F_SilkS; break;
1537  case Eco2_User: layer = B_SilkS; break;
1538  */
1539  default:
1540  break;
1541  }
1542 
1543  gr->SetLayer( layer );
1544  gr->SetTimeStamp( timeStamp( aTree ) );
1545 
1546  gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
1547  gr->SetEnd0( wxPoint( kicad_x( e.x + e.radius ), kicad_y( e.y ) ) );
1548 }
1549 
1550 
1551 void EAGLE_PLUGIN::packageHole( MODULE* aModule, wxXmlNode* aTree ) const
1552 {
1553  EHOLE e( aTree );
1554 
1555  // we add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
1556  D_PAD* pad = new D_PAD( aModule );
1557  aModule->Pads().PushBack( pad );
1558 
1559  pad->SetShape( PAD_SHAPE_CIRCLE );
1561 
1562  // Mechanical purpose only:
1563  // no offset, no net name, no pad name allowed
1564  // pad->SetOffset( wxPoint( 0, 0 ) );
1565  // pad->SetPadName( wxEmptyString );
1566 
1567  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1568 
1569  pad->SetPos0( padpos );
1570  pad->SetPosition( padpos + aModule->GetPosition() );
1571 
1572  wxSize sz( kicad( e.drill ), kicad( e.drill ) );
1573 
1574  pad->SetDrillSize( sz );
1575  pad->SetSize( sz );
1576 
1577  pad->SetLayerSet( LSET::AllCuMask() /* | SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT */ );
1578 }
1579 
1580 
1581 void EAGLE_PLUGIN::packageSMD( MODULE* aModule, wxXmlNode* aTree ) const
1582 {
1583  ESMD e( aTree );
1584  PCB_LAYER_ID layer = kicad_layer( e.layer );
1585 
1586  if( !IsCopperLayer( layer ) )
1587  {
1588  return;
1589  }
1590 
1591  D_PAD* pad = new D_PAD( aModule );
1592  aModule->Pads().PushBack( pad );
1593 
1594  pad->SetPadName( FROM_UTF8( e.name.c_str() ) );
1595  pad->SetShape( PAD_SHAPE_RECT );
1596  pad->SetAttribute( PAD_ATTRIB_SMD );
1597 
1598  // pad's "Position" is not relative to the module's,
1599  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
1600 
1601  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1602 
1603  pad->SetPos0( padpos );
1604 
1605  RotatePoint( &padpos, aModule->GetOrientation() );
1606 
1607  pad->SetPosition( padpos + aModule->GetPosition() );
1608 
1609  pad->SetSize( wxSize( kicad( e.dx ), kicad( e.dy ) ) );
1610 
1611  pad->SetLayer( layer );
1612 
1613  static const LSET front( 3, F_Cu, F_Paste, F_Mask );
1614  static const LSET back( 3, B_Cu, B_Paste, B_Mask );
1615 
1616  if( layer == F_Cu )
1617  pad->SetLayerSet( front );
1618  else if( layer == B_Cu )
1619  pad->SetLayerSet( back );
1620 
1621  // Optional according to DTD
1622  if( e.roundness ) // set set shape to PAD_SHAPE_RECT above, in case roundness is not present
1623  {
1624  if( *e.roundness >= 75 ) // roundness goes from 0-100% as integer
1625  {
1626  if( e.dy == e.dx )
1627  pad->SetShape( PAD_SHAPE_CIRCLE );
1628  else
1629  pad->SetShape( PAD_SHAPE_OVAL );
1630  }
1631  }
1632 
1633  if( e.rot )
1634  {
1635  pad->SetOrientation( e.rot->degrees * 10 );
1636  }
1637 
1638  // don't know what stop, thermals, and cream should look like now.
1639 }
1640 
1642 typedef std::vector<ZONE_CONTAINER*> ZONES;
1643 
1644 
1645 void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
1646 {
1647  ZONES zones; // per net
1648 
1649  m_xpath->push( "signals.signal", "name" );
1650 
1651  int netCode = 1;
1652 
1653  // Get the first signal and iterate
1654  wxXmlNode* net = aSignals->GetChildren();
1655 
1656  while( net )
1657  {
1658  bool sawPad = false;
1659 
1660  zones.clear();
1661 
1662  const string& nname = net->GetAttribute( "name" ).ToStdString();
1663  wxString netName = FROM_UTF8( nname.c_str() );
1664  m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
1665 
1666  m_xpath->Value( nname.c_str() );
1667 
1668  // Get the first net item and iterate
1669  wxXmlNode* netItem = net->GetChildren();
1670 
1671  // (contactref | polygon | wire | via)*
1672  while( netItem )
1673  {
1674  const wxString& itemName = netItem->GetName();
1675  if( itemName == "wire" )
1676  {
1677  m_xpath->push( "wire" );
1678 
1679  EWIRE w( netItem );
1680  PCB_LAYER_ID layer = kicad_layer( w.layer );
1681 
1682  if( IsCopperLayer( layer ) )
1683  {
1684  TRACK* t = new TRACK( m_board );
1685 
1686  t->SetTimeStamp( timeStamp( netItem ) );
1687 
1688  t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
1689  t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
1690 
1691  int width = kicad( w.width );
1692  if( width < m_min_trace )
1693  m_min_trace = width;
1694 
1695  t->SetWidth( width );
1696  t->SetLayer( layer );
1697  t->SetNetCode( netCode );
1698 
1699  m_board->m_Track.Insert( t, NULL );
1700  }
1701  else
1702  {
1703  // put non copper wires where the sun don't shine.
1704  }
1705 
1706  m_xpath->pop();
1707  }
1708 
1709  else if( itemName == "via" )
1710  {
1711  m_xpath->push( "via" );
1712  EVIA v( netItem );
1713 
1714  PCB_LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
1715  PCB_LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
1716 
1717  if( IsCopperLayer( layer_front_most ) &&
1718  IsCopperLayer( layer_back_most ) )
1719  {
1720  int kidiam;
1721  int drillz = kicad( v.drill );
1722  VIA* via = new VIA( m_board );
1723  m_board->m_Track.Insert( via, NULL );
1724 
1725  via->SetLayerPair( layer_front_most, layer_back_most );
1726 
1727  if( v.diam )
1728  {
1729  kidiam = kicad( *v.diam );
1730  via->SetWidth( kidiam );
1731  }
1732  else
1733  {
1734  double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
1735  annulus = Clamp( m_rules->rlMinViaOuter, annulus, m_rules->rlMaxViaOuter );
1736  kidiam = KiROUND( drillz + 2 * annulus );
1737  via->SetWidth( kidiam );
1738  }
1739 
1740  via->SetDrill( drillz );
1741 
1742  if( kidiam < m_min_via )
1743  m_min_via = kidiam;
1744 
1745  if( drillz < m_min_via_hole )
1746  m_min_via_hole = drillz;
1747 
1748  if( layer_front_most == F_Cu && layer_back_most == B_Cu )
1749  via->SetViaType( VIA_THROUGH );
1750  else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
1751  via->SetViaType( VIA_MICROVIA );
1752  else
1753  via->SetViaType( VIA_BLIND_BURIED );
1754 
1755  via->SetTimeStamp( timeStamp( netItem ) );
1756 
1757  wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
1758 
1759  via->SetPosition( pos );
1760  via->SetEnd( pos );
1761 
1762  via->SetNetCode( netCode );
1763  }
1764  m_xpath->pop();
1765  }
1766 
1767  else if( itemName == "contactref" )
1768  {
1769  m_xpath->push( "contactref" );
1770  // <contactref element="RN1" pad="7"/>
1771 
1772  const string& reference = netItem->GetAttribute( "element" ).ToStdString();
1773  const string& pad = netItem->GetAttribute( "pad" ).ToStdString();
1774 
1775  string key = makeKey( reference, pad ) ;
1776 
1777  // D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", reference.c_str(), pad.c_str(), netCode, nname.c_str() );)
1778 
1779  m_pads_to_nets[ key ] = ENET( netCode, nname );
1780 
1781  m_xpath->pop();
1782 
1783  sawPad = true;
1784  }
1785 
1786  else if( itemName == "polygon" )
1787  {
1788  m_xpath->push( "polygon" );
1789 
1790  EPOLYGON p( netItem );
1791  PCB_LAYER_ID layer = kicad_layer( p.layer );
1792 
1793  if( IsCopperLayer( layer ) )
1794  {
1795  // use a "netcode = 0" type ZONE:
1796  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
1797  m_board->Add( zone, ADD_APPEND );
1798  zones.push_back( zone );
1799 
1800  zone->SetTimeStamp( timeStamp( netItem ) );
1801  zone->SetLayer( layer );
1802  zone->SetNetCode( netCode );
1803 
1804  // Get the first vertex and iterate
1805  wxXmlNode* vertex = netItem->GetChildren();
1806 
1807  while( vertex )
1808  {
1809  if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
1810  continue;
1811 
1812  EVERTEX v( vertex );
1813 
1814  // Append the corner
1815  zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
1816 
1817  vertex = vertex->GetNext();
1818  }
1819 
1820  // If the pour is a cutout it needs to be set to a keepout
1821  if( p.pour == EPOLYGON::CUTOUT )
1822  {
1823  zone->SetIsKeepout( true );
1824  zone->SetDoNotAllowCopperPour( true );
1826  }
1827 
1828  // if spacing is set the zone should be hatched
1829  if( p.spacing )
1830  zone->SetHatch( ZONE_CONTAINER::DIAGONAL_EDGE, *p.spacing, true );
1831 
1832  // clearances, etc.
1833  zone->SetArcSegmentCount( 32 ); // @todo: should be a constructor default?
1834  zone->SetMinThickness( kicad( p.width ) );
1835 
1836  // FIXME: KiCad zones have very rounded corners compared to eagle.
1837  // This means that isolation amounts that work well in eagle
1838  // tend to make copper intrude in soldermask free areas around pads.
1839  if( p.isolate )
1840  {
1841  zone->SetZoneClearance( kicad( *p.isolate ) );
1842  }
1843 
1844  // missing == yes per DTD.
1845  bool thermals = !p.thermals || *p.thermals;
1847  if( thermals )
1848  {
1849  // FIXME: eagle calculates dimensions for thermal spokes
1850  // based on what the zone is connecting to.
1851  // (i.e. width of spoke is half of the smaller side of an smd pad)
1852  // This is a basic workaround
1853  zone->SetThermalReliefGap( kicad( p.width + 0.05 ) );
1854  zone->SetThermalReliefCopperBridge( kicad( p.width + 0.05 ) );
1855  }
1856 
1857  int rank = p.rank ? *p.rank : p.max_priority;
1858  zone->SetPriority( rank );
1859  }
1860 
1861  m_xpath->pop(); // "polygon"
1862  }
1863 
1864  netItem = netItem->GetNext();
1865  }
1866 
1867  if( zones.size() && !sawPad )
1868  {
1869  // KiCad does not support an unconnected zone with its own non-zero netcode,
1870  // but only when assigned netcode = 0 w/o a name...
1871  for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it )
1872  (*it)->SetNetCode( NETINFO_LIST::UNCONNECTED );
1873 
1874  // therefore omit this signal/net.
1875  }
1876  else
1877  netCode++;
1878 
1879  // Get next signal
1880  net = net->GetNext();
1881  }
1882 
1883  m_xpath->pop(); // "signals.signal"
1884 }
1885 
1886 
1887 PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
1888 {
1889  int kiLayer;
1890 
1891  // eagle copper layer:
1892  if( aEagleLayer >= 1 && aEagleLayer < int( DIM( m_cu_map ) ) )
1893  {
1894  kiLayer = m_cu_map[aEagleLayer];
1895  }
1896 
1897  else
1898  {
1899  // translate non-copper eagle layer to pcbnew layer
1900  switch( aEagleLayer )
1901  {
1902  // Eagle says "Dimension" layer, but it's for board perimeter
1903  case EAGLE_LAYER::DIMENSION: kiLayer = Edge_Cuts; break;
1904  case EAGLE_LAYER::TPLACE: kiLayer = F_SilkS; break;
1905  case EAGLE_LAYER::BPLACE: kiLayer = B_SilkS; break;
1906  case EAGLE_LAYER::TNAMES: kiLayer = F_SilkS; break;
1907  case EAGLE_LAYER::BNAMES: kiLayer = B_SilkS; break;
1908  case EAGLE_LAYER::TVALUES: kiLayer = F_SilkS; break;
1909  case EAGLE_LAYER::BVALUES: kiLayer = B_SilkS; break;
1910  case EAGLE_LAYER::TSTOP: kiLayer = F_Mask; break;
1911  case EAGLE_LAYER::BSTOP: kiLayer = B_Mask; break;
1912  case EAGLE_LAYER::TCREAM: kiLayer = F_Paste; break;
1913  case EAGLE_LAYER::BCREAM: kiLayer = B_Paste; break;
1914  case EAGLE_LAYER::TFINISH: kiLayer = F_Mask; break;
1915  case EAGLE_LAYER::BFINISH: kiLayer = B_Mask; break;
1916  case EAGLE_LAYER::TGLUE: kiLayer = F_Adhes; break;
1917  case EAGLE_LAYER::BGLUE: kiLayer = B_Adhes; break;
1918  case EAGLE_LAYER::DOCUMENT: kiLayer = Cmts_User; break;
1919  case EAGLE_LAYER::REFERENCELC: kiLayer = Cmts_User; break;
1920  case EAGLE_LAYER::REFERENCELS: kiLayer = Cmts_User; break;
1921 
1922  // Packages show the future chip pins on SMD parts using layer 51.
1923  // This is an area slightly smaller than the PAD/SMD copper area.
1924  // Carry those visual aids into the MODULE on the fabrication layer,
1925  // not silkscreen. This is perhaps not perfect, but there is not a lot
1926  // of other suitable paired layers
1927  case EAGLE_LAYER::TDOCU: kiLayer = F_Fab; break;
1928  case EAGLE_LAYER::BDOCU: kiLayer = B_Fab; break;
1929 
1930  // thes layers are defined as user layers. put them on ECO layers
1931  case EAGLE_LAYER::USERLAYER1: kiLayer = Eco1_User; break;
1932  case EAGLE_LAYER::USERLAYER2: kiLayer = Eco2_User; break;
1933  default:
1934  // some layers do not map to KiCad
1935  wxASSERT_MSG( false, wxString::Format( "Unsupported Eagle layer %d", aEagleLayer ) );
1936  kiLayer = UNDEFINED_LAYER; break;
1937  }
1938  }
1939 
1940  return PCB_LAYER_ID( kiLayer );
1941 }
1942 
1943 
1945 {
1946  if( m_props )
1947  {
1948  UTF8 page_width;
1949  UTF8 page_height;
1950 
1951  if( m_props->Value( "page_width", &page_width ) &&
1952  m_props->Value( "page_height", &page_height ) )
1953  {
1955 
1956  int w = atoi( page_width.c_str() );
1957  int h = atoi( page_height.c_str() );
1958 
1959  int desired_x = ( w - bbbox.GetWidth() ) / 2;
1960  int desired_y = ( h - bbbox.GetHeight() ) / 2;
1961 
1962  DBG(printf( "bbox.width:%d bbox.height:%d w:%d h:%d desired_x:%d desired_y:%d\n",
1963  bbbox.GetWidth(), bbbox.GetHeight(), w, h, desired_x, desired_y );)
1964 
1965  m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
1966  }
1967  }
1968 }
1969 
1970 
1971 wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
1972 {
1973  wxFileName fn( aPath );
1974 
1975  // Do not call wxFileName::GetModificationTime() on a non-existent file, because
1976  // if it fails, wx's implementation calls the crap wxLogSysError() which
1977  // eventually infects our UI with an unwanted popup window, so don't let it fail.
1978  if( !fn.IsFileReadable() )
1979  {
1980  wxString msg = wxString::Format(
1981  _( "File '%s' is not readable." ),
1982  GetChars( aPath ) );
1983 
1984  THROW_IO_ERROR( msg );
1985  }
1986 
1987  /*
1988  // update the writable flag while we have a wxFileName, in a network this
1989  // is possibly quite dynamic anyway.
1990  m_writable = fn.IsFileWritable();
1991  */
1992 
1993  wxDateTime modTime = fn.GetModificationTime();
1994 
1995  if( !modTime.IsValid() )
1996  modTime.Now();
1997 
1998  return modTime;
1999 }
2000 
2001 
2002 void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
2003 {
2004  try
2005  {
2006  wxDateTime modtime = getModificationTime( aLibPath );
2007 
2008  // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
2009  // cache if either of the wxDateTime objects are invalid or the last file modification
2010  // time differs from the current file modification time.
2011  bool load = !m_mod_time.IsValid() || !modtime.IsValid() ||
2012  m_mod_time != modtime;
2013 
2014  if( aLibPath != m_lib_path || load )
2015  {
2016  wxXmlNode* doc;
2017  LOCALE_IO toggle; // toggles on, then off, the C locale.
2018 
2019  m_templates.clear();
2020 
2021  // Set this before completion of loading, since we rely on it for
2022  // text of an exception. Delay setting m_mod_time until after successful load
2023  // however.
2024  m_lib_path = aLibPath;
2025 
2026  // 8 bit "filename" should be encoded according to disk filename encoding,
2027  // (maybe this is current locale, maybe not, its a filesystem issue),
2028  // and is not necessarily utf8.
2029  string filename = (const char*) aLibPath.char_str( wxConvFile );
2030 
2031  // Load the document
2032  wxXmlDocument xmlDocument;
2033  wxFileName fn( filename );
2034 
2035  if( !xmlDocument.Load( fn.GetFullPath() ) )
2036  THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
2037  fn.GetFullPath() ) );
2038 
2039  doc = xmlDocument.GetRoot();
2040 
2041  wxXmlNode* drawing = MapChildren( doc )["drawing"];
2042  NODE_MAP drawingChildren = MapChildren( drawing );
2043 
2044  // clear the cu map and then rebuild it.
2045  clear_cu_map();
2046 
2047  m_xpath->push( "eagle.drawing.layers" );
2048  wxXmlNode* layers = drawingChildren["layers"];
2049  loadLayerDefs( layers );
2050  m_xpath->pop();
2051 
2052  m_xpath->push( "eagle.drawing.library" );
2053  wxXmlNode* library = drawingChildren["library"];
2054  loadLibrary( library, NULL );
2055  m_xpath->pop();
2056 
2057  m_mod_time = modtime;
2058  }
2059  }
2060  catch(...){}
2061  // TODO: Handle exceptions
2062  // catch( file_parser_error fpe )
2063  // {
2064  // // for xml_parser_error, what() has the line number in it,
2065  // // but no byte offset. That should be an adequate error message.
2066  // THROW_IO_ERROR( fpe.what() );
2067  // }
2068  //
2069  // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
2070  // // so one catch should be OK for all errors.
2071  // catch( ptree_error pte )
2072  // {
2073  // string errmsg = pte.what();
2074  //
2075  // errmsg += " @\n";
2076  // errmsg += m_xpath->Contents();
2077  //
2078  // THROW_IO_ERROR( errmsg );
2079  // }
2080 }
2081 
2082 
2083 wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2084 {
2085  init( aProperties );
2086 
2087  cacheLib( aLibraryPath );
2088 
2089  wxArrayString ret;
2090 
2091  for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
2092  ret.Add( FROM_UTF8( it->first.c_str() ) );
2093 
2094  return ret;
2095 }
2096 
2097 
2098 MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
2099  const PROPERTIES* aProperties )
2100 {
2101  init( aProperties );
2102 
2103  cacheLib( aLibraryPath );
2104 
2105  string key = TO_UTF8( aFootprintName );
2106 
2107  MODULE_CITER mi = m_templates.find( key );
2108 
2109  if( mi == m_templates.end() )
2110  return NULL;
2111 
2112  // copy constructor to clone the template
2113  MODULE* ret = new MODULE( *mi->second );
2114 
2115  return ret;
2116 }
2117 
2118 
2119 void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
2120 {
2121  PLUGIN::FootprintLibOptions( aListToAppendTo );
2122 
2123  /*
2124  (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
2125  "Ignore duplicately named footprints within the same Eagle library. "
2126  "Only the first similarly named footprint will be loaded."
2127  ));
2128  */
2129 }
2130 
2131 
2132 /*
2133 void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
2134 {
2135  // Eagle lovers apply here.
2136 }
2137 
2138 
2139 void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties )
2140 {
2141 }
2142 
2143 
2144 void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
2145 {
2146 }
2147 
2148 
2149 void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2150 {
2151 }
2152 
2153 
2154 bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2155 {
2156 }
2157 
2158 
2159 bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
2160 {
2161  return true;
2162 }
2163 
2164 */
void SetMirrored(bool isMirrored)
Definition: eda_text.h:178
opt_double diameter
Definition: eagle_parser.h:553
Eagle vertex.
Definition: eagle_parser.h:593
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
#define DIM(x)
of elements in an array
Definition: macros.h:98
MODULE_MAP::iterator MODULE_ITER
void SetEnd0(const wxPoint &aPoint)
double width
Definition: eagle_parser.h:401
void loadAllSections(wxXmlNode *aDocument)
string package
Definition: eagle_parser.h:647
double rlMaxViaOuter
maximum copper annulus on via
Definition: eagle_plugin.h:57
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
bool mirror
Definition: eagle_parser.h:376
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:412
std::unordered_map< string, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:46
double radius
Definition: eagle_parser.h:445
void SetTextAngle(double aAngle)
double size
Definition: eagle_parser.h:520
TEXTE_MODULE & Reference()
Definition: class_module.h:456
opt_double isolate
Definition: eagle_parser.h:622
void SetShape(STROKE_T aShape)
NETCLASSPTR GetDefault() const
Function GetDefault.
opt_int rank
Definition: eagle_parser.h:625
void clear_cu_map()
const T & Clamp(const T &lower, const T &value, const T &upper)
Function Clamp limits value within the range lower <= value <= upper.
Definition: macros.h:127
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
void centerBoard()
move the BOARD into the center of the page
BOARD * m_board
which BOARD is being worked on, no ownership here
Definition: eagle_plugin.h:143
TEXTE_PCB class definition.
string name
Definition: eagle_parser.h:645
double y
Definition: eagle_parser.h:578
void SetViaType(VIATYPE_T aViaType)
Definition: class_track.h:447
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
void FootprintLibOptions(PROPERTIES *aProperties) const override
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
string name
Definition: eagle_parser.h:576
void SetPosition(const wxPoint &aPoint) override
Definition: class_track.h:417
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
void packageHole(MODULE *aModule, wxXmlNode *aTree) const
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:117
void clear()
Definition: eagle_parser.h:109
NODE_MAP MapChildren(wxXmlNode *currentNode)
Function MapChildren provides an easy access to the children of an XML node via their names...
ERULES * m_rules
Eagle design rules.
Definition: eagle_plugin.h:129
unsigned long timeStamp(wxXmlNode *aTree)
Make a unique time stamp.
MODULE * makeModule(wxXmlNode *aPackage, const std::string &aPkgName) const
Function makeModule creates a MODULE from an Eagle package.
double y
Definition: eagle_parser.h:635
int m_PcbTextWidth
current Pcb (not module) Text width
void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
PCB_LAYER_ID kicad_layer(int aLayer) const
Convert an Eagle layer to a KiCad layer.
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:144
double x
Definition: eagle_parser.h:577
void push(const char *aPathSegment, const char *aAttribute="")
Definition: eagle_parser.h:104
bool Value(const char *aName, UTF8 *aFetchedValue=NULL) const
Function Value fetches a property by aName and returns true if that property was found, else false.
Definition: properties.cpp:24
Eagle element element.
Definition: eagle_parser.h:643
polygon (not yet used for tracks, but could be in microwave apps)
Class XPATH keeps track of what we are working on within a PTREE.
Definition: eagle_parser.h:99
static const int max_priority
Definition: eagle_parser.h:614
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
double rlMaxPadTop
maximum copper annulus on through hole pads
Definition: eagle_plugin.h:53
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:223
void SetVisible(bool aVisible)
Definition: eda_text.h:175
opt_double ratio
Definition: eagle_parser.h:523
int GetHeight() const
int number
Definition: eagle_parser.h:661
double y
Definition: eagle_parser.h:429
void SetCopperLayerCount(int aCount)
opt_erot rot
Definition: eagle_parser.h:653
opt_bool thermals
Definition: eagle_parser.h:624
double x1
Definition: eagle_parser.h:456
void packageText(MODULE *aModule, wxXmlNode *aTree) const
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:483
opt_bool smashed
Definition: eagle_parser.h:652
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:169
Classes to handle copper zones.
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL) override
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:440
wxArrayString FootprintEnumerate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintEnumerate returns a list of footprint names contained within the library at aLibrar...
usual segment : line with rounded ends
void parse(wxXmlNode *aRules)
wxPoint kicad_arc_center(const wxPoint &aStart, const wxPoint &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC.
void SetArcSegmentCount(int aArcSegCount)
Definition: class_zone.h:197
NET_MAP::const_iterator NET_MAP_CITER
Definition: eagle_plugin.h:38
void SetHatch(int aHatchStyle, int aHatchPitch, bool aRebuildHatch)
Function SetHatch sets all hatch parameters for the zone.
Definition: class_zone.cpp:902
void init(const PROPERTIES *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:187
double degrees
Definition: eagle_parser.h:378
opt_double size
Definition: eagle_parser.h:479
void packagePolygon(MODULE *aModule, wxXmlNode *aTree) const
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:214
Eagle SMD pad.
Definition: eagle_parser.h:574
wxSize kicad_fontz(double d) const
create a font size (fontz) from an eagle font size scalar
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Function SetLayerType changes the type of the layer given by aLayer.
opt_double spacing
Definition: eagle_parser.h:607
double y2
Definition: eagle_parser.h:400
const wxSize & GetDrillSize() const
Definition: class_pad.h:188
Class LIB_ID.
Definition: lib_id.h:56
int m_min_via
smallest via we find on Load(), in BIU.
Definition: eagle_plugin.h:146
double rvViaOuter
copper annulus is this percent of via hole
Definition: eagle_plugin.h:55
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
#define cu(a)
Definition: auxiliary.h:88
Eagle hole element.
Definition: eagle_parser.h:632
Class XML_PARSER_ERROR implements a simple wrapper around runtime_error to isolate the errors thrown ...
Definition: eagle_parser.h:57
Eagle text element.
Definition: eagle_parser.h:515
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
#define abs(a)
Definition: auxiliary.h:84
double x2
Definition: eagle_parser.h:399
void loadLayerDefs(wxXmlNode *aLayers)
double x
Definition: eagle_parser.h:649
DLIST< BOARD_ITEM > & GraphicalItems()
Definition: class_module.h:137
void packageCircle(MODULE *aModule, wxXmlNode *aTree) const
opt_erot rot
Definition: eagle_parser.h:482
void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
XPATH * m_xpath
keeps track of what we are working on within XML document during a Load().
Definition: eagle_plugin.h:130
void SetTimeStamp(time_t aNewTimeStamp)
Definition: base_struct.h:203
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
#define DEFAULT_PCB_EDGE_THICKNESS
int m_cu_map[17]
map eagle to kicad, cu layers only.
Definition: eagle_plugin.h:127
bool IsNonCopperLayer(LAYER_NUM aLayerId)
Function IsNonCopperLayer tests whether a layer is a non copper layer.
int kicad_y(double y) const
Definition: eagle_plugin.h:162
This file contains miscellaneous commonly used macros and functions.
void SetWidth(int aWidth)
Definition: class_track.h:114
double dx
Definition: eagle_parser.h:579
void PushBack(T *aNewElement)
Function PushBack puts aNewElement at the end of the list sequence.
Definition: dlist.h:250
int layer_back_most
< extent
Definition: eagle_parser.h:431
const EDA_RECT GetBoardEdgesBoundingBox() const
Function GetBoardEdgesBoundingBox Returns the board bounding box calculated using exclusively the boa...
Definition: class_board.h:839
void SetPriority(unsigned aPriority)
Function SetPriority.
Definition: class_zone.h:113
double y
Definition: eagle_parser.h:650
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
DIMENSION class definition.
PCB_LAYER_ID
A quick note on layer IDs:
int m_min_via_hole
smallest via diameter hole we find on Load(), in BIU.
Definition: eagle_plugin.h:147
string makeKey(const string &aFirst, const string &aSecond)
Assemble a two part key as a simple concatenation of aFirst and aSecond parts, using a separator...
string text
Definition: eagle_parser.h:517
void SetOrigin(const wxPoint &aOrigin)
Function SetOrigin Sets a new origin of the crossbar line.
Class LSET is a set of PCB_LAYER_IDs.
double y
Definition: eagle_parser.h:596
void cacheLib(const wxString &aLibraryPath)
This PLUGIN only caches one footprint library, this determines which one.
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
Definition: eagle_plugin.h:142
LAYER_NUM layer
Definition: eagle_parser.h:402
double x1
Definition: eagle_parser.h:397
int layer
Definition: eagle_parser.h:460
Eagle thru hol pad.
Definition: eagle_parser.h:547
double GetOrientation() const
Definition: class_module.h:148
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:455
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:175
wxSize m_PcbTextSize
current Pcb (not module) Text size
int m_TrackMinWidth
track min value for width ((min copper size value
void SetEnd(const wxPoint &aEnd)
Function SetEnd Sets a new end of the crossbar line.
void AppendCorner(wxPoint position, bool aAllowDuplication=false)
Function AppendCorner.
Definition: class_zone.h:546
int Clamp_Text_PenSize(int aPenSize, int aSize, bool aBold)
Function Clamp_Text_PenSize As a rule, pen width should not be >1/4em, otherwise the character will b...
Definition: drawtxt.cpp:67
string name
Definition: eagle_parser.h:475
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
Arcs (with rounded ends)
int m_ViasMinSize
vias (not micro vias) min diameter
Eagle circle.
Definition: eagle_parser.h:441
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Function SetLayerName changes the name of the layer given by aLayer.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
>
opt_double diam
Definition: eagle_parser.h:433
double y1
Definition: eagle_parser.h:457
wxString m_lib_path
Definition: eagle_plugin.h:152
int m_ViasMinDrill
vias (not micro vias) min drill diameter
D_PAD * Next() const
Definition: class_pad.h:106
const wxSize & GetSize() const
Definition: class_pad.h:182
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:530
void SetSize(const wxSize &aSize)
Definition: class_pad.h:181
double x
Definition: eagle_parser.h:634
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Function SetNetCode sets net using a net code.
subset of eagle.drawing.board.designrules in the XML document
Definition: eagle_plugin.h:42
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer...
void SetReference(const wxString &aReference)
Function SetReference.
Definition: class_module.h:422
opt_string value
Definition: eagle_parser.h:476
int kicad_x(double x) const
Definition: eagle_plugin.h:163
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
void SetFileName(const wxString &aFileName)
Definition: class_board.h:235
double y1
Definition: eagle_parser.h:398
void SetPosition(const wxPoint &aPos) override
void SetZoneClearance(int aZoneClearance)
Definition: class_zone.h:204
int layer
Definition: eagle_parser.h:581
static wxDateTime getModificationTime(const wxString &aPath)
get a file's or dir's modification time.
double mdWireWire
wire to wire spacing I presume.
Definition: eagle_plugin.h:58
std::vector< ZONE_CONTAINER * > ZONES
non-owning container
double x
Definition: eagle_parser.h:550
double width
Definition: eagle_parser.h:605
int m_min_trace
smallest trace we find on Load(), in BIU.
Definition: eagle_plugin.h:145
string value
Definition: eagle_parser.h:648
double dy
Definition: eagle_parser.h:580
opt_int roundness
Definition: eagle_parser.h:582
double mm_per_biu
how many mm in each BIU
Definition: eagle_plugin.h:149
int m_hole_count
generates unique module names from eagle "hole"s.
Definition: eagle_plugin.h:133
LAYER_NUM layer
Definition: eagle_parser.h:447
Eagle XML rectangle in binary.
Definition: eagle_parser.h:454
opt_erot rot
Definition: eagle_parser.h:564
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:348
opt_int align
Definition: eagle_parser.h:540
Eagle net.
Definition: eagle_parser.h:357
void SetPos0(const wxPoint &aPos)
int psElongationLong
percent over 100%.
Definition: eagle_plugin.h:44
void AdjustDimensionDetails(bool aDoNotChangeText=false)
Function AdjustDimensionDetails Calculate coordinates of segments used to draw the dimension...
void SetStart(const wxPoint &aStart)
void SetThermalReliefCopperBridge(int aThermalReliefCopperBridge)
Definition: class_zone.h:191
void loadLibraries(wxXmlNode *aLibs)
void loadPlain(wxXmlNode *aPlain)
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
opt_double x
Definition: eagle_parser.h:477
string name
Definition: eagle_parser.h:549
void orientModuleAndText(MODULE *m, const EELEMENT &e, const EATTR *nameAttr, const EATTR *valueAttr)
string Contents()
return the contents of the XPATH as a single string
Definition: eagle_parser.h:126
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
void SetDoNotAllowCopperPour(bool aEnable)
Definition: class_zone.h:660
Class EATTR parses an Eagle "attribute" XML element.
Definition: eagle_parser.h:473
void packageSMD(MODULE *aModule, wxXmlNode *aTree) const
Eagle via.
Definition: eagle_parser.h:426
double width
Definition: eagle_parser.h:446
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:234
Class NETINFO_ITEM handles the data for a net.
MODULE_MAP::const_iterator MODULE_CITER
string library
Definition: eagle_parser.h:646
opt_erot rot
Definition: eagle_parser.h:524
int netcode
Definition: eagle_parser.h:359
double x2
Definition: eagle_parser.h:458
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
void loadElements(wxXmlNode *aElements)
double drill
Definition: eagle_parser.h:552
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 packagePad(MODULE *aModule, wxXmlNode *aTree) const
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
double x
Definition: eagle_parser.h:443
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:412
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
bool IsMirrored() const
Definition: eda_text.h:179
void SetOrientation(double newangle)
void SetPosition(const wxPoint &aPos) override
Definition: class_track.h:111
void SetHeight(int aHeight)
Function SetHeight Sets the length of feature lines.
MODULE_MAP m_templates
is part of a MODULE factory that operates using copy construction.
Definition: eagle_plugin.h:137
TEXTE_PCB & Text()
wxDateTime m_mod_time
Definition: eagle_plugin.h:153
void packageWire(MODULE *aModule, wxXmlNode *aTree) const
Class EDA_RECT handles the component boundary box.
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: class_track.h:454
void SetStart0(const wxPoint &aPoint)
double drill
< inclusive
Definition: eagle_parser.h:432
void SetValue(const wxString &aValue)
Function SetValue.
Definition: class_module.h:449
opt_double ratio
Definition: eagle_parser.h:481
int GetX() const
void SetHatchStyle(HATCH_STYLE aStyle)
Definition: class_zone.h:559
static double parseEagle(const wxString &aDistance)
Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
NET_MAP m_pads_to_nets
net list
Definition: eagle_plugin.h:135
The common library.
int GetWidth() const
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:167
void SetPadName(const wxString &name)
Set the pad name (sometimes called pad number, although it can be an array ref like AA12 the pad name...
Definition: class_pad.cpp:455
const char * name
int GetY() const
void SetEnd(const wxPoint &aEnd)
Eagle wire.
Definition: eagle_parser.h:395
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:357
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
double x
Definition: eagle_parser.h:428
double y
Definition: eagle_parser.h:519
double x
Definition: eagle_parser.h:595
opt_int shape
Definition: eagle_parser.h:563
static int GetDefaultHatchPitchMils()
Function GetDefaultHatchPitchMils.
Definition: class_zone.h:680
opt_erot rot
Definition: eagle_parser.h:583
#define DBG(x)
Definition: fctsys.h:33
Eagle dimension element.
Definition: eagle_parser.h:498
double rvPadTop
top pad size as percent of drill size
Definition: eagle_plugin.h:49
DLIST< D_PAD > & Pads()
Definition: class_module.h:134
void packageRectangle(MODULE *aModule, wxXmlNode *aTree) const
void SetTextAngle(double aAngle)
DLIST< TRACK > m_Track
Definition: class_board.h:244
bool spin
Definition: eagle_parser.h:377
double biu_per_mm
how many bius in a mm
Definition: eagle_plugin.h:150
Module description (excepted pads)
const wxSize & GetTextSize() const
Definition: eda_text.h:215
double drill
Definition: eagle_parser.h:636
Eagle polygon, without vertices which are parsed as needed.
Definition: eagle_parser.h:603
opt_int display
Definition: eagle_parser.h:490
void pop()
Definition: eagle_parser.h:111
void SetIsKeepout(bool aEnable)
Definition: class_zone.h:659
void loadDesignRules(wxXmlNode *aDesignRules)
void SetPadConnection(ZoneConnection aPadConnection)
Definition: class_zone.h:207
void SetWidth(int aWidth)
EDGE_MODULE class definition.
const wxString PluginName() const override
Function PluginName returns a brief hard coded name for this PLUGIN.
int layer
Definition: eagle_parser.h:521
void SetMinThickness(int aMinThickness)
Definition: class_zone.h:210
opt_double y
Definition: eagle_parser.h:478
double rlMinPadTop
minimum copper annulus on through hole pads
Definition: eagle_plugin.h:52
double rlMinViaOuter
minimum copper annulus on via
Definition: eagle_plugin.h:56
virtual void FootprintLibOptions(PROPERTIES *aListToAppendTo) const
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
Definition: plugin.cpp:122
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Use thermal relief for pads.
Definition: zones.h:58
void SetThermalReliefGap(int aThermalReliefGap)
Definition: class_zone.h:188
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
Class DIMENSION.
opt_bool active
Definition: eagle_parser.h:666
double x
Definition: eagle_parser.h:518
void loadSignals(wxXmlNode *aSignals)
double y
Definition: eagle_parser.h:444
double y2
Definition: eagle_parser.h:459
void Insert(T *aNewElement, T *aElementAfterMe)
Function Insert puts aNewElement just in front of aElementAfterMe in the list sequence.
Definition: dlist.h:200
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.
pads are covered by copper
Definition: zones.h:59
void Value(const char *aValue)
modify the last path node's value
Definition: eagle_parser.h:114
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
int layer_front_most
Definition: eagle_parser.h:430
int sign(T val)
Definition: math_util.h:44
virtual void SetText(const wxString &aText)
Definition: eda_text.h:141
double y
Definition: eagle_parser.h:551
void orientModuleText(MODULE *m, const EELEMENT &e, TEXTE_MODULE *txt, const EATTR *a)
void SetWidth(int aWidth)
int kicad(double d) const
Convert an Eagle distance to a KiCad distance.
void loadLibrary(wxXmlNode *aLib, const std::string *aLibName)
Function loadLibrary loads the Eagle "library" XML element, which can occur either under a "libraries...