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-2020 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 
28 
29 #include <richio.h>
30 
31 #include <functional>
32 #include <sstream>
33 #include <iomanip>
34 #include <cstdio>
35 
37 
38 
39 wxString escapeName( const wxString& aNetName )
40 {
41  wxString ret( aNetName );
42 
43  ret.Replace( "~", "~~" );
44  ret.Replace( "!", "~" );
45 
46  return ret;
47 }
48 
49 
50 template<> template<>
52 {
53  m_isAvailable = !aData.IsEmpty();
54 
55  if( m_isAvailable )
56  Set( aData );
57 }
58 
59 
60 ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
61 {
62  // this array is used to adjust the fraction part value basing on the number of digits in the fraction
63  constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
64  constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
65 
66  int integer, fraction, pre_fraction, post_fraction;
67 
68  // the following check is needed to handle correctly negative fractions where the integer part == 0
69  bool negative = ( aValue[0] == '-' );
70 
71  // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 digits
72  int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction );
73 
74  if( ret == 0 )
75  throw XML_PARSER_ERROR( "Invalid coordinate" );
76 
77  // process the integer part
78  value = ConvertToNm( integer, aUnit );
79 
80  // process the fraction part
81  if( ret == 2 )
82  {
83  int digits = post_fraction - pre_fraction;
84 
85  // adjust the number of digits if necessary as we cannot handle anything smaller than nanometers (rounding)
86  if( (unsigned) digits > DIVIDERS_MAX_IDX )
87  {
88  int diff = digits - DIVIDERS_MAX_IDX;
89  digits = DIVIDERS_MAX_IDX;
90  fraction /= DIVIDERS[diff];
91  }
92 
93  int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
94 
95  // keep the sign in mind
96  value = negative ? value - frac_value : value + frac_value;
97  }
98 }
99 
100 
101 long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
102 {
103  long long int ret;
104 
105  switch( aUnit )
106  {
107  default:
108  case EU_NM: ret = aValue; break;
109  case EU_MM: ret = (long long) aValue * 1000000; break;
110  case EU_INCH: ret = (long long) aValue * 25400000; break;
111  case EU_MIL: ret = (long long) aValue * 25400; break;
112  }
113 
114  if( ( ret > 0 ) != ( aValue > 0 ) )
115  wxLogError( _( "Invalid size %lld: too large" ), aValue );
116 
117  return ret;
118 }
119 
120 
121 // Template specializations below parse wxString to the used types:
122 // - wxString (preferred)
123 // - string
124 // - double
125 // - int
126 // - bool
127 // - EROT
128 // - ECOORD
129 
130 template <>
131 wxString Convert<wxString>( const wxString& aValue )
132 {
133  return aValue;
134 }
135 
136 
137 template <>
138 std::string Convert<std::string>( const wxString& aValue )
139 {
140  return std::string( aValue.ToUTF8() );
141 }
142 
143 
144 template <>
145 double Convert<double>( const wxString& aValue )
146 {
147  double value;
148 
149  if( aValue.ToCDouble( &value ) )
150  return value;
151  else
152  throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
153  aValue.ToStdString() + "'." );
154 }
155 
156 
157 template <>
158 int Convert<int>( const wxString& aValue )
159 {
160  if( aValue.IsEmpty() )
161  throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
162 
163  return wxAtoi( aValue );
164 }
165 
166 
167 template <>
168 bool Convert<bool>( const wxString& aValue )
169 {
170  if( aValue != "yes" && aValue != "no" )
171  throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
172  aValue.ToStdString() +
173  "', is neither 'yes' nor 'no'." );
174 
175  return aValue == "yes";
176 }
177 
178 
181 template<>
182 EROT Convert<EROT>( const wxString& aRot )
183 {
184  EROT value;
185 
186  value.spin = aRot.find( 'S' ) != aRot.npos;
187  value.mirror = aRot.find( 'M' ) != aRot.npos;
188  value.degrees = strtod( aRot.c_str()
189  + 1 // skip leading 'R'
190  + int( value.spin ) // skip optional leading 'S'
191  + int( value.mirror ), // skip optional leading 'M'
192  NULL );
193 
194  return value;
195 }
196 
197 
198 template<>
199 ECOORD Convert<ECOORD>( const wxString& aCoord )
200 {
201  // Eagle uses millimeters as the default unit
202  return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
203 }
204 
205 
214 template<typename T>
215 T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
216 {
217  wxString value;
218 
219  if( aNode->GetAttribute( aAttribute, &value ) )
220  return Convert<T>( value );
221  else
222  throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
223 }
224 
225 
234 template<typename T>
235 OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
236 {
237  return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
238 }
239 
240 
241 NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
242 {
243  // Map node_name -> node_pointer
244  NODE_MAP nodesMap;
245 
246  // Loop through all children mapping them in nodesMap
247  if( aCurrentNode )
248  aCurrentNode = aCurrentNode->GetChildren();
249 
250  while( aCurrentNode )
251  {
252  // Create a new pair in the map
253  // key: current node name
254  // value: current node pointer
255  nodesMap[aCurrentNode->GetName()] = aCurrentNode;
256 
257  // Get next child
258  aCurrentNode = aCurrentNode->GetNext();
259  }
260 
261  return nodesMap;
262 }
263 
264 
265 wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle )
266 {
267  // Eagle give us start and end.
268  // S_ARC wants start to give the center, and end to give the start.
269  double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
270  wxPoint mid = ( aStart + aEnd ) / 2;
271 
272  double dlen = sqrt( dx*dx + dy*dy );
273 
274  if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
275  {
277  wxString::Format( _( "Invalid Arc with radius %f and angle %f" ), dlen, aAngle ) );
278  }
279 
280  double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
281 
282  wxPoint center(
283  mid.x + dist * ( dy / dlen ),
284  mid.y - dist * ( dx / dlen )
285  );
286 
287  return center;
288 }
289 
290 
291 static int parseAlignment( const wxString& aAlignment )
292 {
293  // (bottom-left | bottom-center | bottom-right | center-left |
294  // center | center-right | top-left | top-center | top-right)
295  if( aAlignment == "center" )
296  return ETEXT::CENTER;
297  else if( aAlignment == "center-right" )
298  return ETEXT::CENTER_RIGHT;
299  else if( aAlignment == "top-left" )
300  return ETEXT::TOP_LEFT;
301  else if( aAlignment == "top-center" )
302  return ETEXT::TOP_CENTER;
303  else if( aAlignment == "top-right" )
304  return ETEXT::TOP_RIGHT;
305  else if( aAlignment == "bottom-left" )
306  return ETEXT::BOTTOM_LEFT;
307  else if( aAlignment == "bottom-center" )
308  return ETEXT::BOTTOM_CENTER;
309  else if( aAlignment == "bottom-right" )
310  return ETEXT::BOTTOM_RIGHT;
311  else if( aAlignment == "center-left" )
312  return ETEXT::CENTER_LEFT;
313 
314  return DEFAULT_ALIGNMENT;
315 }
316 
317 
318 EWIRE::EWIRE( wxXmlNode* aWire )
319 {
320  /*
321  <!ELEMENT wire EMPTY>
322  <!ATTLIST wire
323  x1 %Coord; #REQUIRED
324  y1 %Coord; #REQUIRED
325  x2 %Coord; #REQUIRED
326  y2 %Coord; #REQUIRED
327  width %Dimension; #REQUIRED
328  layer %Layer; #REQUIRED
329  extent %Extent; #IMPLIED -- only applicable for airwires --
330  style %WireStyle; "continuous"
331  curve %WireCurve; "0"
332  cap %WireCap; "round" -- only applicable if 'curve' is not zero --
333  >
334  */
335 
336  x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
337  y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
338  x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
339  y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
340  width = parseRequiredAttribute<ECOORD>( aWire, "width" );
341  layer = parseRequiredAttribute<int>( aWire, "layer" );
342  curve = parseOptionalAttribute<double>( aWire, "curve" );
343 
344  opt_wxString s = parseOptionalAttribute<wxString>( aWire, "style" );
345 
346  if( s == "continuous" )
348  else if( s == "longdash" )
350  else if( s == "shortdash" )
352  else if( s == "dashdot" )
354 
355  s = parseOptionalAttribute<wxString>( aWire, "cap" );
356 
357  if( s == "round" )
358  cap = EWIRE::ROUND;
359  else if( s == "flat" )
360  cap = EWIRE::FLAT;
361 }
362 
363 
364 EJUNCTION::EJUNCTION( wxXmlNode* aJunction )
365 {
366  /*
367  <!ELEMENT junction EMPTY>
368  <!ATTLIST junction
369  x %Coord; #REQUIRED
370  y %Coord; #REQUIRED
371  >
372  */
373 
374  x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
375  y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
376 }
377 
378 
379 ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName )
380 {
381  /*
382  <!ELEMENT label EMPTY>
383  <!ATTLIST label
384  x %Coord; #REQUIRED
385  y %Coord; #REQUIRED
386  size %Dimension; #REQUIRED
387  layer %Layer; #REQUIRED
388  font %TextFont; "proportional"
389  ratio %Int; "8"
390  rot %Rotation; "R0"
391  xref %Bool; "no"
392  >
393  */
394 
395  x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
396  y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
397  size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
398  layer = parseRequiredAttribute<int>( aLabel, "layer" );
399  rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
400  xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
401  netname = aNetName;
402 }
403 
404 
405 EVIA::EVIA( wxXmlNode* aVia )
406 {
407  /*
408  <!ELEMENT via EMPTY>
409  <!ATTLIST via
410  x %Coord; #REQUIRED
411  y %Coord; #REQUIRED
412  extent %Extent; #REQUIRED
413  drill %Dimension; #REQUIRED
414  diameter %Dimension; "0"
415  shape %ViaShape; "round"
416  alwaysstop %Bool; "no"
417  >
418  */
419 
420  x = parseRequiredAttribute<ECOORD>( aVia, "x" );
421  y = parseRequiredAttribute<ECOORD>( aVia, "y" );
422 
423  wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
424  sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
425 
426  drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
427  diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
428  shape = parseOptionalAttribute<wxString>( aVia, "shape" );
429 }
430 
431 
432 ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
433 {
434  /*
435  <!ELEMENT circle EMPTY>
436  <!ATTLIST circle
437  x %Coord; #REQUIRED
438  y %Coord; #REQUIRED
439  radius %Coord; #REQUIRED
440  width %Dimension; #REQUIRED
441  layer %Layer; #REQUIRED
442  >
443  */
444 
445  x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
446  y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
447  radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
448  width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
449  layer = parseRequiredAttribute<int>( aCircle, "layer" );
450 }
451 
452 
453 ERECT::ERECT( wxXmlNode* aRect )
454 {
455  /*
456  <!ELEMENT rectangle EMPTY>
457  <!ATTLIST rectangle
458  x1 %Coord; #REQUIRED
459  y1 %Coord; #REQUIRED
460  x2 %Coord; #REQUIRED
461  y2 %Coord; #REQUIRED
462  layer %Layer; #REQUIRED
463  rot %Rotation; "R0"
464  >
465  */
466 
467  x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
468  y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
469  x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
470  y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
471  layer = parseRequiredAttribute<int>( aRect, "layer" );
472  rot = parseOptionalAttribute<EROT>( aRect, "rot" );
473 }
474 
475 
476 EATTR::EATTR( wxXmlNode* aTree )
477 {
478  /*
479  <!ELEMENT attribute EMPTY>
480  <!ATTLIST attribute
481  name %String; #REQUIRED
482  value %String; #IMPLIED
483  x %Coord; #IMPLIED
484  y %Coord; #IMPLIED
485  size %Dimension; #IMPLIED
486  layer %Layer; #IMPLIED
487  font %TextFont; #IMPLIED
488  ratio %Int; #IMPLIED
489  rot %Rotation; "R0"
490  display %AttributeDisplay; "value" -- only in <element> or <instance> context --
491  constant %Bool; "no" -- only in <device> context --
492  >
493  */
494 
495  name = parseRequiredAttribute<wxString>( aTree, "name" );
496  value = parseOptionalAttribute<wxString>( aTree, "value" );
497 
498  x = parseOptionalAttribute<ECOORD>( aTree, "x" );
499  y = parseOptionalAttribute<ECOORD>( aTree, "y" );
500  size = parseOptionalAttribute<ECOORD>( aTree, "size" );
501 
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  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
602  }
603  }
604  else
605  {
606  textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() );
607  }
608 
609  return textsize;
610 }
611 
612 
613 EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
614 {
615  // #REQUIRED says DTD, throw exception if not found
616  name = parseRequiredAttribute<wxString>( aPad, "name" );
617  x = parseRequiredAttribute<ECOORD>( aPad, "x" );
618  y = parseRequiredAttribute<ECOORD>( aPad, "y" );
619  rot = parseOptionalAttribute<EROT>( aPad, "rot" );
620  stop = parseOptionalAttribute<bool>( aPad, "stop" );
621  thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
622 }
623 
624 
625 EPAD::EPAD( wxXmlNode* aPad )
626  : EPAD_COMMON( aPad )
627 {
628  /*
629  <!ELEMENT pad EMPTY>
630  <!ATTLIST pad
631  name %String; #REQUIRED
632  x %Coord; #REQUIRED
633  y %Coord; #REQUIRED
634  drill %Dimension; #REQUIRED
635  diameter %Dimension; "0"
636  shape %PadShape; "round"
637  rot %Rotation; "R0"
638  stop %Bool; "yes"
639  thermals %Bool; "yes"
640  first %Bool; "no"
641  >
642  */
643 
644  // #REQUIRED says DTD, throw exception if not found
645  drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
646 
647  // Optional attributes
648  diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
649 
650  opt_wxString s = parseOptionalAttribute<wxString>( aPad, "shape" );
651 
652  // (square | round | octagon | long | offset)
653  if( s == "square" )
655  else if( s == "round" )
656  shape = EPAD::ROUND;
657  else if( s == "octagon" )
659  else if( s == "long" )
660  shape = EPAD::LONG;
661  else if( s == "offset" )
663 
664  first = parseOptionalAttribute<bool>( aPad, "first" );
665 }
666 
667 
668 ESMD::ESMD( wxXmlNode* aSMD )
669  : EPAD_COMMON( aSMD )
670 {
671  /*
672  <!ATTLIST smd
673  name %String; #REQUIRED
674  x %Coord; #REQUIRED
675  y %Coord; #REQUIRED
676  dx %Dimension; #REQUIRED
677  dy %Dimension; #REQUIRED
678  layer %Layer; #REQUIRED
679  roundness %Int; "0"
680  rot %Rotation; "R0"
681  stop %Bool; "yes"
682  thermals %Bool; "yes"
683  cream %Bool; "yes"
684  >
685  */
686 
687  // DTD #REQUIRED, throw exception if not found
688  dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
689  dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
690  layer = parseRequiredAttribute<int>( aSMD, "layer" );
691 
692  roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
693  cream = parseOptionalAttribute<bool>( aSMD, "cream" );
694 }
695 
696 
697 EPIN::EPIN( wxXmlNode* aPin )
698 {
699  /*
700  <!ELEMENT pin EMPTY>
701  <!ATTLIST pin
702  name %String; #REQUIRED
703  x %Coord; #REQUIRED
704  y %Coord; #REQUIRED
705  visible %PinVisible; "both"
706  length %PinLength; "long"
707  direction %PinDirection; "io"
708  function %PinFunction; "none"
709  swaplevel %Int; "0"
710  rot %Rotation; "R0"
711  >
712  */
713 
714  // DTD #REQUIRED, throw exception if not found
715  name = parseRequiredAttribute<wxString>( aPin, "name" );
716  x = parseRequiredAttribute<ECOORD>( aPin, "x" );
717  y = parseRequiredAttribute<ECOORD>( aPin, "y" );
718 
719  visible = parseOptionalAttribute<wxString>( aPin, "visible" );
720  length = parseOptionalAttribute<wxString>( aPin, "length" );
721  direction = parseOptionalAttribute<wxString>( aPin, "direction" );
722  function = parseOptionalAttribute<wxString>( aPin, "function" );
723  swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
724  rot = parseOptionalAttribute<EROT>( aPin, "rot" );
725 }
726 
727 
728 EVERTEX::EVERTEX( wxXmlNode* aVertex )
729 {
730  /*
731  <!ELEMENT vertex EMPTY>
732  <!ATTLIST vertex
733  x %Coord; #REQUIRED
734  y %Coord; #REQUIRED
735  curve %WireCurve; "0" -- the curvature from this vertex to the next one --
736  >
737  */
738 
739  x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
740  y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
741  curve = parseOptionalAttribute<double>( aVertex, "curve" );
742 }
743 
744 
745 EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
746 {
747  /*
748  <!ATTLIST polygon
749  width %Dimension; #REQUIRED
750  layer %Layer; #REQUIRED
751  spacing %Dimension; #IMPLIED
752  pour %PolygonPour; "solid"
753  isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
754  orphans %Bool; "no" -- only in <signal> context --
755  thermals %Bool; "yes" -- only in <signal> context --
756  rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
757  >
758  */
759 
760  width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
761  layer = parseRequiredAttribute<int>( aPolygon, "layer" );
762 
763  spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
764  isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
765  opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
766 
767  // default pour to solid fill
769 
770  // (solid | hatch | cutout)
771  if( s == "hatch" )
773  else if( s == "cutout" )
775 
776  orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
777  thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
778  rank = parseOptionalAttribute<int>( aPolygon, "rank" );
779 }
780 
781 
782 EHOLE::EHOLE( wxXmlNode* aHole )
783 {
784  /*
785  <!ELEMENT hole EMPTY>
786  <!ATTLIST hole
787  x %Coord; #REQUIRED
788  y %Coord; #REQUIRED
789  drill %Dimension; #REQUIRED
790  >
791  */
792 
793  // #REQUIRED:
794  x = parseRequiredAttribute<ECOORD>( aHole, "x" );
795  y = parseRequiredAttribute<ECOORD>( aHole, "y" );
796  drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
797 }
798 
799 
800 EELEMENT::EELEMENT( wxXmlNode* aElement )
801 {
802  /*
803  <!ELEMENT element (attribute*, variant*)>
804  <!ATTLIST element
805  name %String; #REQUIRED
806  library %String; #REQUIRED
807  package %String; #REQUIRED
808  value %String; #REQUIRED
809  x %Coord; #REQUIRED
810  y %Coord; #REQUIRED
811  locked %Bool; "no"
812  smashed %Bool; "no"
813  rot %Rotation; "R0"
814  >
815  */
816 
817  // #REQUIRED
818  name = parseRequiredAttribute<wxString>( aElement, "name" );
819  library = parseRequiredAttribute<wxString>( aElement, "library" );
820  value = parseRequiredAttribute<wxString>( aElement, "value" );
821  std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
822  ReplaceIllegalFileNameChars( &p, '_' );
823  package = wxString::FromUTF8( p.c_str() );
824 
825  x = parseRequiredAttribute<ECOORD>( aElement, "x" );
826  y = parseRequiredAttribute<ECOORD>( aElement, "y" );
827 
828  // optional
829  locked = parseOptionalAttribute<bool>( aElement, "locked" );
830  smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
831  rot = parseOptionalAttribute<EROT>( aElement, "rot" );
832 }
833 
834 
835 ELAYER::ELAYER( wxXmlNode* aLayer )
836 {
837  /*
838  <!ELEMENT layer EMPTY>
839  <!ATTLIST layer
840  number %Layer; #REQUIRED
841  name %String; #REQUIRED
842  color %Int; #REQUIRED
843  fill %Int; #REQUIRED
844  visible %Bool; "yes"
845  active %Bool; "yes"
846  >
847  */
848 
849  number = parseRequiredAttribute<int>( aLayer, "number" );
850  name = parseRequiredAttribute<wxString>( aLayer, "name" );
851  color = parseRequiredAttribute<int>( aLayer, "color" );
852  fill = 1; // Temporary value.
853  visible = parseOptionalAttribute<bool>( aLayer, "visible" );
854  active = parseOptionalAttribute<bool>( aLayer, "active" );
855 }
856 
857 
858 EPART::EPART( wxXmlNode* aPart )
859 {
860  /*
861  * <!ELEMENT part (attribute*, variant*)>
862  * <!ATTLIST part
863  * name %String; #REQUIRED
864  * library %String; #REQUIRED
865  * deviceset %String; #REQUIRED
866  * device %String; #REQUIRED
867  * technology %String; ""
868  * value %String; #IMPLIED
869  * >
870  */
871  // #REQUIRED
872  name = parseRequiredAttribute<wxString>( aPart, "name" );
873  library = parseRequiredAttribute<wxString>( aPart, "library" );
874  deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
875  device = parseRequiredAttribute<wxString>( aPart, "device" );
876  technology = parseOptionalAttribute<wxString>( aPart, "technology" );
877  value = parseOptionalAttribute<wxString>( aPart, "value" );
878 
879  for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
880  {
881 
882  if( child->GetName() == "attribute" )
883  {
884  std::string aname, avalue;
885  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
886  {
887 
888  if( x->GetName() == "name" )
889  aname = x->GetValue();
890  else if( x->GetName() == "value" )
891  avalue = x->GetValue();
892  }
893 
894  if( aname.size() && avalue.size() )
895  attribute[aname] = avalue;
896  }
897  else if( child->GetName() == "variant" )
898  {
899  std::string aname, avalue;
900  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
901  {
902 
903  if( x->GetName() == "name" )
904  aname = x->GetValue();
905  else if( x->GetName() == "value" )
906  avalue = x->GetValue();
907  }
908 
909  if( aname.size() && avalue.size() )
910  variant[aname] = avalue;
911  }
912  }
913 }
914 
915 
916 EINSTANCE::EINSTANCE( wxXmlNode* aInstance )
917 {
918  /*
919  * <!ELEMENT instance (attribute)*>
920  * <!ATTLIST instance
921  * part %String; #REQUIRED
922  * gate %String; #REQUIRED
923  * x %Coord; #REQUIRED
924  * y %Coord; #REQUIRED
925  * smashed %Bool; "no"
926  * rot %Rotation; "R0"
927  * >
928  */
929  part = parseRequiredAttribute<wxString>( aInstance, "part" );
930  gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
931 
932  x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
933  y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
934 
935  // optional
936  smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
937  rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
938 }
939 
940 
941 EGATE::EGATE( wxXmlNode* aGate )
942 {
943  /*
944  * <!ELEMENT gate EMPTY>
945  * <!ATTLIST gate
946  * name %String; #REQUIRED
947  * symbol %String; #REQUIRED
948  * x %Coord; #REQUIRED
949  * y %Coord; #REQUIRED
950  * addlevel %GateAddLevel; "next"
951  * swaplevel %Int; "0"
952  * >
953  */
954 
955  name = parseRequiredAttribute<wxString>( aGate, "name" );
956  symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
957 
958  x = parseRequiredAttribute<ECOORD>( aGate, "x" );
959  y = parseRequiredAttribute<ECOORD>( aGate, "y" );
960 
961  opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
962 
963  // (off | value | name | both)
964  if( stemp == "must" )
965  addlevel = EGATE::MUST;
966  else if( stemp == "can" )
967  addlevel = EGATE::CAN;
968  else if( stemp == "next" )
969  addlevel = EGATE::NEXT;
970  else if( stemp == "request" )
971  addlevel = EGATE::REQUEST;
972  else if( stemp == "always" )
973  addlevel = EGATE::ALWAYS;
974  else
975  addlevel = EGATE::NEXT;
976 }
977 
978 
979 ECONNECT::ECONNECT( wxXmlNode* aConnect )
980 {
981  /*
982  * <!ELEMENT connect EMPTY>
983  * <!ATTLIST connect
984  * gate %String; #REQUIRED
985  * pin %String; #REQUIRED
986  * pad %String; #REQUIRED
987  * route %ContactRoute; "all"
988  * >
989  */
990  gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
991  pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
992  pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
993 }
994 
995 
996 EDEVICE::EDEVICE( wxXmlNode* aDevice )
997 {
998  /*
999  <!ELEMENT device (connects?, technologies?)>
1000  <!ATTLIST device
1001  name %String; ""
1002  package %String; #IMPLIED
1003  >
1004 */
1005  name = parseRequiredAttribute<wxString>( aDevice, "name" );
1006  opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1007 
1008  if( pack )
1009  {
1010  std::string p( pack->c_str() );
1011  ReplaceIllegalFileNameChars( &p, '_' );
1012  package.Set( wxString::FromUTF8( p.c_str() ) );
1013  }
1014 
1015  NODE_MAP aDeviceChildren = MapChildren( aDevice );
1016  wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, "connects" );
1017 
1018  while( connectNode )
1019  {
1020  connects.emplace_back( connectNode );
1021  connectNode = connectNode->GetNext();
1022  }
1023 }
1024 
1025 
1026 EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
1027 {
1028  /*
1029  <!ELEMENT deviceset (description?, gates, devices)>
1030  <!ATTLIST deviceset
1031  name %String; #REQUIRED
1032  prefix %String; ""
1033  uservalue %Bool; "no"
1034  >
1035  */
1036 
1037  name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
1038  prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1039  uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1040 
1041  /* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp
1042  *
1043  //TODO: description
1044 
1045  NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet);
1046  wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, "device");
1047 
1048  while(deviceNode){
1049  devices.push_back(EDEVICE(deviceNode));
1050  deviceNode->GetNext();
1051  }
1052 
1053  wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, "gate");
1054 
1055  while(gateNode){
1056  gates.push_back(EGATE(gateNode));
1057  gateNode->GetNext();
1058  }
1059  */
1060 
1061 }
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:60
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:735
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
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
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
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:201
constexpr auto DEFAULT_ALIGNMENT
opt_ecoord diameter
Definition: eagle_parser.h:696
double DEG2RAD(double deg)
Definition: trigo.h:220
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)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
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