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