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::EAGLE_UNIT unit = ( aDistance.npos != aDistance.find( "mil" ) )
89  ? ECOORD::EAGLE_UNIT::EAGLE_MIL : ECOORD::EAGLE_UNIT::EAGLE_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::EAGLE_UNIT::EAGLE_NM );
704  d.y2 = ECOORD( newY, ECOORD::EAGLE_UNIT::EAGLE_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::EAGLE_UNIT::EAGLE_NM );
710  d.x2 = ECOORD( newX, ECOORD::EAGLE_UNIT::EAGLE_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 ) // OPT
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  if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
1486  {
1487  wxLogMessage( wxString::Format(
1488  "Unsupported rectangle on copper layer in package %s.\nMoving to Dwgs.User layer.",
1489  aModule->GetFPID().GetLibItemName().c_str() ) );
1490  layer = Dwgs_User;
1491  }
1492 
1493  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
1494  aModule->GraphicalItemsList().PushBack( dwg );
1495 
1496  dwg->SetLayer( layer );
1497  dwg->SetWidth( 0 );
1498 
1499  dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
1500 
1501  std::vector<wxPoint> pts;
1502 
1503  wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
1504  wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
1505 
1506  pts.push_back( start );
1507  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
1508  pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
1509  pts.push_back( end );
1510 
1511  dwg->SetPolyPoints( pts );
1512 
1513  dwg->SetStart0( start );
1514  dwg->SetEnd0( end );
1515 }
1516 
1517 
1518 void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
1519 {
1520  EPOLYGON p( aTree );
1521  PCB_LAYER_ID layer = kicad_layer( p.layer );
1522 
1523  if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
1524  {
1525  wxLogMessage( wxString::Format(
1526  "Unsupported polygon on copper layer in package %s.\nMoving to Dwgs.User layer.",
1527  aModule->GetFPID().GetLibItemName().c_str() ) );
1528  layer = Dwgs_User;
1529  }
1530 
1531  EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
1532  aModule->GraphicalItemsList().PushBack( dwg );
1533 
1534  dwg->SetWidth( 0 ); // it's filled, no need for boundary width
1535 
1536  dwg->SetLayer( layer );
1537 
1538  dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
1539 
1540  std::vector<wxPoint> pts;
1541  // TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
1542  // pts.reserve( aTree.size() );
1543 
1544  // Get the first vertex and iterate
1545  wxXmlNode* vertex = aTree->GetChildren();
1546 
1547  while( vertex )
1548  {
1549  if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
1550  continue;
1551 
1552  EVERTEX v( vertex );
1553 
1554  pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
1555 
1556  vertex = vertex->GetNext();
1557  }
1558 
1559  dwg->SetPolyPoints( pts );
1560  dwg->SetStart0( *pts.begin() );
1561  dwg->SetEnd0( pts.back() );
1562  dwg->SetDrawCoord();
1563 }
1564 
1565 
1566 void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
1567 {
1568  ECIRCLE e( aTree );
1569  PCB_LAYER_ID layer = kicad_layer( e.layer );
1570 
1571  if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
1572  {
1573  wxLogMessage( wxString::Format(
1574  "Unsupported circle on copper layer in package %s.\nMoving to Dwgs.User layer.",
1575  aModule->GetFPID().GetLibItemName().c_str() ) );
1576  layer = Dwgs_User;
1577  }
1578 
1579  EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
1580 
1581  aModule->GraphicalItemsList().PushBack( gr );
1582 
1583  gr->SetWidth( e.width.ToPcbUnits() );
1584 
1585  switch( (int) layer )
1586  {
1587  case UNDEFINED_LAYER: layer = Cmts_User; break;
1588  /*
1589  case Eco1_User: layer = F_SilkS; break;
1590  case Eco2_User: layer = B_SilkS; break;
1591  */
1592  default:
1593  break;
1594  }
1595 
1596  gr->SetLayer( layer );
1597  gr->SetTimeStamp( EagleTimeStamp( aTree ) );
1598  gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
1599  gr->SetEnd0( wxPoint( kicad_x( e.x + e.radius ), kicad_y( e.y ) ) );
1600  gr->SetDrawCoord();
1601 }
1602 
1603 
1604 void EAGLE_PLUGIN::packageHole( MODULE* aModule, wxXmlNode* aTree ) const
1605 {
1606  EHOLE e( aTree );
1607 
1608  // we add a PAD_ATTRIB_HOLE_NOT_PLATED pad to this module.
1609  D_PAD* pad = new D_PAD( aModule );
1610  aModule->PadsList().PushBack( pad );
1611 
1612  pad->SetShape( PAD_SHAPE_CIRCLE );
1614 
1615  // Mechanical purpose only:
1616  // no offset, no net name, no pad name allowed
1617  // pad->SetOffset( wxPoint( 0, 0 ) );
1618  // pad->SetName( wxEmptyString );
1619 
1620  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1621 
1622  pad->SetPos0( padpos );
1623  pad->SetPosition( padpos + aModule->GetPosition() );
1624 
1625  wxSize sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
1626 
1627  pad->SetDrillSize( sz );
1628  pad->SetSize( sz );
1629 
1630  pad->SetLayerSet( LSET::AllCuMask() /* | SOLDERMASK_LAYER_BACK | SOLDERMASK_LAYER_FRONT */ );
1631 }
1632 
1633 
1634 void EAGLE_PLUGIN::packageSMD( MODULE* aModule, wxXmlNode* aTree ) const
1635 {
1636  ESMD e( aTree );
1637  PCB_LAYER_ID layer = kicad_layer( e.layer );
1638 
1639  if( !IsCopperLayer( layer ) )
1640  {
1641  return;
1642  }
1643 
1644  D_PAD* pad = new D_PAD( aModule );
1645  aModule->PadsList().PushBack( pad );
1646 
1647  pad->SetName( FROM_UTF8( e.name.c_str() ) );
1648  pad->SetShape( PAD_SHAPE_RECT );
1649  pad->SetAttribute( PAD_ATTRIB_SMD );
1650 
1651  // pad's "Position" is not relative to the module's,
1652  // whereas Pos0 is relative to the module's but is the unrotated coordinate.
1653 
1654  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
1655 
1656  pad->SetPos0( padpos );
1657 
1658  RotatePoint( &padpos, aModule->GetOrientation() );
1659 
1660  pad->SetPosition( padpos + aModule->GetPosition() );
1661 
1662  pad->SetSize( wxSize( e.dx.ToPcbUnits(), e.dy.ToPcbUnits() ) );
1663 
1664  pad->SetLayer( layer );
1665 
1666  static const LSET front( 3, F_Cu, F_Paste, F_Mask );
1667  static const LSET back( 3, B_Cu, B_Paste, B_Mask );
1668 
1669  if( layer == F_Cu )
1670  pad->SetLayerSet( front );
1671  else if( layer == B_Cu )
1672  pad->SetLayerSet( back );
1673 
1674  // Optional according to DTD
1675  if( e.roundness ) // set set shape to PAD_SHAPE_RECT above, in case roundness is not present
1676  {
1677  if( *e.roundness >= 75 ) // roundness goes from 0-100% as integer
1678  {
1679  if( e.dy == e.dx )
1680  pad->SetShape( PAD_SHAPE_CIRCLE );
1681  else
1682  pad->SetShape( PAD_SHAPE_OVAL );
1683  }
1684  }
1685 
1686  if( e.rot )
1687  {
1688  pad->SetOrientation( e.rot->degrees * 10 );
1689  }
1690 
1691  // don't know what stop, thermals, and cream should look like now.
1692 }
1693 
1694 
1696 {
1697  for( auto& t : m_templates )
1698  delete t.second;
1699 
1700  m_templates.clear();
1701 }
1702 
1703 
1705 typedef std::vector<ZONE_CONTAINER*> ZONES;
1706 
1707 
1708 void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
1709 {
1710  ZONES zones; // per net
1711 
1712  m_xpath->push( "signals.signal", "name" );
1713 
1714  int netCode = 1;
1715 
1716  // Get the first signal and iterate
1717  wxXmlNode* net = aSignals->GetChildren();
1718 
1719  while( net )
1720  {
1721  bool sawPad = false;
1722 
1723  zones.clear();
1724 
1725  const string& nname = net->GetAttribute( "name" ).ToStdString();
1726  wxString netName = FROM_UTF8( nname.c_str() );
1727  m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
1728 
1729  m_xpath->Value( nname.c_str() );
1730 
1731  // Get the first net item and iterate
1732  wxXmlNode* netItem = net->GetChildren();
1733 
1734  // (contactref | polygon | wire | via)*
1735  while( netItem )
1736  {
1737  const wxString& itemName = netItem->GetName();
1738  if( itemName == "wire" )
1739  {
1740  m_xpath->push( "wire" );
1741 
1742  EWIRE w( netItem );
1743  PCB_LAYER_ID layer = kicad_layer( w.layer );
1744 
1745  if( IsCopperLayer( layer ) )
1746  {
1747  TRACK* t = new TRACK( m_board );
1748 
1749  t->SetTimeStamp( EagleTimeStamp( netItem ) );
1750 
1751  t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
1752  t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
1753 
1754  int width = w.width.ToPcbUnits();
1755  if( width < m_min_trace )
1756  m_min_trace = width;
1757 
1758  t->SetWidth( width );
1759  t->SetLayer( layer );
1760  t->SetNetCode( netCode );
1761 
1762  m_board->m_Track.Insert( t, NULL );
1763  }
1764  else
1765  {
1766  // put non copper wires where the sun don't shine.
1767  }
1768 
1769  m_xpath->pop();
1770  }
1771 
1772  else if( itemName == "via" )
1773  {
1774  m_xpath->push( "via" );
1775  EVIA v( netItem );
1776 
1777  PCB_LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
1778  PCB_LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
1779 
1780  if( IsCopperLayer( layer_front_most ) &&
1781  IsCopperLayer( layer_back_most ) )
1782  {
1783  int kidiam;
1784  int drillz = v.drill.ToPcbUnits();
1785  VIA* via = new VIA( m_board );
1786  m_board->m_Track.Insert( via, NULL );
1787 
1788  via->SetLayerPair( layer_front_most, layer_back_most );
1789 
1790  if( v.diam )
1791  {
1792  kidiam = v.diam->ToPcbUnits();
1793  via->SetWidth( kidiam );
1794  }
1795  else
1796  {
1797  double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
1798  annulus = Clamp( m_rules->rlMinViaOuter, annulus, m_rules->rlMaxViaOuter );
1799  kidiam = KiROUND( drillz + 2 * annulus );
1800  via->SetWidth( kidiam );
1801  }
1802 
1803  via->SetDrill( drillz );
1804 
1805  // make sure the via diameter respects the restring rules
1806 
1807  if( !v.diam || via->GetWidth() <= via->GetDrill() )
1808  {
1809  double annulus = Clamp( m_rules->rlMinViaOuter,
1810  (double)( via->GetWidth() / 2 - via->GetDrill() ), m_rules->rlMaxViaOuter );
1811  via->SetWidth( drillz + 2 * annulus );
1812  }
1813 
1814  if( kidiam < m_min_via )
1815  m_min_via = kidiam;
1816 
1817  if( drillz < m_min_via_hole )
1818  m_min_via_hole = drillz;
1819 
1820  if( layer_front_most == F_Cu && layer_back_most == B_Cu )
1821  via->SetViaType( VIA_THROUGH );
1822  else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
1823  via->SetViaType( VIA_MICROVIA );
1824  else
1825  via->SetViaType( VIA_BLIND_BURIED );
1826 
1827  via->SetTimeStamp( EagleTimeStamp( netItem ) );
1828 
1829  wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
1830 
1831  via->SetPosition( pos );
1832  via->SetEnd( pos );
1833 
1834  via->SetNetCode( netCode );
1835  }
1836 
1837  m_xpath->pop();
1838  }
1839 
1840  else if( itemName == "contactref" )
1841  {
1842  m_xpath->push( "contactref" );
1843  // <contactref element="RN1" pad="7"/>
1844 
1845  const string& reference = netItem->GetAttribute( "element" ).ToStdString();
1846  const string& pad = netItem->GetAttribute( "pad" ).ToStdString();
1847 
1848  string key = makeKey( reference, pad ) ;
1849 
1850  // D(printf( "adding refname:'%s' pad:'%s' netcode:%d netname:'%s'\n", reference.c_str(), pad.c_str(), netCode, nname.c_str() );)
1851 
1852  m_pads_to_nets[ key ] = ENET( netCode, nname );
1853 
1854  m_xpath->pop();
1855 
1856  sawPad = true;
1857  }
1858 
1859  else if( itemName == "polygon" )
1860  {
1861  m_xpath->push( "polygon" );
1862 
1863  EPOLYGON p( netItem );
1864  PCB_LAYER_ID layer = kicad_layer( p.layer );
1865 
1866  if( IsCopperLayer( layer ) )
1867  {
1868  // use a "netcode = 0" type ZONE:
1869  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
1870  m_board->Add( zone, ADD_APPEND );
1871  zones.push_back( zone );
1872 
1873  zone->SetTimeStamp( EagleTimeStamp( netItem ) );
1874  zone->SetLayer( layer );
1875  zone->SetNetCode( netCode );
1876 
1877  // Get the first vertex and iterate
1878  wxXmlNode* vertex = netItem->GetChildren();
1879 
1880  while( vertex )
1881  {
1882  if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
1883  continue;
1884 
1885  EVERTEX v( vertex );
1886 
1887  // Append the corner
1888  zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ), -1 );
1889 
1890  vertex = vertex->GetNext();
1891  }
1892 
1893  // If the pour is a cutout it needs to be set to a keepout
1894  if( p.pour == EPOLYGON::CUTOUT )
1895  {
1896  zone->SetIsKeepout( true );
1897  zone->SetDoNotAllowCopperPour( true );
1899  }
1900 
1901  // if spacing is set the zone should be hatched
1902  // However, use the default hatch step, p.spacing value has no meaning for Kicad
1903  // TODO: see if this parameter is related to a grid fill option.
1904  if( p.spacing )
1906 
1907  // clearances, etc.
1908  zone->SetArcSegmentCount( 32 ); // @todo: should be a constructor default?
1909  zone->SetMinThickness( p.width.ToPcbUnits() );
1910 
1911  // FIXME: KiCad zones have very rounded corners compared to eagle.
1912  // This means that isolation amounts that work well in eagle
1913  // tend to make copper intrude in soldermask free areas around pads.
1914  if( p.isolate )
1915  {
1916  zone->SetZoneClearance( p.isolate->ToPcbUnits() );
1917  } else
1918  {
1919  zone->SetZoneClearance( 0 );
1920  }
1921 
1922  // missing == yes per DTD.
1923  bool thermals = !p.thermals || *p.thermals;
1925  if( thermals )
1926  {
1927  // FIXME: eagle calculates dimensions for thermal spokes
1928  // based on what the zone is connecting to.
1929  // (i.e. width of spoke is half of the smaller side of an smd pad)
1930  // This is a basic workaround
1931  zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
1932  zone->SetThermalReliefCopperBridge( p.width.ToPcbUnits() + 50000 );
1933  }
1934 
1935  int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;
1936  zone->SetPriority( rank );
1937  }
1938 
1939  m_xpath->pop(); // "polygon"
1940  }
1941 
1942  netItem = netItem->GetNext();
1943  }
1944 
1945  if( zones.size() && !sawPad )
1946  {
1947  // KiCad does not support an unconnected zone with its own non-zero netcode,
1948  // but only when assigned netcode = 0 w/o a name...
1949  for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it )
1950  (*it)->SetNetCode( NETINFO_LIST::UNCONNECTED );
1951 
1952  // therefore omit this signal/net.
1953  }
1954  else
1955  netCode++;
1956 
1957  // Get next signal
1958  net = net->GetNext();
1959  }
1960 
1961  m_xpath->pop(); // "signals.signal"
1962 }
1963 
1964 
1965 PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
1966 {
1967  int kiLayer;
1968 
1969  // eagle copper layer:
1970  if( aEagleLayer >= 1 && aEagleLayer < int( DIM( m_cu_map ) ) )
1971  {
1972  kiLayer = m_cu_map[aEagleLayer];
1973  }
1974 
1975  else
1976  {
1977  // translate non-copper eagle layer to pcbnew layer
1978  switch( aEagleLayer )
1979  {
1980  // Eagle says "Dimension" layer, but it's for board perimeter
1981  case EAGLE_LAYER::DIMENSION: kiLayer = Edge_Cuts; break;
1982  case EAGLE_LAYER::TPLACE: kiLayer = F_SilkS; break;
1983  case EAGLE_LAYER::BPLACE: kiLayer = B_SilkS; break;
1984  case EAGLE_LAYER::TNAMES: kiLayer = F_SilkS; break;
1985  case EAGLE_LAYER::BNAMES: kiLayer = B_SilkS; break;
1986  case EAGLE_LAYER::TVALUES: kiLayer = F_SilkS; break;
1987  case EAGLE_LAYER::BVALUES: kiLayer = B_SilkS; break;
1988  case EAGLE_LAYER::TSTOP: kiLayer = F_Mask; break;
1989  case EAGLE_LAYER::BSTOP: kiLayer = B_Mask; break;
1990  case EAGLE_LAYER::TCREAM: kiLayer = F_Paste; break;
1991  case EAGLE_LAYER::BCREAM: kiLayer = B_Paste; break;
1992  case EAGLE_LAYER::TFINISH: kiLayer = F_Mask; break;
1993  case EAGLE_LAYER::BFINISH: kiLayer = B_Mask; break;
1994  case EAGLE_LAYER::TGLUE: kiLayer = F_Adhes; break;
1995  case EAGLE_LAYER::BGLUE: kiLayer = B_Adhes; break;
1996  case EAGLE_LAYER::DOCUMENT: kiLayer = Cmts_User; break;
1997  case EAGLE_LAYER::REFERENCELC: kiLayer = Cmts_User; break;
1998  case EAGLE_LAYER::REFERENCELS: kiLayer = Cmts_User; break;
1999 
2000  // Packages show the future chip pins on SMD parts using layer 51.
2001  // This is an area slightly smaller than the PAD/SMD copper area.
2002  // Carry those visual aids into the MODULE on the fabrication layer,
2003  // not silkscreen. This is perhaps not perfect, but there is not a lot
2004  // of other suitable paired layers
2005  case EAGLE_LAYER::TDOCU: kiLayer = F_Fab; break;
2006  case EAGLE_LAYER::BDOCU: kiLayer = B_Fab; break;
2007 
2008  // thes layers are defined as user layers. put them on ECO layers
2009  case EAGLE_LAYER::USERLAYER1: kiLayer = Eco1_User; break;
2010  case EAGLE_LAYER::USERLAYER2: kiLayer = Eco2_User; break;
2011 
2012  case EAGLE_LAYER::UNROUTED:
2013  case EAGLE_LAYER::TKEEPOUT:
2014  case EAGLE_LAYER::BKEEPOUT:
2015  case EAGLE_LAYER::TTEST:
2016  case EAGLE_LAYER::BTEST:
2017  case EAGLE_LAYER::MILLING:
2018  case EAGLE_LAYER::HOLES:
2019  default:
2020  // some layers do not map to KiCad
2021  wxLogMessage( wxString::Format( "Unsupported Eagle layer '%s' (%d), converted to Dwgs.User layer",
2022  eagle_layer_name( aEagleLayer ), aEagleLayer ) );
2023 
2024  kiLayer = Dwgs_User;
2025  break;
2026  }
2027  }
2028 
2029  return PCB_LAYER_ID( kiLayer );
2030 }
2031 
2032 
2033 const string& EAGLE_PLUGIN::eagle_layer_name( int aLayer ) const
2034 {
2035  static const string unknown( "unknown" );
2036  auto it = m_eagleLayers.find( aLayer );
2037  return it == m_eagleLayers.end() ? unknown : it->second.name;
2038 }
2039 
2040 
2042 {
2043  if( m_props )
2044  {
2045  UTF8 page_width;
2046  UTF8 page_height;
2047 
2048  if( m_props->Value( "page_width", &page_width ) &&
2049  m_props->Value( "page_height", &page_height ) )
2050  {
2052 
2053  int w = atoi( page_width.c_str() );
2054  int h = atoi( page_height.c_str() );
2055 
2056  int desired_x = ( w - bbbox.GetWidth() ) / 2;
2057  int desired_y = ( h - bbbox.GetHeight() ) / 2;
2058 
2059  DBG(printf( "bbox.width:%d bbox.height:%d w:%d h:%d desired_x:%d desired_y:%d\n",
2060  bbbox.GetWidth(), bbbox.GetHeight(), w, h, desired_x, desired_y );)
2061 
2062  m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
2063  }
2064  }
2065 }
2066 
2067 
2068 wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
2069 {
2070  wxFileName fn( aPath );
2071 
2072  // Do not call wxFileName::GetModificationTime() on a non-existent file, because
2073  // if it fails, wx's implementation calls the crap wxLogSysError() which
2074  // eventually infects our UI with an unwanted popup window, so don't let it fail.
2075  if( !fn.IsFileReadable() )
2076  {
2077  wxString msg = wxString::Format(
2078  _( "File '%s' is not readable." ),
2079  GetChars( aPath ) );
2080 
2081  THROW_IO_ERROR( msg );
2082  }
2083 
2084  /*
2085  // update the writable flag while we have a wxFileName, in a network this
2086  // is possibly quite dynamic anyway.
2087  m_writable = fn.IsFileWritable();
2088  */
2089 
2090  wxDateTime modTime = fn.GetModificationTime();
2091 
2092  if( !modTime.IsValid() )
2093  modTime.Now();
2094 
2095  return modTime;
2096 }
2097 
2098 
2099 void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
2100 {
2101  try
2102  {
2103  wxDateTime modtime = getModificationTime( aLibPath );
2104 
2105  // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
2106  // cache if either of the wxDateTime objects are invalid or the last file modification
2107  // time differs from the current file modification time.
2108  bool load = !m_mod_time.IsValid() || !modtime.IsValid() ||
2109  m_mod_time != modtime;
2110 
2111  if( aLibPath != m_lib_path || load )
2112  {
2113  wxXmlNode* doc;
2114  LOCALE_IO toggle; // toggles on, then off, the C locale.
2115 
2116  deleteTemplates();
2117 
2118  // Set this before completion of loading, since we rely on it for
2119  // text of an exception. Delay setting m_mod_time until after successful load
2120  // however.
2121  m_lib_path = aLibPath;
2122 
2123  // 8 bit "filename" should be encoded according to disk filename encoding,
2124  // (maybe this is current locale, maybe not, its a filesystem issue),
2125  // and is not necessarily utf8.
2126  string filename = (const char*) aLibPath.char_str( wxConvFile );
2127 
2128  // Load the document
2129  wxXmlDocument xmlDocument;
2130  wxFileName fn( filename );
2131 
2132  if( !xmlDocument.Load( fn.GetFullPath() ) )
2133  THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
2134  fn.GetFullPath() ) );
2135 
2136  doc = xmlDocument.GetRoot();
2137 
2138  wxXmlNode* drawing = MapChildren( doc )["drawing"];
2139  NODE_MAP drawingChildren = MapChildren( drawing );
2140 
2141  // clear the cu map and then rebuild it.
2142  clear_cu_map();
2143 
2144  m_xpath->push( "eagle.drawing.layers" );
2145  wxXmlNode* layers = drawingChildren["layers"];
2146  loadLayerDefs( layers );
2147  m_xpath->pop();
2148 
2149  m_xpath->push( "eagle.drawing.library" );
2150  wxXmlNode* library = drawingChildren["library"];
2151  loadLibrary( library, NULL );
2152  m_xpath->pop();
2153 
2154  m_mod_time = modtime;
2155  }
2156  }
2157  catch(...){}
2158  // TODO: Handle exceptions
2159  // catch( file_parser_error fpe )
2160  // {
2161  // // for xml_parser_error, what() has the line number in it,
2162  // // but no byte offset. That should be an adequate error message.
2163  // THROW_IO_ERROR( fpe.what() );
2164  // }
2165  //
2166  // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
2167  // // so one catch should be OK for all errors.
2168  // catch( ptree_error pte )
2169  // {
2170  // string errmsg = pte.what();
2171  //
2172  // errmsg += " @\n";
2173  // errmsg += m_xpath->Contents();
2174  //
2175  // THROW_IO_ERROR( errmsg );
2176  // }
2177 }
2178 
2179 
2180 void EAGLE_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
2181  const PROPERTIES* aProperties )
2182 {
2183  init( aProperties );
2184 
2185  cacheLib( aLibraryPath );
2186 
2187  for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
2188  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
2189 }
2190 
2191 
2192 MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
2193  const PROPERTIES* aProperties )
2194 {
2195  init( aProperties );
2196 
2197  cacheLib( aLibraryPath );
2198 
2199  string key = TO_UTF8( aFootprintName );
2200 
2201  MODULE_CITER mi = m_templates.find( key );
2202 
2203  if( mi == m_templates.end() )
2204  return NULL;
2205 
2206  // copy constructor to clone the template
2207  MODULE* ret = new MODULE( *mi->second );
2208 
2209  return ret;
2210 }
2211 
2212 
2213 void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
2214 {
2215  PLUGIN::FootprintLibOptions( aListToAppendTo );
2216 
2217  /*
2218  (*aListToAppendTo)["ignore_duplicates"] = UTF8( _(
2219  "Ignore duplicately named footprints within the same Eagle library. "
2220  "Only the first similarly named footprint will be loaded."
2221  ));
2222  */
2223 }
2224 
2225 
2226 /*
2227 void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
2228 {
2229  // Eagle lovers apply here.
2230 }
2231 
2232 
2233 void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties )
2234 {
2235 }
2236 
2237 
2238 void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
2239 {
2240 }
2241 
2242 
2243 void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2244 {
2245 }
2246 
2247 
2248 bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2249 {
2250 }
2251 
2252 
2253 bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
2254 {
2255  return true;
2256 }
2257 
2258 */
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:60
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:483
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:444
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:416
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:119
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:175
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:467
usual segment : line with rounded ends
void parse(wxXmlNode *aRules)
void SetArcSegmentCount(int aArcSegCount)
Definition: class_zone.h:186
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
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
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:458
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
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:116
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:95
ECOORD dy
Definition: eagle_parser.h:704
const LIB_ID & GetFPID() const
Definition: class_module.h:184
#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:180
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:482
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:262
wxSize m_PcbTextSize
current Pcb (not module) Text size
const UTF8 & GetLibItemName() const
Definition: lib_id.h:115
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:205
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:449
opt_string value
Definition: eagle_parser.h:596
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:67
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:193
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:180
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:608
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:439
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:117
void SetOrientation(double newangle)
void SetPosition(const wxPoint &aPos) override
Definition: class_track.h:113
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:451
void SetStart0(const wxPoint &aPoint)
void SetValue(const wxString &aValue)
Function SetValue.
Definition: class_module.h:476
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:503
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:157
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:154
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:607
void loadDesignRules(wxXmlNode *aDesignRules)
void SetPadConnection(ZoneConnection aPadConnection)
Definition: class_zone.h:196
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:199
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:177
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
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:230
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...