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