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