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  wxASSERT( ( ret > 0 ) == ( aValue > 0 ) ); // check for overflow
113  return ret;
114 }
115 
116 
117 // Template specializations below parse wxString to the used types:
118 // - wxString (preferred)
119 // - string
120 // - double
121 // - int
122 // - bool
123 // - EROT
124 // - ECOORD
125 
126 template <>
127 wxString Convert<wxString>( const wxString& aValue )
128 {
129  return aValue;
130 }
131 
132 
133 template <>
134 std::string Convert<std::string>( const wxString& aValue )
135 {
136  return std::string( aValue.ToUTF8() );
137 }
138 
139 
140 template <>
141 double Convert<double>( const wxString& aValue )
142 {
143  double value;
144 
145  if( aValue.ToDouble( &value ) )
146  return value;
147  else
148  throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
149  aValue.ToStdString() + "'." );
150 }
151 
152 
153 template <>
154 int Convert<int>( const wxString& aValue )
155 {
156  if( aValue.IsEmpty() )
157  throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
158 
159  return wxAtoi( aValue );
160 }
161 
162 
163 template <>
164 bool Convert<bool>( const wxString& aValue )
165 {
166  if( aValue != "yes" && aValue != "no" )
167  throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
168  aValue.ToStdString() +
169  "', is neither 'yes' nor 'no'." );
170 
171  return aValue == "yes";
172 }
173 
174 
177 template<>
178 EROT Convert<EROT>( const wxString& aRot )
179 {
180  EROT value;
181 
182  value.spin = aRot.find( 'S' ) != aRot.npos;
183  value.mirror = aRot.find( 'M' ) != aRot.npos;
184  value.degrees = strtod( aRot.c_str()
185  + 1 // skip leading 'R'
186  + int( value.spin ) // skip optional leading 'S'
187  + int( value.mirror ), // skip optional leading 'M'
188  NULL );
189 
190  return value;
191 }
192 
193 
194 template<>
195 ECOORD Convert<ECOORD>( const wxString& aCoord )
196 {
197  // Eagle uses millimeters as the default unit
198  return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
199 }
200 
201 
210 template<typename T>
211 T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
212 {
213  wxString value;
214 
215  if( aNode->GetAttribute( aAttribute, &value ) )
216  return Convert<T>( value );
217  else
218  throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
219 }
220 
221 
230 template<typename T>
231 OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
232 {
233  return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
234 }
235 
236 
237 NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
238 {
239  // Map node_name -> node_pointer
240  NODE_MAP nodesMap;
241 
242  // Loop through all children mapping them in nodesMap
243  if( aCurrentNode )
244  aCurrentNode = aCurrentNode->GetChildren();
245 
246  while( aCurrentNode )
247  {
248  // Create a new pair in the map
249  // key: current node name
250  // value: current node pointer
251  nodesMap[aCurrentNode->GetName()] = aCurrentNode;
252 
253  // Get next child
254  aCurrentNode = aCurrentNode->GetNext();
255  }
256 
257  return nodesMap;
258 }
259 
260 
261 timestamp_t EagleTimeStamp( wxXmlNode* aTree )
262 {
263  // in this case from a unique tree memory location
264  return (timestamp_t) reinterpret_cast<uintptr_t>( aTree );
265 }
266 
267 
268 timestamp_t EagleModuleTstamp( const wxString& aName, const wxString& aValue, int aUnit )
269 {
270  std::size_t h1 = std::hash<wxString>{}( aName );
271  std::size_t h2 = std::hash<wxString>{}( aValue );
272  std::size_t h3 = std::hash<int>{}( aUnit );
273 
274  return (timestamp_t)( h1 ^ (h2 << 1) ^ (h3 << 2) );
275 }
276 
277 
278 wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle )
279 {
280  // Eagle give us start and end.
281  // S_ARC wants start to give the center, and end to give the start.
282  double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
283  wxPoint mid = ( aStart + aEnd ) / 2;
284 
285  double dlen = sqrt( dx*dx + dy*dy );
286  wxASSERT( dlen != 0 );
287  wxASSERT( aAngle != 0 );
288  double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
289 
290  wxPoint center(
291  mid.x + dist * ( dy / dlen ),
292  mid.y - dist * ( dx / dlen )
293  );
294 
295  return center;
296 }
297 
298 
299 static int parseAlignment( const wxString& aAlignment )
300 {
301  // (bottom-left | bottom-center | bottom-right | center-left |
302  // center | center-right | top-left | top-center | top-right)
303  if( aAlignment == "center" )
304  return ETEXT::CENTER;
305  else if( aAlignment == "center-right" )
306  return ETEXT::CENTER_RIGHT;
307  else if( aAlignment == "top-left" )
308  return ETEXT::TOP_LEFT;
309  else if( aAlignment == "top-center" )
310  return ETEXT::TOP_CENTER;
311  else if( aAlignment == "top-right" )
312  return ETEXT::TOP_RIGHT;
313  else if( aAlignment == "bottom-left" )
314  return ETEXT::BOTTOM_LEFT;
315  else if( aAlignment == "bottom-center" )
316  return ETEXT::BOTTOM_CENTER;
317  else if( aAlignment == "bottom-right" )
318  return ETEXT::BOTTOM_RIGHT;
319  else if( aAlignment == "center-left" )
320  return ETEXT::CENTER_LEFT;
321 
322  return DEFAULT_ALIGNMENT;
323 }
324 
325 
326 EWIRE::EWIRE( wxXmlNode* aWire )
327 {
328  /*
329  <!ELEMENT wire EMPTY>
330  <!ATTLIST wire
331  x1 %Coord; #REQUIRED
332  y1 %Coord; #REQUIRED
333  x2 %Coord; #REQUIRED
334  y2 %Coord; #REQUIRED
335  width %Dimension; #REQUIRED
336  layer %Layer; #REQUIRED
337  extent %Extent; #IMPLIED -- only applicable for airwires --
338  style %WireStyle; "continuous"
339  curve %WireCurve; "0"
340  cap %WireCap; "round" -- only applicable if 'curve' is not zero --
341  >
342  */
343 
344  x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
345  y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
346  x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
347  y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
348  width = parseRequiredAttribute<ECOORD>( aWire, "width" );
349  layer = parseRequiredAttribute<int>( aWire, "layer" );
350  curve = parseOptionalAttribute<double>( aWire, "curve" );
351 
352  opt_wxString s = parseOptionalAttribute<wxString>( aWire, "style" );
353 
354  if( s == "continuous" )
355  style = EWIRE::CONTINUOUS;
356  else if( s == "longdash" )
357  style = EWIRE::LONGDASH;
358  else if( s == "shortdash" )
359  style = EWIRE::SHORTDASH;
360  else if( s == "dashdot" )
361  style = EWIRE::DASHDOT;
362 
363  s = parseOptionalAttribute<wxString>( aWire, "cap" );
364 
365  if( s == "round" )
366  cap = EWIRE::ROUND;
367  else if( s == "flat" )
368  cap = EWIRE::FLAT;
369 }
370 
371 
372 EJUNCTION::EJUNCTION( wxXmlNode* aJunction )
373 {
374  /*
375  <!ELEMENT junction EMPTY>
376  <!ATTLIST junction
377  x %Coord; #REQUIRED
378  y %Coord; #REQUIRED
379  >
380  */
381 
382  x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
383  y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
384 }
385 
386 
387 ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName )
388 {
389  /*
390  <!ELEMENT label EMPTY>
391  <!ATTLIST label
392  x %Coord; #REQUIRED
393  y %Coord; #REQUIRED
394  size %Dimension; #REQUIRED
395  layer %Layer; #REQUIRED
396  font %TextFont; "proportional"
397  ratio %Int; "8"
398  rot %Rotation; "R0"
399  xref %Bool; "no"
400  >
401  */
402 
403  x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
404  y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
405  size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
406  layer = parseRequiredAttribute<int>( aLabel, "layer" );
407  rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
408  xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
409  netname = aNetName;
410 }
411 
412 
413 EVIA::EVIA( wxXmlNode* aVia )
414 {
415  /*
416  <!ELEMENT via EMPTY>
417  <!ATTLIST via
418  x %Coord; #REQUIRED
419  y %Coord; #REQUIRED
420  extent %Extent; #REQUIRED
421  drill %Dimension; #REQUIRED
422  diameter %Dimension; "0"
423  shape %ViaShape; "round"
424  alwaysstop %Bool; "no"
425  >
426  */
427 
428  x = parseRequiredAttribute<ECOORD>( aVia, "x" );
429  y = parseRequiredAttribute<ECOORD>( aVia, "y" );
430 
431  wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
432  sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
433 
434  drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
435  diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
436  shape = parseOptionalAttribute<wxString>( aVia, "shape" );
437 }
438 
439 
440 ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
441 {
442  /*
443  <!ELEMENT circle EMPTY>
444  <!ATTLIST circle
445  x %Coord; #REQUIRED
446  y %Coord; #REQUIRED
447  radius %Coord; #REQUIRED
448  width %Dimension; #REQUIRED
449  layer %Layer; #REQUIRED
450  >
451  */
452 
453  x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
454  y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
455  radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
456  width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
457  layer = parseRequiredAttribute<int>( aCircle, "layer" );
458 }
459 
460 
461 ERECT::ERECT( wxXmlNode* aRect )
462 {
463  /*
464  <!ELEMENT rectangle EMPTY>
465  <!ATTLIST rectangle
466  x1 %Coord; #REQUIRED
467  y1 %Coord; #REQUIRED
468  x2 %Coord; #REQUIRED
469  y2 %Coord; #REQUIRED
470  layer %Layer; #REQUIRED
471  rot %Rotation; "R0"
472  >
473  */
474 
475  x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
476  y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
477  x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
478  y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
479  layer = parseRequiredAttribute<int>( aRect, "layer" );
480  rot = parseOptionalAttribute<EROT>( aRect, "rot" );
481 }
482 
483 
484 EATTR::EATTR( wxXmlNode* aTree )
485 {
486  /*
487  <!ELEMENT attribute EMPTY>
488  <!ATTLIST attribute
489  name %String; #REQUIRED
490  value %String; #IMPLIED
491  x %Coord; #IMPLIED
492  y %Coord; #IMPLIED
493  size %Dimension; #IMPLIED
494  layer %Layer; #IMPLIED
495  font %TextFont; #IMPLIED
496  ratio %Int; #IMPLIED
497  rot %Rotation; "R0"
498  display %AttributeDisplay; "value" -- only in <element> or <instance> context --
499  constant %Bool; "no" -- only in <device> context --
500  >
501  */
502 
503  name = parseRequiredAttribute<wxString>( aTree, "name" );
504  value = parseOptionalAttribute<wxString>( aTree, "value" );
505 
506  x = parseOptionalAttribute<ECOORD>( aTree, "x" );
507  y = parseOptionalAttribute<ECOORD>( aTree, "y" );
508  size = parseOptionalAttribute<ECOORD>( aTree, "size" );
509 
510  // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
511  // Eagle can it seems.
512  layer = parseOptionalAttribute<int>( aTree, "layer" );
513  ratio = parseOptionalAttribute<double>( aTree, "ratio" );
514  rot = parseOptionalAttribute<EROT>( aTree, "rot" );
515 
516  opt_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
517 
518  // (off | value | name | both)
519  if( stemp == "off" )
520  display = EATTR::Off;
521  else if( stemp == "name" )
522  display = EATTR::NAME;
523  else if( stemp == "both" )
524  display = EATTR::BOTH;
525  else // "value" is the default
526  display = EATTR::VALUE;
527 
528  stemp = parseOptionalAttribute<wxString>( aTree, "align" );
529 
530  align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
531 }
532 
533 
534 EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
535 {
536  /*
537  <!ELEMENT dimension EMPTY>
538  <!ATTLIST dimension
539  x1 %Coord; #REQUIRED
540  y1 %Coord; #REQUIRED
541  x2 %Coord; #REQUIRED
542  y2 %Coord; #REQUIRED
543  x3 %Coord; #REQUIRED
544  y3 %Coord; #REQUIRED
545  layer %Layer; #REQUIRED
546  dtype %DimensionType; "parallel"
547  >
548  */
549 
550  x1 = parseRequiredAttribute<ECOORD>( aDimension, "x1" );
551  y1 = parseRequiredAttribute<ECOORD>( aDimension, "y1" );
552  x2 = parseRequiredAttribute<ECOORD>( aDimension, "x2" );
553  y2 = parseRequiredAttribute<ECOORD>( aDimension, "y2" );
554  x3 = parseRequiredAttribute<ECOORD>( aDimension, "x3" );
555  y3 = parseRequiredAttribute<ECOORD>( aDimension, "y3" );
556  layer = parseRequiredAttribute<int>( aDimension, "layer" );
557  dimensionType = parseOptionalAttribute<wxString>( aDimension, "dtype" );
558 }
559 
560 
561 ETEXT::ETEXT( wxXmlNode* aText )
562 {
563  /*
564  <!ELEMENT text (#PCDATA)>
565  <!ATTLIST text
566  x %Coord; #REQUIRED
567  y %Coord; #REQUIRED
568  size %Dimension; #REQUIRED
569  layer %Layer; #REQUIRED
570  font %TextFont; "proportional"
571  ratio %Int; "8"
572  rot %Rotation; "R0"
573  align %Align; "bottom-left"
574  >
575  */
576 
577  text = aText->GetNodeContent();
578  x = parseRequiredAttribute<ECOORD>( aText, "x" );
579  y = parseRequiredAttribute<ECOORD>( aText, "y" );
580  size = parseRequiredAttribute<ECOORD>( aText, "size" );
581  layer = parseRequiredAttribute<int>( aText, "layer" );
582 
583  font = parseOptionalAttribute<wxString>( aText, "font" );
584  ratio = parseOptionalAttribute<double>( aText, "ratio" );
585  rot = parseOptionalAttribute<EROT>( aText, "rot" );
586 
587  opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
588 
589  align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
590 }
591 
592 
593 wxSize ETEXT::ConvertSize() const
594 {
595  wxSize textsize;
596 
597  if( font )
598  {
599  const wxString& fontName = font.CGet();
600 
601  if( fontName == "vector" )
602  {
603  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
604  }
605  else if( fontName == "fixed" )
606  {
607  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
608  }
609  else
610  {
611  wxASSERT( false );
612  textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
613  }
614  }
615  else
616  {
617  textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() );
618  }
619 
620  return textsize;
621 }
622 
623 
624 EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
625 {
626  // #REQUIRED says DTD, throw exception if not found
627  name = parseRequiredAttribute<wxString>( aPad, "name" );
628  x = parseRequiredAttribute<ECOORD>( aPad, "x" );
629  y = parseRequiredAttribute<ECOORD>( aPad, "y" );
630  rot = parseOptionalAttribute<EROT>( aPad, "rot" );
631  stop = parseOptionalAttribute<bool>( aPad, "stop" );
632  thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
633 }
634 
635 
636 EPAD::EPAD( wxXmlNode* aPad )
637  : EPAD_COMMON( aPad )
638 {
639  /*
640  <!ELEMENT pad EMPTY>
641  <!ATTLIST pad
642  name %String; #REQUIRED
643  x %Coord; #REQUIRED
644  y %Coord; #REQUIRED
645  drill %Dimension; #REQUIRED
646  diameter %Dimension; "0"
647  shape %PadShape; "round"
648  rot %Rotation; "R0"
649  stop %Bool; "yes"
650  thermals %Bool; "yes"
651  first %Bool; "no"
652  >
653  */
654 
655  // #REQUIRED says DTD, throw exception if not found
656  drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
657 
658  // Optional attributes
659  diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
660 
661  opt_wxString s = parseOptionalAttribute<wxString>( aPad, "shape" );
662 
663  // (square | round | octagon | long | offset)
664  if( s == "square" )
666  else if( s == "round" )
667  shape = EPAD::ROUND;
668  else if( s == "octagon" )
670  else if( s == "long" )
671  shape = EPAD::LONG;
672  else if( s == "offset" )
674 
675  first = parseOptionalAttribute<bool>( aPad, "first" );
676 }
677 
678 
679 ESMD::ESMD( wxXmlNode* aSMD )
680  : EPAD_COMMON( aSMD )
681 {
682  /*
683  <!ATTLIST smd
684  name %String; #REQUIRED
685  x %Coord; #REQUIRED
686  y %Coord; #REQUIRED
687  dx %Dimension; #REQUIRED
688  dy %Dimension; #REQUIRED
689  layer %Layer; #REQUIRED
690  roundness %Int; "0"
691  rot %Rotation; "R0"
692  stop %Bool; "yes"
693  thermals %Bool; "yes"
694  cream %Bool; "yes"
695  >
696  */
697 
698  // DTD #REQUIRED, throw exception if not found
699  dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
700  dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
701  layer = parseRequiredAttribute<int>( aSMD, "layer" );
702 
703  roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
704  cream = parseOptionalAttribute<bool>( aSMD, "cream" );
705 }
706 
707 
708 EPIN::EPIN( wxXmlNode* aPin )
709 {
710  /*
711  <!ELEMENT pin EMPTY>
712  <!ATTLIST pin
713  name %String; #REQUIRED
714  x %Coord; #REQUIRED
715  y %Coord; #REQUIRED
716  visible %PinVisible; "both"
717  length %PinLength; "long"
718  direction %PinDirection; "io"
719  function %PinFunction; "none"
720  swaplevel %Int; "0"
721  rot %Rotation; "R0"
722  >
723  */
724 
725  // DTD #REQUIRED, throw exception if not found
726  name = parseRequiredAttribute<wxString>( aPin, "name" );
727  x = parseRequiredAttribute<ECOORD>( aPin, "x" );
728  y = parseRequiredAttribute<ECOORD>( aPin, "y" );
729 
730  visible = parseOptionalAttribute<wxString>( aPin, "visible" );
731  length = parseOptionalAttribute<wxString>( aPin, "length" );
732  direction = parseOptionalAttribute<wxString>( aPin, "direction" );
733  function = parseOptionalAttribute<wxString>( aPin, "function" );
734  swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
735  rot = parseOptionalAttribute<EROT>( aPin, "rot" );
736 }
737 
738 
739 EVERTEX::EVERTEX( wxXmlNode* aVertex )
740 {
741  /*
742  <!ELEMENT vertex EMPTY>
743  <!ATTLIST vertex
744  x %Coord; #REQUIRED
745  y %Coord; #REQUIRED
746  curve %WireCurve; "0" -- the curvature from this vertex to the next one --
747  >
748  */
749 
750  x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
751  y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
752  curve = parseOptionalAttribute<double>( aVertex, "curve" );
753 }
754 
755 
756 EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
757 {
758  /*
759  <!ATTLIST polygon
760  width %Dimension; #REQUIRED
761  layer %Layer; #REQUIRED
762  spacing %Dimension; #IMPLIED
763  pour %PolygonPour; "solid"
764  isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
765  orphans %Bool; "no" -- only in <signal> context --
766  thermals %Bool; "yes" -- only in <signal> context --
767  rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
768  >
769  */
770 
771  width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
772  layer = parseRequiredAttribute<int>( aPolygon, "layer" );
773 
774  spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
775  isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
776  opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
777 
778  // default pour to solid fill
779  pour = EPOLYGON::SOLID;
780 
781  // (solid | hatch | cutout)
782  if( s == "hatch" )
783  pour = EPOLYGON::HATCH;
784  else if( s == "cutout" )
785  pour = EPOLYGON::CUTOUT;
786 
787  orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
788  thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
789  rank = parseOptionalAttribute<int>( aPolygon, "rank" );
790 }
791 
792 
793 EHOLE::EHOLE( wxXmlNode* aHole )
794 {
795  /*
796  <!ELEMENT hole EMPTY>
797  <!ATTLIST hole
798  x %Coord; #REQUIRED
799  y %Coord; #REQUIRED
800  drill %Dimension; #REQUIRED
801  >
802  */
803 
804  // #REQUIRED:
805  x = parseRequiredAttribute<ECOORD>( aHole, "x" );
806  y = parseRequiredAttribute<ECOORD>( aHole, "y" );
807  drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
808 }
809 
810 
811 EELEMENT::EELEMENT( wxXmlNode* aElement )
812 {
813  /*
814  <!ELEMENT element (attribute*, variant*)>
815  <!ATTLIST element
816  name %String; #REQUIRED
817  library %String; #REQUIRED
818  package %String; #REQUIRED
819  value %String; #REQUIRED
820  x %Coord; #REQUIRED
821  y %Coord; #REQUIRED
822  locked %Bool; "no"
823  smashed %Bool; "no"
824  rot %Rotation; "R0"
825  >
826  */
827 
828  // #REQUIRED
829  name = parseRequiredAttribute<wxString>( aElement, "name" );
830  library = parseRequiredAttribute<wxString>( aElement, "library" );
831  value = parseRequiredAttribute<wxString>( aElement, "value" );
832  std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
833  ReplaceIllegalFileNameChars( &p, '_' );
834  package = wxString::FromUTF8( p.c_str() );
835 
836  x = parseRequiredAttribute<ECOORD>( aElement, "x" );
837  y = parseRequiredAttribute<ECOORD>( aElement, "y" );
838 
839  // optional
840  locked = parseOptionalAttribute<bool>( aElement, "locked" );
841  smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
842  rot = parseOptionalAttribute<EROT>( aElement, "rot" );
843 }
844 
845 
846 ELAYER::ELAYER( wxXmlNode* aLayer )
847 {
848  /*
849  <!ELEMENT layer EMPTY>
850  <!ATTLIST layer
851  number %Layer; #REQUIRED
852  name %String; #REQUIRED
853  color %Int; #REQUIRED
854  fill %Int; #REQUIRED
855  visible %Bool; "yes"
856  active %Bool; "yes"
857  >
858  */
859 
860  number = parseRequiredAttribute<int>( aLayer, "number" );
861  name = parseRequiredAttribute<wxString>( aLayer, "name" );
862  color = parseRequiredAttribute<int>( aLayer, "color" );
863  fill = 1; // Temporary value.
864  visible = parseOptionalAttribute<bool>( aLayer, "visible" );
865  active = parseOptionalAttribute<bool>( aLayer, "active" );
866 }
867 
868 
869 EPART::EPART( wxXmlNode* aPart )
870 {
871  /*
872  * <!ELEMENT part (attribute*, variant*)>
873  * <!ATTLIST part
874  * name %String; #REQUIRED
875  * library %String; #REQUIRED
876  * deviceset %String; #REQUIRED
877  * device %String; #REQUIRED
878  * technology %String; ""
879  * value %String; #IMPLIED
880  * >
881  */
882  // #REQUIRED
883  name = parseRequiredAttribute<wxString>( aPart, "name" );
884  library = parseRequiredAttribute<wxString>( aPart, "library" );
885  deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
886  device = parseRequiredAttribute<wxString>( aPart, "device" );
887  technology = parseOptionalAttribute<wxString>( aPart, "technology" );
888  value = parseOptionalAttribute<wxString>( aPart, "value" );
889 
890  for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
891  {
892 
893  if( child->GetName() == "attribute" )
894  {
895  std::string aname, avalue;
896  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
897  {
898 
899  if( x->GetName() == "name" )
900  aname = x->GetValue();
901  else if( x->GetName() == "value" )
902  avalue = x->GetValue();
903  }
904 
905  if( aname.size() && avalue.size() )
906  attribute[aname] = avalue;
907  }
908  else if( child->GetName() == "variant" )
909  {
910  std::string aname, avalue;
911  for( auto x = child->GetAttributes(); x; x = x->GetNext() )
912  {
913 
914  if( x->GetName() == "name" )
915  aname = x->GetValue();
916  else if( x->GetName() == "value" )
917  avalue = x->GetValue();
918  }
919 
920  if( aname.size() && avalue.size() )
921  variant[aname] = avalue;
922  }
923  }
924 }
925 
926 
927 EINSTANCE::EINSTANCE( wxXmlNode* aInstance )
928 {
929  /*
930  * <!ELEMENT instance (attribute)*>
931  * <!ATTLIST instance
932  * part %String; #REQUIRED
933  * gate %String; #REQUIRED
934  * x %Coord; #REQUIRED
935  * y %Coord; #REQUIRED
936  * smashed %Bool; "no"
937  * rot %Rotation; "R0"
938  * >
939  */
940  part = parseRequiredAttribute<wxString>( aInstance, "part" );
941  gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
942 
943  x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
944  y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
945 
946  // optional
947  smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
948  rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
949 }
950 
951 
952 EGATE::EGATE( wxXmlNode* aGate )
953 {
954  /*
955  * <!ELEMENT gate EMPTY>
956  * <!ATTLIST gate
957  * name %String; #REQUIRED
958  * symbol %String; #REQUIRED
959  * x %Coord; #REQUIRED
960  * y %Coord; #REQUIRED
961  * addlevel %GateAddLevel; "next"
962  * swaplevel %Int; "0"
963  * >
964  */
965 
966  name = parseRequiredAttribute<wxString>( aGate, "name" );
967  symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
968 
969  x = parseRequiredAttribute<ECOORD>( aGate, "x" );
970  y = parseRequiredAttribute<ECOORD>( aGate, "y" );
971 
972  opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
973 
974  // (off | value | name | both)
975  if( stemp == "must" )
976  addlevel = EGATE::MUST;
977  else if( stemp == "can" )
978  addlevel = EGATE::CAN;
979  else if( stemp == "next" )
980  addlevel = EGATE::NEXT;
981  else if( stemp == "request" )
982  addlevel = EGATE::REQUEST;
983  else if( stemp == "always" )
984  addlevel = EGATE::ALWAYS;
985  else
986  addlevel = EGATE::NEXT;
987 }
988 
989 
990 ECONNECT::ECONNECT( wxXmlNode* aConnect )
991 {
992  /*
993  * <!ELEMENT connect EMPTY>
994  * <!ATTLIST connect
995  * gate %String; #REQUIRED
996  * pin %String; #REQUIRED
997  * pad %String; #REQUIRED
998  * route %ContactRoute; "all"
999  * >
1000  */
1001  gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
1002  pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
1003  pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
1004 }
1005 
1006 
1007 EDEVICE::EDEVICE( wxXmlNode* aDevice )
1008 {
1009  /*
1010  <!ELEMENT device (connects?, technologies?)>
1011  <!ATTLIST device
1012  name %String; ""
1013  package %String; #IMPLIED
1014  >
1015 */
1016  name = parseRequiredAttribute<wxString>( aDevice, "name" );
1017  opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1018 
1019  if( pack )
1020  {
1021  std::string p( pack->c_str() );
1022  ReplaceIllegalFileNameChars( &p, '_' );
1023  package.Set( wxString::FromUTF8( p.c_str() ) );
1024  }
1025 
1026  NODE_MAP aDeviceChildren = MapChildren( aDevice );
1027  wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, "connects" );
1028 
1029  while( connectNode )
1030  {
1031  connects.push_back( ECONNECT( connectNode ) );
1032  connectNode = connectNode->GetNext();
1033  }
1034 }
1035 
1036 
1037 EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
1038 {
1039  /*
1040  <!ELEMENT deviceset (description?, gates, devices)>
1041  <!ATTLIST deviceset
1042  name %String; #REQUIRED
1043  prefix %String; ""
1044  uservalue %Bool; "no"
1045  >
1046  */
1047 
1048  name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
1049  prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1050  uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1051 
1052  /* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp
1053  *
1054  //TODO: description
1055 
1056  NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet);
1057  wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, "device");
1058 
1059  while(deviceNode){
1060  devices.push_back(EDEVICE(deviceNode));
1061  deviceNode->GetNext();
1062  }
1063 
1064  wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, "gate");
1065 
1066  while(gateNode){
1067  gates.push_back(EGATE(gateNode));
1068  gateNode->GetNext();
1069  }
1070  */
1071 
1072 }
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:479
ECOORD Convert< ECOORD >(const wxString &aCoord)
bool mirror
Definition: eagle_parser.h:481
static const int dist[10][10]
Definition: ar_matrix.cpp:320
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
int color
Definition: DXF_plotter.cpp:62
OPTIONAL_XML_ATTRIBUTE()
Constructor OPTIONAL_XML_ATTRIBUTE construct a default OPTIONAL_XML_ATTRIBUTE, whose data is not avai...
Definition: eagle_parser.h:204
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Function ReplaceIllegalFileNameChars checks aName for illegal file name characters.
Definition: string.cpp:650
wxString name
Definition: eagle_parser.h:683
EROT Convert< EROT >(const wxString &aRot)
parse an Eagle XML "rot" field.
double degrees
Definition: eagle_parser.h:483
T parseRequiredAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Function parseRequiredAttribute parsese the aAttribute of the XML node aNode.
Class XML_PARSER_ERROR implements a simple wrapper around runtime_error to isolate the errors thrown ...
Definition: eagle_parser.h:70
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:687
EPIN(wxXmlNode *aPin)
EDEVICE(wxXmlNode *aDevice)
EPART(wxXmlNode *aPart)
ECONNECT(wxXmlNode *aConnect)
EVERTEX(wxXmlNode *aVertex)
ECOORD dy
Definition: eagle_parser.h:718
ESMD(wxXmlNode *aSMD)
EJUNCTION(wxXmlNode *aJunction)
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
wxString Convert< wxString >(const wxString &aValue)
EDIMENSION(wxXmlNode *aDimension)
ELABEL(wxXmlNode *aLabel, const wxString &aNetName)
EWIRE(wxXmlNode *aWire)
EHOLE(wxXmlNode *aHole)
timestamp_t EagleModuleTstamp(const wxString &aName, const wxString &aValue, int aUnit)
Computes module timestamp basing on its name, value and unit
ECOORD dx
Definition: eagle_parser.h:717
EPOLYGON(wxXmlNode *aPolygon)
bool m_isAvailable
A boolean indicating if the data is present or not.
Definition: eagle_parser.h:194
Class OPTIONAL_XML_ATTRIBUTE models an optional XML attribute.
Definition: eagle_parser.h:190
EDEVICE_SET(wxXmlNode *aDeviceSet)
timestamp_t EagleTimeStamp(wxXmlNode *aTree)
Make a unique time stamp
int layer
Definition: eagle_parser.h:719
EVIA(wxXmlNode *aVia)
EGATE(wxXmlNode *aGate)
opt_int roundness
Definition: eagle_parser.h:720
static int parseAlignment(const wxString &aAlignment)
int Convert< int >(const wxString &aValue)
OPTIONAL_XML_ATTRIBUTE< T > parseOptionalAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Function parseOptionalAttribute parses the aAttribute of the XML node aNode.
EPAD_COMMON(wxXmlNode *aPad)
const char * name
Definition: DXF_plotter.cpp:61
constexpr auto DEFAULT_ALIGNMENT
opt_ecoord diameter
Definition: eagle_parser.h:697
double DEG2RAD(double deg)
Definition: trigo.h:199
Structure holding common properties for through-hole and SMD pads.
Definition: eagle_parser.h:681
wxPoint ConvertArcCenter(const wxPoint &aStart, const wxPoint &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC
opt_erot rot
Definition: eagle_parser.h:685
opt_bool first
Definition: eagle_parser.h:708
ERECT(wxXmlNode *aRect)
opt_int shape
Definition: eagle_parser.h:707
double Convert< double >(const wxString &aValue)
bool spin
Definition: eagle_parser.h:482
ECOORD drill
Definition: eagle_parser.h:696
wxSize ConvertSize() const
Calculate text size based on font type and size.
ECIRCLE(wxXmlNode *aCircle)
ETEXT(wxXmlNode *aText)
EELEMENT(wxXmlNode *aElement)
static long long int ConvertToNm(int aValue, enum EAGLE_UNIT aUnit)
Converts a size expressed in a certain unit to nanometers.
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
Definition: eagle_parser.h:48
static wxXmlNode * getChildrenNodes(NODE_MAP &aMap, const wxString &aName)
Definition: eagle_parser.h:58
EINSTANCE(wxXmlNode *aInstance)
EPAD(wxXmlNode *aPad)
opt_bool cream
Definition: eagle_parser.h:721
bool Convert< bool >(const wxString &aValue)