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