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