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