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-2020 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 <cerrno>
54 
55 #include <wx/string.h>
56 #include <wx/xml/xml.h>
57 #include <wx/filename.h>
58 
60 #include <core/arraydim.h>
62 #include <kicad_string.h>
63 #include <locale_io.h>
64 #include <properties.h>
65 #include <trigo.h>
66 #include <math/util.h> // for KiROUND
67 
68 #include <board.h>
69 #include <footprint.h>
70 #include <track.h>
71 #include <fp_shape.h>
72 #include <zone.h>
73 #include <pcb_text.h>
74 #include <dimension.h>
75 
77 
78 using namespace std;
79 
80 
83 static int parseEagle( const wxString& aDistance )
84 {
85  ECOORD::EAGLE_UNIT unit = ( aDistance.npos != aDistance.find( "mil" ) )
86  ? ECOORD::EAGLE_UNIT::EU_MIL : ECOORD::EAGLE_UNIT::EU_MM;
87 
88  ECOORD coord( aDistance, unit );
89 
90  return coord.ToPcbUnits();
91 }
92 
93 
94 // In Eagle one can specify DRC rules where min value > max value,
95 // in such case the max value has the priority
96 template<typename T>
97 static T eagleClamp( T aMin, T aValue, T aMax )
98 {
99  T ret = std::max( aMin, aValue );
100  return std::min( aMax, ret );
101 }
102 
103 
106 static wxString makeKey( const wxString& aFirst, const wxString& aSecond )
107 {
108  wxString key = aFirst + '\x02' + aSecond;
109  return key;
110 }
111 
113 static wxString interpret_text( const wxString& aText )
114 {
115  wxString text;
116  bool sectionOpen = false;
117 
118  for ( wxString::size_type i = 0; i < aText.size(); i++ )
119  {
120  // Interpret escaped characters
121  if ( aText[ i ] == '\\' )
122  {
123  if ( i + 1 != aText.size() )
124  text.Append( aText[ i + 1 ] );
125 
126  i++;
127  continue;
128  }
129 
130  // Escape ~ for KiCAD
131  if( aText[i] == '~' )
132  {
133  text.Append( '~' );
134  text.Append( '~' );
135  continue;
136  }
137 
138  if ( aText[ i ] == '!' )
139  {
140  if ( sectionOpen )
141  {
142  text.Append( '~' );
143  sectionOpen = false;
144  continue;
145  }
146 
147  static wxString escapeChars( " )]}'\"" );
148 
149  if( i + 1 != aText.size() && escapeChars.Find( aText[i + 1] ) == wxNOT_FOUND )
150  {
151  sectionOpen = true;
152  text.Append( '~' );
153  }
154  else
155  {
156  text.Append( aText[ i ] );
157  }
158  continue;
159  }
160 
161  if( aText[i] == ',' && sectionOpen )
162  {
163  text.Append( '~' );
164  sectionOpen = false;
165  }
166 
167  text.Append( aText[ i ] );
168  }
169 
170  return text;
171 }
172 
173 
174 static void setKeepoutSettingsToZone( ZONE* aZone, LAYER_NUM aLayer )
175 {
176  if( aLayer == EAGLE_LAYER::TRESTRICT || aLayer == EAGLE_LAYER::BRESTRICT )
177  {
178  aZone->SetIsRuleArea( true );
179  aZone->SetDoNotAllowVias( true );
180  aZone->SetDoNotAllowTracks( true );
181  aZone->SetDoNotAllowCopperPour( true );
182  aZone->SetDoNotAllowPads( true );
183  aZone->SetDoNotAllowFootprints( false );
184 
185  if( aLayer == EAGLE_LAYER::TRESTRICT ) // front layer keepout
186  aZone->SetLayer( F_Cu );
187  else // bottom layer keepout
188  aZone->SetLayer( B_Cu );
189  }
190  else if( aLayer == EAGLE_LAYER::VRESTRICT )
191  {
192  aZone->SetIsRuleArea( true );
193  aZone->SetDoNotAllowVias( true );
194  aZone->SetDoNotAllowTracks( false );
195  aZone->SetDoNotAllowCopperPour( false );
196  aZone->SetDoNotAllowPads( false );
197  aZone->SetDoNotAllowFootprints( false );
198 
199  aZone->SetLayerSet( LSET::AllCuMask() );
200  }
201 }
202 
203 
204 void ERULES::parse( wxXmlNode* aRules )
205 {
206  wxXmlNode* child = aRules->GetChildren();
207 
208  while( child )
209  {
210  if( child->GetName() == "param" )
211  {
212  const wxString& name = child->GetAttribute( "name" );
213  const wxString& value = child->GetAttribute( "value" );
214 
215  if( name == "psElongationLong" )
216  psElongationLong = wxAtoi( value );
217  else if( name == "psElongationOffset" )
218  psElongationOffset = wxAtoi( value );
219 
220  else if( name == "mvStopFrame" )
221  value.ToCDouble( &mvStopFrame );
222  else if( name == "mvCreamFrame" )
223  value.ToCDouble( &mvCreamFrame );
224  else if( name == "mlMinStopFrame" )
225  mlMinStopFrame = parseEagle( value );
226  else if( name == "mlMaxStopFrame" )
227  mlMaxStopFrame = parseEagle( value );
228  else if( name == "mlMinCreamFrame" )
229  mlMinCreamFrame = parseEagle( value );
230  else if( name == "mlMaxCreamFrame" )
231  mlMaxCreamFrame = parseEagle( value );
232 
233  else if( name == "srRoundness" )
234  value.ToCDouble( &srRoundness );
235  else if( name == "srMinRoundness" )
236  srMinRoundness = parseEagle( value );
237  else if( name == "srMaxRoundness" )
238  srMaxRoundness = parseEagle( value );
239 
240  else if( name == "psTop" )
241  psTop = wxAtoi( value );
242  else if( name == "psBottom" )
243  psBottom = wxAtoi( value );
244  else if( name == "psFirst" )
245  psFirst = wxAtoi( value );
246 
247  else if( name == "rvPadTop" )
248  value.ToCDouble( &rvPadTop );
249  else if( name == "rlMinPadTop" )
250  rlMinPadTop = parseEagle( value );
251  else if( name == "rlMaxPadTop" )
252  rlMaxPadTop = parseEagle( value );
253 
254  else if( name == "rvViaOuter" )
255  value.ToCDouble( &rvViaOuter );
256  else if( name == "rlMinViaOuter" )
257  rlMinViaOuter = parseEagle( value );
258  else if( name == "rlMaxViaOuter" )
259  rlMaxViaOuter = parseEagle( value );
260  else if( name == "mdWireWire" )
261  mdWireWire = parseEagle( value );
262  }
263 
264  child = child->GetNext();
265  }
266 }
267 
268 
270  m_rules( new ERULES() ),
271  m_xpath( new XPATH() ),
272  m_mod_time( wxDateTime::Now() )
273 {
274  using namespace std::placeholders;
275 
276  init( NULL );
277  clear_cu_map();
278  RegisterLayerMappingCallback( std::bind(
280 }
281 
282 
284 {
285  deleteTemplates();
286  delete m_rules;
287  delete m_xpath;
288 }
289 
290 
291 const wxString EAGLE_PLUGIN::PluginName() const
292 {
293  return wxT( "Eagle" );
294 }
295 
296 
297 const wxString EAGLE_PLUGIN::GetFileExtension() const
298 {
299  return wxT( "brd" );
300 }
301 
302 wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d, int aTextThickness ) const
303 {
304  // Eagle includes stroke thickness in the text size, KiCAD does not
305  int kz = d.ToPcbUnits();
306  return wxSize( kz - aTextThickness, kz - aTextThickness );
307 }
308 
309 
310 BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
311 {
312  LOCALE_IO toggle; // toggles on, then off, the C locale.
313  wxXmlNode* doc;
314 
315  init( aProperties );
316 
317  m_board = aAppendToMe ? aAppendToMe : new BOARD();
318 
319  // Give the filename to the board if it's new
320  if( !aAppendToMe )
321  m_board->SetFileName( aFileName );
322 
323  // delete on exception, if I own m_board, according to aAppendToMe
324  unique_ptr<BOARD> deleter( aAppendToMe ? NULL : m_board );
325 
326  try
327  {
328  // Load the document
329  wxXmlDocument xmlDocument;
330  wxFileName fn = aFileName;
331 
332  if( !xmlDocument.Load( fn.GetFullPath() ) )
333  {
334  THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ),
335  fn.GetFullPath() ) );
336  }
337 
338  doc = xmlDocument.GetRoot();
339 
340  m_min_trace = INT_MAX;
341  m_min_hole = INT_MAX;
342  m_min_via = INT_MAX;
343  m_min_annulus = INT_MAX;
344 
345  loadAllSections( doc );
346 
347  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
348 
349  if( m_min_trace < designSettings.m_TrackMinWidth )
350  designSettings.m_TrackMinWidth = m_min_trace;
351 
352  if( m_min_via < designSettings.m_ViasMinSize )
353  designSettings.m_ViasMinSize = m_min_via;
354 
355  if( m_min_hole < designSettings.m_MinThroughDrill )
356  designSettings.m_MinThroughDrill = m_min_hole;
357 
358  if( m_min_annulus < designSettings.m_ViasMinAnnulus )
359  designSettings.m_ViasMinAnnulus = m_min_annulus;
360 
361  if( m_rules->mdWireWire )
362  {
363  NETCLASS* defaultNetclass = designSettings.GetDefault();
364  int clearance = KiROUND( m_rules->mdWireWire );
365 
366  if( clearance < defaultNetclass->GetClearance() )
367  defaultNetclass->SetClearance( clearance );
368  }
369 
370  // should be empty, else missing m_xpath->pop()
371  wxASSERT( m_xpath->Contents().size() == 0 );
372  }
373  // Catch all exceptions thrown from the parser.
374  catch( const XML_PARSER_ERROR &exc )
375  {
376  wxString errmsg = exc.what();
377 
378  errmsg += "\n@ ";
379  errmsg += m_xpath->Contents();
380 
381  THROW_IO_ERROR( errmsg );
382  }
383 
384  // IO_ERROR exceptions are left uncaught, they pass upwards from here.
385 
386  // Ensure the copper layers count is a multiple of 2
387  // Pcbnew does not like boards with odd layers count
388  // (these boards cannot exist. they actually have a even layers count)
389  int lyrcnt = m_board->GetCopperLayerCount();
390 
391  if( (lyrcnt % 2) != 0 )
392  {
393  lyrcnt++;
394  m_board->SetCopperLayerCount( lyrcnt );
395  }
396 
397  centerBoard();
398 
399  deleter.release();
400  return m_board;
401 }
402 
403 
404 void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
405 {
406  m_hole_count = 0;
407  m_min_trace = 0;
408  m_min_hole = 0;
409  m_min_via = 0;
410  m_min_annulus = 0;
411  m_xpath->clear();
412  m_pads_to_nets.clear();
413 
414  m_board = NULL;
415  m_props = aProperties;
416 
417 
418  delete m_rules;
419  m_rules = new ERULES();
420 }
421 
422 
424 {
425  // All cu layers are invalid until we see them in the <layers> section while
426  // loading either a board or library. See loadLayerDefs().
427  for( unsigned i = 0; i < arrayDim(m_cu_map); ++i )
428  m_cu_map[i] = -1;
429 }
430 
431 
432 void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
433 {
434  wxXmlNode* drawing = MapChildren( aDoc )["drawing"];
435  NODE_MAP drawingChildren = MapChildren( drawing );
436 
437  wxXmlNode* board = drawingChildren["board"];
438  NODE_MAP boardChildren = MapChildren( board );
439 
440  m_xpath->push( "eagle.drawing" );
441 
442  {
443  m_xpath->push( "board" );
444 
445  wxXmlNode* designrules = boardChildren["designrules"];
446  loadDesignRules( designrules );
447 
448  m_xpath->pop();
449  }
450 
451  {
452  m_xpath->push( "layers" );
453 
454  wxXmlNode* layers = drawingChildren["layers"];
455  loadLayerDefs( layers );
457 
458  m_xpath->pop();
459  }
460 
461  {
462  m_xpath->push( "board" );
463 
464  wxXmlNode* plain = boardChildren["plain"];
465  loadPlain( plain );
466 
467  wxXmlNode* signals = boardChildren["signals"];
468  loadSignals( signals );
469 
470  wxXmlNode* libs = boardChildren["libraries"];
471  loadLibraries( libs );
472 
473  wxXmlNode* elems = boardChildren["elements"];
474  loadElements( elems );
475 
476  m_xpath->pop(); // "board"
477  }
478 
479  m_xpath->pop(); // "eagle.drawing"
480 }
481 
482 
483 void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
484 {
485  if( aDesignRules )
486  {
487  m_xpath->push( "designrules" );
488  m_rules->parse( aDesignRules );
489  m_xpath->pop(); // "designrules"
490  }
491 }
492 
493 
494 void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
495 {
496  if( !aLayers )
497  return;
498 
499  ELAYERS cu; // copper layers
500 
501  // Get the first layer and iterate
502  wxXmlNode* layerNode = aLayers->GetChildren();
503 
504  m_eagleLayers.clear();
505  m_eagleLayersIds.clear();
506 
507  while( layerNode )
508  {
509  ELAYER elayer( layerNode );
510  m_eagleLayers.insert( std::make_pair( elayer.number, elayer ) );
511  m_eagleLayersIds.insert( std::make_pair( elayer.name, elayer.number ) );
512 
513  // find the subset of layers that are copper and active
514  if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
515  {
516  cu.push_back( elayer );
517  }
518 
519  layerNode = layerNode->GetNext();
520  }
521 
522  // establish cu layer map:
523  int ki_layer_count = 0;
524 
525  for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
526  {
527  if( ki_layer_count == 0 )
528  m_cu_map[it->number] = F_Cu;
529  else if( ki_layer_count == int( cu.size()-1 ) )
530  m_cu_map[it->number] = B_Cu;
531  else
532  {
533  // some eagle boards do not have contiguous layer number sequences.
534  m_cu_map[it->number] = ki_layer_count;
535  }
536  }
537 
538  // Set the layer names and cu count if we're loading a board.
539  if( m_board )
540  {
541  m_board->SetCopperLayerCount( cu.size() );
542 
543  for( EITER it = cu.begin(); it != cu.end(); ++it )
544  {
545  PCB_LAYER_ID layer = kicad_layer( it->number );
546 
547  // these function provide their own protection against non enabled layers:
548  if( layer >= 0 && layer < PCB_LAYER_ID_COUNT ) // layer should be valid
549  {
550  m_board->SetLayerName( layer, FROM_UTF8( it->name.c_str() ) );
551  m_board->SetLayerType( layer, LT_SIGNAL );
552  }
553  // could map the colors here
554  }
555  }
556 }
557 
558 
559 #define DIMENSION_PRECISION 1 // 0.001 mm
560 
561 void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
562 {
563  if( !aGraphics )
564  return;
565 
566  m_xpath->push( "plain" );
567 
568  // Get the first graphic and iterate
569  wxXmlNode* gr = aGraphics->GetChildren();
570 
571  // (polygon | wire | text | circle | rectangle | frame | hole)*
572  while( gr )
573  {
574  wxString grName = gr->GetName();
575 
576  if( grName == "wire" )
577  {
578  m_xpath->push( "wire" );
579 
580  EWIRE w( gr );
581  PCB_LAYER_ID layer = kicad_layer( w.layer );
582 
583  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
584  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
585 
586  if( layer != UNDEFINED_LAYER )
587  {
588  PCB_SHAPE* shape = new PCB_SHAPE( m_board );
589  int width = w.width.ToPcbUnits();
590 
591  // KiCad cannot handle zero or negative line widths
592  if( width <= 0 )
593  width = m_board->GetDesignSettings().GetLineThickness( layer );
594 
595  m_board->Add( shape, ADD_MODE::APPEND );
596 
597  if( !w.curve )
598  {
599  shape->SetStart( start );
600  shape->SetEnd( end );
601  }
602  else
603  {
604  wxPoint center = ConvertArcCenter( start, end, *w.curve );
605 
606  shape->SetShape( S_ARC );
607  shape->SetStart( center );
608  shape->SetEnd( start );
609  shape->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
610  }
611 
612  shape->SetLayer( layer );
613  shape->SetWidth( width );
614  }
615 
616  m_xpath->pop();
617  }
618  else if( grName == "text" )
619  {
620  m_xpath->push( "text" );
621 
622  ETEXT t( gr );
623  PCB_LAYER_ID layer = kicad_layer( t.layer );
624 
625  if( layer != UNDEFINED_LAYER )
626  {
627  PCB_TEXT* pcbtxt = new PCB_TEXT( m_board );
628  m_board->Add( pcbtxt, ADD_MODE::APPEND );
629 
630  pcbtxt->SetLayer( layer );
631  wxString kicadText = interpret_text( t.text );
632  pcbtxt->SetText( FROM_UTF8( kicadText.c_str() ) );
633  pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
634 
635  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
636  int textThickness = KiROUND( t.size.ToPcbUnits() * ratio / 100 );
637  pcbtxt->SetTextThickness( textThickness );
638  pcbtxt->SetTextSize( kicad_fontz( t.size, textThickness ) );
639 
640  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
641 
642  if( t.rot )
643  {
644  int sign = t.rot->mirror ? -1 : 1;
645  pcbtxt->SetMirrored( t.rot->mirror );
646 
647  double degrees = t.rot->degrees;
648 
649  if( degrees == 90 || t.rot->spin )
650  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
651  else if( degrees == 180 )
652  align = ETEXT::TOP_RIGHT;
653  else if( degrees == 270 )
654  {
655  pcbtxt->SetTextAngle( sign * 90 * 10 );
656  align = ETEXT::TOP_RIGHT;
657  }
658  else // Ok so text is not at 90,180 or 270 so do some funny stuff to get placement right
659  {
660  if( ( degrees > 0 ) && ( degrees < 90 ) )
661  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
662  else if( ( degrees > 90 ) && ( degrees < 180 ) )
663  {
664  pcbtxt->SetTextAngle( sign * ( t.rot->degrees + 180 ) * 10 );
665  align = ETEXT::TOP_RIGHT;
666  }
667  else if( ( degrees > 180 ) && ( degrees < 270 ) )
668  {
669  pcbtxt->SetTextAngle( sign * ( t.rot->degrees - 180 ) * 10 );
670  align = ETEXT::TOP_RIGHT;
671  }
672  else if( ( degrees > 270 ) && ( degrees < 360 ) )
673  {
674  pcbtxt->SetTextAngle( sign * t.rot->degrees * 10 );
675  align = ETEXT::BOTTOM_LEFT;
676  }
677  }
678  }
679 
680  switch( align )
681  {
682  case ETEXT::CENTER:
683  // this was the default in pcbtxt's constructor
684  break;
685 
686  case ETEXT::CENTER_LEFT:
688  break;
689 
690  case ETEXT::CENTER_RIGHT:
692  break;
693 
694  case ETEXT::TOP_CENTER:
696  break;
697 
698  case ETEXT::TOP_LEFT:
701  break;
702 
703  case ETEXT::TOP_RIGHT:
706  break;
707 
710  break;
711 
712  case ETEXT::BOTTOM_LEFT:
715  break;
716 
717  case ETEXT::BOTTOM_RIGHT:
720  break;
721  }
722  }
723  m_xpath->pop();
724  }
725  else if( grName == "circle" )
726  {
727  m_xpath->push( "circle" );
728 
729  ECIRCLE c( gr );
730 
731  int width = c.width.ToPcbUnits();
732  int radius = c.radius.ToPcbUnits();
733 
735  || c.layer == EAGLE_LAYER::VRESTRICT )
736  {
737  ZONE* zone = new ZONE( m_board );
738  m_board->Add( zone, ADD_MODE::APPEND );
739 
740  setKeepoutSettingsToZone( zone, c.layer );
741 
742  // approximate circle as polygon with a edge every 10 degree
743  wxPoint center( kicad_x( c.x ), kicad_y( c.y ) );
744  int outlineRadius = radius + ( width / 2 );
745  for( int angle = 0; angle < 360; angle += 10 )
746  {
747  wxPoint rotatedPoint( outlineRadius, 0 );
748  RotatePoint( &rotatedPoint, angle * 10. );
749  zone->AppendCorner( center + rotatedPoint, -1 );
750  }
751 
752  if( width > 0 )
753  {
754  zone->NewHole();
755  int innerRadius = radius - ( width / 2 );
756  for( int angle = 0; angle < 360; angle += 10 )
757  {
758  wxPoint rotatedPoint( innerRadius, 0 );
759  RotatePoint( &rotatedPoint, angle * 10. );
760  zone->AppendCorner( center + rotatedPoint, 0 );
761  }
762  }
763 
765  ZONE::GetDefaultHatchPitch(), true );
766  }
767  else
768  {
769  PCB_LAYER_ID layer = kicad_layer( c.layer );
770 
771  if( layer != UNDEFINED_LAYER ) // unsupported layer
772  {
773  PCB_SHAPE* shape = new PCB_SHAPE( m_board );
774  m_board->Add( shape, ADD_MODE::APPEND );
775 
776  shape->SetShape( S_CIRCLE );
777  shape->SetFilled( false );
778  shape->SetLayer( layer );
779  shape->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
780  shape->SetEnd( wxPoint( kicad_x( c.x ) + radius, kicad_y( c.y ) ) );
781  shape->SetWidth( width );
782  }
783  }
784  m_xpath->pop();
785  }
786  else if( grName == "rectangle" )
787  {
788  // This seems to be a simplified rectangular [copper] zone, cannot find any
789  // net related info on it from the DTD.
790  m_xpath->push( "rectangle" );
791 
792  ERECT r( gr );
793  PCB_LAYER_ID layer = kicad_layer( r.layer );
794 
795  if( IsCopperLayer( layer ) )
796  {
797  // use a "netcode = 0" type ZONE:
798  ZONE* zone = new ZONE( m_board );
799  m_board->Add( zone, ADD_MODE::APPEND );
800 
801  zone->SetLayer( layer );
803 
805 
806  const int outlineIdx = -1; // this is the id of the copper zone main outline
807  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx );
808  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx );
809  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx );
810  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx );
811 
812  if( r.rot )
813  zone->Rotate( zone->GetPosition(), r.rot->degrees * 10 );
814 
815  // this is not my fault:
816  zone->SetBorderDisplayStyle( outline_hatch, ZONE::GetDefaultHatchPitch(),
817  true );
818  }
819 
820  m_xpath->pop();
821  }
822  else if( grName == "hole" )
823  {
824  m_xpath->push( "hole" );
825 
826  // Fabricate a FOOTPRINT with a single PAD_ATTRIB_NPTH pad.
827  // Use m_hole_count to gen up a unique name.
828 
829  FOOTPRINT* footprint = new FOOTPRINT( m_board );
830  m_board->Add( footprint, ADD_MODE::APPEND );
831  footprint->SetReference( wxString::Format( "@HOLE%d", m_hole_count++ ) );
832  footprint->Reference().SetVisible( false );
833 
834  packageHole( footprint, gr, true );
835 
836  m_xpath->pop();
837  }
838  else if( grName == "frame" )
839  {
840  // picture this
841  }
842  else if( grName == "polygon" )
843  {
844  m_xpath->push( "polygon" );
845  loadPolygon( gr );
846  m_xpath->pop(); // "polygon"
847  }
848  else if( grName == "dimension" )
849  {
850  EDIMENSION d( gr );
851  PCB_LAYER_ID layer = kicad_layer( d.layer );
852 
853  if( layer != UNDEFINED_LAYER )
854  {
855  const BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
856  ALIGNED_DIMENSION* dimension = new ALIGNED_DIMENSION( m_board );
857  m_board->Add( dimension, ADD_MODE::APPEND );
858 
859  if( d.dimensionType )
860  {
861  // Eagle dimension graphic arms may have different lengths, but they look
862  // incorrect in KiCad (the graphic is tilted). Make them even length in such case.
863  if( *d.dimensionType == "horizontal" )
864  {
865  int newY = ( d.y1.ToPcbUnits() + d.y2.ToPcbUnits() ) / 2;
866  d.y1 = ECOORD( newY, ECOORD::EAGLE_UNIT::EU_NM );
867  d.y2 = ECOORD( newY, ECOORD::EAGLE_UNIT::EU_NM );
868  }
869  else if( *d.dimensionType == "vertical" )
870  {
871  int newX = ( d.x1.ToPcbUnits() + d.x2.ToPcbUnits() ) / 2;
872  d.x1 = ECOORD( newX, ECOORD::EAGLE_UNIT::EU_NM );
873  d.x2 = ECOORD( newX, ECOORD::EAGLE_UNIT::EU_NM );
874  }
875  }
876 
877  dimension->SetLayer( layer );
878  dimension->SetPrecision( DIMENSION_PRECISION );
879  // The origin and end are assumed to always be in this order from eagle
880  dimension->SetStart( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ) );
881  dimension->SetEnd( wxPoint( kicad_x( d.x2 ), kicad_y( d.y2 ) ) );
882  dimension->Text().SetTextSize( designSettings.GetTextSize( layer ) );
883  dimension->Text().SetTextThickness( designSettings.GetTextThickness( layer ) );
884  dimension->SetLineThickness( designSettings.GetLineThickness( layer ) );
885  dimension->SetUnits( EDA_UNITS::MILLIMETRES );
886 
887  // check which axis the dimension runs in
888  // because the "height" of the dimension is perpendicular to that axis
889  // Note the check is just if two axes are close enough to each other
890  // Eagle appears to have some rounding errors
891  if( abs( ( d.x1 - d.x2 ).ToPcbUnits() ) < 50000 ) // 50000 nm = 0.05 mm
892  dimension->SetHeight( kicad_x( d.x3 - d.x1 ) );
893  else
894  dimension->SetHeight( kicad_y( d.y3 - d.y1 ) );
895  }
896  }
897 
898  // Get next graphic
899  gr = gr->GetNext();
900  }
901  m_xpath->pop();
902 }
903 
904 
905 void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const wxString* aLibName )
906 {
907  if( !aLib )
908  return;
909 
910  // library will have <xmlattr> node, skip that and get the single packages node
911  wxXmlNode* packages = MapChildren( aLib )["packages"];
912 
913  if( !packages )
914  return;
915 
916  m_xpath->push( "packages" );
917 
918  // Create a FOOTPRINT for all the eagle packages, for use later via a copy constructor
919  // to instantiate needed footprints in our BOARD. Save the FOOTPRINT templates in
920  // a FOOTPRINT_MAP using a single lookup key consisting of libname+pkgname.
921 
922  // Get the first package and iterate
923  wxXmlNode* package = packages->GetChildren();
924 
925  while( package )
926  {
927  m_xpath->push( "package", "name" );
928 
929  wxString pack_ref = package->GetAttribute( "name" );
930  ReplaceIllegalFileNameChars( pack_ref, '_' );
931 
932  m_xpath->Value( pack_ref.ToUTF8() );
933 
934  wxString key = aLibName ? makeKey( *aLibName, pack_ref ) : pack_ref;
935 
936  FOOTPRINT* m = makeFootprint( package, pack_ref );
937 
938  // add the templating FOOTPRINT to the FOOTPRINT template factory "m_templates"
939  std::pair<FOOTPRINT_MAP::iterator, bool> r = m_templates.insert( {key, m} );
940 
941  if( !r.second /* && !( m_props && m_props->Value( "ignore_duplicates" ) ) */ )
942  {
943  wxString lib = aLibName ? *aLibName : m_lib_path;
944  const wxString& pkg = pack_ref;
945 
946  wxString emsg = wxString::Format(
947  _( "<package> name: \"%s\" duplicated in eagle <library>: \"%s\"" ), pkg, lib );
948  THROW_IO_ERROR( emsg );
949  }
950 
951  m_xpath->pop();
952 
953  package = package->GetNext();
954  }
955 
956  m_xpath->pop(); // "packages"
957 }
958 
959 
960 void EAGLE_PLUGIN::loadLibraries( wxXmlNode* aLibs )
961 {
962  if( !aLibs )
963  return;
964 
965  m_xpath->push( "libraries.library", "name" );
966 
967  // Get the first library and iterate
968  wxXmlNode* library = aLibs->GetChildren();
969 
970  while( library )
971  {
972  const wxString& lib_name = library->GetAttribute( "name" );
973 
974  m_xpath->Value( lib_name.c_str() );
975  loadLibrary( library, &lib_name );
976  library = library->GetNext();
977  }
978 
979  m_xpath->pop();
980 }
981 
982 
983 void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
984 {
985  if( !aElements )
986  return;
987 
988  m_xpath->push( "elements.element", "name" );
989 
990  EATTR name;
991  EATTR value;
992  bool refanceNamePresetInPackageLayout;
993  bool valueNamePresetInPackageLayout;
994 
995  // Get the first element and iterate
996  wxXmlNode* element = aElements->GetChildren();
997 
998  while( element )
999  {
1000  if( element->GetName() != "element" )
1001  {
1002  // Get next item
1003  element = element->GetNext();
1004  continue;
1005  }
1006 
1007  EELEMENT e( element );
1008 
1009  // use "NULL-ness" as an indication of presence of the attribute:
1010  EATTR* nameAttr = nullptr;
1011  EATTR* valueAttr = nullptr;
1012 
1013  m_xpath->Value( e.name.c_str() );
1014 
1015  wxString pkg_key = makeKey( e.library, e.package );
1016 
1017  FOOTPRINT_MAP::const_iterator it = m_templates.find( pkg_key );
1018 
1019  if( it == m_templates.end() )
1020  {
1021  wxString emsg = wxString::Format( _( "No \"%s\" package in library \"%s\"" ),
1022  FROM_UTF8( e.package.c_str() ),
1023  FROM_UTF8( e.library.c_str() ) );
1024  THROW_IO_ERROR( emsg );
1025  }
1026 
1027  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( it->second->Duplicate() );
1028 
1029  m_board->Add( footprint, ADD_MODE::APPEND );
1030 
1031  // update the nets within the pads of the clone
1032  for( PAD* pad : footprint->Pads() )
1033  {
1034  wxString pn_key = makeKey( e.name, pad->GetName() );
1035 
1036  NET_MAP_CITER ni = m_pads_to_nets.find( pn_key );
1037  if( ni != m_pads_to_nets.end() )
1038  {
1039  const ENET* enet = &ni->second;
1040  pad->SetNetCode( enet->netcode );
1041  }
1042  }
1043 
1044  refanceNamePresetInPackageLayout = true;
1045  valueNamePresetInPackageLayout = true;
1046  footprint->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
1047 
1048  // Is >NAME field set in package layout ?
1049  if( footprint->GetReference().size() == 0 )
1050  {
1051  footprint->Reference().SetVisible( false ); // No so no show
1052  refanceNamePresetInPackageLayout = false;
1053  }
1054 
1055  // Is >VALUE field set in package layout
1056  if( footprint->GetValue().size() == 0 )
1057  {
1058  footprint->Value().SetVisible( false ); // No so no show
1059  valueNamePresetInPackageLayout = false;
1060  }
1061 
1062  footprint->SetReference( FROM_UTF8( e.name.c_str() ) );
1063  footprint->SetValue( FROM_UTF8( e.value.c_str() ) );
1064 
1065  if( !e.smashed )
1066  { // Not smashed so show NAME & VALUE
1067  if( valueNamePresetInPackageLayout )
1068  footprint->Value().SetVisible( true ); // Only if place holder in package layout
1069 
1070  if( refanceNamePresetInPackageLayout )
1071  footprint->Reference().SetVisible( true ); // Only if place holder in package layout
1072  }
1073  else if( *e.smashed == true )
1074  { // Smashed so set default to no show for NAME and VALUE
1075  footprint->Value().SetVisible( false );
1076  footprint->Reference().SetVisible( false );
1077 
1078  // initialize these to default values in case the <attribute> elements are not present.
1079  m_xpath->push( "attribute", "name" );
1080 
1081  // VALUE and NAME can have something like our text "effects" overrides
1082  // in SWEET and new schematic. Eagle calls these XML elements "attribute".
1083  // There can be one for NAME and/or VALUE both. Features present in the
1084  // EATTR override the ones established in the package only if they are
1085  // present here (except for rot, which if not present means angle zero).
1086  // So the logic is a bit different than in packageText() and in plain text.
1087 
1088  // Get the first attribute and iterate
1089  wxXmlNode* attribute = element->GetChildren();
1090 
1091  while( attribute )
1092  {
1093  if( attribute->GetName() != "attribute" )
1094  {
1095  attribute = attribute->GetNext();
1096  continue;
1097  }
1098 
1099  EATTR a( attribute );
1100 
1101  if( a.name == "NAME" )
1102  {
1103  name = a;
1104  nameAttr = &name;
1105 
1106  // do we have a display attribute ?
1107  if( a.display )
1108  {
1109  // Yes!
1110  switch( *a.display )
1111  {
1112  case EATTR::VALUE :
1113  {
1114  wxString reference = e.name;
1115 
1116  // EAGLE allows references to be single digits. This breaks KiCad netlisting, which requires
1117  // parts to have non-digit + digit annotation. If the reference begins with a number,
1118  // we prepend 'UNK' (unknown) for the symbol designator
1119  if( reference.find_first_not_of( "0123456789" ) == wxString::npos )
1120  reference.Prepend( "UNK" );
1121 
1122  nameAttr->name = reference;
1123  footprint->SetReference( reference );
1124 
1125  if( refanceNamePresetInPackageLayout )
1126  footprint->Reference().SetVisible( true );
1127 
1128  break;
1129  }
1130  case EATTR::NAME :
1131  if( refanceNamePresetInPackageLayout )
1132  {
1133  footprint->SetReference( "NAME" );
1134  footprint->Reference().SetVisible( true );
1135  }
1136  break;
1137 
1138  case EATTR::BOTH :
1139  if( refanceNamePresetInPackageLayout )
1140  footprint->Reference().SetVisible( true );
1141 
1142  nameAttr->name = nameAttr->name + " = " + e.name;
1143  footprint->SetReference( "NAME = " + e.name );
1144  break;
1145 
1146  case EATTR::Off :
1147  footprint->Reference().SetVisible( false );
1148  break;
1149 
1150  default:
1151  nameAttr->name = e.name;
1152 
1153  if( refanceNamePresetInPackageLayout )
1154  footprint->Reference().SetVisible( true );
1155  }
1156  }
1157  else
1158  // No display, so default is visible, and show value of NAME
1159  footprint->Reference().SetVisible( true );
1160  }
1161  else if( a.name == "VALUE" )
1162  {
1163  value = a;
1164  valueAttr = &value;
1165 
1166  if( a.display )
1167  {
1168  // Yes!
1169  switch( *a.display )
1170  {
1171  case EATTR::VALUE :
1172  valueAttr->value = opt_wxString( e.value );
1173  footprint->SetValue( e.value );
1174 
1175  if( valueNamePresetInPackageLayout )
1176  footprint->Value().SetVisible( true );
1177 
1178  break;
1179 
1180  case EATTR::NAME :
1181  if( valueNamePresetInPackageLayout )
1182  footprint->Value().SetVisible( true );
1183 
1184  footprint->SetValue( "VALUE" );
1185  break;
1186 
1187  case EATTR::BOTH :
1188  if( valueNamePresetInPackageLayout )
1189  footprint->Value().SetVisible( true );
1190 
1191  valueAttr->value = opt_wxString( "VALUE = " + e.value );
1192  footprint->SetValue( "VALUE = " + e.value );
1193  break;
1194 
1195  case EATTR::Off :
1196  footprint->Value().SetVisible( false );
1197  break;
1198 
1199  default:
1200  valueAttr->value = opt_wxString( e.value );
1201 
1202  if( valueNamePresetInPackageLayout )
1203  footprint->Value().SetVisible( true );
1204  }
1205  }
1206  else
1207  {
1208  // No display, so default is visible, and show value of NAME
1209  footprint->Value().SetVisible( true );
1210  }
1211 
1212  }
1213 
1214  attribute = attribute->GetNext();
1215  }
1216 
1217  m_xpath->pop(); // "attribute"
1218  }
1219 
1220  orientFootprintAndText( footprint, e, nameAttr, valueAttr );
1221 
1222  // Set the local coordinates for the footprint text items
1223  footprint->Reference().SetLocalCoord();
1224  footprint->Value().SetLocalCoord();
1225 
1226  // Get next element
1227  element = element->GetNext();
1228  }
1229 
1230  m_xpath->pop(); // "elements.element"
1231 }
1232 
1233 
1234 ZONE* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
1235 {
1236  EPOLYGON p( aPolyNode );
1237  PCB_LAYER_ID layer = kicad_layer( p.layer );
1238  ZONE* zone = nullptr;
1239  bool keepout = ( p.layer == EAGLE_LAYER::TRESTRICT
1241  || p.layer == EAGLE_LAYER::VRESTRICT );
1242 
1243  if( layer == UNDEFINED_LAYER ) {
1244  wxLogMessage( wxString::Format(
1245  _( "Ignoring a polygon since Eagle layer '%s' (%d) "
1246  "was not mapped" ),
1247  eagle_layer_name( p.layer ),
1248  p.layer ) );
1249  return nullptr;
1250  }
1251 
1252  if( !IsCopperLayer( layer ) && !keepout )
1253  return nullptr;
1254 
1255  // use a "netcode = 0" type ZONE:
1256  zone = new ZONE( m_board );
1257  m_board->Add( zone, ADD_MODE::APPEND );
1258 
1259  if( !keepout )
1260  zone->SetLayer( layer );
1261  else
1262  setKeepoutSettingsToZone( zone, p.layer );
1263 
1264  // Get the first vertex and iterate
1265  wxXmlNode* vertex = aPolyNode->GetChildren();
1266  std::vector<EVERTEX> vertices;
1267 
1268  // Create a circular vector of vertices
1269  // The "curve" parameter indicates a curve from the current
1270  // to the next vertex, so we keep the first at the end as well
1271  // to allow the curve to link back
1272  while( vertex )
1273  {
1274  if( vertex->GetName() == "vertex" )
1275  vertices.emplace_back( vertex );
1276 
1277  vertex = vertex->GetNext();
1278  }
1279 
1280  vertices.push_back( vertices[0] );
1281 
1282  SHAPE_POLY_SET polygon;
1283  polygon.NewOutline();
1284 
1285  for( size_t i = 0; i < vertices.size() - 1; i++ )
1286  {
1287  EVERTEX v1 = vertices[i];
1288 
1289  // Append the corner
1290  polygon.Append( kicad_x( v1.x ), kicad_y( v1.y ) );
1291 
1292  if( v1.curve )
1293  {
1294  EVERTEX v2 = vertices[i + 1];
1295  wxPoint center = ConvertArcCenter( wxPoint( kicad_x( v1.x ), kicad_y( v1.y ) ),
1296  wxPoint( kicad_x( v2.x ), kicad_y( v2.y ) ),
1297  *v1.curve );
1298  double angle = DEG2RAD( *v1.curve );
1299  double end_angle = atan2( kicad_y( v2.y ) - center.y,
1300  kicad_x( v2.x ) - center.x );
1301  double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
1302  + pow( center.y - kicad_y( v1.y ), 2 ) );
1303 
1304  int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve );
1305  double delta_angle = angle / segCount;
1306 
1307  for( double a = end_angle + angle;
1308  fabs( a - end_angle ) > fabs( delta_angle );
1309  a -= delta_angle )
1310  {
1311  polygon.Append( KiROUND( radius * cos( a ) ) + center.x,
1312  KiROUND( radius * sin( a ) ) + center.y );
1313  }
1314  }
1315  }
1316 
1317  // Eagle traces the zone such that half of the pen width is outside the polygon.
1318  // We trace the zone such that the copper is completely inside.
1319  if( p.width.ToPcbUnits() > 0 )
1320  {
1323  }
1324 
1325  zone->AddPolygon( polygon.COutline( 0 ) );
1326 
1327  // If the pour is a cutout it needs to be set to a keepout
1328  if( p.pour == EPOLYGON::CUTOUT )
1329  {
1330  zone->SetIsRuleArea( true );
1331  zone->SetDoNotAllowVias( false );
1332  zone->SetDoNotAllowTracks( false );
1333  zone->SetDoNotAllowPads( false );
1334  zone->SetDoNotAllowFootprints( false );
1335  zone->SetDoNotAllowCopperPour( true );
1337  }
1338  else if( p.pour == EPOLYGON::HATCH )
1339  {
1340  int spacing = p.spacing ? p.spacing->ToPcbUnits() : 50 * IU_PER_MILS;
1341 
1343  zone->SetHatchThickness( p.width.ToPcbUnits() );
1344  zone->SetHatchGap( spacing - p.width.ToPcbUnits() );
1345  zone->SetHatchOrientation( 0 );
1346  }
1347 
1348  // We divide the thickness by half because we are tracing _inside_ the zone outline
1349  // This means the radius of curvature will be twice the size for an equivalent EAGLE zone
1351  p.width.ToPcbUnits() / 2 ) );
1352 
1353  if( p.isolate )
1354  zone->SetLocalClearance( p.isolate->ToPcbUnits() );
1355  else
1356  zone->SetLocalClearance( 1 ); // @todo: set minimum clearance value based on board settings
1357 
1358  // missing == yes per DTD.
1359  bool thermals = !p.thermals || *p.thermals;
1361 
1362  if( thermals )
1363  {
1364  // FIXME: eagle calculates dimensions for thermal spokes
1365  // based on what the zone is connecting to.
1366  // (i.e. width of spoke is half of the smaller side of an smd pad)
1367  // This is a basic workaround
1368  zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
1369  zone->SetThermalReliefSpokeWidth( p.width.ToPcbUnits() + 50000 );
1370  }
1371 
1372  int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;
1373  zone->SetPriority( rank );
1374 
1375  return zone;
1376 }
1377 
1378 
1380  const EATTR* aNameAttr, const EATTR* aValueAttr )
1381 {
1382  if( e.rot )
1383  {
1384  if( e.rot->mirror )
1385  {
1386  double orientation = e.rot->degrees + 180.0;
1387  aFootprint->SetOrientation( orientation * 10 );
1388  aFootprint->Flip( aFootprint->GetPosition(), false );
1389  }
1390  else
1391  {
1392  aFootprint->SetOrientation( e.rot->degrees * 10 );
1393  }
1394  }
1395 
1396  orientFPText( aFootprint, e, &aFootprint->Reference(), aNameAttr );
1397  orientFPText( aFootprint, e, &aFootprint->Value(), aValueAttr );
1398 }
1399 
1400 
1401 void EAGLE_PLUGIN::orientFPText( FOOTPRINT* aFootprint, const EELEMENT& e, FP_TEXT* aFPText,
1402  const EATTR* aAttr )
1403 {
1404  // Smashed part ?
1405  if( aAttr )
1406  { // Yes
1407  const EATTR& a = *aAttr;
1408 
1409  if( a.value )
1410  {
1411  aFPText->SetText( FROM_UTF8( a.value->c_str() ) );
1412  }
1413 
1414  if( a.x && a.y ) // OPT
1415  {
1416  wxPoint pos( kicad_x( *a.x ), kicad_y( *a.y ) );
1417  aFPText->SetTextPos( pos );
1418  }
1419 
1420  // Even though size and ratio are both optional, I am not seeing
1421  // a case where ratio is present but size is not.
1422  double ratio = 8;
1423  wxSize fontz = aFPText->GetTextSize();
1424  int textThickness = KiROUND( fontz.y * ratio / 100 );
1425 
1426  aFPText->SetTextThickness( textThickness );
1427  if( a.size )
1428  {
1429  fontz = kicad_fontz( *a.size, textThickness );
1430  aFPText->SetTextSize( fontz );
1431 
1432  if( a.ratio )
1433  ratio = *a.ratio;
1434  }
1435 
1436 
1437 
1438  int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
1439 
1440  if( a.align )
1441  align = a.align;
1442 
1443  // The "rot" in a EATTR seems to be assumed to be zero if it is not
1444  // present, and this zero rotation becomes an override to the
1445  // package's text field. If they did not want zero, they specify
1446  // what they want explicitly.
1447  double degrees = a.rot ? a.rot->degrees : 0;
1448  double orient; // relative to parent
1449 
1450  int sign = 1;
1451  bool spin = false;
1452 
1453  if( a.rot )
1454  {
1455  spin = a.rot->spin;
1456  sign = a.rot->mirror ? -1 : 1;
1457  aFPText->SetMirrored( a.rot->mirror );
1458  }
1459 
1460  if( degrees == 90 || degrees == 0 || spin )
1461  {
1462  orient = degrees - aFootprint->GetOrientation() / 10;
1463  aFPText->SetTextAngle( sign * orient * 10 );
1464  }
1465  else if( degrees == 180 )
1466  {
1467  orient = 0 - aFootprint->GetOrientation() / 10;
1468  aFPText->SetTextAngle( sign * orient * 10 );
1469  align = -align;
1470  }
1471  else if( degrees == 270 )
1472  {
1473  orient = 90 - aFootprint->GetOrientation() / 10;
1474  align = -align;
1475  aFPText->SetTextAngle( sign * orient * 10 );
1476  }
1477  else
1478  {
1479  orient = 90 - degrees - aFootprint->GetOrientation() / 10;
1480  aFPText->SetTextAngle( sign * orient * 10 );
1481  }
1482 
1483  switch( align )
1484  {
1485  case ETEXT::TOP_RIGHT:
1488  break;
1489 
1490  case ETEXT::BOTTOM_LEFT:
1493  break;
1494 
1495  case ETEXT::TOP_LEFT:
1498  break;
1499 
1500  case ETEXT::BOTTOM_RIGHT:
1503  break;
1504 
1505  case ETEXT::TOP_CENTER:
1508  break;
1509 
1510  case ETEXT::BOTTOM_CENTER:
1513  break;
1514 
1515  default:
1516  ;
1517  }
1518  }
1519  else // Part is not smash so use Lib default for NAME/VALUE // the text is per the original package, sans <attribute>
1520  {
1521  double degrees = ( aFPText->GetTextAngle() + aFootprint->GetOrientation() ) / 10;
1522 
1523  // @todo there are a few more cases than these to contend with:
1524  if( ( !aFPText->IsMirrored() && ( abs( degrees ) == 180 || abs( degrees ) == 270 ) )
1525  || ( aFPText->IsMirrored() && ( degrees == 360 ) ) )
1526  {
1527  // ETEXT::TOP_RIGHT:
1530  }
1531  }
1532 }
1533 
1534 
1535 FOOTPRINT* EAGLE_PLUGIN::makeFootprint( wxXmlNode* aPackage, const wxString& aPkgName )
1536 {
1537  std::unique_ptr<FOOTPRINT> m = std::make_unique<FOOTPRINT>( m_board );
1538 
1539  LIB_ID fpID;
1540  fpID.Parse( aPkgName, LIB_ID::ID_PCB, true );
1541  m->SetFPID( fpID );
1542 
1543  // Get the first package item and iterate
1544  wxXmlNode* packageItem = aPackage->GetChildren();
1545 
1546  while( packageItem )
1547  {
1548  const wxString& itemName = packageItem->GetName();
1549 
1550  if( itemName == "description" )
1551  m->SetDescription( FROM_UTF8( packageItem->GetNodeContent().c_str() ) );
1552 
1553  else if( itemName == "wire" )
1554  packageWire( m.get(), packageItem );
1555 
1556  else if( itemName == "pad" )
1557  packagePad( m.get(), packageItem );
1558 
1559  else if( itemName == "text" )
1560  packageText( m.get(), packageItem );
1561 
1562  else if( itemName == "rectangle" )
1563  packageRectangle( m.get(), packageItem );
1564 
1565  else if( itemName == "polygon" )
1566  packagePolygon( m.get(), packageItem );
1567 
1568  else if( itemName == "circle" )
1569  packageCircle( m.get(), packageItem );
1570 
1571  else if( itemName == "hole" )
1572  packageHole( m.get(), packageItem, false );
1573 
1574  else if( itemName == "smd" )
1575  packageSMD( m.get(), packageItem );
1576 
1577  packageItem = packageItem->GetNext();
1578  }
1579 
1580  return m.release();
1581 }
1582 
1583 
1584 void EAGLE_PLUGIN::packageWire( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
1585 {
1586  EWIRE w( aTree );
1587  PCB_LAYER_ID layer = kicad_layer( w.layer );
1588  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
1589  wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
1590  int width = w.width.ToPcbUnits();
1591 
1592  if( layer == UNDEFINED_LAYER )
1593  {
1594  wxLogMessage( wxString::Format( _( "Ignoring a wire since Eagle layer '%s' (%d) "
1595  "was not mapped" ),
1596  eagle_layer_name( w.layer ),
1597  w.layer ) );
1598  return;
1599  }
1600 
1601  // KiCad cannot handle zero or negative line widths which apparently have meaning in Eagle.
1602  if( width <= 0 )
1603  {
1604  BOARD* board = aFootprint->GetBoard();
1605 
1606  if( board )
1607  {
1608  width = board->GetDesignSettings().GetLineThickness( layer );
1609  }
1610  else
1611  {
1612  // When loading footprint libraries, there is no board so use the default KiCad
1613  // line widths.
1614  switch( layer )
1615  {
1616  case Edge_Cuts: width = Millimeter2iu( DEFAULT_EDGE_WIDTH ); break;
1617 
1618  case F_SilkS:
1619  case B_SilkS: width = Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ); break;
1620 
1621  case F_CrtYd:
1622  case B_CrtYd: width = Millimeter2iu( DEFAULT_COURTYARD_WIDTH ); break;
1623 
1624  default: width = Millimeter2iu( DEFAULT_LINE_WIDTH ); break;
1625  }
1626  }
1627  }
1628 
1629  // FIXME: the cap attribute is ignored because KiCad can't create lines
1630  // with flat ends.
1631  FP_SHAPE* dwg;
1632 
1633  if( !w.curve )
1634  {
1635  dwg = new FP_SHAPE( aFootprint, S_SEGMENT );
1636 
1637  dwg->SetStart0( start );
1638  dwg->SetEnd0( end );
1639  }
1640  else
1641  {
1642  dwg = new FP_SHAPE( aFootprint, S_ARC );
1643  wxPoint center = ConvertArcCenter( start, end, *w.curve );
1644 
1645  dwg->SetStart0( center );
1646  dwg->SetEnd0( start );
1647  dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
1648  }
1649 
1650  dwg->SetLayer( layer );
1651  dwg->SetWidth( width );
1652  dwg->SetDrawCoord();
1653 
1654  aFootprint->Add( dwg );
1655 }
1656 
1657 
1658 void EAGLE_PLUGIN::packagePad( FOOTPRINT* aFootprint, wxXmlNode* aTree )
1659 {
1660  // this is thru hole technology here, no SMDs
1661  EPAD e( aTree );
1662  int shape = EPAD::UNDEF;
1663  int eagleDrillz = e.drill.ToPcbUnits();
1664 
1665  PAD* pad = new PAD( aFootprint );
1666  aFootprint->Add( pad );
1667  transferPad( e, pad );
1668 
1669  if( e.first && *e.first && m_rules->psFirst != EPAD::UNDEF )
1670  shape = m_rules->psFirst;
1671  else if( aFootprint->GetLayer() == F_Cu && m_rules->psTop != EPAD::UNDEF )
1672  shape = m_rules->psTop;
1673  else if( aFootprint->GetLayer() == B_Cu && m_rules->psBottom != EPAD::UNDEF )
1674  shape = m_rules->psBottom;
1675 
1676  pad->SetDrillSize( wxSize( eagleDrillz, eagleDrillz ) );
1677  pad->SetLayerSet( LSET::AllCuMask() );
1678 
1679  if( eagleDrillz < m_min_hole )
1680  m_min_hole = eagleDrillz;
1681 
1682  // Solder mask
1683  if( !e.stop || *e.stop == true ) // enabled by default
1684  pad->SetLayerSet( pad->GetLayerSet().set( B_Mask ).set( F_Mask ) );
1685 
1686  if( shape == EPAD::ROUND || shape == EPAD::SQUARE || shape == EPAD::OCTAGON )
1687  e.shape = shape;
1688 
1689  if( e.shape )
1690  {
1691  switch( *e.shape )
1692  {
1693  case EPAD::ROUND:
1694  pad->SetShape( PAD_SHAPE_CIRCLE );
1695  break;
1696 
1697  case EPAD::OCTAGON:
1698  // no KiCad octagonal pad shape, use PAD_CIRCLE for now.
1699  // pad->SetShape( PAD_OCTAGON );
1700  wxASSERT( pad->GetShape() == PAD_SHAPE_CIRCLE ); // verify set in PAD constructor
1703  pad->SetChamferRectRatio( 0.25 );
1704  break;
1705 
1706  case EPAD::LONG:
1707  pad->SetShape( PAD_SHAPE_OVAL );
1708  break;
1709 
1710  case EPAD::SQUARE:
1711  pad->SetShape( PAD_SHAPE_RECT );
1712  break;
1713 
1714  case EPAD::OFFSET:
1715  pad->SetShape( PAD_SHAPE_OVAL );
1716  break;
1717  }
1718  }
1719  else
1720  {
1721  // if shape is not present, our default is circle and that matches their default "round"
1722  }
1723 
1724  if( e.diameter )
1725  {
1726  int diameter = e.diameter->ToPcbUnits();
1727  pad->SetSize( wxSize( diameter, diameter ) );
1728  }
1729  else
1730  {
1731  double drillz = pad->GetDrillSize().x;
1732  double annulus = drillz * m_rules->rvPadTop; // copper annulus, eagle "restring"
1733  annulus = eagleClamp( m_rules->rlMinPadTop, annulus, m_rules->rlMaxPadTop );
1734  int diameter = KiROUND( drillz + 2 * annulus );
1735  pad->SetSize( wxSize( KiROUND( diameter ), KiROUND( diameter ) ) );
1736  }
1737 
1738  if( pad->GetShape() == PAD_SHAPE_OVAL )
1739  {
1740  // The Eagle "long" pad is wider than it is tall,
1741  // m_elongation is percent elongation
1742  wxSize sz = pad->GetSize();
1743  sz.x = ( sz.x * ( 100 + m_rules->psElongationLong ) ) / 100;
1744  pad->SetSize( sz );
1745 
1746  if( e.shape && *e.shape == EPAD::OFFSET )
1747  {
1748  int offset = KiROUND( ( sz.x - sz.y ) / 2.0 );
1749  pad->SetOffset( wxPoint( offset, 0 ) );
1750  }
1751  }
1752 
1753  if( e.rot )
1754  {
1755  pad->SetOrientation( e.rot->degrees * 10 );
1756  }
1757 }
1758 
1759 
1760 void EAGLE_PLUGIN::packageText( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
1761 {
1762  ETEXT t( aTree );
1763  PCB_LAYER_ID layer = kicad_layer( t.layer );
1764 
1765  if( layer == UNDEFINED_LAYER )
1766  {
1767  wxLogMessage( wxString::Format( _( "Ignoring a text since Eagle layer '%s' (%d) "
1768  "was not mapped" ),
1769  eagle_layer_name( t.layer ),
1770  t.layer ) );
1771  return;
1772  }
1773 
1774  FP_TEXT* txt;
1775 
1776  if( t.text == ">NAME" || t.text == ">name" )
1777  txt = &aFootprint->Reference();
1778  else if( t.text == ">VALUE" || t.text == ">value" )
1779  txt = &aFootprint->Value();
1780  else
1781  {
1782  // FIXME: graphical text items are rotated for some reason.
1783  txt = new FP_TEXT( aFootprint );
1784  aFootprint->Add( txt );
1785  }
1786 
1787  txt->SetText( FROM_UTF8( t.text.c_str() ) );
1788 
1789  wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
1790 
1791  txt->SetTextPos( pos );
1792  txt->SetPos0( pos - aFootprint->GetPosition() );
1793 
1794  txt->SetLayer( layer );
1795 
1796 
1797  double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
1798  int textThickness = KiROUND( t.size.ToPcbUnits() * ratio / 100 );
1799 
1800  txt->SetTextThickness( textThickness );
1801  txt->SetTextSize( kicad_fontz( t.size, textThickness ) );
1802 
1803  int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
1804 
1805  // An eagle package is never rotated, the DTD does not allow it.
1806  // angle -= aFootprint->GetOrienation();
1807 
1808  if( t.rot )
1809  {
1810  int sign = t.rot->mirror ? -1 : 1;
1811  txt->SetMirrored( t.rot->mirror );
1812 
1813  double degrees = t.rot->degrees;
1814 
1815  if( degrees == 90 || t.rot->spin )
1816  txt->SetTextAngle( sign * degrees * 10 );
1817  else if( degrees == 180 )
1818  align = ETEXT::TOP_RIGHT;
1819  else if( degrees == 270 )
1820  {
1821  align = ETEXT::TOP_RIGHT;
1822  txt->SetTextAngle( sign * 90 * 10 );
1823  }
1824  }
1825 
1826  switch( align )
1827  {
1828  case ETEXT::CENTER:
1829  // this was the default in pcbtxt's constructor
1830  break;
1831 
1832  case ETEXT::CENTER_LEFT:
1834  break;
1835 
1836  case ETEXT::CENTER_RIGHT:
1838  break;
1839 
1840  case ETEXT::TOP_CENTER:
1842  break;
1843 
1844  case ETEXT::TOP_LEFT:
1847  break;
1848 
1849  case ETEXT::TOP_RIGHT:
1852  break;
1853 
1854  case ETEXT::BOTTOM_CENTER:
1856  break;
1857 
1858  case ETEXT::BOTTOM_LEFT:
1861  break;
1862 
1863  case ETEXT::BOTTOM_RIGHT:
1866  break;
1867  }
1868 }
1869 
1870 
1871 void EAGLE_PLUGIN::packageRectangle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
1872 {
1873  ERECT r( aTree );
1874 
1876  || r.layer == EAGLE_LAYER::VRESTRICT )
1877  {
1878  FP_ZONE* zone = new FP_ZONE( aFootprint );
1879  aFootprint->Add( zone, ADD_MODE::APPEND );
1880 
1881  setKeepoutSettingsToZone( zone, r.layer );
1882 
1883  const int outlineIdx = -1; // this is the id of the copper zone main outline
1884  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx );
1885  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx );
1886  zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx );
1887  zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx );
1888 
1889  if( r.rot )
1890  {
1891  wxPoint center( ( kicad_x( r.x1 ) + kicad_x( r.x2 ) ) / 2,
1892  ( kicad_y( r.y1 ) + kicad_y( r.y2 ) ) / 2 );
1893  zone->Rotate( center, r.rot->degrees * 10 );
1894  }
1895 
1897  ZONE::GetDefaultHatchPitch(), true );
1898  }
1899  else
1900  {
1901  PCB_LAYER_ID layer = kicad_layer( r.layer );
1902 
1903  if( layer == UNDEFINED_LAYER )
1904  {
1905  wxLogMessage( wxString::Format( _( "Ignoring a rectange since Eagle layer '%s' (%d) "
1906  "was not mapped" ),
1907  eagle_layer_name( r.layer ),
1908  r.layer ) );
1909  return;
1910  }
1911 
1912  FP_SHAPE* dwg = new FP_SHAPE( aFootprint, S_POLYGON );
1913 
1914  aFootprint->Add( dwg );
1915 
1916  dwg->SetLayer( layer );
1917  dwg->SetWidth( 0 );
1918 
1919  std::vector<wxPoint> pts;
1920 
1921  wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
1922  wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
1923 
1924  pts.push_back( start );
1925  pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y1 ) );
1926  pts.emplace_back( kicad_x( r.x2 ), kicad_y( r.y2 ) );
1927  pts.push_back( end );
1928 
1929  dwg->SetPolyPoints( pts );
1930 
1931  dwg->SetStart0( start );
1932  dwg->SetEnd0( end );
1933 
1934  if( r.rot )
1935  dwg->Rotate( dwg->GetCenter(), r.rot->degrees * 10 );
1936  }
1937 }
1938 
1939 
1940 void EAGLE_PLUGIN::packagePolygon( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
1941 {
1942  EPOLYGON p( aTree );
1943 
1944  std::vector<wxPoint> pts;
1945 
1946  // Get the first vertex and iterate
1947  wxXmlNode* vertex = aTree->GetChildren();
1948  std::vector<EVERTEX> vertices;
1949 
1950  // Create a circular vector of vertices
1951  // The "curve" parameter indicates a curve from the current
1952  // to the next vertex, so we keep the first at the end as well
1953  // to allow the curve to link back
1954  while( vertex )
1955  {
1956  if( vertex->GetName() == "vertex" )
1957  vertices.emplace_back( vertex );
1958 
1959  vertex = vertex->GetNext();
1960  }
1961 
1962  vertices.push_back( vertices[0] );
1963 
1964  for( size_t i = 0; i < vertices.size() - 1; i++ )
1965  {
1966  EVERTEX v1 = vertices[i];
1967 
1968  // Append the corner
1969  pts.emplace_back( kicad_x( v1.x ), kicad_y( v1.y ) );
1970 
1971  if( v1.curve )
1972  {
1973  EVERTEX v2 = vertices[i + 1];
1974  wxPoint center = ConvertArcCenter(
1975  wxPoint( kicad_x( v1.x ), kicad_y( v1.y ) ),
1976  wxPoint( kicad_x( v2.x ), kicad_y( v2.y ) ), *v1.curve );
1977  double angle = DEG2RAD( *v1.curve );
1978  double end_angle = atan2( kicad_y( v2.y ) - center.y,
1979  kicad_x( v2.x ) - center.x );
1980  double radius = sqrt( pow( center.x - kicad_x( v1.x ), 2 )
1981  + pow( center.y - kicad_y( v1.y ), 2 ) );
1982 
1983  // Don't allow a zero-radius curve
1984  if( KiROUND( radius ) == 0 )
1985  radius = 1.0;
1986 
1987  int segCount = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *v1.curve );
1988  double delta = angle / segCount;
1989 
1990  for( double a = end_angle + angle; fabs( a - end_angle ) > fabs( delta ); a -= delta )
1991  {
1992  pts.push_back( wxPoint( KiROUND( radius * cos( a ) ),
1993  KiROUND( radius * sin( a ) ) ) + center );
1994  }
1995  }
1996  }
1997 
1998  if( p.layer == EAGLE_LAYER::TRESTRICT
2000  || p.layer == EAGLE_LAYER::VRESTRICT )
2001  {
2002  FP_ZONE* zone = new FP_ZONE( aFootprint );
2003  aFootprint->Add( zone, ADD_MODE::APPEND );
2004 
2005  setKeepoutSettingsToZone( zone, p.layer );
2006 
2007  SHAPE_LINE_CHAIN outline( pts );
2008  outline.SetClosed( true );
2009  zone->Outline()->AddOutline( outline );
2010 
2012  ZONE::GetDefaultHatchPitch(), true );
2013  }
2014  else
2015  {
2016  PCB_LAYER_ID layer = kicad_layer( p.layer );
2017 
2018  if( layer == UNDEFINED_LAYER )
2019  {
2020  wxLogMessage( wxString::Format( _( "Ignoring a polygon since Eagle layer '%s' (%d) "
2021  "was not mapped" ),
2022  eagle_layer_name( p.layer ),
2023  p.layer ) );
2024  return;
2025  }
2026 
2027  FP_SHAPE* dwg = new FP_SHAPE( aFootprint, S_POLYGON );
2028 
2029  aFootprint->Add( dwg );
2030 
2031  dwg->SetWidth( 0 ); // it's filled, no need for boundary width
2032  dwg->SetLayer( layer );
2033 
2034  dwg->SetPolyPoints( pts );
2035  dwg->SetStart0( *pts.begin() );
2036  dwg->SetEnd0( pts.back() );
2037  dwg->SetDrawCoord();
2038  dwg->GetPolyShape().Inflate( p.width.ToPcbUnits() / 2, 32,
2040  }
2041 }
2042 
2043 void EAGLE_PLUGIN::packageCircle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2044 {
2045  ECIRCLE e( aTree );
2046 
2047  int width = e.width.ToPcbUnits();
2048  int radius = e.radius.ToPcbUnits();
2049 
2050  if( e.layer == EAGLE_LAYER::TRESTRICT
2052  || e.layer == EAGLE_LAYER::VRESTRICT )
2053  {
2054  FP_ZONE* zone = new FP_ZONE( aFootprint );
2055  aFootprint->Add( zone, ADD_MODE::APPEND );
2056 
2057  setKeepoutSettingsToZone( zone, e.layer );
2058 
2059  // approximate circle as polygon with a edge every 10 degree
2060  wxPoint center( kicad_x( e.x ), kicad_y( e.y ) );
2061  int outlineRadius = radius + ( width / 2 );
2062  for( int angle = 0; angle < 360; angle += 10 )
2063  {
2064  wxPoint rotatedPoint( outlineRadius, 0 );
2065  RotatePoint( &rotatedPoint, angle * 10. );
2066  zone->AppendCorner( center + rotatedPoint, -1 );
2067  }
2068 
2069  if( width > 0 )
2070  {
2071  zone->NewHole();
2072  int innerRadius = radius - ( width / 2 );
2073  for( int angle = 0; angle < 360; angle += 10 )
2074  {
2075  wxPoint rotatedPoint( innerRadius, 0 );
2076  RotatePoint( &rotatedPoint, angle * 10. );
2077  zone->AppendCorner( center + rotatedPoint, 0 );
2078  }
2079  }
2080 
2082  ZONE::GetDefaultHatchPitch(), true );
2083  }
2084  else
2085  {
2086  PCB_LAYER_ID layer = kicad_layer( e.layer );
2087 
2088  if( layer == UNDEFINED_LAYER )
2089  {
2090  wxLogMessage( wxString::Format( _( "Ignoring a circle since Eagle layer '%s' (%d) "
2091  "was not mapped" ),
2092  eagle_layer_name( e.layer ),
2093  e.layer ) );
2094  return;
2095  }
2096 
2097  FP_SHAPE* gr = new FP_SHAPE( aFootprint, S_CIRCLE );
2098 
2099  // with == 0 means filled circle
2100  if( width <= 0 )
2101  {
2102  width = radius;
2103  radius = radius / 2;
2104  }
2105 
2106  aFootprint->Add( gr );
2107  gr->SetWidth( width );
2108 
2109  switch( (int) layer )
2110  {
2111  case UNDEFINED_LAYER:
2112  layer = Cmts_User;
2113  break;
2114  default:
2115  break;
2116  }
2117 
2118  gr->SetLayer( layer );
2119  gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
2120  gr->SetEnd0( wxPoint( kicad_x( e.x ) + radius, kicad_y( e.y ) ) );
2121  gr->SetDrawCoord();
2122  }
2123 }
2124 
2125 
2126 void EAGLE_PLUGIN::packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aCenter ) const
2127 {
2128  EHOLE e( aTree );
2129 
2130  // we add a PAD_ATTRIB_NPTH pad to this footprint.
2131  PAD* pad = new PAD( aFootprint );
2132  aFootprint->Add( pad );
2133 
2134  pad->SetShape( PAD_SHAPE_CIRCLE );
2135  pad->SetAttribute( PAD_ATTRIB_NPTH );
2136 
2137  // Mechanical purpose only:
2138  // no offset, no net name, no pad name allowed
2139  // pad->SetOffset( wxPoint( 0, 0 ) );
2140  // pad->SetName( wxEmptyString );
2141 
2142  wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) );
2143 
2144  if( aCenter )
2145  {
2146  pad->SetPos0( wxPoint( 0, 0 ) );
2147  aFootprint->SetPosition( padpos );
2148  pad->SetPosition( padpos );
2149  }
2150  else
2151  {
2152  pad->SetPos0( padpos );
2153  pad->SetPosition( padpos + aFootprint->GetPosition() );
2154  }
2155 
2156  wxSize sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
2157 
2158  pad->SetDrillSize( sz );
2159  pad->SetSize( sz );
2160 
2161  pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
2162 }
2163 
2164 
2165 void EAGLE_PLUGIN::packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
2166 {
2167  ESMD e( aTree );
2168  PCB_LAYER_ID layer = kicad_layer( e.layer );
2169 
2170  if( !IsCopperLayer( layer ) )
2171  return;
2172 
2173  PAD* pad = new PAD( aFootprint );
2174  aFootprint->Add( pad );
2175  transferPad( e, pad );
2176 
2177  pad->SetShape( PAD_SHAPE_RECT );
2178  pad->SetAttribute( PAD_ATTRIB_SMD );
2179 
2180  wxSize padSize( e.dx.ToPcbUnits(), e.dy.ToPcbUnits() );
2181  pad->SetSize( padSize );
2182  pad->SetLayer( layer );
2183 
2184  const LSET front( 3, F_Cu, F_Paste, F_Mask );
2185  const LSET back( 3, B_Cu, B_Paste, B_Mask );
2186 
2187  if( layer == F_Cu )
2188  pad->SetLayerSet( front );
2189  else if( layer == B_Cu )
2190  pad->SetLayerSet( back );
2191 
2192  int minPadSize = std::min( padSize.x, padSize.y );
2193 
2194  // Rounded rectangle pads
2195  int roundRadius = eagleClamp( m_rules->srMinRoundness * 2,
2196  (int)( minPadSize * m_rules->srRoundness ), m_rules->srMaxRoundness * 2 );
2197 
2198  if( e.roundness || roundRadius > 0 )
2199  {
2200  double roundRatio = (double) roundRadius / minPadSize / 2.0;
2201 
2202  // Eagle uses a different definition of roundness, hence division by 200
2203  if( e.roundness )
2204  roundRatio = std::fmax( *e.roundness / 200.0, roundRatio );
2205 
2206  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2207  pad->SetRoundRectRadiusRatio( roundRatio );
2208  }
2209 
2210  if( e.rot )
2211  pad->SetOrientation( e.rot->degrees * 10 );
2212 
2214  (int) ( m_rules->mvCreamFrame * minPadSize ),
2215  m_rules->mlMaxCreamFrame ) );
2216 
2217  // Solder mask
2218  if( e.stop && *e.stop == false ) // enabled by default
2219  {
2220  if( layer == F_Cu )
2221  pad->SetLayerSet( pad->GetLayerSet().set( F_Mask, false ) );
2222  else if( layer == B_Cu )
2223  pad->SetLayerSet( pad->GetLayerSet().set( B_Mask, false ) );
2224  }
2225 
2226  // Solder paste (only for SMD pads)
2227  if( e.cream && *e.cream == false ) // enabled by default
2228  {
2229  if( layer == F_Cu )
2230  pad->SetLayerSet( pad->GetLayerSet().set( F_Paste, false ) );
2231  else if( layer == B_Cu )
2232  pad->SetLayerSet( pad->GetLayerSet().set( B_Paste, false ) );
2233  }
2234 }
2235 
2236 
2237 void EAGLE_PLUGIN::transferPad( const EPAD_COMMON& aEaglePad, PAD* aPad ) const
2238 {
2239  aPad->SetName( FROM_UTF8( aEaglePad.name.c_str() ) );
2240 
2241  // pad's "Position" is not relative to the footprint's,
2242  // whereas Pos0 is relative to the footprint's but is the unrotated coordinate.
2243  wxPoint padPos( kicad_x( aEaglePad.x ), kicad_y( aEaglePad.y ) );
2244  aPad->SetPos0( padPos );
2245 
2246  // Solder mask
2247  const wxSize& padSize( aPad->GetSize() );
2248 
2250  (int)( m_rules->mvStopFrame * std::min( padSize.x, padSize.y ) ),
2251  m_rules->mlMaxStopFrame ) );
2252 
2253  // Solid connection to copper zones
2254  if( aEaglePad.thermals && !*aEaglePad.thermals )
2256 
2257  FOOTPRINT* footprint = aPad->GetParent();
2258  wxCHECK( footprint, /* void */ );
2259  RotatePoint( &padPos, footprint->GetOrientation() );
2260  aPad->SetPosition( padPos + footprint->GetPosition() );
2261 }
2262 
2263 
2265 {
2266  for( auto& t : m_templates )
2267  delete t.second;
2268 
2269  m_templates.clear();
2270 }
2271 
2272 
2273 void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
2274 {
2275  ZONES zones; // per net
2276 
2277  m_xpath->push( "signals.signal", "name" );
2278 
2279  int netCode = 1;
2280 
2281  // Get the first signal and iterate
2282  wxXmlNode* net = aSignals->GetChildren();
2283 
2284  while( net )
2285  {
2286  bool sawPad = false;
2287 
2288  zones.clear();
2289 
2290  const wxString& netName = escapeName( net->GetAttribute( "name" ) );
2291  m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
2292 
2293  m_xpath->Value( netName.c_str() );
2294 
2295  // Get the first net item and iterate
2296  wxXmlNode* netItem = net->GetChildren();
2297 
2298  // (contactref | polygon | wire | via)*
2299  while( netItem )
2300  {
2301  const wxString& itemName = netItem->GetName();
2302 
2303  if( itemName == "wire" )
2304  {
2305  m_xpath->push( "wire" );
2306 
2307  EWIRE w( netItem );
2308  PCB_LAYER_ID layer = kicad_layer( w.layer );
2309 
2310  if( IsCopperLayer( layer ) )
2311  {
2312  wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
2313  double angle = 0.0;
2314  double end_angle = 0.0;
2315  double radius = 0.0;
2316  double delta_angle = 0.0;
2317  wxPoint center;
2318 
2319  int width = w.width.ToPcbUnits();
2320  if( width < m_min_trace )
2321  m_min_trace = width;
2322 
2323  if( w.curve )
2324  {
2325  center = ConvertArcCenter(
2326  wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ),
2327  wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ),
2328  *w.curve );
2329 
2330  angle = DEG2RAD( *w.curve );
2331 
2332  end_angle = atan2( kicad_y( w.y2 ) - center.y,
2333  kicad_x( w.x2 ) - center.x );
2334 
2335  radius = sqrt( pow( center.x - kicad_x( w.x1 ), 2 ) +
2336  pow( center.y - kicad_y( w.y1 ), 2 ) );
2337 
2338  int segs = GetArcToSegmentCount( KiROUND( radius ), ARC_HIGH_DEF, *w.curve );
2339  delta_angle = angle / segs;
2340  }
2341 
2342  while( fabs( angle ) > fabs( delta_angle ) )
2343  {
2344  wxASSERT( radius > 0.0 );
2345  wxPoint end( KiROUND( radius * cos( end_angle + angle ) + center.x ),
2346  KiROUND( radius * sin( end_angle + angle ) + center.y ) );
2347 
2348  TRACK* t = new TRACK( m_board );
2349 
2350  t->SetPosition( start );
2351  t->SetEnd( end );
2352  t->SetWidth( width );
2353  t->SetLayer( layer );
2354  t->SetNetCode( netCode );
2355 
2356  m_board->Add( t );
2357 
2358  start = end;
2359  angle -= delta_angle;
2360  }
2361 
2362  TRACK* t = new TRACK( m_board );
2363 
2364  t->SetPosition( start );
2365  t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
2366  t->SetWidth( width );
2367  t->SetLayer( layer );
2368  t->SetNetCode( netCode );
2369 
2370  m_board->Add( t );
2371  }
2372  else
2373  {
2374  // put non copper wires where the sun don't shine.
2375  }
2376 
2377  m_xpath->pop();
2378  }
2379 
2380  else if( itemName == "via" )
2381  {
2382  m_xpath->push( "via" );
2383  EVIA v( netItem );
2384 
2385  PCB_LAYER_ID layer_front_most = kicad_layer( v.layer_front_most );
2386  PCB_LAYER_ID layer_back_most = kicad_layer( v.layer_back_most );
2387 
2388  if( IsCopperLayer( layer_front_most ) &&
2389  IsCopperLayer( layer_back_most ) )
2390  {
2391  int kidiam;
2392  int drillz = v.drill.ToPcbUnits();
2393  VIA* via = new VIA( m_board );
2394  m_board->Add( via );
2395 
2396  via->SetLayerPair( layer_front_most, layer_back_most );
2397 
2398  if( v.diam )
2399  {
2400  kidiam = v.diam->ToPcbUnits();
2401  via->SetWidth( kidiam );
2402  }
2403  else
2404  {
2405  double annulus = drillz * m_rules->rvViaOuter; // eagle "restring"
2406  annulus = eagleClamp( m_rules->rlMinViaOuter, annulus,
2408  kidiam = KiROUND( drillz + 2 * annulus );
2409  via->SetWidth( kidiam );
2410  }
2411 
2412  via->SetDrill( drillz );
2413 
2414  // make sure the via diameter respects the restring rules
2415 
2416  if( !v.diam || via->GetWidth() <= via->GetDrill() )
2417  {
2418  double annulus = eagleClamp( m_rules->rlMinViaOuter,
2419  (double)( via->GetWidth() / 2 - via->GetDrill() ),
2421  via->SetWidth( drillz + 2 * annulus );
2422  }
2423 
2424  if( kidiam < m_min_via )
2425  m_min_via = kidiam;
2426 
2427  if( drillz < m_min_hole )
2428  m_min_hole = drillz;
2429 
2430  if( ( kidiam - drillz ) / 2 < m_min_annulus )
2431  m_min_annulus = ( kidiam - drillz ) / 2;
2432 
2433  if( layer_front_most == F_Cu && layer_back_most == B_Cu )
2434  via->SetViaType( VIATYPE::THROUGH );
2435  else if( layer_front_most == F_Cu || layer_back_most == B_Cu )
2436  via->SetViaType( VIATYPE::MICROVIA );
2437  else
2439 
2440  wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
2441 
2442  via->SetPosition( pos );
2443  via->SetEnd( pos );
2444 
2445  via->SetNetCode( netCode );
2446  }
2447 
2448  m_xpath->pop();
2449  }
2450 
2451  else if( itemName == "contactref" )
2452  {
2453  m_xpath->push( "contactref" );
2454  // <contactref element="RN1" pad="7"/>
2455 
2456  const wxString& reference = netItem->GetAttribute( "element" );
2457  const wxString& pad = netItem->GetAttribute( "pad" );
2458  wxString key = makeKey( reference, pad ) ;
2459 
2460  m_pads_to_nets[ key ] = ENET( netCode, netName );
2461 
2462  m_xpath->pop();
2463 
2464  sawPad = true;
2465  }
2466 
2467  else if( itemName == "polygon" )
2468  {
2469  m_xpath->push( "polygon" );
2470  auto* zone = loadPolygon( netItem );
2471 
2472  if( zone )
2473  {
2474  zones.push_back( zone );
2475 
2476  if( !zone->GetIsRuleArea() )
2477  zone->SetNetCode( netCode );
2478  }
2479 
2480  m_xpath->pop(); // "polygon"
2481  }
2482 
2483  netItem = netItem->GetNext();
2484  }
2485 
2486  if( zones.size() && !sawPad )
2487  {
2488  // KiCad does not support an unconnected zone with its own non-zero netcode,
2489  // but only when assigned netcode = 0 w/o a name...
2490  for( ZONE* zone : zones )
2491  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2492 
2493  // therefore omit this signal/net.
2494  }
2495  else
2496  netCode++;
2497 
2498  // Get next signal
2499  net = net->GetNext();
2500  }
2501 
2502  m_xpath->pop(); // "signals.signal"
2503 }
2504 
2505 std::map<wxString, PCB_LAYER_ID> EAGLE_PLUGIN::DefaultLayerMappingCallback(
2506  const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
2507 {
2508  std::map<wxString, PCB_LAYER_ID> layer_map;
2509 
2510  for ( const INPUT_LAYER_DESC& layer : aInputLayerDescriptionVector )
2511  {
2512  PCB_LAYER_ID layerId = std::get<0>( defaultKicadLayer( eagle_layer_id( layer.Name ) ) );
2513  layer_map.emplace( layer.Name, layerId );
2514  }
2515 
2516  return layer_map;
2517 }
2518 
2520 {
2521  std::vector<INPUT_LAYER_DESC> inputDescs;
2522 
2523  for ( const std::pair<const int, ELAYER>& layerPair : m_eagleLayers )
2524  {
2525  const ELAYER& eLayer = layerPair.second;
2526 
2527  INPUT_LAYER_DESC layerDesc;
2528  std::tie( layerDesc.AutoMapLayer, layerDesc.PermittedLayers, layerDesc.Required ) =
2529  defaultKicadLayer( eLayer.number );
2530 
2531  if( layerDesc.AutoMapLayer == UNDEFINED_LAYER )
2532  continue; // Ignore unused copper layers
2533 
2534  layerDesc.Name = eLayer.name;
2535 
2536  inputDescs.push_back( layerDesc );
2537  }
2538 
2539  m_layer_map = m_layer_mapping_handler( inputDescs );
2540 }
2541 
2542 PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
2543 {
2544  auto result = m_layer_map.find( eagle_layer_name( aEagleLayer ) );
2545  return result == m_layer_map.end() ? UNDEFINED_LAYER : result->second;
2546 }
2547 
2548 std::tuple<PCB_LAYER_ID, LSET, bool> EAGLE_PLUGIN::defaultKicadLayer( int aEagleLayer ) const
2549 {
2550  // eagle copper layer:
2551  if( aEagleLayer >= 1 && aEagleLayer < int( arrayDim( m_cu_map ) ) )
2552  {
2553  LSET copperLayers;
2554  for( int copperLayer : m_cu_map )
2555  {
2556  if( copperLayer >= 0 )
2557  copperLayers[copperLayer] = true;
2558  }
2559 
2560  return { PCB_LAYER_ID( m_cu_map[aEagleLayer] ), copperLayers, true };
2561  }
2562 
2563  int kiLayer = UNSELECTED_LAYER;
2564  bool required = false;
2565  LSET permittedLayers;
2566 
2567  permittedLayers.set();
2568 
2569  // translate non-copper eagle layer to pcbnew layer
2570  switch( aEagleLayer )
2571  {
2572  // Eagle says "Dimension" layer, but it's for board perimeter
2574  kiLayer = Edge_Cuts;
2575  required = true;
2576  permittedLayers = LSET( 1, Edge_Cuts );
2577  break;
2578 
2579  case EAGLE_LAYER::TPLACE:
2580  kiLayer = F_SilkS;
2581  break;
2582  case EAGLE_LAYER::BPLACE:
2583  kiLayer = B_SilkS;
2584  break;
2585  case EAGLE_LAYER::TNAMES:
2586  kiLayer = F_SilkS;
2587  break;
2588  case EAGLE_LAYER::BNAMES:
2589  kiLayer = B_SilkS;
2590  break;
2591  case EAGLE_LAYER::TVALUES:
2592  kiLayer = F_Fab;
2593  break;
2594  case EAGLE_LAYER::BVALUES:
2595  kiLayer = B_Fab;
2596  break;
2597  case EAGLE_LAYER::TSTOP:
2598  kiLayer = F_Mask;
2599  break;
2600  case EAGLE_LAYER::BSTOP:
2601  kiLayer = B_Mask;
2602  break;
2603  case EAGLE_LAYER::TCREAM:
2604  kiLayer = F_Paste;
2605  break;
2606  case EAGLE_LAYER::BCREAM:
2607  kiLayer = B_Paste;
2608  break;
2609  case EAGLE_LAYER::TFINISH:
2610  kiLayer = F_Mask;
2611  break;
2612  case EAGLE_LAYER::BFINISH:
2613  kiLayer = B_Mask;
2614  break;
2615  case EAGLE_LAYER::TGLUE:
2616  kiLayer = F_Adhes;
2617  break;
2618  case EAGLE_LAYER::BGLUE:
2619  kiLayer = B_Adhes;
2620  break;
2621  case EAGLE_LAYER::DOCUMENT:
2622  kiLayer = Cmts_User;
2623  break;
2625  kiLayer = Cmts_User;
2626  break;
2628  kiLayer = Cmts_User;
2629  break;
2630 
2631  // Packages show the future chip pins on SMD parts using layer 51.
2632  // This is an area slightly smaller than the PAD/SMD copper area.
2633  // Carry those visual aids into the FOOTPRINT on the fabrication layer,
2634  // not silkscreen. This is perhaps not perfect, but there is not a lot
2635  // of other suitable paired layers
2636  case EAGLE_LAYER::TDOCU:
2637  kiLayer = F_Fab;
2638  break;
2639  case EAGLE_LAYER::BDOCU:
2640  kiLayer = B_Fab;
2641  break;
2642 
2643  // these layers are defined as user layers. put them on ECO layers
2645  kiLayer = Eco1_User;
2646  break;
2648  kiLayer = Eco2_User;
2649  break;
2650 
2651  // these will also appear in the ratsnest, so there's no need for a warning
2652  case EAGLE_LAYER::UNROUTED:
2653  kiLayer = Dwgs_User;
2654  break;
2655 
2656  case EAGLE_LAYER::TKEEPOUT:
2657  kiLayer = F_CrtYd;
2658  break;
2659  case EAGLE_LAYER::BKEEPOUT:
2660  kiLayer = B_CrtYd;
2661  break;
2662 
2663  case EAGLE_LAYER::MILLING:
2664  case EAGLE_LAYER::TTEST:
2665  case EAGLE_LAYER::BTEST:
2666  case EAGLE_LAYER::HOLES:
2667  default:
2668  kiLayer = UNSELECTED_LAYER;
2669  break;
2670  }
2671 
2672  return { PCB_LAYER_ID( kiLayer ), permittedLayers, required };
2673 }
2674 
2675 
2676 const wxString& EAGLE_PLUGIN::eagle_layer_name( int aLayer ) const
2677 {
2678  static const wxString unknown( "unknown" );
2679  auto it = m_eagleLayers.find( aLayer );
2680  return it == m_eagleLayers.end() ? unknown : it->second.name;
2681 }
2682 
2683 
2684 int EAGLE_PLUGIN::eagle_layer_id( const wxString& aLayerName ) const
2685 {
2686  static const int unknown = -1;
2687  auto it = m_eagleLayersIds.find( aLayerName );
2688  return it == m_eagleLayersIds.end() ? unknown : it->second;
2689 }
2690 
2691 
2693 {
2694  if( m_props )
2695  {
2696  UTF8 page_width;
2697  UTF8 page_height;
2698 
2699  if( m_props->Value( "page_width", &page_width ) &&
2700  m_props->Value( "page_height", &page_height ) )
2701  {
2703 
2704  int w = atoi( page_width.c_str() );
2705  int h = atoi( page_height.c_str() );
2706 
2707  int desired_x = ( w - bbbox.GetWidth() ) / 2;
2708  int desired_y = ( h - bbbox.GetHeight() ) / 2;
2709 
2710  m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
2711  }
2712  }
2713 }
2714 
2715 
2716 wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
2717 {
2718  // File hasn't been loaded yet.
2719  if( aPath.IsEmpty() )
2720  return wxDateTime::Now();
2721 
2722  wxFileName fn( aPath );
2723 
2724  if( fn.IsFileReadable() )
2725  return fn.GetModificationTime();
2726  else
2727  return wxDateTime( 0.0 );
2728 }
2729 
2730 
2731 void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
2732 {
2733  try
2734  {
2735  wxDateTime modtime = getModificationTime( aLibPath );
2736 
2737  // Fixes assertions in wxWidgets debug builds for the wxDateTime object. Refresh the
2738  // cache if either of the wxDateTime objects are invalid or the last file modification
2739  // time differs from the current file modification time.
2740  bool load = !m_mod_time.IsValid() || !modtime.IsValid() || m_mod_time != modtime;
2741 
2742  if( aLibPath != m_lib_path || load )
2743  {
2744  wxXmlNode* doc;
2745  LOCALE_IO toggle; // toggles on, then off, the C locale.
2746 
2747  deleteTemplates();
2748 
2749  // Set this before completion of loading, since we rely on it for
2750  // text of an exception. Delay setting m_mod_time until after successful load
2751  // however.
2752  m_lib_path = aLibPath;
2753 
2754  // 8 bit "filename" should be encoded according to disk filename encoding,
2755  // (maybe this is current locale, maybe not, its a filesystem issue),
2756  // and is not necessarily utf8.
2757  string filename = (const char*) aLibPath.char_str( wxConvFile );
2758 
2759  // Load the document
2760  wxXmlDocument xmlDocument;
2761  wxFileName fn( filename );
2762 
2763  if( !xmlDocument.Load( fn.GetFullPath() ) )
2764  THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ),
2765  fn.GetFullPath() ) );
2766 
2767  doc = xmlDocument.GetRoot();
2768 
2769  wxXmlNode* drawing = MapChildren( doc )["drawing"];
2770  NODE_MAP drawingChildren = MapChildren( drawing );
2771 
2772  // clear the cu map and then rebuild it.
2773  clear_cu_map();
2774 
2775  m_xpath->push( "eagle.drawing.layers" );
2776  wxXmlNode* layers = drawingChildren["layers"];
2777  loadLayerDefs( layers );
2778  m_xpath->pop();
2779 
2780  m_xpath->push( "eagle.drawing.library" );
2781  wxXmlNode* library = drawingChildren["library"];
2782  loadLibrary( library, NULL );
2783  m_xpath->pop();
2784 
2785  m_mod_time = modtime;
2786  }
2787  }
2788  catch(...){}
2789  // TODO: Handle exceptions
2790  // catch( file_parser_error fpe )
2791  // {
2792  // // for xml_parser_error, what() has the line number in it,
2793  // // but no byte offset. That should be an adequate error message.
2794  // THROW_IO_ERROR( fpe.what() );
2795  // }
2796  //
2797  // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
2798  // // so one catch should be OK for all errors.
2799  // catch( ptree_error pte )
2800  // {
2801  // string errmsg = pte.what();
2802  //
2803  // errmsg += " @\n";
2804  // errmsg += m_xpath->Contents();
2805  //
2806  // THROW_IO_ERROR( errmsg );
2807  // }
2808 }
2809 
2810 
2811 void EAGLE_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
2812  bool aBestEfforts, const PROPERTIES* aProperties )
2813 {
2814  wxString errorMsg;
2815 
2816  init( aProperties );
2817 
2818  try
2819  {
2820  cacheLib( aLibraryPath );
2821  }
2822  catch( const IO_ERROR& ioe )
2823  {
2824  errorMsg = ioe.What();
2825  }
2826 
2827  // Some of the files may have been parsed correctly so we want to add the valid files to
2828  // the library.
2829 
2830  for( FOOTPRINT_MAP::const_iterator it = m_templates.begin(); it != m_templates.end(); ++it )
2831  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
2832 
2833  if( !errorMsg.IsEmpty() && !aBestEfforts )
2834  THROW_IO_ERROR( errorMsg );
2835 }
2836 
2837 
2838 FOOTPRINT* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
2839  const wxString& aFootprintName,
2840  const PROPERTIES* aProperties )
2841 {
2842  init( aProperties );
2843  cacheLib( aLibraryPath );
2844  FOOTPRINT_MAP::const_iterator it = m_templates.find( aFootprintName );
2845 
2846  if( it == m_templates.end() )
2847  return NULL;
2848 
2849  // Return a copy of the template
2850  FOOTPRINT* copy = (FOOTPRINT*) it->second->Duplicate();
2851  copy->SetParent( nullptr );
2852  return copy;
2853 }
2854 
2855 
2856 void EAGLE_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
2857 {
2858  PLUGIN::FootprintLibOptions( aListToAppendTo );
2859 
2860  /*
2861  (*aListToAppendTo)["ignore_duplicates"] = UTF8( _( "Ignore duplicately named footprints within "
2862  "the same Eagle library. "
2863  "Only the first similarly named footprint "
2864  "will be loaded." ) );
2865  */
2866 }
2867 
2868 
2869 /*
2870 void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
2871 {
2872  // Eagle lovers apply here.
2873 }
2874 
2875 
2876 void EAGLE_PLUGIN::FootprintSave( const wxString& aLibraryPath, const FOOTPRINT* aFootprint,
2877  const PROPERTIES* aProperties )
2878 {
2879 }
2880 
2881 
2882 void EAGLE_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName )
2883 {
2884 }
2885 
2886 
2887 void EAGLE_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2888 {
2889 }
2890 
2891 
2892 bool EAGLE_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2893 {
2894 }
2895 
2896 
2897 bool EAGLE_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
2898 {
2899  return true;
2900 }
2901 
2902 */
void SetMirrored(bool isMirrored)
Definition: eda_text.h:194
void SetReference(const wxString &aReference)
Function SetReference.
Definition: footprint.h:450
std::vector< ZONE * > ZONES
Definition: eagle_plugin.h:42
wxString Contents()
return the contents of the XPATH as a single string
Definition: eagle_parser.h:139
Eagle vertex.
Definition: eagle_parser.h:746
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
#define DEFAULT_EDGE_WIDTH
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
int sign(T val)
Definition: util.h:101
void loadAllSections(wxXmlNode *aDocument)
double rlMaxViaOuter
maximum copper annulus on via
Definition: eagle_plugin.h:78
bool mirror
Definition: eagle_parser.h:480
void SetOffset(const wxPoint &aOffset)
Definition: pad.h:242
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:516
Definition: track.h:354
#define DEFAULT_COURTYARD_WIDTH
int kicad_x(const ECOORD &x) const
Definition: eagle_plugin.h:222
void SetHatchThickness(int aThickness)
Definition: zone.h:252
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
void SetEnd0(const wxPoint &aPoint)
Definition: fp_shape.h:108
bool IsMirrored() const
Definition: eda_text.h:195
opt_int rank
Definition: eagle_parser.h:779
void packageHole(FOOTPRINT *aFootprint, wxXmlNode *aTree, bool aCenter) const
Function packageHole @parameter aFootprint - The KiCad footprint to which to assign the hole @paramet...
void clear_cu_map()
static T eagleClamp(T aMin, T aValue, T aMax)
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:109
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:205
void SetDoNotAllowTracks(bool aEnable)
Definition: zone.h:757
int eagle_layer_id(const wxString &aLayerName) const
Get Eagle leayer number by its name.
PCB_LAYER_ID kicad_layer(int aLayer) const
Convert an Eagle layer to a KiCad layer.
SHAPE_POLY_SET & GetPolyShape()
Definition: pcb_shape.h:259
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
void FootprintLibOptions(PROPERTIES *aProperties) const override
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
opt_ecoord diam
Definition: eagle_parser.h:562
virtual void SetStart(const wxPoint &aPoint)
Definition: dimension.cpp:296
void SetPosition(const wxPoint &aPoint) override
Definition: track.h:423
int psTop
Shape of the top pads.
Definition: eagle_plugin.h:62
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Definition: board_item.h:206
void SetEnd(const wxPoint &aEnd)
Definition: track.h:112
void clear()
Definition: eagle_parser.h:122
std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
Default callback - just returns the automapped layers.
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition: zone.h:613
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aHatchStyle, int aHatchPitch, bool aRebuildHatch)
Function SetBorderDisplayStyle sets all hatch parameters for the zone.
Definition: zone.cpp:892
const wxString GetValue() const
Function GetValue.
Definition: footprint.h:465
int GetX() const
Definition: eda_rect.h:111
ERULES * m_rules
Eagle design rules.
Definition: eagle_plugin.h:191
const EDA_RECT GetBoardEdgesBoundingBox() const
Returns the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition: board.h:777
void SetTextAngle(double aAngle) override
Definition: pcb_text.cpp:101
void SetFilled(bool aFlag)
Definition: pcb_shape.h:94
void SetTextAngle(double aAngle) override
Definition: fp_text.cpp:69
ECOORD drill
< inclusive
Definition: eagle_parser.h:561
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:243
SHAPE_POLY_SET * Outline()
Definition: zone.h:318
void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
Definition: dimension.cpp:212
ECOORD y
Definition: eagle_parser.h:749
void push(const char *aPathSegment, const char *aAttribute="")
Definition: eagle_parser.h:117
Eagle element element.
Definition: eagle_parser.h:797
XPATH keeps track of what we are working on within a PTREE.
Definition: eagle_parser.h:112
ECOORD x2
Definition: eagle_parser.h:587
static const int max_priority
Definition: eagle_parser.h:768
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
double rlMaxPadTop
maximum copper annulus on through hole pads
Definition: eagle_plugin.h:74
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:253
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:56
void SetVisible(bool aVisible)
Definition: eda_text.h:191
int GetWidth() const
Definition: eda_rect.h:119
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: pad.h:126
int mlMinStopFrame
solder mask, minimum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:57
opt_double ratio
Definition: eagle_parser.h:653
int number
Definition: eagle_parser.h:815
double GetOrientation() const
Definition: footprint.h:204
double GetTextAngle() const
Definition: eda_text.h:180
void SetCopperLayerCount(int aCount)
Definition: board.cpp:431
#define DEFAULT_LINE_WIDTH
bool SetNetCode(int aNetCode, bool aNoAssert)
Sets net using a net code.
opt_erot rot
Definition: eagle_parser.h:807
static int parseEagle(const wxString &aDistance)
Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
int srMinRoundness
corner rounding radius, minimum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:67
ECOORD width
Definition: eagle_parser.h:505
opt_bool thermals
Definition: eagle_parser.h:778
usual segment : line with rounded ends
Definition: board_item.h:52
std::map< wxString, int > m_eagleLayersIds
Eagle layer ids stored by layer name.
Definition: eagle_plugin.h:188
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
Definition: string.cpp:741
opt_bool smashed
Definition: eagle_parser.h:806
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...
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:58
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:559
void parse(wxXmlNode *aRules)
wxString name
Definition: eagle_parser.h:682
Arcs (with rounded ends)
Definition: board_item.h:54
NET_MAP::const_iterator NET_MAP_CITER
Definition: eagle_plugin.h:44
PAD_SHAPE_T GetShape() const
Definition: pad.h:159
void init(const PROPERTIES *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
void SetUnits(EDA_UNITS aUnits)
Definition: dimension.cpp:144
opt_erot rot
Definition: eagle_parser.h:590
double degrees
Definition: eagle_parser.h:482
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
ECOORD width
Definition: eagle_parser.h:759
virtual void FootprintLibOptions(PROPERTIES *aListToAppendTo) const
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
Definition: plugin.cpp:141
void SetSize(const wxSize &aSize)
Definition: pad.h:225
Eagle SMD pad.
Definition: eagle_parser.h:715
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:380
ECOORD y
Definition: eagle_parser.h:573
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
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:209
double rvViaOuter
copper annulus is this percent of via hole
Definition: eagle_plugin.h:76
int GetTextThickness(PCB_LAYER_ID aLayer) const
Function GetTextThickness Returns the default text thickness from the layer class for the given layer...
ECOORD y
Definition: eagle_parser.h:804
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
Eagle hole element.
Definition: eagle_parser.h:786
XML_PARSER_ERROR implements a simple wrapper around runtime_error to isolate the errors thrown by the...
Definition: eagle_parser.h:70
void SetPriority(unsigned aPriority)
Function SetPriority.
Definition: zone.h:118
Eagle text element.
Definition: eagle_parser.h:645
const wxString & eagle_layer_name(int aLayer) const
Get Eagle layer name by its number.
FOOTPRINT_MAP m_templates
is part of a FOOTPRINT factory that operates using copy construction.
Definition: eagle_plugin.h:199
Describes an imported layer and how it could be mapped to KiCad Layers.
void loadLayerDefs(wxXmlNode *aLayers)
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition: zone.h:180
opt_erot rot
Definition: eagle_parser.h:611
NODE_MAP MapChildren(wxXmlNode *aCurrentNode)
Function MapChildren provides an easy access to the children of an XML node via their names.
opt_bool thermals
Definition: eagle_parser.h:686
ECOORD width
Definition: eagle_parser.h:575
ECOORD x
Definition: eagle_parser.h:572
XPATH * m_xpath
keeps track of what we are working on within XML document during a Load().
Definition: eagle_plugin.h:192
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:184
virtual void RegisterLayerMappingCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
int m_cu_map[17]
map eagle to kicad, cu layers only.
Definition: eagle_plugin.h:186
PADS & Pads()
Definition: footprint.h:182
void SetWidth(int aWidth)
Definition: track.h:109
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:480
const char * c_str() const
Definition: utf8.h:107
OPTIONAL_XML_ATTRIBUTE< wxString > opt_wxString
Definition: eagle_parser.h:373
int layer_back_most
< extent
Definition: eagle_parser.h:560
void SetIsRuleArea(bool aEnable)
Definition: zone.h:754
FP_TEXT & Reference()
Definition: footprint.h:481
opt_int align
Definition: eagle_parser.h:620
void packageWire(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
ECOORD dy
Definition: eagle_parser.h:718
void Rotate(const wxPoint &aCentre, double aAngle) override
Function Rotate Move the outlines.
Definition: zone.cpp:703
int GetLineThickness(PCB_LAYER_ID aLayer) const
Function GetLineThickness Returns the default graphic segment thickness from the layer class for the ...
opt_ecoord isolate
Definition: eagle_parser.h:776
wxString name
Definition: eagle_parser.h:604
void SetLocalSolderMaskMargin(int aMargin)
Definition: pad.h:361
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:553
void SetClosed(bool aClosed)
Function SetClosed()
const wxSize & GetDrillSize() const
Definition: pad.h:236
wxString name
Definition: eagle_parser.h:816
PCB_LAYER_ID
A quick note on layer IDs:
ECOORD y1
Definition: eagle_parser.h:502
static wxString makeKey(const wxString &aFirst, const wxString &aSecond)
Assemble a two part key as a simple concatenation of aFirst and aSecond parts, using a separator.
void SetHeight(int aHeight)
Sets the distance from the feature points to the crossbar line.
Definition: dimension.cpp:529
wxString value
Definition: eagle_parser.h:802
LSET is a set of PCB_LAYER_IDs.
#define DEFAULT_SILK_LINE_WIDTH
void NewHole()
Function NewHole creates a new hole on the zone; i.e., a new contour on the zone's outline.
Definition: zone.h:597
void cacheLib(const wxString &aLibraryPath)
This PLUGIN only caches one footprint library, this determines which one.
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
pads are covered by copper
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
Definition: eagle_plugin.h:204
ECOORD x
Definition: eagle_parser.h:788
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
LAYER_NUM layer
Definition: eagle_parser.h:506
#define NULL
void SetHatchGap(int aStep)
Definition: zone.h:255
void SetPos0(const wxPoint &aPos)
Definition: pad.h:219
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:128
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
std::map< int, ELAYER > m_eagleLayers
Eagle layer data stored by layer number.
Definition: eagle_plugin.h:187
opt_ecoord y
Definition: eagle_parser.h:607
int layer
Definition: eagle_parser.h:589
Eagle thru hole pad.
Definition: eagle_parser.h:693
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
Definition: zone.cpp:1090
opt_ecoord spacing
Definition: eagle_parser.h:761
void SetDoNotAllowPads(bool aEnable)
Definition: zone.h:758
void SetClearance(int aClearance)
Definition: netclass.h:160
wxString name
Definition: eagle_parser.h:799
SHAPE_POLY_SET.
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: track.h:492
ECOORD y1
Definition: eagle_parser.h:586
void SetOrientation(double aNewAngle)
Definition: footprint.cpp:1444
const wxSize & GetTextSize() const
Definition: eda_text.h:245
void packageRectangle(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate an edge of the footprint.
Definition: fp_shape.cpp:271
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:209
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
void packagePad(FOOTPRINT *aFootprint, wxXmlNode *aTree)
void SetDrillSize(const wxSize &aSize)
Definition: pad.h:235
void SetAngle(double aAngle, bool aUpdateEnd=true) override
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: fp_shape.cpp:141
Eagle circle.
Definition: eagle_parser.h:570
const wxSize & GetSize() const
Definition: pad.h:226
PCB_TEXT & Text()
Definition: dimension.h:209
NETCLASS handles a collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:49
wxPoint GetCenter() const override
Function GetCenter()
Definition: pcb_shape.cpp:343
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
Definition: footprint.cpp:1279
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:348
ECOORD dx
Definition: eagle_parser.h:717
wxString m_lib_path
Definition: eagle_plugin.h:212
bool Required
Should we require the layer to be assigned?
ECOORD x
Definition: eagle_parser.h:648
FOOTPRINT * makeFootprint(wxXmlNode *aPackage, const wxString &aPkgName)
Function makeFootprint creates a FOOTPRINT from an Eagle package.
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
void SetDoNotAllowVias(bool aEnable)
Definition: zone.h:756
LAYER_MAPPING_HANDLER m_layer_mapping_handler
Callback to get layer mapping.
BOARD_ITEM * Duplicate() const override
Function Duplicate creates a copy of a BOARD_ITEM.
Definition: footprint.cpp:1482
a few functions useful in geometry calculations.
subset of eagle.drawing.board.designrules in the XML document
Definition: eagle_plugin.h:48
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.
Definition: track.cpp:401
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: pad.h:345
void orientFootprintAndText(FOOTPRINT *aFootprint, const EELEMENT &e, const EATTR *aNameAttr, const EATTR *aValueAttr)
void SetZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:456
const wxString GetReference() const
Function GetReference.
Definition: footprint.h:440
void SetFileName(const wxString &aFileName)
Definition: board.h:276
ECOORD size
Definition: eagle_parser.h:650
void SetMinThickness(int aMinThickness)
Definition: zone.h:243
int layer
Definition: eagle_parser.h:719
static wxDateTime getModificationTime(const wxString &aPath)
get a file's or dir's modification time.
opt_wxString value
Definition: eagle_parser.h:605
void SetValue(const wxString &aValue)
Function SetValue.
Definition: footprint.h:474
double mdWireWire
wire to wire spacing I presume.
Definition: eagle_plugin.h:79
wxString text
Definition: eagle_parser.h:647
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: pad.h:150
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
int m_min_trace
smallest trace we find on Load(), in BIU.
Definition: eagle_plugin.h:207
ECOORD x
Definition: eagle_parser.h:803
opt_int roundness
Definition: eagle_parser.h:720
int NewOutline()
Creates a new empty polygon in the set and returns its index
void SetRoundRectRadiusRatio(double aRadiusScale)
has meaning only for rounded rect pads Set the ratio between the smaller X or Y size and the rounded ...
Definition: pcbnew/pad.cpp:236
int m_hole_count
generates unique footprint names from eagle "hole"s.
Definition: eagle_plugin.h:195
LAYER_NUM layer
Definition: eagle_parser.h:576
Eagle XML rectangle in binary.
Definition: eagle_parser.h:583
double srRoundness
corner rounding ratio for SMD pads (percentage)
Definition: eagle_plugin.h:66
opt_int align
Definition: eagle_parser.h:670
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
void SetStart0(const wxPoint &aPoint)
Definition: fp_shape.h:105
int GetHeight() const
Definition: eda_rect.h:120
Eagle net.
Definition: eagle_parser.h:461
void SetPos0(const wxPoint &aPos)
Definition: fp_text.h:165
int psElongationLong
percent over 100%.
Definition: eagle_plugin.h:50
int psFirst
Shape of the first pads.
Definition: eagle_plugin.h:64
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:750
int LAYER_NUM
This can be replaced with int and removed.
void loadLibraries(wxXmlNode *aLibs)
void loadPlain(wxXmlNode *aPlain)
std::tuple< PCB_LAYER_ID, LSET, bool > defaultKicadLayer(int aEagleLayer) const
Get default KiCAD layer corresponding to an Eagle layer of the board, a set of sensible layer mapping...
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
FOOTPRINT * GetParent() const
void SetChamferPositions(int aPositions)
has meaning only for chamfered rect pads set the position of the chamfers for orientation 0.
Definition: pad.h:518
void transferPad(const EPAD_COMMON &aEaglePad, PAD *aPad) const
Handles common pad properties
ECOORD y2
Definition: eagle_parser.h:504
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
Definition: board.cpp:240
Use thermal relief for pads.
EATTR parses an Eagle "attribute" XML element.
Definition: eagle_parser.h:602
opt_ecoord x
Definition: eagle_parser.h:606
Eagle via.
Definition: eagle_parser.h:555
static wxString interpret_text(const wxString &aText)
interpret special characters in Eagle text and converts them to KiCAD notation
FOOTPRINT * 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...
std::vector< ELAYER > ELAYERS
Definition: eagle_plugin.h:183
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
ECOORD x1
Definition: eagle_parser.h:585
wxSize kicad_fontz(const ECOORD &d, int aTextThickness) const
create a font size (fontz) from an eagle font size scalar and KiCAD font thickness
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:240
opt_wxString dimensionType
Definition: eagle_parser.h:638
int mlMinCreamFrame
solder paste mask, minimum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:59
bool AppendCorner(wxPoint aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition: zone.cpp:832
void SetLayerSet(LSET aLayers) override
Definition: pad.h:344
#define ZONE_THICKNESS_MIN_VALUE_MIL
Definition: zones.h:32
opt_erot rot
Definition: eagle_parser.h:654
int netcode
Definition: eagle_parser.h:463
wxPoint GetPosition() const override
Definition: zone.cpp:209
void loadElements(wxXmlNode *aElements)
int GetWidth() const
Definition: track.h:110
const char * name
Definition: DXF_plotter.cpp:59
ECOORD x
Definition: eagle_parser.h:748
std::map< wxString, PCB_LAYER_ID > m_layer_map
Map of Eagle layers to KiCAD layers.
Definition: eagle_plugin.h:189
opt_ecoord diameter
Definition: eagle_parser.h:696
void packageCircle(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
double DEG2RAD(double deg)
Definition: trigo.h:217
void SetLocalSolderPasteMargin(int aMargin)
Definition: pad.h:368
void SetStart(const wxPoint &aStart)
Definition: pcb_shape.h:147
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:186
void packagePolygon(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
void packageText(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:208
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
Structure holding common properties for through-hole and SMD pads.
Definition: eagle_parser.h:680
void SetDoNotAllowCopperPour(bool aEnable)
Definition: zone.h:755
wxString Name
Imported layer name as displayed in original application.
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
void SetPrecision(int aPrecision)
Definition: dimension.h:170
void SetPosition(const wxPoint &aPos) override
Definition: track.h:105
wxPoint ConvertArcCenter(const wxPoint &aStart, const wxPoint &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void SetPosition(const wxPoint &aPos) override
Definition: pad.h:161
#define DIMENSION_PRECISION
ECOORD radius
Definition: eagle_parser.h:574
ELAYERS::const_iterator EITER
Definition: eagle_plugin.h:184
int GetCopperLayerCount() const
Definition: board.cpp:425
wxDateTime m_mod_time
Definition: eagle_plugin.h:213
void packageSMD(FOOTPRINT *aFootprint, wxXmlNode *aTree) const
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: track.h:485
NETCLASS * GetDefault() const
Function GetDefault.
void loadLibrary(wxXmlNode *aLib, const wxString *aLibName)
Function loadLibrary loads the Eagle "library" XML element, which can occur either under a "libraries...
opt_double ratio
Definition: eagle_parser.h:610
opt_erot rot
Definition: eagle_parser.h:684
void SetWidth(int aWidth)
Definition: pcb_shape.h:117
void SetLocalCoord()
Set relative coordinates.
Definition: fp_text.cpp:217
double mvStopFrame
solder mask, expressed as percentage of the smaller pad/via dimension
Definition: eagle_plugin.h:55
#define IU_PER_MILS
Definition: plotter.cpp:137
int GetY() const
Definition: eda_rect.h:112
ECOORD y
Definition: eagle_parser.h:558
void SetHatchOrientation(double aStep)
Definition: zone.h:258
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
int m_min_annulus
smallest via annulus we find on Load(), in BIU.
Definition: eagle_plugin.h:210
NET_MAP m_pads_to_nets
net list
Definition: eagle_plugin.h:197
static void setKeepoutSettingsToZone(ZONE *aZone, LAYER_NUM aLayer)
wxPoint GetPosition() const override
Definition: footprint.h:200
opt_bool first
Definition: eagle_parser.h:708
Eagle wire.
Definition: eagle_parser.h:499
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
ECOORD x
Definition: eagle_parser.h:557
ring
Definition: board_item.h:55
void SetThermalReliefGap(int aThermalReliefGap)
Definition: zone.h:183
void orientFPText(FOOTPRINT *aFootprint, const EELEMENT &e, FP_TEXT *aFPText, const EATTR *aAttr)
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:46
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
Definition: zone.cpp:235
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:164
opt_int shape
Definition: eagle_parser.h:707
int m_min_hole
smallest diameter hole we find on Load(), in BIU.
Definition: eagle_plugin.h:208
Eagle dimension element.
Definition: eagle_parser.h:628
double rvPadTop
top pad size as percent of drill size
Definition: eagle_plugin.h:70
wxString package
Definition: eagle_parser.h:801
void deleteTemplates()
Deletes the footprint templates list
void SetLocalClearance(int aClearance)
Definition: zone.h:156
bool spin
Definition: eagle_parser.h:481
void AddPolygon(std::vector< wxPoint > &aPolygon)
add a polygon to the zone outline if the zone outline is empty, this is the main outline else it is a...
Definition: zone.cpp:815
ECOORD y2
Definition: eagle_parser.h:588
ECOORD y
Definition: eagle_parser.h:649
Eagle polygon, without vertices which are parsed as needed.
Definition: eagle_parser.h:757
opt_int display
Definition: eagle_parser.h:619
void pop()
Definition: eagle_parser.h:124
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Definition: footprint.cpp:442
void SetLineThickness(int aWidth)
Definition: dimension.h:188
void loadDesignRules(wxXmlNode *aDesignRules)
ECOORD drill
Definition: eagle_parser.h:695
Definition: pad.h:59
void SetPosition(const wxPoint &aPos) override
Definition: footprint.cpp:1344
ECOORD y
Definition: eagle_parser.h:789
void SetChamferRectRatio(double aChamferScale)
has meaning only for chamfered rect pads Set the ratio between the smaller X or Y size and chamfered ...
Definition: pcbnew/pad.cpp:244
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
For better understanding of the points that make a dimension:
Definition: dimension.h:329
opt_bool stop
Definition: eagle_parser.h:685
const wxString PluginName() const override
Function PluginName returns a brief hard coded name for this PLUGIN.
int layer
Definition: eagle_parser.h:651
ECOORD x1
Definition: eagle_parser.h:501
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:444
void SetViaType(VIATYPE aViaType)
Definition: track.h:385
wxString library
Definition: eagle_parser.h:800
int psBottom
Shape of the bottom pads.
Definition: eagle_plugin.h:63
static constexpr int Millimeter2iu(double mm)
double rlMinPadTop
minimum copper annulus on through hole pads
Definition: eagle_plugin.h:73
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Definition: board_item.h:185
virtual void SetEnd(const wxPoint &aPoint)
Definition: dimension.cpp:303
double rlMinViaOuter
minimum copper annulus on via
Definition: eagle_plugin.h:77
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:478
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
ECOORD drill
Definition: eagle_parser.h:790
just inflate the polygon. Acute angles create spikes
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
void SetPolyPoints(const std::vector< wxPoint > &aPoints)
Definition: pcb_shape.cpp:1043
bool Value(const char *aName, UTF8 *aFetchedValue=NULL) const
Function Value fetches a property by aName and returns true if that property was found,...
Definition: properties.cpp:24
int mlMaxCreamFrame
solder paste mask, maximum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:60
FP_ZONE is a specialization of ZONE for use in footprints.
Definition: zone.h:957
wxSize GetTextSize(PCB_LAYER_ID aLayer) const
Function GetTextSize Returns the default text size from the layer class for the given layer.
int srMaxRoundness
corner rounding radius, maximum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:68
opt_bool active
Definition: eagle_parser.h:820
void mapEagleLayersToKicad()
Generate mapping between Eagle na KiCAD layers.
ECOORD x2
Definition: eagle_parser.h:503
void loadSignals(wxXmlNode *aSignals)
int kicad_y(const ECOORD &y) const
Convert an Eagle distance to a KiCad distance.
Definition: eagle_plugin.h:221
Definition: track.h:83
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: pcbnew/pad.cpp:531
int ToPcbUnits() const
Definition: eagle_parser.h:438
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:48
void SetEnd(const wxPoint &aEnd)
Definition: pcb_shape.h:158
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.
opt_ecoord size
Definition: eagle_parser.h:608
ZONE * loadPolygon(wxXmlNode *aPolyNode)
Loads a copper or keepout polygon and adds it to the board.
void SetDoNotAllowFootprints(bool aEnable)
Definition: zone.h:759
void Value(const char *aValue)
modify the last path node's value
Definition: eagle_parser.h:127
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
int layer_front_most
Definition: eagle_parser.h:559
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int mlMaxStopFrame
solder mask, maximum size (Eagle mils, here nanometers)
Definition: eagle_plugin.h:58
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition: zone.h:193
double mvCreamFrame
solderpaste mask, expressed as percentage of the smaller pad/via dimension
Definition: eagle_plugin.h:56
opt_bool cream
Definition: eagle_parser.h:721
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: pcbnew/pad.cpp:512