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