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