KiCad PCB EDA Suite
eagle_parser.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-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * Copyright (C) 2017 CERN.
7  *
8  * @author Alejandro GarcĂ­a Montoro <alejandro.garciamontoro@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
29 
30 #include <richio.h>
31 
32 #include <functional>
33 #include <sstream>
34 #include <iomanip>
35 #include <cstdio>
36 
38 
39 
40 wxString escapeName( const wxString& aNetName )
41 {
42  wxString ret( aNetName );
43 
44  ret.Replace( "~", "~~" );
45  ret.Replace( "!", "~" );
46 
47  return ret;
48 }
49 
50 
51 template<> template<>
53 {
54  m_isAvailable = !aData.IsEmpty();
55 
56  if( m_isAvailable )
57  Set( aData );
58 }
59 
60 
61 ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
62 {
63  // This array is used to adjust the fraction part value basing on the number of digits
64  // in the fraction.
65  constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
66  constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
67 
68  int integer, fraction, pre_fraction, post_fraction;
69 
70  // The following check is needed to handle correctly negative fractions where the integer
71  // part == 0.
72  bool negative = ( aValue[0] == '-' );
73 
74  // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3
75  // digits.
76  int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction,
77  &post_fraction );
78 
79  if( ret == 0 )
80  throw XML_PARSER_ERROR( "Invalid coordinate" );
81 
82  // process the integer part
83  value = ConvertToNm( integer, aUnit );
84 
85  // process the fraction part
86  if( ret == 2 )
87  {
88  int digits = post_fraction - pre_fraction;
89 
90  // adjust the number of digits if necessary as we cannot handle anything smaller than
91  // nanometers (rounding).
92  if( (unsigned) digits > DIVIDERS_MAX_IDX )
93  {
94  int diff = digits - DIVIDERS_MAX_IDX;
95  digits = DIVIDERS_MAX_IDX;
96  fraction /= DIVIDERS[diff];
97  }
98 
99  int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
100 
101  // keep the sign in mind
102  value = negative ? value - frac_value : value + frac_value;
103  }
104 }
105 
106 
107 long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
108 {
109  long long int ret;
110 
111  switch( aUnit )
112  {
113  default:
114  case EU_NM: ret = aValue; break;
115  case EU_MM: ret = (long long) aValue * 1000000; break;
116  case EU_INCH: ret = (long long) aValue * 25400000; break;
117  case EU_MIL: ret = (long long) aValue * 25400; break;
118  }
119 
120  if( ( ret > 0 ) != ( aValue > 0 ) )
121  wxLogError( _( "Invalid size %lld: too large" ), aValue );
122 
123  return ret;
124 }
125 
126 
127 // Template specializations below parse wxString to the used types:
128 // - wxString (preferred)
129 // - string
130 // - double
131 // - int
132 // - bool
133 // - EROT
134 // - ECOORD
135 
136 template <>
137 wxString Convert<wxString>( const wxString& aValue )
138 {
139  return aValue;
140 }
141 
142 
143 template <>
144 std::string Convert<std::string>( const wxString& aValue )
145 {
146  return std::string( aValue.ToUTF8() );
147 }
148 
149 
150 template <>
151 double Convert<double>( const wxString& aValue )
152 {
153  double value;
154 
155  if( aValue.ToCDouble( &value ) )
156  return value;
157  else
158  throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
159  aValue.ToStdString() + "'." );
160 }
161 
162 
163 template <>
164 int Convert<int>( const wxString& aValue )
165 {
166  if( aValue.IsEmpty() )
167  throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
168 
169  return wxAtoi( aValue );
170 }
171 
172 
173 template <>
174 bool Convert<bool>( const wxString& aValue )
175 {
176  if( aValue != "yes" && aValue != "no" )
177  throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
178  aValue.ToStdString() +
179  "', is neither 'yes' nor 'no'." );
180 
181  return aValue == "yes";
182 }
183 
184 
187 template<>
188 EROT Convert<EROT>( const wxString& aRot )
189 {
190  EROT value;
191 
192  value.spin = aRot.find( 'S' ) != aRot.npos;
193  value.mirror = aRot.find( 'M' ) != aRot.npos;
194  value.degrees = strtod( aRot.c_str()
195  + 1 // skip leading 'R'
196  + int( value.spin ) // skip optional leading 'S'
197  + int( value.mirror ), // skip optional leading 'M'
198  NULL );
199 
200  return value;
201 }
202 
203 
204 template<>
205 ECOORD Convert<ECOORD>( const wxString& aCoord )
206 {
207  // Eagle uses millimeters as the default unit
208  return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
209 }
210 
211 
220 template<typename T>
221 T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
222 {
223  wxString value;
224 
225  if( aNode->GetAttribute( aAttribute, &value ) )
226  return Convert<T>( value );
227  else
228  throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
229 }
230 
231 
240 template<typename T>
241 OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
242 {
243  return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
244 }
245 
246 
247 NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
248 {
249  // Map node_name -> node_pointer
250  NODE_MAP nodesMap;
251 
252  // Loop through all children mapping them in nodesMap
253  if( aCurrentNode )
254  aCurrentNode = aCurrentNode->GetChildren();
255 
256  while( aCurrentNode )
257  {
258  // Create a new pair in the map
259  // key: current node name
260  // value: current node pointer
261  nodesMap[aCurrentNode->GetName()] = aCurrentNode;
262 
263  // Get next child
264  aCurrentNode = aCurrentNode->GetNext();
265  }
266 
267  return nodesMap;
268 }
269 
270 
271 wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle )
272 {
273  // Eagle give us start and end.
274  // S_ARC wants start to give the center, and end to give the start.
275  double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
276  wxPoint mid = ( aStart + aEnd ) / 2;
277 
278  double dlen = sqrt( dx*dx + dy*dy );
279 
280  if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
281  {
283  wxString::Format( _( "Invalid Arc with radius %f and angle %f" ), dlen, aAngle ) );
284  }
285 
286  double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
287 
288  wxPoint center(
289  mid.x + dist * ( dy / dlen ),
290  mid.y - dist * ( dx / dlen )
291  );
292 
293  return center;
294 }
295 
296 
297 static int parseAlignment( const wxString& aAlignment )
298 {
299  // (bottom-left | bottom-center | bottom-right | center-left |
300  // center | center-right | top-left | top-center | top-right)
301  if( aAlignment == "center" )
302  return ETEXT::CENTER;
303  else if( aAlignment == "center-right" )
304  return ETEXT::CENTER_RIGHT;
305  else if( aAlignment == "top-left" )
306  return ETEXT::TOP_LEFT;
307  else if( aAlignment == "top-center" )
308  return ETEXT::TOP_CENTER;
309  else if( aAlignment == "top-right" )
310  return ETEXT::TOP_RIGHT;
311  else if( aAlignment == "bottom-left" )
312  return ETEXT::BOTTOM_LEFT;
313  else if( aAlignment == "bottom-center" )
314  return ETEXT::BOTTOM_CENTER;
315  else if( aAlignment == "bottom-right" )
316  return ETEXT::BOTTOM_RIGHT;
317  else if( aAlignment == "center-left" )
318  return ETEXT::CENTER_LEFT;
319 
320  return DEFAULT_ALIGNMENT;
321 }
322 
323 
324 EWIRE::EWIRE( wxXmlNode* aWire )
325 {
326  /*
327  <!ELEMENT wire EMPTY>
328  <!ATTLIST wire
329  x1 %Coord; #REQUIRED
330  y1 %Coord; #REQUIRED
331  x2 %Coord; #REQUIRED
332  y2 %Coord; #REQUIRED
333  width %Dimension; #REQUIRED
334  layer %Layer; #REQUIRED
335  extent %Extent; #IMPLIED -- only applicable for airwires --
336  style %WireStyle; "continuous"
337  curve %WireCurve; "0"
338  cap %WireCap; "round" -- only applicable if 'curve' is not zero --
339  >
340  */
341 
342  x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
343  y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
344  x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
345  y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
346  width = parseRequiredAttribute<ECOORD>( aWire, "width" );
347  layer = parseRequiredAttribute<int>( aWire, "layer" );
348  curve = parseOptionalAttribute<double>( aWire, "curve" );
349 
350  opt_wxString s = parseOptionalAttribute<wxString>( aWire, "style" );
351 
352  if( s == "continuous" )
354  else if( s == "longdash" )
356  else if( s == "shortdash" )
358  else if( s == "dashdot" )
360 
361  s = parseOptionalAttribute<wxString>( aWire, "cap" );
362 
363  if( s == "round" )
364  cap = EWIRE::ROUND;
365  else if( s == "flat" )
366  cap = EWIRE::FLAT;
367 }
368 
369 
370 EJUNCTION::EJUNCTION( wxXmlNode* aJunction )
371 {
372  /*
373  <!ELEMENT junction EMPTY>
374  <!ATTLIST junction
375  x %Coord; #REQUIRED
376  y %Coord; #REQUIRED
377  >
378  */
379 
380  x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
381  y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
382 }
383 
384 
385 ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName )
386 {
387  /*
388  <!ELEMENT label EMPTY>
389  <!ATTLIST label
390  x %Coord; #REQUIRED
391  y %Coord; #REQUIRED
392  size %Dimension; #REQUIRED
393  layer %Layer; #REQUIRED
394  font %TextFont; "proportional"
395  ratio %Int; "8"
396  rot %Rotation; "R0"
397  xref %Bool; "no"
398  >
399  */
400 
401  x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
402  y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
403  size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
404  layer = parseRequiredAttribute<int>( aLabel, "layer" );
405  rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
406  xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
407  netname = aNetName;
408 }
409 
410 
411 EVIA::EVIA( wxXmlNode* aVia )
412 {
413  /*
414  <!ELEMENT via EMPTY>
415  <!ATTLIST via
416  x %Coord; #REQUIRED
417  y %Coord; #REQUIRED
418  extent %Extent; #REQUIRED
419  drill %Dimension; #REQUIRED
420  diameter %Dimension; "0"
421  shape %ViaShape; "round"
422  alwaysstop %Bool; "no"
423  >
424  */
425 
426  x = parseRequiredAttribute<ECOORD>( aVia, "x" );
427  y = parseRequiredAttribute<ECOORD>( aVia, "y" );
428 
429  wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
430  sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
431 
432  drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
433  diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
434  shape = parseOptionalAttribute<wxString>( aVia, "shape" );
435 }
436 
437 
438 ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
439 {
440  /*
441  <!ELEMENT circle EMPTY>
442  <!ATTLIST circle
443  x %Coord; #REQUIRED
444  y %Coord; #REQUIRED
445  radius %Coord; #REQUIRED
446  width %Dimension; #REQUIRED
447  layer %Layer; #REQUIRED
448  >
449  */
450 
451  x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
452  y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
453  radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
454  width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
455  layer = parseRequiredAttribute<int>( aCircle, "layer" );
456 }
457 
458 
459 ERECT::ERECT( wxXmlNode* aRect )
460 {
461  /*
462  <!ELEMENT rectangle EMPTY>
463  <!ATTLIST rectangle
464  x1 %Coord; #REQUIRED
465  y1 %Coord; #REQUIRED
466  x2 %Coord; #REQUIRED
467  y2 %Coord; #REQUIRED
468  layer %Layer; #REQUIRED
469  rot %Rotation; "R0"
470  >
471  */
472 
473  x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
474  y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
475  x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
476  y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
477  layer = parseRequiredAttribute<int>( aRect, "layer" );
478  rot = parseOptionalAttribute<EROT>( aRect, "rot" );
479 }
480 
481 
482 EATTR::EATTR( wxXmlNode* aTree )
483 {
484  /*
485  <!ELEMENT attribute EMPTY>
486  <!ATTLIST attribute
487  name %String; #REQUIRED
488  value %String; #IMPLIED
489  x %Coord; #IMPLIED
490  y %Coord; #IMPLIED
491  size %Dimension; #IMPLIED
492  layer %Layer; #IMPLIED
493  font %TextFont; #IMPLIED
494  ratio %Int; #IMPLIED
495  rot %Rotation; "R0"
496  display %AttributeDisplay; "value" -- only in <element> or <instance> context --
497  constant %Bool; "no" -- only in <device> context --
498  >
499  */
500 
501  name = parseRequiredAttribute<wxString>( aTree, "name" );
502  value = parseOptionalAttribute<wxString>( aTree, "value" );
503 
504  x = parseOptionalAttribute<ECOORD>( aTree, "x" );
505  y = parseOptionalAttribute<ECOORD>( aTree, "y" );
506  size = parseOptionalAttribute<ECOORD>( aTree, "size" );
507 
508  layer = parseOptionalAttribute<int>( aTree, "layer" );
509  ratio = parseOptionalAttribute<double>( aTree, "ratio" );
510  rot = parseOptionalAttribute<EROT>( aTree, "rot" );
511 
512  opt_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
513 
514  // (off | value | name | both)
515  if( stemp == "off" )
517  else if( stemp == "name" )
519  else if( stemp == "both" )
521  else // "value" is the default
523 
524  stemp = parseOptionalAttribute<wxString>( aTree, "align" );
525 
526  align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
527 }
528 
529 
530 EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
531 {
532  /*
533  <!ELEMENT dimension EMPTY>
534  <!ATTLIST dimension
535  x1 %Coord; #REQUIRED
536  y1 %Coord; #REQUIRED
537  x2 %Coord; #REQUIRED
538  y2 %Coord; #REQUIRED
539  x3 %Coord; #REQUIRED
540  y3 %Coord; #REQUIRED
541  layer %Layer; #REQUIRED
542  dtype %DimensionType; "parallel"
543  >
544  */
545 
546  x1 = parseRequiredAttribute<ECOORD>( aDimension, "x1" );
547  y1 = parseRequiredAttribute<ECOORD>( aDimension, "y1" );
548  x2 = parseRequiredAttribute<ECOORD>( aDimension, "x2" );
549  y2 = parseRequiredAttribute<ECOORD>( aDimension, "y2" );
550  x3 = parseRequiredAttribute<ECOORD>( aDimension, "x3" );
551  y3 = parseRequiredAttribute<ECOORD>( aDimension, "y3" );
552  layer = parseRequiredAttribute<int>( aDimension, "layer" );
553  dimensionType = parseOptionalAttribute<wxString>( aDimension, "dtype" );
554 }
555 
556 
557 ETEXT::ETEXT( wxXmlNode* aText )
558 {
559  /*
560  <!ELEMENT text (#PCDATA)>
561  <!ATTLIST text
562  x %Coord; #REQUIRED
563  y %Coord; #REQUIRED
564  size %Dimension; #REQUIRED
565  layer %Layer; #REQUIRED
566  font %TextFont; "proportional"
567  ratio %Int; "8"
568  rot %Rotation; "R0"
569  align %Align; "bottom-left"
570  >
571  */
572 
573  text = aText->GetNodeContent();
574  x = parseRequiredAttribute<ECOORD>( aText, "x" );
575  y = parseRequiredAttribute<ECOORD>( aText, "y" );
576  size = parseRequiredAttribute<ECOORD>( aText, "size" );
577  layer = parseRequiredAttribute<int>( aText, "layer" );
578 
579  font = parseOptionalAttribute<wxString>( aText, "font" );
580  ratio = parseOptionalAttribute<double>( aText, "ratio" );
581  rot = parseOptionalAttribute<EROT>( aText, "rot" );
582 
583  opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
584 
585  align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
586 }
587 
588 
589 wxSize ETEXT::ConvertSize() const
590 {
591  wxSize textsize;
592 
593  if( font )
594  {
595  const wxString& fontName = font.CGet();
596 
597  if( fontName == "vector" )
598  {
599  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
600  }
601  else if( fontName == "fixed" )
602  {
603  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
604  }
605  else
606  {
607  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
608  }
609  }
610  else
611  {
612  textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() );
613  }
614 
615  return textsize;
616 }
617 
618 
619 EFRAME::EFRAME( wxXmlNode* aFrameNode )
620 {
621  /*
622  * <!ELEMENT frame EMPTY>
623  * <!ATTLIST frame
624  * x1 %Coord; #REQUIRED
625  * y1 %Coord; #REQUIRED
626  * x2 %Coord; #REQUIRED
627  * y2 %Coord; #REQUIRED
628  * columns %Int; #REQUIRED
629  * rows %Int; #REQUIRED
630  * layer %Layer; #REQUIRED
631  * border-left %Bool; "yes"
632  * border-top %Bool; "yes"
633  * border-right %Bool; "yes"
634  * border-bottom %Bool; "yes"
635  * >
636  */
637  border_left = true;
638  border_top = true;
639  border_right = true;
640  border_bottom = true;
641 
642  x1 = parseRequiredAttribute<ECOORD>( aFrameNode, "x1" );
643  y1 = parseRequiredAttribute<ECOORD>( aFrameNode, "y1" );
644  x2 = parseRequiredAttribute<ECOORD>( aFrameNode, "x2" );
645  y2 = parseRequiredAttribute<ECOORD>( aFrameNode, "y2" );
646  columns = parseRequiredAttribute<int>( aFrameNode, "columns" );
647  rows = parseRequiredAttribute<int>( aFrameNode, "rows" );
648  layer = parseRequiredAttribute<int>( aFrameNode, "layer" );
649  border_left = parseOptionalAttribute<bool>( aFrameNode, "border-left" );
650  border_top = parseOptionalAttribute<bool>( aFrameNode, "border-top" );
651  border_right = parseOptionalAttribute<bool>( aFrameNode, "border-right" );
652  border_bottom = parseOptionalAttribute<bool>( aFrameNode, "border-bottom" );
653 }
654 
655 
656 EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
657 {
658  // #REQUIRED says DTD, throw exception if not found
659  name = parseRequiredAttribute<wxString>( aPad, "name" );
660  x = parseRequiredAttribute<ECOORD>( aPad, "x" );
661  y = parseRequiredAttribute<ECOORD>( aPad, "y" );
662  rot = parseOptionalAttribute<EROT>( aPad, "rot" );
663  stop = parseOptionalAttribute<bool>( aPad, "stop" );
664  thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
665 }
666 
667 
668 EPAD::EPAD( wxXmlNode* aPad )
669  : EPAD_COMMON( aPad )
670 {
671  /*
672  <!ELEMENT pad EMPTY>
673  <!ATTLIST pad
674  name %String; #REQUIRED
675  x %Coord; #REQUIRED
676  y %Coord; #REQUIRED
677  drill %Dimension; #REQUIRED
678  diameter %Dimension; "0"
679  shape %PadShape; "round"
680  rot %Rotation; "R0"
681  stop %Bool; "yes"
682  thermals %Bool; "yes"
683  first %Bool; "no"
684  >
685  */
686 
687  // #REQUIRED says DTD, throw exception if not found
688  drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
689 
690  // Optional attributes
691  diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
692 
693  opt_wxString s = parseOptionalAttribute<wxString>( aPad, "shape" );
694 
695  // (square | round | octagon | long | offset)
696  if( s == "square" )
698  else if( s == "round" )
699  shape = EPAD::ROUND;
700  else if( s == "octagon" )
702  else if( s == "long" )
703  shape = EPAD::LONG;
704  else if( s == "offset" )
706 
707  first = parseOptionalAttribute<bool>( aPad, "first" );
708 }
709 
710 
711 ESMD::ESMD( wxXmlNode* aSMD )
712  : EPAD_COMMON( aSMD )
713 {
714  /*
715  <!ATTLIST smd
716  name %String; #REQUIRED
717  x %Coord; #REQUIRED
718  y %Coord; #REQUIRED
719  dx %Dimension; #REQUIRED
720  dy %Dimension; #REQUIRED
721  layer %Layer; #REQUIRED
722  roundness %Int; "0"
723  rot %Rotation; "R0"
724  stop %Bool; "yes"
725  thermals %Bool; "yes"
726  cream %Bool; "yes"
727  >
728  */
729 
730  // DTD #REQUIRED, throw exception if not found
731  dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
732  dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
733  layer = parseRequiredAttribute<int>( aSMD, "layer" );
734 
735  roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
736  cream = parseOptionalAttribute<bool>( aSMD, "cream" );
737 }
738 
739 
740 EPIN::EPIN( wxXmlNode* aPin )
741 {
742  /*
743  <!ELEMENT pin EMPTY>
744  <!ATTLIST pin
745  name %String; #REQUIRED
746  x %Coord; #REQUIRED
747  y %Coord; #REQUIRED
748  visible %PinVisible; "both"
749  length %PinLength; "long"
750  direction %PinDirection; "io"
751  function %PinFunction; "none"
752  swaplevel %Int; "0"
753  rot %Rotation; "R0"
754  >
755  */
756 
757  // DTD #REQUIRED, throw exception if not found
758  name = parseRequiredAttribute<wxString>( aPin, "name" );
759  x = parseRequiredAttribute<ECOORD>( aPin, "x" );
760  y = parseRequiredAttribute<ECOORD>( aPin, "y" );
761 
762  visible = parseOptionalAttribute<wxString>( aPin, "visible" );
763  length = parseOptionalAttribute<wxString>( aPin, "length" );
764  direction = parseOptionalAttribute<wxString>( aPin, "direction" );
765  function = parseOptionalAttribute<wxString>( aPin, "function" );
766  swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
767  rot = parseOptionalAttribute<EROT>( aPin, "rot" );
768 }
769 
770 
771 EVERTEX::EVERTEX( wxXmlNode* aVertex )
772 {
773  /*
774  <!ELEMENT vertex EMPTY>
775  <!ATTLIST vertex
776  x %Coord; #REQUIRED
777  y %Coord; #REQUIRED
778  curve %WireCurve; "0" -- the curvature from this vertex to the next one --
779  >
780  */
781 
782  x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
783  y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
784  curve = parseOptionalAttribute<double>( aVertex, "curve" );
785 }
786 
787 
788 EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
789 {
790  /*
791  <!ATTLIST polygon
792  width %Dimension; #REQUIRED
793  layer %Layer; #REQUIRED
794  spacing %Dimension; #IMPLIED
795  pour %PolygonPour; "solid"
796  isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
797  orphans %Bool; "no" -- only in <signal> context --
798  thermals %Bool; "yes" -- only in <signal> context --
799  rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in
800  <package> context --
801  >
802  */
803 
804  width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
805  layer = parseRequiredAttribute<int>( aPolygon, "layer" );
806 
807  spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
808  isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
809  opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
810 
811  // default pour to solid fill
813 
814  // (solid | hatch | cutout)
815  if( s == "hatch" )
817  else if( s == "cutout" )
819 
820  orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
821  thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
822  rank = parseOptionalAttribute<int>( aPolygon, "rank" );
823 }
824 
825 
826 EHOLE::EHOLE( wxXmlNode* aHole )
827 {
828  /*
829  <!ELEMENT hole EMPTY>
830  <!ATTLIST hole
831  x %Coord; #REQUIRED
832  y %Coord; #REQUIRED
833  drill %Dimension; #REQUIRED
834  >
835  */
836 
837  // #REQUIRED:
838  x = parseRequiredAttribute<ECOORD>( aHole, "x" );
839  y = parseRequiredAttribute<ECOORD>( aHole, "y" );
840  drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
841 }
842 
843 
844 EELEMENT::EELEMENT( wxXmlNode* aElement )
845 {
846  /*
847  <!ELEMENT element (attribute*, variant*)>
848  <!ATTLIST element
849  name %String; #REQUIRED
850  library %String; #REQUIRED
851  package %String; #REQUIRED
852  value %String; #REQUIRED
853  x %Coord; #REQUIRED
854  y %Coord; #REQUIRED
855  locked %Bool; "no"
856  smashed %Bool; "no"
857  rot %Rotation; "R0"
858  >
859  */
860 
861  // #REQUIRED
862  name = parseRequiredAttribute<wxString>( aElement, "name" );
863  library = parseRequiredAttribute<wxString>( aElement, "library" );
864  value = parseRequiredAttribute<wxString>( aElement, "value" );
865  std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
866  ReplaceIllegalFileNameChars( &p, '_' );
867  package = wxString::FromUTF8( p.c_str() );
868 
869  x = parseRequiredAttribute<ECOORD>( aElement, "x" );
870  y = parseRequiredAttribute<ECOORD>( aElement, "y" );
871 
872  // optional
873  locked = parseOptionalAttribute<bool>( aElement, "locked" );
874  smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
875  rot = parseOptionalAttribute<EROT>( aElement, "rot" );
876 }
877 
878 
879 ELAYER::ELAYER( wxXmlNode* aLayer )
880 {
881  /*
882  <!ELEMENT layer EMPTY>
883  <!ATTLIST layer
884  number %Layer; #REQUIRED
885  name %String; #REQUIRED
886  color %Int; #REQUIRED
887  fill %Int; #REQUIRED
888  visible %Bool; "yes"
889  active %Bool; "yes"
890  >
891  */
892 
893  number = parseRequiredAttribute<int>( aLayer, "number" );
894  name = parseRequiredAttribute<wxString>( aLayer, "name" );
895  color = parseRequiredAttribute<int>( aLayer, "color" );
896  fill = 1; // Temporary value.
897  visible = parseOptionalAttribute<bool>( aLayer, "visible" );
898  active = parseOptionalAttribute<bool>( aLayer, "active" );
899 }
900 
901 
902 EPART::EPART( wxXmlNode* aPart )
903 {
904  /*
905  * <!ELEMENT part (attribute*, variant*)>
906  * <!ATTLIST part
907  * name %String; #REQUIRED
908  * library %String; #REQUIRED
909  * deviceset %String; #REQUIRED
910  * device %String; #REQUIRED
911  * technology %String; ""
912  * value %String; #IMPLIED
913  * >
914  */
915  // #REQUIRED
916  name = parseRequiredAttribute<wxString>( aPart, "name" );
917  library = parseRequiredAttribute<wxString>( aPart, "library" );
918  deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
919  device = parseRequiredAttribute<wxString>( aPart, "device" );
920  technology = parseOptionalAttribute<wxString>( aPart, "technology" );
921  value = parseOptionalAttribute<wxString>( aPart, "value" );
922 
923  for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
924  {
925 
926  if( child->GetName() == "attribute" )
927  {
928  std::string aname, avalue;
929  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
930  {
931 
932  if( x->GetName() == "name" )
933  aname = x->GetValue();
934  else if( x->GetName() == "value" )
935  avalue = x->GetValue();
936  }
937 
938  if( aname.size() && avalue.size() )
939  attribute[aname] = avalue;
940  }
941  else if( child->GetName() == "variant" )
942  {
943  std::string aname, avalue;
944  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
945  {
946 
947  if( x->GetName() == "name" )
948  aname = x->GetValue();
949  else if( x->GetName() == "value" )
950  avalue = x->GetValue();
951  }
952 
953  if( aname.size() && avalue.size() )
954  variant[aname] = avalue;
955  }
956  }
957 }
958 
959 
960 EINSTANCE::EINSTANCE( wxXmlNode* aInstance )
961 {
962  /*
963  * <!ELEMENT instance (attribute)*>
964  * <!ATTLIST instance
965  * part %String; #REQUIRED
966  * gate %String; #REQUIRED
967  * x %Coord; #REQUIRED
968  * y %Coord; #REQUIRED
969  * smashed %Bool; "no"
970  * rot %Rotation; "R0"
971  * >
972  */
973  part = parseRequiredAttribute<wxString>( aInstance, "part" );
974  gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
975 
976  x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
977  y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
978 
979  // optional
980  smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
981  rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
982 }
983 
984 
985 EGATE::EGATE( wxXmlNode* aGate )
986 {
987  /*
988  * <!ELEMENT gate EMPTY>
989  * <!ATTLIST gate
990  * name %String; #REQUIRED
991  * symbol %String; #REQUIRED
992  * x %Coord; #REQUIRED
993  * y %Coord; #REQUIRED
994  * addlevel %GateAddLevel; "next"
995  * swaplevel %Int; "0"
996  * >
997  */
998 
999  name = parseRequiredAttribute<wxString>( aGate, "name" );
1000  symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
1001 
1002  x = parseRequiredAttribute<ECOORD>( aGate, "x" );
1003  y = parseRequiredAttribute<ECOORD>( aGate, "y" );
1004 
1005  opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
1006 
1007  // (off | value | name | both)
1008  if( stemp == "must" )
1009  addlevel = EGATE::MUST;
1010  else if( stemp == "can" )
1011  addlevel = EGATE::CAN;
1012  else if( stemp == "next" )
1013  addlevel = EGATE::NEXT;
1014  else if( stemp == "request" )
1015  addlevel = EGATE::REQUEST;
1016  else if( stemp == "always" )
1017  addlevel = EGATE::ALWAYS;
1018  else
1019  addlevel = EGATE::NEXT;
1020 }
1021 
1022 
1023 ECONNECT::ECONNECT( wxXmlNode* aConnect )
1024 {
1025  /*
1026  * <!ELEMENT connect EMPTY>
1027  * <!ATTLIST connect
1028  * gate %String; #REQUIRED
1029  * pin %String; #REQUIRED
1030  * pad %String; #REQUIRED
1031  * route %ContactRoute; "all"
1032  * >
1033  */
1034  gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
1035  pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
1036  pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
1037 }
1038 
1039 
1040 EDEVICE::EDEVICE( wxXmlNode* aDevice )
1041 {
1042  /*
1043  <!ELEMENT device (connects?, technologies?)>
1044  <!ATTLIST device
1045  name %String; ""
1046  package %String; #IMPLIED
1047  >
1048  */
1049  name = parseRequiredAttribute<wxString>( aDevice, "name" );
1050  opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1051 
1052  if( pack )
1053  {
1054  std::string p( pack->c_str() );
1055  ReplaceIllegalFileNameChars( &p, '_' );
1056  package.Set( wxString::FromUTF8( p.c_str() ) );
1057  }
1058 
1059  NODE_MAP aDeviceChildren = MapChildren( aDevice );
1060  wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, "connects" );
1061 
1062  while( connectNode )
1063  {
1064  connects.emplace_back( connectNode );
1065  connectNode = connectNode->GetNext();
1066  }
1067 }
1068 
1069 
1070 EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
1071 {
1072  /*
1073  <!ELEMENT deviceset (description?, gates, devices)>
1074  <!ATTLIST deviceset
1075  name %String; #REQUIRED
1076  prefix %String; ""
1077  uservalue %Bool; "no"
1078  >
1079  */
1080 
1081  name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
1082  prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1083  uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1084 
1085  /* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp
1086  *
1087  //TODO: description
1088 
1089  NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet);
1090  wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, "device");
1091 
1092  while(deviceNode){
1093  devices.push_back(EDEVICE(deviceNode));
1094  deviceNode->GetNext();
1095  }
1096 
1097  wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, "gate");
1098 
1099  while(gateNode){
1100  gates.push_back(EGATE(gateNode));
1101  gateNode->GetNext();
1102  }
1103  */
1104 
1105 }
void Set(const wxString &aString)
Attempt to convert a string to the base type.
Definition: eagle_parser.h:283
Eagle rotation.
Definition: eagle_parser.h:472
ECOORD Convert< ECOORD >(const wxString &aCoord)
bool mirror
Definition: eagle_parser.h:474
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:510
ECOORD x
Definition: eagle_parser.h:746
opt_int rank
Definition: eagle_parser.h:794
int ToSchUnits() const
Definition: eagle_parser.h:431
ECOORD x
Definition: eagle_parser.h:536
opt_ecoord diam
Definition: eagle_parser.h:556
opt_wxString direction
Definition: eagle_parser.h:751
opt_erot rot
Definition: eagle_parser.h:540
opt_int cap
Definition: eagle_parser.h:517
opt_bool border_bottom
Definition: eagle_parser.h:688
const T & CGet() const
Return a constant reference to the value of the attribute assuming it is available.
Definition: eagle_parser.h:305
ECOORD drill
< inclusive
Definition: eagle_parser.h:555
opt_wxString shape
Definition: eagle_parser.h:557
ECOORD y
Definition: eagle_parser.h:764
opt_bool border_left
Definition: eagle_parser.h:685
int color
Definition: DXF_plotter.cpp:60
ECOORD x2
Definition: eagle_parser.h:581
opt_double ratio
Definition: eagle_parser.h:647
OPTIONAL_XML_ATTRIBUTE()
Construct a default OPTIONAL_XML_ATTRIBUTE, whose data is not available.
Definition: eagle_parser.h:203
opt_wxString xref
Definition: eagle_parser.h:541
opt_erot rot
Definition: eagle_parser.h:822
ECOORD width
Definition: eagle_parser.h:499
opt_bool thermals
Definition: eagle_parser.h:793
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
Definition: string.cpp:746
opt_bool smashed
Definition: eagle_parser.h:821
wxString name
Definition: eagle_parser.h:697
EROT Convert< EROT >(const wxString &aRot)
parse an Eagle XML "rot" field.
opt_erot rot
Definition: eagle_parser.h:584
double degrees
Definition: eagle_parser.h:476
ECOORD width
Definition: eagle_parser.h:774
ECOORD y
Definition: eagle_parser.h:567
ECOORD x1
Definition: eagle_parser.h:678
T parseRequiredAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Parse aAttribute of the XML node aNode.
ECOORD y1
Definition: eagle_parser.h:679
ECOORD y
Definition: eagle_parser.h:819
ECOORD y
Definition: eagle_parser.h:527
Implement a simple wrapper around runtime_error to isolate the errors thrown by the Eagle XML parser.
Definition: eagle_parser.h:70
wxString netname
Definition: eagle_parser.h:542
int layer
Definition: eagle_parser.h:684
opt_erot rot
Definition: eagle_parser.h:605
NODE_MAP MapChildren(wxXmlNode *aCurrentNode)
Provide an easy access to the children of an XML node via their names.
ELAYER(wxXmlNode *aLayer)
opt_bool thermals
Definition: eagle_parser.h:701
ECOORD width
Definition: eagle_parser.h:569
opt_int swaplevel
Definition: eagle_parser.h:753
ECOORD x
Definition: eagle_parser.h:566
EPIN(wxXmlNode *aPin)
nanometers
Definition: eagle_parser.h:387
EDEVICE(wxXmlNode *aDevice)
ECOORD y
Definition: eagle_parser.h:537
EPART(wxXmlNode *aPart)
int layer_back_most
< extent
Definition: eagle_parser.h:554
ECONNECT(wxXmlNode *aConnect)
EVERTEX(wxXmlNode *aVertex)
opt_int align
Definition: eagle_parser.h:614
ECOORD dy
Definition: eagle_parser.h:733
ESMD(wxXmlNode *aSMD)
opt_ecoord isolate
Definition: eagle_parser.h:791
wxString name
Definition: eagle_parser.h:598
ECOORD y1
Definition: eagle_parser.h:496
EJUNCTION(wxXmlNode *aJunction)
wxString value
Definition: eagle_parser.h:817
wxString escapeName(const wxString &aNetName)
opt_int style
Definition: eagle_parser.h:509
wxString Convert< wxString >(const wxString &aValue)
ECOORD x
Definition: eagle_parser.h:803
EDIMENSION(wxXmlNode *aDimension)
LAYER_NUM layer
Definition: eagle_parser.h:500
#define NULL
opt_ecoord y
Definition: eagle_parser.h:601
ELABEL(wxXmlNode *aLabel, const wxString &aNetName)
int layer
Definition: eagle_parser.h:583
opt_ecoord spacing
Definition: eagle_parser.h:776
wxString name
Definition: eagle_parser.h:814
ECOORD size
Definition: eagle_parser.h:538
EWIRE(wxXmlNode *aWire)
EHOLE(wxXmlNode *aHole)
ECOORD y1
Definition: eagle_parser.h:580
ECOORD x2
Definition: eagle_parser.h:680
ECOORD dx
Definition: eagle_parser.h:732
EPOLYGON(wxXmlNode *aPolygon)
ECOORD x
Definition: eagle_parser.h:642
int columns
Definition: eagle_parser.h:682
bool m_isAvailable
A boolean indicating if the data is present or not.
Definition: eagle_parser.h:194
wxSize ConvertSize() const
Calculate text size based on font type and size.
Model an optional XML attribute.
Definition: eagle_parser.h:190
ECOORD size
Definition: eagle_parser.h:644
EDEVICE_SET(wxXmlNode *aDeviceSet)
int layer
Definition: eagle_parser.h:734
opt_wxString value
Definition: eagle_parser.h:599
wxString text
Definition: eagle_parser.h:641
EVIA(wxXmlNode *aVia)
EGATE(wxXmlNode *aGate)
ECOORD x
Definition: eagle_parser.h:818
opt_int roundness
Definition: eagle_parser.h:735
mils/thous
Definition: eagle_parser.h:390
LAYER_NUM layer
Definition: eagle_parser.h:570
opt_int align
Definition: eagle_parser.h:664
ECOORD y2
Definition: eagle_parser.h:681
static int parseAlignment(const wxString &aAlignment)
opt_double curve
range is -359.9..359.9
Definition: eagle_parser.h:765
millimeters
Definition: eagle_parser.h:388
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
int rows
Definition: eagle_parser.h:683
int Convert< int >(const wxString &aValue)
ECOORD y2
Definition: eagle_parser.h:498
OPTIONAL_XML_ATTRIBUTE< T > parseOptionalAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Parse option aAttribute of the XML node aNode.
opt_bool border_right
Definition: eagle_parser.h:687
opt_ecoord x
Definition: eagle_parser.h:600
opt_int layer
Definition: eagle_parser.h:603
ECOORD x1
Definition: eagle_parser.h:579
opt_wxString dimensionType
Definition: eagle_parser.h:632
EPAD_COMMON(wxXmlNode *aPad)
opt_erot rot
Definition: eagle_parser.h:648
opt_wxString font
Definition: eagle_parser.h:646
ECOORD x
Definition: eagle_parser.h:763
constexpr auto DEFAULT_ALIGNMENT
opt_ecoord diameter
Definition: eagle_parser.h:711
double DEG2RAD(double deg)
Definition: trigo.h:231
Structure holding common properties for through-hole and SMD pads.
Definition: eagle_parser.h:695
#define _(s)
Definition: 3d_actions.cpp:33
wxPoint ConvertArcCenter(const wxPoint &aStart, const wxPoint &aEnd, double aAngle)
ECOORD radius
Definition: eagle_parser.h:568
EFRAME(wxXmlNode *aFrameNode)
opt_double ratio
Definition: eagle_parser.h:604
opt_erot rot
Definition: eagle_parser.h:699
ECOORD y
Definition: eagle_parser.h:552
ECOORD x
Definition: eagle_parser.h:526
LAYER_NUM layer
Definition: eagle_parser.h:539
opt_bool first
Definition: eagle_parser.h:723
opt_bool orphans
Definition: eagle_parser.h:792
ECOORD x
Definition: eagle_parser.h:551
ECOORD y
Definition: eagle_parser.h:747
ERECT(wxXmlNode *aRect)
wxString name
Definition: eagle_parser.h:745
opt_int shape
Definition: eagle_parser.h:722
wxString package
Definition: eagle_parser.h:816
double Convert< double >(const wxString &aValue)
bool spin
Definition: eagle_parser.h:475
ECOORD y2
Definition: eagle_parser.h:582
ECOORD y
Definition: eagle_parser.h:643
opt_int display
Definition: eagle_parser.h:613
ECOORD drill
Definition: eagle_parser.h:710
ECOORD y
Definition: eagle_parser.h:804
opt_bool stop
Definition: eagle_parser.h:700
int layer
Definition: eagle_parser.h:645
ECOORD x1
Definition: eagle_parser.h:495
wxString library
Definition: eagle_parser.h:815
ECIRCLE(wxXmlNode *aCircle)
opt_wxString visible
Definition: eagle_parser.h:749
ECOORD drill
Definition: eagle_parser.h:805
ETEXT(wxXmlNode *aText)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
EELEMENT(wxXmlNode *aElement)
opt_wxString length
Definition: eagle_parser.h:750
static long long int ConvertToNm(int aValue, enum EAGLE_UNIT aUnit)
opt_bool border_top
Definition: eagle_parser.h:686
ECOORD x2
Definition: eagle_parser.h:497
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:49
long long int value
Unit used for the value field.
Definition: eagle_parser.h:394
static wxXmlNode * getChildrenNodes(NODE_MAP &aMap, const wxString &aName)
Definition: eagle_parser.h:59
EINSTANCE(wxXmlNode *aInstance)
opt_ecoord size
Definition: eagle_parser.h:602
EPAD(wxXmlNode *aPad)
int layer_front_most
Definition: eagle_parser.h:553
opt_bool cream
Definition: eagle_parser.h:736
opt_bool locked
Definition: eagle_parser.h:820
bool Convert< bool >(const wxString &aValue)
opt_erot rot
Definition: eagle_parser.h:754