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