KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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, see <https://www.gnu.org/licenses/>.
22 */
23
25
26#include <core/profile.h>
27#include <io/io_base.h>
28
29#include <string_utils.h>
30#include <richio.h>
31#include <trace_helpers.h>
32#include <wx/log.h>
33#include <wx/regex.h>
34#include <wx/tokenzr.h>
35
36#include <functional>
37#include <cstdio>
38#include <array>
39
41
42
43wxString escapeName( const wxString& aNetName )
44{
45 wxString ret( aNetName );
46
47 ret.Replace( "!", "~" );
48
49 return ConvertToNewOverbarNotation( ret );
50}
51
52
53wxString interpretText( const wxString& aText )
54{
55 wxString token = aText;
56
57 if( substituteVariable( &token ) )
58 return token;
59
60 wxString text;
61 bool sectionOpen = false;
62
63 for( wxString::size_type i = 0; i < aText.size(); i++ )
64 {
65 // Interpret escaped characters
66 if( aText[i] == '\\' )
67 {
68 if( i+1 < aText.size() )
69 text.Append( aText[i+1] );
70
71 i++;
72 continue;
73 }
74
75 // Escape ~ for KiCAD when it would otherwise be interpreted as markup
76 if( aText[i] == '~' )
77 {
78 if( ( i+1 < aText.size() && aText[i+1] == '{' ) // overbar opening sequence
79 || ( aText == "~" ) ) // legacy empty string token
80 {
81 text.Append( '~' );
82 text.Append( '~' );
83 continue;
84 }
85 }
86
87 if( aText[i] == '!' )
88 {
89 if( sectionOpen )
90 {
91 text.Append( '~' );
92 sectionOpen = false;
93 continue;
94 }
95
96 static wxString escapeChars( wxT( " )]}'\"" ) );
97
98 if( i+1 < aText.size() && escapeChars.Find( aText[i+1] ) == wxNOT_FOUND )
99 {
100 sectionOpen = true;
101 text.Append( '~' );
102 }
103 else
104 {
105 text.Append( aText[i] );
106 }
107
108 continue;
109 }
110
111 if( aText[i] == ',' && sectionOpen )
112 {
113 text.Append( '~' );
114 sectionOpen = false;
115 }
116
117 text.Append( aText[i] );
118 }
119
120 return text;
121}
122
123
124bool substituteVariable( wxString* aText )
125{
126 if( aText->StartsWith( '>' ) && aText->AfterFirst( ' ' ).IsEmpty() )
127 {
128 wxString token = aText->Upper();
129
130 if ( token == wxT( ">NAME" ) ) *aText = wxT( "${REFERENCE}" );
131 else if( token == wxT( ">VALUE" ) ) *aText = wxT( "${VALUE}" );
132 else if( token == wxT( ">PART" ) ) *aText = wxT( "${REFERENCE}" );
133 else if( token == wxT( ">GATE" ) ) *aText = wxT( "${UNIT}" );
134 else if( token == wxT( ">MODULE" ) ) *aText = wxT( "${FOOTPRINT_NAME}" );
135 else if( token == wxT( ">SHEETNR" ) ) *aText = wxT( "${#}" );
136 else if( token == wxT( ">SHEETS" ) ) *aText = wxT( "${##}" );
137 else if( token == wxT( ">SHEET" ) ) *aText = wxT( "${#}/${##}" );
138 else if( token == wxT( ">SHEETNR_TOTAL" ) ) *aText = wxT( "${#}" );
139 else if( token == wxT( ">SHEETS_TOTAL" ) ) *aText = wxT( "${##}" );
140 else if( token == wxT( ">SHEET_TOTAL" ) ) *aText = wxT( "${#}/${##}" );
141 else if( token == wxT( ">SHEET_HEADLINE" ) ) *aText = wxT( "${SHEETNAME}" );
142 else if( token == wxT( ">ASSEMBLY_VARIANT" ) ) *aText = wxT( "${ASSEMBLY_VARIANT}" );
143 else if( token == wxT( ">DRAWING_NAME" ) ) *aText = wxT( "${PROJECTNAME}" );
144 else if( token == wxT( ">LAST_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
145 else if( token == wxT( ">PLOT_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
146 else if( token == wxT( ">DATE" ) ) *aText = wxT( "${ISSUE_DATE}" );
147 else *aText = wxString::Format( wxS( "${%s}" ), aText->Mid( 1 ).Trim() );
148
149 return true;
150 }
151
152 return false;
153}
154
155
156wxString convertDescription( wxString aDescr )
157{
158 aDescr.Replace( wxS( "\n" ), wxS( " " ) );
159 aDescr.Replace( wxS( "\r" ), wxEmptyString );
160
161 wxRegEx( wxS( "<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\"[^>]*>" ) ).ReplaceAll( &aDescr, wxS( "\\1 " ) );
162
163 aDescr.Replace( wxS( "<p>" ), wxS( "\n\n" ) );
164 aDescr.Replace( wxS( "</p>" ), wxS( "\n\n" ) );
165
166 aDescr.Replace( wxS( "<br>" ), wxS( "\n" ) );
167 aDescr.Replace( wxS( "<ul>" ), wxS( "\n" ) );
168 aDescr.Replace( wxS( "</ul>" ), wxS( "\n\n" ) );
169 aDescr.Replace( wxS( "<li></li>" ), wxS( "\n" ) );
170 aDescr.Replace( wxS( "<li>" ), wxS( "\n \u2022 " ) ); // Bullet point
171
172 aDescr = RemoveHTMLTags( aDescr );
173
174 wxRegEx( wxS( "\n +" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
175 wxRegEx( wxS( " +\n" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
176
177 wxRegEx( wxS( "\n{3,}" ) ).ReplaceAll( &aDescr, wxS( "\n\n" ) );
178 wxRegEx( wxS( "^\n+" ) ).ReplaceAll( &aDescr, wxEmptyString );
179 wxRegEx( wxS( "\n+$" ) ).ReplaceAll( &aDescr, wxEmptyString );
180
181 return aDescr;
182}
183
184
185size_t GetNodeCount( const wxXmlNode* aNode )
186{
187 size_t cnt = 0;
188
189 PROF_TIMER timer;
190
191 std::function<size_t( const wxXmlNode* )> countNodes =
192 [&]( const wxXmlNode* node )
193 {
194 size_t count = 0;
195
196 while( node )
197 {
198 if( const wxXmlNode* child = node->GetChildren() )
199 count += countNodes( child );
200 else
201 count++;
202
203 node = node->GetNext();
204 }
205
206 return count;
207 };
208
209 cnt = countNodes( aNode );
210
211 timer.Stop();
212
213 wxLogTrace( traceEagleIo, wxS( "XML node '%s' count = %zu took %0.4f ms." ), aNode->GetName(), cnt, timer.msecs() );
214
215 return cnt;
216}
217
218
219ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
220{
221 // This array is used to adjust the fraction part value basing on the number of digits
222 // in the fraction.
223 static std::array<int, 9> DIVIDERS = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
224
225 int integer, pre_fraction, post_fraction;
226 long long unsigned fraction;
227
228 // The following check is needed to handle correctly negative fractions where the integer
229 // part == 0.
230 bool negative = ( aValue[0] == '-' );
231
232 // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3
233 // digits.
234 int ret = sscanf( aValue.c_str(), "%d.%n%llu%n", &integer, &pre_fraction, &fraction, &post_fraction );
235
236 if( ret == 0 )
237 throw XML_PARSER_ERROR( "Invalid coordinate" );
238
239 // process the integer part
240 value = ConvertToNm( integer, aUnit );
241
242 // process the fraction part
243 if( ret == 2 )
244 {
245 int digits = post_fraction - pre_fraction;
246
247 // adjust the number of digits if necessary as we cannot handle anything smaller than
248 // nanometers (rounding).
249 if( digits >= static_cast<int>( DIVIDERS.size() ) )
250 {
251 long long unsigned denom = pow( 10, digits - DIVIDERS.size() + 1 );
252 digits = DIVIDERS.size() - 1;
253 fraction /= denom;
254 }
255
256 int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
257
258 // keep the sign in mind
259 value = negative ? value - frac_value : value + frac_value;
260 }
261}
262
263
264long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
265{
266 long long int ret;
267
268 switch( aUnit )
269 {
270 default:
271 case EU_NM: ret = aValue; break;
272 case EU_MM: ret = (long long) aValue * 1000000; break;
273 case EU_INCH: ret = (long long) aValue * 25400000; break;
274 case EU_MIL: ret = (long long) aValue * 25400; break;
275 }
276
277 if( ( ret > 0 ) != ( aValue > 0 ) )
278 wxLogTrace( traceEagleIo, wxT( "Invalid size %d: too large" ), aValue );
279
280 return ret;
281}
282
283
284EURN::EURN( const wxString& aUrn )
285{
286 Parse( aUrn );
287}
288
289
290void EURN::Parse( const wxString& aUrn )
291{
292 wxStringTokenizer tokens( aUrn, ":" );
293
294 host = tokens.GetNextToken();
295 path = tokens.GetNextToken();
296 assetType = tokens.GetNextToken();
297
298 // Split off the version if there is one.
299 wxString tmp = tokens.GetNextToken();
300
301 assetId = tmp.BeforeFirst( '/' );
302 assetVersion = tmp.AfterLast( '/' );
303}
304
305
306bool EURN::IsValid() const
307{
308 if( host != "urn" )
309 return false;
310
311 if( path.IsEmpty() )
312 return false;
313
314 static std::set<wxString> validAssetTypes =
315 {
316 "component",
317 "footprint",
318 "library",
319 "package",
320 "symbol",
321 "fs.file"
322 };
323
324 if( validAssetTypes.count( assetType ) == 0 )
325 return false;
326
327 if( assetId.IsEmpty() )
328 return false;
329
330 return true;
331}
332
333
334// Template specializations below parse wxString to the used types:
335// - wxString (preferred)
336// - string
337// - double
338// - int
339// - bool
340// - EROT
341// - ECOORD
342
343template <>
344wxString Convert<wxString>( const wxString& aValue )
345{
346 return aValue;
347}
348
349
350template <>
351std::string Convert<std::string>( const wxString& aValue )
352{
353 return std::string( aValue.ToUTF8() );
354}
355
356
357template <>
358double Convert<double>( const wxString& aValue )
359{
360 double value;
361
362 if( aValue.ToCDouble( &value ) )
363 return value;
364 else
365 throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" + aValue.ToStdString() + "'." );
366}
367
368
369template <>
370int Convert<int>( const wxString& aValue )
371{
372 if( aValue.IsEmpty() )
373 throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
374
375 return wxAtoi( aValue );
376}
377
378
379template <>
380bool Convert<bool>( const wxString& aValue )
381{
382 if( aValue != "yes" && aValue != "no" )
383 {
384 throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" + aValue.ToStdString() +
385 "', is neither 'yes' nor 'no'." );
386 }
387
388 return aValue == "yes";
389}
390
391
394template<>
395EROT Convert<EROT>( const wxString& aRot )
396{
397 EROT value;
398
399 value.spin = aRot.find( 'S' ) != aRot.npos;
400 value.mirror = aRot.find( 'M' ) != aRot.npos;
401
402 size_t rPos = aRot.find( 'R' );
403
404 if( rPos == wxString::npos )
405 {
406 value.degrees = 0.0;
407 return value;
408 }
409
410 // Calculate the offset after 'R', 'S', and 'M'
411 size_t offset;
412
413 for( offset = 0; offset < aRot.size(); offset++ )
414 {
415 if( wxIsdigit( aRot[offset] ) )
416 break;
417 }
418
419 wxString degreesStr = aRot.Mid( offset );
420
421 // Use locale-independent conversion
422 if( !degreesStr.ToCDouble( &value.degrees ) )
423 value.degrees = 0.0;
424
425 return value;
426}
427
428
429template<>
430ECOORD Convert<ECOORD>( const wxString& aCoord )
431{
432 // Eagle uses millimeters as the default unit
433 return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
434}
435
436
437template<>
438EURN Convert<EURN>( const wxString& aUrn )
439{
440 return EURN( aUrn );
441}
442
443
452template<typename T>
453T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
454{
455 wxString value;
456
457 if( aNode->GetAttribute( aAttribute, &value ) )
458 {
459 return Convert<T>( value );
460 }
461 else
462 {
463 throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing at "
464 "line " + wxString::Format( "%d", aNode->GetLineNumber() ) + "." );
465 }
466}
467
468
476template<typename T>
477std::optional<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
478{
479 wxString value = aNode->GetAttribute( aAttribute );
480
481 if( value.IsEmpty() )
482 return std::optional<T>();
483
484 return Convert<T>( value );
485}
486
487
488NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
489{
490 // Map node_name -> node_pointer
491 NODE_MAP nodesMap;
492
493 // Loop through all children mapping them in nodesMap
494 if( aCurrentNode )
495 aCurrentNode = aCurrentNode->GetChildren();
496
497 while( aCurrentNode )
498 {
499 // Create a new pair in the map
500 // key: current node name
501 // value: current node pointer
502 nodesMap[aCurrentNode->GetName()] = aCurrentNode;
503
504 // Get next child
505 aCurrentNode = aCurrentNode->GetNext();
506 }
507
508 return nodesMap;
509}
510
511
512VECTOR2I ConvertArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle )
513{
514 // Eagle give us start and end.
515 // S_ARC wants start to give the center, and end to give the start.
516 double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
517 VECTOR2I mid = ( aStart + aEnd ) / 2;
518
519 double dlen = sqrt( dx*dx + dy*dy );
520
521 if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
522 {
523 // Note that we allow the floating point output here because this message is displayed to the user and should
524 // be in their locale.
525 THROW_IO_ERRORF( _( "Invalid Arc with radius %0.2f and angle %0.2f" ), //format:allow
526 dlen, aAngle );
527 }
528
529 double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
530
532 mid.x + dist * ( dy / dlen ),
533 mid.y - dist * ( dx / dlen )
534 );
535
536 return center;
537}
538
539
540static int parseAlignment( const wxString& aAlignment )
541{
542 // (bottom-left | bottom-center | bottom-right | center-left |
543 // center | center-right | top-left | top-center | top-right)
544 if( aAlignment == "center" )
545 return ETEXT::CENTER;
546 else if( aAlignment == "center-right" )
547 return ETEXT::CENTER_RIGHT;
548 else if( aAlignment == "top-left" )
549 return ETEXT::TOP_LEFT;
550 else if( aAlignment == "top-center" )
551 return ETEXT::TOP_CENTER;
552 else if( aAlignment == "top-right" )
553 return ETEXT::TOP_RIGHT;
554 else if( aAlignment == "bottom-left" )
555 return ETEXT::BOTTOM_LEFT;
556 else if( aAlignment == "bottom-center" )
558 else if( aAlignment == "bottom-right" )
559 return ETEXT::BOTTOM_RIGHT;
560 else if( aAlignment == "center-left" )
561 return ETEXT::CENTER_LEFT;
562
563 return DEFAULT_ALIGNMENT;
564}
565
566
567void EAGLE_BASE::Report( const wxString& aMsg, SEVERITY aSeverity )
568{
569 if( !io )
570 return;
571
572 io->Report( aMsg, aSeverity );
573}
574
575
577{
578 if( !io )
579 return;
580
581 io->AdvanceProgressPhase();
582}
583
584
585EWIRE::EWIRE( wxXmlNode* aWire, IO_BASE* aIo ) :
586 EAGLE_BASE( aIo )
587{
588 /*
589 * <!ELEMENT wire EMPTY>
590 * <!ATTLIST wire
591 * x1 %Coord; #REQUIRED
592 * y1 %Coord; #REQUIRED
593 * x2 %Coord; #REQUIRED
594 * y2 %Coord; #REQUIRED
595 * width %Dimension; #REQUIRED
596 * layer %Layer; #REQUIRED
597 * extent %Extent; #IMPLIED -- only applicable for airwires --
598 * style %WireStyle; "continuous"
599 * curve %WireCurve; "0"
600 * cap %WireCap; "round" -- only applicable if 'curve' is not zero --
601 * >
602 */
603
604 x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
605 y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
606 x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
607 y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
608 width = parseRequiredAttribute<ECOORD>( aWire, "width" );
609 layer = parseRequiredAttribute<int>( aWire, "layer" );
610 curve = parseOptionalAttribute<double>( aWire, "curve" );
611
612 std::optional<wxString> s = parseOptionalAttribute<wxString>( aWire, "style" );
613
614 if( s.has_value() )
615 {
616 if( s.value() == "continuous" )
618 else if( s.value() == "longdash" )
620 else if( s.value() == "shortdash" )
622 else if( s.value() == "dashdot" )
624 }
625
626 s = parseOptionalAttribute<wxString>( aWire, "cap" );
627
628 if( s.has_value() )
629 {
630 if( s.value() == "round" )
632 else if( s.value() == "flat" )
634 }
635
637}
638
639
640ESEGMENT::ESEGMENT( wxXmlNode* aSegment, IO_BASE* aIo ) :
641 EAGLE_BASE( aIo )
642{
643 /*
644 * <!ELEMENT segment (pinref | portref | wire | junction | label | probe)*>
645 * <!-- 'pinref' and 'junction' are only valid in a <net> context -->
646 */
647 for( wxXmlNode* child = aSegment->GetChildren(); child; child = child->GetNext() )
648 {
649 if( child->GetName() == "pinref" )
650 pinRefs.emplace_back( std::make_unique<EPINREF>( child, aIo ) );
651 else if( child->GetName() == "portref" )
652 portRefs.emplace_back( std::make_unique<EPORTREF>( child, aIo ) );
653 else if( child->GetName() == "wire" )
654 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
655 else if( child->GetName() == "junction" )
656 junctions.emplace_back( std::make_unique<EJUNCTION>( child, aIo ) );
657 else if( child->GetName() == "label" )
658 labels.emplace_back( std::make_unique<ELABEL>( child, aIo ) );
659 else if( child->GetName() == "probe" )
660 probes.emplace_back( std::make_unique<EPROBE>( child, aIo ) );
661 }
662
664}
665
666
667EBUS::EBUS( wxXmlNode* aBus, IO_BASE* aIo ) :
668 EAGLE_BASE( aIo )
669{
670 /*
671 * <!ELEMENT bus (segment)*>
672 * <!ATTLIST bus
673 * name %String; #REQUIRED
674 * >
675 */
676 name = parseRequiredAttribute<wxString>( aBus, "name" );
677
678 for( wxXmlNode* child = aBus->GetChildren(); child; child = child->GetNext() )
679 {
680 if( child->GetName() == "segment" )
681 segments.emplace_back( std::make_unique<ESEGMENT>( child, aIo ) );
682 }
683
685}
686
687
688EJUNCTION::EJUNCTION( wxXmlNode* aJunction, IO_BASE* aIo ) :
689 EAGLE_BASE( aIo )
690{
691 /*
692 * <!ELEMENT junction EMPTY>
693 * <!ATTLIST junction
694 * x %Coord; #REQUIRED
695 * y %Coord; #REQUIRED
696 * >
697 */
698
699 x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
700 y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
701
703}
704
705
706ELABEL::ELABEL( wxXmlNode* aLabel, IO_BASE* aIo ) :
707 EAGLE_BASE( aIo )
708{
709 /*
710 * <!ELEMENT label EMPTY>
711 * <!ATTLIST label
712 * x %Coord; #REQUIRED
713 * y %Coord; #REQUIRED
714 * size %Dimension; #REQUIRED
715 * layer %Layer; #REQUIRED
716 * font %TextFont; "proportional"
717 * ratio %Int; "8"
718 * rot %Rotation; "R0"
719 * xref %Bool; "no"
720 * align %Align; "bottom-left"
721 * grouprefs IDREFS #IMPLIED
722 * >
723 * <!-- rot: Only 0, 90, 180 or 270 -->
724 * <!-- xref: Only in <net> context -->
725 */
726 x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
727 y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
728 size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
729 layer = parseRequiredAttribute<int>( aLabel, "layer" );
730 font = parseOptionalAttribute<wxString>( aLabel, "font" );
731 ratio = parseOptionalAttribute<int>( aLabel, "ratio" );
732 rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
733 xref = parseOptionalAttribute<bool>( aLabel, "xref" );
734 align = parseOptionalAttribute<wxString>( aLabel, "align" );
735
737}
738
739
740ENET::ENET( wxXmlNode* aNet, IO_BASE* aIo ) :
741 EAGLE_BASE( aIo )
742{
743 /*
744 * <!ELEMENT net (segment)*>
745 * <!ATTLIST net
746 * name %String; #REQUIRED
747 * class %Class; "0"
748 * >
749 */
751 netcode = parseRequiredAttribute<int>( aNet, "class" );
752
753 for( wxXmlNode* segment = aNet->GetChildren(); segment; segment = segment->GetNext() )
754 segments.emplace_back( std::make_unique<ESEGMENT>( segment ) );
755
757}
758
759
760EVIA::EVIA( wxXmlNode* aVia, IO_BASE* aIo ) :
761 EAGLE_BASE( aIo )
762{
763 /*
764 * <!ELEMENT via EMPTY>
765 * <!ATTLIST via
766 * x %Coord; #REQUIRED
767 * y %Coord; #REQUIRED
768 * extent %Extent; #REQUIRED
769 * drill %Dimension; #REQUIRED
770 * diameter %Dimension; "0"
771 * shape %ViaShape; "round"
772 * alwaysstop %Bool; "no"
773 * >
774 */
775
776 x = parseRequiredAttribute<ECOORD>( aVia, "x" );
777 y = parseRequiredAttribute<ECOORD>( aVia, "y" );
778
779 wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
780 sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
781
782 drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
783 diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
784 shape = parseOptionalAttribute<wxString>( aVia, "shape" );
785
787}
788
789
790ECIRCLE::ECIRCLE( wxXmlNode* aCircle, IO_BASE* aIo ) :
791 EAGLE_BASE( aIo )
792{
793 /*
794 * <!ELEMENT circle EMPTY>
795 * <!ATTLIST circle
796 * x %Coord; #REQUIRED
797 * y %Coord; #REQUIRED
798 * radius %Coord; #REQUIRED
799 * width %Dimension; #REQUIRED
800 * layer %Layer; #REQUIRED
801 * >
802 */
803
804 x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
805 y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
806 radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
807 width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
808 layer = parseRequiredAttribute<int>( aCircle, "layer" );
809
811}
812
813
814ERECT::ERECT( wxXmlNode* aRect, IO_BASE* aIo ) :
815 EAGLE_BASE( aIo )
816{
817 /*
818 * <!ELEMENT rectangle EMPTY>
819 * <!ATTLIST rectangle
820 * x1 %Coord; #REQUIRED
821 * y1 %Coord; #REQUIRED
822 * x2 %Coord; #REQUIRED
823 * y2 %Coord; #REQUIRED
824 * layer %Layer; #REQUIRED
825 * rot %Rotation; "R0"
826 * >
827 */
828
829 x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
830 y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
831 x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
832 y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
833 layer = parseRequiredAttribute<int>( aRect, "layer" );
834 rot = parseOptionalAttribute<EROT>( aRect, "rot" );
835
837}
838
839
840EDESCRIPTION::EDESCRIPTION( wxXmlNode* aDescription, IO_BASE* aIo ) :
841 EAGLE_BASE( aIo )
842{
843 /*
844 * <!ELEMENT description (#PCDATA)>
845 * <!ATTLIST description
846 * language %String; "en"
847 * >
848 */
849
850 text = aDescription->GetNodeContent();
851 language = parseOptionalAttribute<wxString>( aDescription, "language" );
852
854}
855
856
857EATTR::EATTR( wxXmlNode* aTree, IO_BASE* aIo ) :
858 EAGLE_BASE( aIo )
859{
860 /*
861 * <!ELEMENT attribute EMPTY>
862 * <!ATTLIST attribute
863 * name %String; #REQUIRED
864 * value %String; #IMPLIED
865 * x %Coord; #IMPLIED
866 * y %Coord; #IMPLIED
867 * size %Dimension; #IMPLIED
868 * layer %Layer; #IMPLIED
869 * font %TextFont; #IMPLIED
870 * ratio %Int; #IMPLIED
871 * rot %Rotation; "R0"
872 * display %AttributeDisplay; "value" -- only in <element> or <instance> context --
873 * constant %Bool; "no" -- only in <device> context --
874 * >
875 */
876
877 name = parseRequiredAttribute<wxString>( aTree, "name" );
878 value = parseOptionalAttribute<wxString>( aTree, "value" );
879
880 x = parseOptionalAttribute<ECOORD>( aTree, "x" );
881 y = parseOptionalAttribute<ECOORD>( aTree, "y" );
882 size = parseOptionalAttribute<ECOORD>( aTree, "size" );
883
884 layer = parseOptionalAttribute<int>( aTree, "layer" );
885 ratio = parseOptionalAttribute<double>( aTree, "ratio" );
886 rot = parseOptionalAttribute<EROT>( aTree, "rot" );
887
888 std::optional<wxString> stemp = parseOptionalAttribute<wxString>( aTree, "display" );
889
890 display = EATTR::VALUE; // "value" is the default
891
892 if( stemp.has_value() )
893 {
894 // (off | value | name | both)
895 if( stemp.value_or( wxEmptyString ) == "off" )
897 else if( stemp.value_or( wxEmptyString ) == "name" )
899 else if( stemp.value_or( wxEmptyString ) == "both" )
901 }
902
903 stemp = parseOptionalAttribute<wxString>( aTree, "align" );
904
906
907 if( stemp.has_value() )
908 align = parseAlignment( stemp.value() );;
909
911}
912
913
914EPINREF::EPINREF( wxXmlNode* aPinRef, IO_BASE* aIo ) :
915 EAGLE_BASE( aIo )
916{
917 /*
918 * <!ELEMENT pinref EMPTY>
919 * <!ATTLIST pinref
920 * part %String; #REQUIRED
921 * gate %String; #REQUIRED
922 * pin %String; #REQUIRED
923 * >
924 */
925 part = parseRequiredAttribute<wxString>( aPinRef, "part" );
926 gate = parseRequiredAttribute<wxString>( aPinRef, "gate" );
927 pin = parseRequiredAttribute<wxString>( aPinRef, "pin" );
928
930}
931
932
933EPORTREF::EPORTREF( wxXmlNode* aPortRef, IO_BASE* aIo ) :
934 EAGLE_BASE( aIo )
935{
936 /*
937 * <!ELEMENT portref EMPTY>
938 * <!ATTLIST portref
939 * moduleinst %String; #REQUIRED
940 * port %String; #REQUIRED
941 * >
942 */
943 moduleinst = parseRequiredAttribute<wxString>( aPortRef, "moduleinst" );
944 port = parseRequiredAttribute<wxString>( aPortRef, "port" );
945
947}
948
949
950EPROBE::EPROBE( wxXmlNode* aProbe, IO_BASE* aIo ) :
951 EAGLE_BASE( aIo )
952{
953 /*
954 * <!ELEMENT probe EMPTY>
955 * <!ATTLIST probe
956 * x %Coord; #REQUIRED
957 * y %Coord; #REQUIRED
958 * size %Dimension; #REQUIRED
959 * layer %Layer; #REQUIRED
960 * font %TextFont; "proportional"
961 * ratio %Int; "8"
962 * rot %Rotation; "R0"
963 * xref %Bool; "no"
964 * grouprefs IDREFS #IMPLIED
965 * >
966 * <!-- rot: Only 0, 90, 180 or 270 -->
967 * <!-- xref: Only in <net> context -->
968 */
969 x = parseRequiredAttribute<ECOORD>( aProbe, "x" );
970 y = parseRequiredAttribute<ECOORD>( aProbe, "y" );
971 size = parseRequiredAttribute<double>( aProbe, "size" );
972 layer = parseRequiredAttribute<int>( aProbe, "layer" );
973 font = parseOptionalAttribute<wxString>( aProbe, "font" );
974 ratio = parseOptionalAttribute<int>( aProbe, "ratio" );
975 rot = parseOptionalAttribute<EROT>( aProbe, "rot" );
976 xref = parseOptionalAttribute<bool>( aProbe, "xref" );
977
979}
980
981
982EDIMENSION::EDIMENSION( wxXmlNode* aDimension, IO_BASE* aIo ) :
983 EAGLE_BASE( aIo )
984{
985 /*
986 * <!ELEMENT dimension EMPTY>
987 * <!ATTLIST dimension
988 * x1 %Coord; #REQUIRED
989 * y1 %Coord; #REQUIRED
990 * x2 %Coord; #REQUIRED
991 * y2 %Coord; #REQUIRED
992 * x3 %Coord; #REQUIRED
993 * y3 %Coord; #REQUIRED
994 * textsize %Coord;
995 * layer %Layer; #REQUIRED
996 * dtype %DimensionType; "parallel"
997 * >
998 */
999
1000 x1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x1" ) );
1001 y1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y1" ) );
1002 x2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x2" ) );
1003 y2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y2" ) );
1004 x3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x3" ) );
1005 y3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y3" ) );
1006 textsize = parseOptionalAttribute<ECOORD>( aDimension, wxT( "textsize" ) );
1007 layer = parseRequiredAttribute<int>( aDimension, wxT( "layer" ) );
1008 dimensionType = parseOptionalAttribute<wxString>( aDimension, wxT( "dtype" ) );
1009
1011}
1012
1013
1014ETEXT::ETEXT( wxXmlNode* aText, IO_BASE* aIo ) :
1015 EAGLE_BASE( aIo )
1016{
1017 /*
1018 <!ELEMENT text (#PCDATA)>
1019 <!ATTLIST text
1020 x %Coord; #REQUIRED
1021 y %Coord; #REQUIRED
1022 size %Dimension; #REQUIRED
1023 layer %Layer; #REQUIRED
1024 font %TextFont; "proportional"
1025 ratio %Int; "8"
1026 rot %Rotation; "R0"
1027 align %Align; "bottom-left"
1028 >
1029 */
1030
1031 text = aText->GetNodeContent();
1032 x = parseRequiredAttribute<ECOORD>( aText, "x" );
1033 y = parseRequiredAttribute<ECOORD>( aText, "y" );
1034 size = parseRequiredAttribute<ECOORD>( aText, "size" );
1035 layer = parseRequiredAttribute<int>( aText, "layer" );
1036
1037 font = parseOptionalAttribute<wxString>( aText, "font" );
1038 ratio = parseOptionalAttribute<double>( aText, "ratio" );
1039 rot = parseOptionalAttribute<EROT>( aText, "rot" );
1040
1041 std::optional<wxString> stemp = parseOptionalAttribute<wxString>( aText, "align" );
1042
1044
1045 if( stemp.has_value() )
1046 align = parseAlignment( stemp.value() );
1047
1049}
1050
1051
1052VECTOR2I ConvertEagleTextSize( const std::optional<wxString>& font, const ECOORD& size )
1053{
1054 VECTOR2I textsize;
1055
1056 if( font.has_value() )
1057 {
1058 const wxString& fontName = font.value();
1059
1060 if( fontName == "vector" )
1061 {
1062 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1063 }
1064 else if( fontName == "fixed" )
1065 {
1066 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
1067 }
1068 else
1069 {
1070 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1071 }
1072 }
1073 else
1074 {
1075 textsize = VECTOR2I( size.ToSchUnits() * 0.85, size.ToSchUnits() );
1076 }
1077
1078 return textsize;
1079}
1080
1081
1083{
1084 return ConvertEagleTextSize( font, size );
1085}
1086
1087
1088EFRAME::EFRAME( wxXmlNode* aFrameNode, IO_BASE* aIo ) :
1089 EAGLE_BASE( aIo )
1090{
1091 /*
1092 * <!ELEMENT frame EMPTY>
1093 * <!ATTLIST frame
1094 * x1 %Coord; #REQUIRED
1095 * y1 %Coord; #REQUIRED
1096 * x2 %Coord; #REQUIRED
1097 * y2 %Coord; #REQUIRED
1098 * columns %Int; #REQUIRED
1099 * rows %Int; #REQUIRED
1100 * layer %Layer; #REQUIRED
1101 * border-left %Bool; "yes"
1102 * border-top %Bool; "yes"
1103 * border-right %Bool; "yes"
1104 * border-bottom %Bool; "yes"
1105 * >
1106 */
1107 border_left = true;
1108 border_top = true;
1109 border_right = true;
1110 border_bottom = true;
1111
1112 x1 = parseRequiredAttribute<ECOORD>( aFrameNode, "x1" );
1113 y1 = parseRequiredAttribute<ECOORD>( aFrameNode, "y1" );
1114 x2 = parseRequiredAttribute<ECOORD>( aFrameNode, "x2" );
1115 y2 = parseRequiredAttribute<ECOORD>( aFrameNode, "y2" );
1116 columns = parseRequiredAttribute<int>( aFrameNode, "columns" );
1117 rows = parseRequiredAttribute<int>( aFrameNode, "rows" );
1118 layer = parseRequiredAttribute<int>( aFrameNode, "layer" );
1119 border_left = parseOptionalAttribute<bool>( aFrameNode, "border-left" );
1120 border_top = parseOptionalAttribute<bool>( aFrameNode, "border-top" );
1121 border_right = parseOptionalAttribute<bool>( aFrameNode, "border-right" );
1122 border_bottom = parseOptionalAttribute<bool>( aFrameNode, "border-bottom" );
1123
1125}
1126
1127
1128EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad, IO_BASE* aIo ) :
1129 EAGLE_BASE( aIo )
1130{
1131 // #REQUIRED says DTD, throw exception if not found
1132 name = parseRequiredAttribute<wxString>( aPad, "name" );
1133 x = parseRequiredAttribute<ECOORD>( aPad, "x" );
1134 y = parseRequiredAttribute<ECOORD>( aPad, "y" );
1135 rot = parseOptionalAttribute<EROT>( aPad, "rot" );
1136 stop = parseOptionalAttribute<bool>( aPad, "stop" );
1137 thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
1138}
1139
1140
1141EPAD::EPAD( wxXmlNode* aPad, IO_BASE* aIo ) :
1142 EPAD_COMMON( aPad, aIo )
1143{
1144 /*
1145 <!ELEMENT pad EMPTY>
1146 <!ATTLIST pad
1147 name %String; #REQUIRED
1148 x %Coord; #REQUIRED
1149 y %Coord; #REQUIRED
1150 drill %Dimension; #REQUIRED
1151 diameter %Dimension; "0"
1152 shape %PadShape; "round"
1153 rot %Rotation; "R0"
1154 stop %Bool; "yes"
1155 thermals %Bool; "yes"
1156 first %Bool; "no"
1157 >
1158 */
1159
1160 // #REQUIRED says DTD, but DipTrace doesn't write it sometimes
1161 drill = parseOptionalAttribute<ECOORD>( aPad, "drill" );
1162
1163 // Optional attributes
1164 diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
1165
1166 std::optional<wxString> s = parseOptionalAttribute<wxString>( aPad, "shape" );
1167
1169
1170 // (square | round | octagon | long | offset)
1171 if( s.has_value() )
1172 {
1173 if( s == "square" )
1175 else if( s == "round" )
1177 else if( s == "octagon" )
1179 else if( s == "long" )
1180 shape = EPAD::LONG;
1181 else if( s == "offset" )
1183 }
1184
1185 first = parseOptionalAttribute<bool>( aPad, "first" );
1186
1188}
1189
1190
1191ESMD::ESMD( wxXmlNode* aSMD, IO_BASE* aIo ) :
1192 EPAD_COMMON( aSMD, aIo )
1193{
1194 /*
1195 <!ATTLIST smd
1196 name %String; #REQUIRED
1197 x %Coord; #REQUIRED
1198 y %Coord; #REQUIRED
1199 dx %Dimension; #REQUIRED
1200 dy %Dimension; #REQUIRED
1201 layer %Layer; #REQUIRED
1202 roundness %Int; "0"
1203 rot %Rotation; "R0"
1204 stop %Bool; "yes"
1205 thermals %Bool; "yes"
1206 cream %Bool; "yes"
1207 >
1208 */
1209
1210 // DTD #REQUIRED, throw exception if not found
1211 dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
1212 dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
1213 layer = parseRequiredAttribute<int>( aSMD, "layer" );
1214
1215 roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
1216 cream = parseOptionalAttribute<bool>( aSMD, "cream" );
1217
1219}
1220
1221
1222EPIN::EPIN( wxXmlNode* aPin, IO_BASE* aIo ) :
1223 EAGLE_BASE( aIo )
1224{
1225 /*
1226 <!ELEMENT pin EMPTY>
1227 <!ATTLIST pin
1228 name %String; #REQUIRED
1229 x %Coord; #REQUIRED
1230 y %Coord; #REQUIRED
1231 visible %PinVisible; "both"
1232 length %PinLength; "long"
1233 direction %PinDirection; "io"
1234 function %PinFunction; "none"
1235 swaplevel %Int; "0"
1236 rot %Rotation; "R0"
1237 >
1238 */
1239
1240 // DTD #REQUIRED, throw exception if not found
1241 name = parseRequiredAttribute<wxString>( aPin, "name" );
1242 x = parseRequiredAttribute<ECOORD>( aPin, "x" );
1243 y = parseRequiredAttribute<ECOORD>( aPin, "y" );
1244
1245 visible = parseOptionalAttribute<wxString>( aPin, "visible" );
1246 length = parseOptionalAttribute<wxString>( aPin, "length" );
1247 direction = parseOptionalAttribute<wxString>( aPin, "direction" );
1248 function = parseOptionalAttribute<wxString>( aPin, "function" );
1249 swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
1250 rot = parseOptionalAttribute<EROT>( aPin, "rot" );
1251
1253}
1254
1255
1256EVERTEX::EVERTEX( wxXmlNode* aVertex, IO_BASE* aIo ) :
1257 EAGLE_BASE( aIo )
1258{
1259 /*
1260 * <!ELEMENT vertex EMPTY>
1261 * <!ATTLIST vertex
1262 * x %Coord; #REQUIRED
1263 * y %Coord; #REQUIRED
1264 * curve %WireCurve; "0" -- the curvature from this vertex to the next one --
1265 * >
1266 */
1267
1268 x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
1269 y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
1270 curve = parseOptionalAttribute<double>( aVertex, "curve" );
1271
1273}
1274
1275
1276EPOLYGON::EPOLYGON( wxXmlNode* aPolygon, IO_BASE* aIo ) :
1277 EAGLE_BASE( aIo )
1278{
1279 /*
1280 * <!ELEMENT polygon (vertex)*>
1281 * <!-- the vertices must define a valid polygon; if the last vertex is the same
1282 * as the first one, it is ignored -->
1283 * <!ATTLIST polygon
1284 * width %Dimension; #REQUIRED
1285 * layer %Layer; #REQUIRED
1286 * spacing %Dimension; #IMPLIED
1287 * pour %PolygonPour; "solid"
1288 * isolate %Dimension; #IMPLIED
1289 * orphans %Bool; "no"
1290 * thermals %Bool; "yes"
1291 * rank %Int; "0"
1292 * grouprefs IDREFS #IMPLIED
1293 * >
1294 * <!-- isolate: Only in <signal> or <package> context -->
1295 * <!-- orphans: Only in <signal> context -->
1296 * <!-- thermals:Only in <signal> context -->
1297 * <!-- rank: 1..6 in <signal> context, 0 or 7 in <package> context -->
1298 */
1299
1300 width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
1301 layer = parseRequiredAttribute<int>( aPolygon, "layer" );
1302
1303 spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
1304 isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
1305 std::optional<wxString> s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
1306
1307 // default pour to solid fill
1309
1310 if( s.has_value() )
1311 {
1312 // (solid | hatch | cutout)
1313 if( s.value() == "hatch" )
1315 else if( s.value() == "cutout" )
1317 }
1318
1319 orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
1320 thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
1321 rank = parseOptionalAttribute<int>( aPolygon, "rank" );
1322
1323 for( wxXmlNode* child = aPolygon->GetChildren(); child; child = child->GetNext() )
1324 {
1325 if( child->GetName() == "vertex" )
1326 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1327 }
1328
1330}
1331
1332
1333ESPLINE::ESPLINE( wxXmlNode* aSpline, IO_BASE* aIo ) :
1334 EAGLE_BASE( aIo )
1335{
1336 /*
1337 * <!ELEMENT spline (vertex)*>
1338 * <!-- Four simple (non-curve) vertices define the control points of a degree-3 spline
1339 * curve -->
1340 * <!ATTLIST spline
1341 * width %Dimension; #REQUIRED
1342 * >
1343 */
1344 width = parseRequiredAttribute<double>( aSpline, "width" );
1345
1346 for( wxXmlNode* child = aSpline->GetChildren(); child; child = child->GetNext() )
1347 {
1348 if( child->GetName() == "vertex" )
1349 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1350 }
1351
1353}
1354
1355
1356EVARIANT::EVARIANT( wxXmlNode* aVariant, IO_BASE* aIo ) :
1357 EAGLE_BASE( aIo )
1358{
1359 /*
1360 * <!ELEMENT variant EMPTY>
1361 * <!ATTLIST variant
1362 * name %String; #REQUIRED
1363 * populate %Bool; "yes"
1364 * value %String; #IMPLIED
1365 * technology %String; #IMPLIED
1366 * >
1367 * <!-- technology: Only in part context -->
1368 */
1369 name = parseRequiredAttribute<wxString>( aVariant, "name" );
1370 populate = parseOptionalAttribute<bool>( aVariant, "populate" );
1371 value = parseOptionalAttribute<wxString>( aVariant, "value" );
1372 technology = parseOptionalAttribute<wxString>( aVariant, "technology" );
1373
1375}
1376
1377
1378EMODEL::EMODEL( wxXmlNode* aModel, IO_BASE* aIo ) :
1379 EAGLE_BASE( aIo )
1380{
1381 /*
1382 * <!ELEMENT model (#PCDATA)>
1383 * <!ATTLIST model
1384 * name %String; #REQUIRED
1385 * >
1386 */
1387 name = parseRequiredAttribute<wxString>( aModel, "name" );
1388 model = aModel->GetNodeContent();
1389
1391}
1392
1393
1394EPINMAP::EPINMAP( wxXmlNode* aPinMap, IO_BASE* aIo ) :
1395 EAGLE_BASE( aIo )
1396{
1397 /*
1398 * <!ELEMENT pinmap EMPTY>
1399 * <!ATTLIST pinmap
1400 * gate %String; #REQUIRED
1401 * pin %String; #REQUIRED
1402 * pinorder %String; #REQUIRED
1403 * >
1404 */
1405 gate = parseRequiredAttribute<wxString>( aPinMap, "gate" );
1406 pin = parseRequiredAttribute<wxString>( aPinMap, "pin" );
1407 pinorder = parseRequiredAttribute<wxString>( aPinMap, "pinorder" );
1408
1410}
1411
1412
1413EPINMAPPING::EPINMAPPING( wxXmlNode* aPinMapping, IO_BASE* aIo ) :
1414 EAGLE_BASE( aIo )
1415{
1416 /*
1417 * <!ELEMENT pinmapping (pinmap+)>
1418 * <!ATTLIST pinmapping
1419 * isusermap %Bool; "no"
1420 * iddevicewide %Bool; "yes"
1421 * spiceprefix %String; ""
1422 * >
1423 */
1424 isusermap = parseOptionalAttribute<bool>( aPinMapping, "isusermap" );
1425 iddevicewide = parseOptionalAttribute<bool>( aPinMapping, "iddevicewide" );
1426 spiceprefix = parseOptionalAttribute<wxString>( aPinMapping, "spiceprefix" );
1427
1428 for( wxXmlNode* child = aPinMapping->GetChildren(); child; child = child->GetNext() )
1429 {
1430 if( child->GetName() == "pinmap" )
1431 pinmaps.emplace_back( std::make_unique<EPINMAP>( child, aIo ) );
1432 }
1433
1435}
1436
1437
1438ESPICE::ESPICE( wxXmlNode* aSpice, IO_BASE* aIo ) :
1439 EAGLE_BASE( aIo )
1440{
1441 /*
1442 * <!ELEMENT spice (pinmapping, model)>
1443 */
1444 pinmapping = std::make_unique<EPINMAPPING>( aSpice );
1445
1446 if( aSpice->GetName() == "model" )
1447 model = std::make_unique<EMODEL>( aSpice );
1448
1450}
1451
1452
1453EHOLE::EHOLE( wxXmlNode* aHole, IO_BASE* aIo ) :
1454 EAGLE_BASE( aIo )
1455{
1456 /*
1457 <!ELEMENT hole EMPTY>
1458 <!ATTLIST hole
1459 x %Coord; #REQUIRED
1460 y %Coord; #REQUIRED
1461 drill %Dimension; #REQUIRED
1462 >
1463 */
1464
1465 // #REQUIRED:
1466 x = parseRequiredAttribute<ECOORD>( aHole, "x" );
1467 y = parseRequiredAttribute<ECOORD>( aHole, "y" );
1468 drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
1469
1471}
1472
1473
1474EELEMENT::EELEMENT( wxXmlNode* aElement, IO_BASE* aIo ) :
1475 EAGLE_BASE( aIo )
1476{
1477 /*
1478 <!ELEMENT element (attribute*, variant*)>
1479 <!ATTLIST element
1480 name %String; #REQUIRED
1481 library %String; #REQUIRED
1482 library_urn %Urn; ""
1483 package %String; #REQUIRED
1484 package3d_urn %Urn; ""
1485 override_package3d_urn %Urn; ""
1486 override_package_urn %Urn; ""
1487 override_locally_modified %Bool; "no"
1488 value %String; #REQUIRED
1489 x %Coord; #REQUIRED
1490 y %Coord; #REQUIRED
1491 locked %Bool; "no"
1492 populate %Bool; "yes"
1493 smashed %Bool; "no"
1494 rot %Rotation; "R0"
1495 grouprefs IDREFS #IMPLIED
1496 >
1497 */
1498
1499 // #REQUIRED
1500 name = parseRequiredAttribute<wxString>( aElement, "name" );
1501 library = parseRequiredAttribute<wxString>( aElement, "library" );
1502 value = parseRequiredAttribute<wxString>( aElement, "value" );
1503 std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
1505 package = wxString::FromUTF8( p.c_str() );
1506
1507 x = parseRequiredAttribute<ECOORD>( aElement, "x" );
1508 y = parseRequiredAttribute<ECOORD>( aElement, "y" );
1509
1510 // optional
1511 library_urn = parseOptionalAttribute<EURN>( aElement, "library_urn" );
1512 locked = parseOptionalAttribute<bool>( aElement, "locked" );
1513 smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
1514 rot = parseOptionalAttribute<EROT>( aElement, "rot" );
1515
1516 for( wxXmlNode* child = aElement->GetChildren(); child; child = child->GetNext() )
1517 {
1518 if( child->GetName() == "attribute" )
1519 {
1520 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1521 attributes[ attr->name ] = std::move( attr );
1522 }
1523 else if( child->GetName() == "variant" )
1524 {
1525 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1526 variants[ variant->name ] = std::move( variant );
1527 }
1528 }
1529
1531}
1532
1533
1534ELAYER::ELAYER( wxXmlNode* aLayer, IO_BASE* aIo ) :
1535 EAGLE_BASE( aIo )
1536{
1537 /*
1538 <!ELEMENT layer EMPTY>
1539 <!ATTLIST layer
1540 number %Layer; #REQUIRED
1541 name %String; #REQUIRED
1542 color %Int; #REQUIRED
1543 fill %Int; #REQUIRED
1544 visible %Bool; "yes"
1545 active %Bool; "yes"
1546 >
1547 */
1548
1549 number = parseRequiredAttribute<int>( aLayer, "number" );
1550 name = parseRequiredAttribute<wxString>( aLayer, "name" );
1551 color = parseRequiredAttribute<int>( aLayer, "color" );
1552 fill = parseRequiredAttribute<int>( aLayer, "fill" );
1553 visible = parseOptionalAttribute<bool>( aLayer, "visible" );
1554 active = parseOptionalAttribute<bool>( aLayer, "active" );
1555
1557}
1558
1559
1560EPART::EPART( wxXmlNode* aPart, IO_BASE* aIo ) :
1561 EAGLE_BASE( aIo )
1562{
1563 /*
1564 * <!ELEMENT part (attribute*, variant*)>
1565 * <!ATTLIST part
1566 * name %String; #REQUIRED
1567 * library %String; #REQUIRED
1568 * deviceset %String; #REQUIRED
1569 * device %String; #REQUIRED
1570 * technology %String; ""
1571 * value %String; #IMPLIED
1572 * >
1573 */
1574 name = parseRequiredAttribute<wxString>( aPart, "name" );
1575 library = parseRequiredAttribute<wxString>( aPart, "library" );
1576 libraryUrn = parseOptionalAttribute<EURN>( aPart, "library_urn" );
1577 deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
1578 device = parseRequiredAttribute<wxString>( aPart, "device" );
1579 package3d_urn = parseOptionalAttribute<wxString>( aPart, "package3d_urn" );
1580 override_package3d_urn = parseOptionalAttribute<wxString>( aPart, "override_package3d_urn" );
1581 override_package_urn = parseOptionalAttribute<wxString>( aPart, "override_package_urn" );
1582 override_locally_modified = parseOptionalAttribute<bool>( aPart, "override_locally_modified" );
1583 technology = parseOptionalAttribute<wxString>( aPart, "technology" );
1584 value = parseOptionalAttribute<wxString>( aPart, "value" );
1585
1586 for( wxXmlNode* child = aPart->GetChildren(); child; child = child->GetNext() )
1587 {
1588 if( child->GetName() == "attribute" )
1589 {
1590 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1591 attributes[ attr->name ] = std::move( attr );
1592 }
1593 else if( child->GetName() == "variant" )
1594 {
1595 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1596 variants[ variant->name ] = std::move( variant );
1597 }
1598 else if( child->GetName() == "spice" )
1599 {
1600 spice = std::make_unique<ESPICE>( child, aIo );
1601 }
1602 }
1603
1605}
1606
1607
1608EINSTANCE::EINSTANCE( wxXmlNode* aInstance, IO_BASE* aIo ) :
1609 EAGLE_BASE( aIo )
1610{
1611 /*
1612 * <!ELEMENT instance (attribute)*>
1613 * <!ATTLIST instance
1614 * part %String; #REQUIRED
1615 * gate %String; #REQUIRED
1616 * x %Coord; #REQUIRED
1617 * y %Coord; #REQUIRED
1618 * smashed %Bool; "no"
1619 * rot %Rotation; "R0"
1620 * >
1621 */
1622 part = parseRequiredAttribute<wxString>( aInstance, "part" );
1623 gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
1624
1625 x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
1626 y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
1627
1628 // optional
1629 smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
1630 rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
1631
1632 for( wxXmlNode* child = aInstance->GetChildren(); child; child = child->GetNext() )
1633 {
1634 if( child->GetName() == "attribute" )
1635 {
1636 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1637 attributes[ attr->name ] = std::move( attr );
1638 }
1639 }
1640
1642}
1643
1644
1645EGATE::EGATE( wxXmlNode* aGate, IO_BASE* aIo ) :
1646 EAGLE_BASE( aIo )
1647{
1648 /*
1649 * <!ELEMENT gate EMPTY>
1650 * <!ATTLIST gate
1651 * name %String; #REQUIRED
1652 * symbol %String; #REQUIRED
1653 * x %Coord; #REQUIRED
1654 * y %Coord; #REQUIRED
1655 * addlevel %GateAddLevel; "next"
1656 * swaplevel %Int; "0"
1657 * >
1658 */
1659
1660 name = parseRequiredAttribute<wxString>( aGate, "name" );
1661 symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
1662
1663 x = parseRequiredAttribute<ECOORD>( aGate, "x" );
1664 y = parseRequiredAttribute<ECOORD>( aGate, "y" );
1665
1666 std::optional<wxString> stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
1667
1669
1670 if( stemp.has_value() )
1671 {
1672 // (off | value | name | both)
1673 if( stemp.value_or( wxEmptyString ) == "must" )
1675 else if( stemp.value_or( wxEmptyString ) == "can" )
1677 else if( stemp.value_or( wxEmptyString ) == "next" )
1679 else if( stemp.value_or( wxEmptyString ) == "request" )
1681 else if( stemp.value_or( wxEmptyString ) == "always" )
1683 }
1684
1685 swaplevel = parseOptionalAttribute<int>( aGate, "swaplevel" );
1686
1688}
1689
1690
1691ECONNECT::ECONNECT( wxXmlNode* aConnect, IO_BASE* aIo ) :
1692 EAGLE_BASE( aIo )
1693{
1694 /*
1695 * <!ELEMENT connect EMPTY>
1696 * <!ATTLIST connect
1697 * gate %String; #REQUIRED
1698 * pin %String; #REQUIRED
1699 * pad %String; #REQUIRED
1700 * route %ContactRoute; "all"
1701 * >
1702 */
1703 gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
1704 pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
1705 pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
1706 contactroute = parseOptionalAttribute<wxString>( aConnect, "contactroute" );
1707
1709}
1710
1711
1712ETECHNOLOGY::ETECHNOLOGY( wxXmlNode* aTechnology, IO_BASE* aIo ) :
1713 EAGLE_BASE( aIo )
1714{
1715 /*
1716 * <!ELEMENT technology (attribute)*>
1717 * <!ATTLIST technology
1718 * name %String; #REQUIRED
1719 * >
1720 */
1721 name = parseRequiredAttribute<wxString>( aTechnology, "name" );
1722
1723 for( wxXmlNode* child = aTechnology->GetChildren(); child; child = child->GetNext() )
1724 {
1725 if( child->GetName() == "attribute" )
1726 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
1727 }
1728
1730}
1731
1732
1733EPACKAGE3DINST::EPACKAGE3DINST( wxXmlNode* aPackage3dInst, IO_BASE* aIo ) :
1734 EAGLE_BASE( aIo )
1735{
1736 /*
1737 * <!ELEMENT package3dinstance EMPTY>
1738 * <!ATTLIST package3dinstance
1739 * package3d_urn %Urn; #REQUIRED
1740 * >
1741 */
1742 package3d_urn = parseRequiredAttribute<wxString>( aPackage3dInst, "package3d_urn" );
1743
1745}
1746
1747
1748EDEVICE::EDEVICE( wxXmlNode* aDevice, IO_BASE* aIo ) :
1749 EAGLE_BASE( aIo )
1750{
1751 /*
1752 * <!ELEMENT device (connects?, package3dinstances?, technologies?)>
1753 * <!ATTLIST device
1754 * name %String; ""
1755 * package %String; #IMPLIED
1756 */
1757 name = parseRequiredAttribute<wxString>( aDevice, "name" );
1758 std::optional<wxString> pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1759
1760 if( pack.has_value() )
1761 {
1762 std::string p( pack.value().c_str() );
1764 package = wxString::FromUTF8( p.c_str() );
1765 }
1766
1767 for( wxXmlNode* child = aDevice->GetChildren(); child; child = child->GetNext() )
1768 {
1769 if( child->GetName() == "connects" )
1770 {
1771 for( wxXmlNode* connect = child->GetChildren(); connect; connect = connect->GetNext() )
1772 {
1773 if( connect->GetName() == "connect" )
1774 connects.emplace_back( std::make_unique<ECONNECT>( connect, aIo ) );
1775 }
1776
1778 }
1779 else if( child->GetName() == "packages3dinstances" )
1780 {
1781 for( wxXmlNode* package3dinst = child->GetChildren(); package3dinst;
1782 package3dinst = package3dinst->GetNext() )
1783 {
1784 if( package3dinst->GetName() == "package3dinstance" )
1785 package3dinstances.emplace_back( std::make_unique<EPACKAGE3DINST>( package3dinst, aIo ) );
1786 }
1787
1789 }
1790 else if( child->GetName() == "technologies" )
1791 {
1792 for( wxXmlNode* technology = child->GetChildren(); technology; technology = technology->GetNext() )
1793 {
1794 if( technology->GetName() == "technology" )
1795 {
1796 std::unique_ptr<ETECHNOLOGY> tmp = std::make_unique<ETECHNOLOGY>( technology, aIo );
1797 technologies[tmp->name] = std::move( tmp );
1798 }
1799 }
1800
1802 }
1803 }
1804
1806}
1807
1808
1809EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet, IO_BASE* aIo ) :
1810 EAGLE_BASE( aIo )
1811{
1812 /*
1813 * <!ELEMENT deviceset (description?, gates, devices, spice?)>
1814 * <!ATTLIST deviceset
1815 * name %String; #REQUIRED
1816 * urn %Urn; ""
1817 * locally_modified %Bool; "no"
1818 * prefix %String; ""
1819 * uservalue %Bool; "no"
1820 * library_version %Int; ""
1821 * library_locally_modified %Bool; "no"
1822 * >
1823 * <!-- library_version and library_locally_modified: Only in managed libraries
1824 * inside boards or schematics -->
1825 */
1826 name = parseRequiredAttribute<wxString>( aDeviceSet, "name" );
1827 urn = parseOptionalAttribute<EURN>( aDeviceSet, "urn" );
1828 locally_modified = parseOptionalAttribute<bool>( aDeviceSet, "locally_modified" );
1829 prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1830 uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1831 library_version = parseOptionalAttribute<int>( aDeviceSet, "library_version" );
1832 library_locally_modified = parseOptionalAttribute<bool>( aDeviceSet, "library_locally_modified" );
1833
1834 for( wxXmlNode* child = aDeviceSet->GetChildren(); child; child = child->GetNext() )
1835 {
1836 if( child->GetName() == "description" )
1837 {
1838 description = std::make_optional<EDESCRIPTION>( child, aIo );
1839 }
1840 else if( child->GetName() == "gates" )
1841 {
1842 for( wxXmlNode* gate = child->GetChildren(); gate; gate = gate->GetNext() )
1843 {
1844 std::unique_ptr<EGATE> tmp = std::make_unique<EGATE>( gate, aIo );
1845 gates[tmp->name] = std::move( tmp );
1846 }
1847
1849 }
1850 else if( child->GetName() == "devices" )
1851 {
1852 for( wxXmlNode* device = child->GetChildren(); device; device = device->GetNext() )
1853 {
1854 std::unique_ptr<EDEVICE> tmp = std::make_unique<EDEVICE>( device, aIo );
1855 devices[tmp->name] = std::move( tmp );
1856 }
1857
1859 }
1860 else if( child->GetName() == "spice" )
1861 {
1862 spice = std::make_optional<ESPICE>( child, aIo );
1863 }
1864 }
1865
1867}
1868
1869
1870ECLASS::ECLASS( wxXmlNode* aClass, IO_BASE* aIo ) :
1871 EAGLE_BASE( aIo )
1872{
1873 /*
1874 * <!ELEMENT class (clearance)*>
1875 * <!ATTLIST class
1876 * number %Class; #REQUIRED
1877 * name %String; #REQUIRED
1878 * width %Dimension; "0"
1879 * drill %Dimension; "0"
1880 * >
1881 */
1882 number = parseRequiredAttribute<wxString>( aClass, "number" );
1883 name = parseRequiredAttribute<wxString>( aClass, "name" );
1884 width = parseOptionalAttribute<ECOORD>( aClass, "width" );
1885 drill = parseOptionalAttribute<ECOORD>( aClass, "drill" );
1886
1887 for( wxXmlNode* child = aClass->GetChildren(); child; child = child->GetNext() )
1888 {
1889 if( child->GetName() == "clearance" )
1890 {
1891 wxString to = parseRequiredAttribute<wxString>( child, "class" );
1892 ECOORD value = parseRequiredAttribute<ECOORD>( child, "value" );
1893
1894 clearanceMap[to] = value;
1895
1897 }
1898 }
1899
1901}
1902
1903
1904EPLAIN::EPLAIN( wxXmlNode* aPlain, IO_BASE* aIo ) :
1905 EAGLE_BASE( aIo )
1906{
1907 /*
1908 * <!ELEMENT plain (polygon | wire | text | dimension | circle | spline | rectangle |
1909 * frame | hole)*>
1910 */
1911 for( wxXmlNode* child = aPlain->GetChildren(); child; child = child->GetNext() )
1912 {
1913 if( child->GetName() == "polygon" )
1914 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
1915 else if( child->GetName() == "wire" )
1916 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
1917 else if( child->GetName() == "text" )
1918 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
1919 else if( child->GetName() == "dimension" )
1920 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
1921 else if( child->GetName() == "circle" )
1922 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
1923 else if( child->GetName() == "spline" )
1924 splines.emplace_back( std::make_unique<ESPLINE>( child, aIo ) );
1925 else if( child->GetName() == "rectangle" )
1926 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
1927 else if( child->GetName() == "frame" )
1928 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
1929 else if( child->GetName() == "hole" )
1930 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
1931 }
1932
1934}
1935
1936
1937EMODULEINST::EMODULEINST( wxXmlNode* aModuleInst, IO_BASE* aIo ) :
1938 EAGLE_BASE( aIo )
1939{
1940 /*
1941 * <!ELEMENT moduleinst (attribute)*>
1942 * <!ATTLIST moduleinst
1943 * name %String; #REQUIRED
1944 * module %String; #REQUIRED
1945 * modulevariant %String; ""
1946 * x %Coord; #REQUIRED
1947 * y %Coord; #REQUIRED
1948 * offset %Int; "0"
1949 * smashed %Bool; "no"
1950 * rot %Rotation; "R0"
1951 * >
1952 * <!-- rot: Only 0, 90, 180 or 270 -->
1953 */
1954 name = parseRequiredAttribute<wxString>( aModuleInst, "name" );
1955 moduleinst = parseRequiredAttribute<wxString>( aModuleInst, "module" );
1956 moduleVariant = parseOptionalAttribute<wxString>( aModuleInst, "modulevariant" );
1957 x = parseRequiredAttribute<ECOORD>( aModuleInst, "x" );
1958 y = parseRequiredAttribute<ECOORD>( aModuleInst, "y" );
1959 offset = parseOptionalAttribute<int>( aModuleInst, "offset" );
1960 smashed = parseOptionalAttribute<bool>( aModuleInst, "smashed" );
1961 rotation = parseOptionalAttribute<EROT>( aModuleInst, "rot" );
1962
1964}
1965
1966
1967ESHEET::ESHEET( wxXmlNode* aSheet, IO_BASE* aIo ) :
1968 EAGLE_BASE( aIo )
1969{
1970 /*
1971 * <!ELEMENT sheet (description?, plain?, moduleinsts?, instances?, busses?, nets?)>
1972 */
1973 for( wxXmlNode* child = aSheet->GetChildren(); child; child = child->GetNext() )
1974 {
1975 if( child->GetName() == "description" )
1976 {
1977 description = std::make_optional<EDESCRIPTION>( child, aIo );
1978 }
1979 else if( child->GetName() == "plain" )
1980 {
1981 plain = std::make_unique<EPLAIN>( child, aIo );
1982 }
1983 else if( child->GetName() == "moduleinsts" )
1984 {
1985 for( wxXmlNode* moduleinst = child->GetChildren(); moduleinst;
1986 moduleinst = moduleinst->GetNext() )
1987 {
1988 if( moduleinst->GetName() == "moduleinst" )
1989 {
1990 std::unique_ptr<EMODULEINST> inst = std::make_unique<EMODULEINST>( moduleinst, aIo );
1991 moduleinsts[ inst->name ] = std::move( inst );
1992 }
1993 }
1994
1996 }
1997 else if( child->GetName() == "instances" )
1998 {
1999 for( wxXmlNode* instance = child->GetChildren(); instance; instance = instance->GetNext() )
2000 {
2001 if( instance->GetName() == "instance" )
2002 instances.emplace_back( std::make_unique<EINSTANCE>( instance, aIo ) );
2003 }
2004
2005 AdvanceProgressPhase();
2006 }
2007 else if( child->GetName() == "busses" )
2008 {
2009 for( wxXmlNode* bus = child->GetChildren(); bus; bus = bus->GetNext() )
2010 {
2011 if( bus->GetName() == "bus" )
2012 busses.emplace_back( std::make_unique<EBUS>( bus, aIo ) );
2013 }
2014
2015 AdvanceProgressPhase();
2016 }
2017 else if( child->GetName() == "nets" )
2018 {
2019 for( wxXmlNode* net = child->GetChildren(); net; net = net->GetNext() )
2020 {
2021 if( net->GetName() == "net" )
2022 nets.emplace_back( std::make_unique<ENET>( net, aIo ) );
2023 }
2024
2025 AdvanceProgressPhase();
2026 }
2027 }
2028
2029 AdvanceProgressPhase();
2030}
2031
2032
2033ESCHEMATIC_GROUP::ESCHEMATIC_GROUP( wxXmlNode* aSchematicGroup, IO_BASE* aIo ) :
2034 EAGLE_BASE( aIo )
2035{
2036 /*
2037 * <!ELEMENT schematic_group (attribute*, description?)>
2038 * <!ATTLIST schematic_group
2039 * name ID #REQUIRED
2040 * selectable %Bool; #IMPLIED
2041 * width %Dimension; #IMPLIED
2042 * titleSize %Dimension; #IMPLIED
2043 * titleFont %TextFont; #IMPLIED
2044 * style %WireStyle; #IMPLIED
2045 * showAnnotations %Bool; #IMPLIED
2046 * layer %Layer; #IMPLIED
2047 * grouprefs IDREFS #IMPLIED
2048 * >
2049 */
2050 name = parseRequiredAttribute<wxString>( aSchematicGroup, "name" );
2051 selectable = parseOptionalAttribute<bool>( aSchematicGroup, "selectable" );
2052 width = parseOptionalAttribute<ECOORD>( aSchematicGroup, "width" );
2053 titleSize = parseOptionalAttribute<ECOORD>( aSchematicGroup, "titleSize" );
2054 titleFont = parseOptionalAttribute<wxString>( aSchematicGroup, "font" );
2055 wireStyle = parseOptionalAttribute<wxString>( aSchematicGroup, "style" );
2056 showAnnotations = parseOptionalAttribute<bool>( aSchematicGroup, "showAnnotations" );
2057 layer = parseOptionalAttribute<int>( aSchematicGroup, "layer" );
2058 grouprefs = parseOptionalAttribute<wxString>( aSchematicGroup, "grouprefs" );
2059
2060 for( wxXmlNode* child = aSchematicGroup->GetChildren(); child; child = child->GetNext() )
2061 {
2062 if( child->GetName() == "description" )
2063 {
2064 description = std::make_optional<EDESCRIPTION>( child, aIo );
2065 }
2066 else if( child->GetName() == "attribute" )
2067 {
2068 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
2069 }
2070 }
2071
2073}
2074
2075
2076EMODULE::EMODULE( wxXmlNode* aModule, IO_BASE* aIo ) :
2077 EAGLE_BASE( aIo )
2078{
2079 /*
2080 * <!ELEMENT module (description?, ports?, variantdefs?, groups?, parts?, sheets?)>
2081 * <!ATTLIST module
2082 * name %String; #REQUIRED
2083 * prefix %String; ""
2084 * dx %Coord; #REQUIRED
2085 * dy %Coord; #REQUIRED
2086 * >
2087 */
2088 name = parseRequiredAttribute<wxString>( aModule, "name" );
2089 prefix = parseOptionalAttribute<wxString>( aModule, "prefix" );
2090 dx = parseRequiredAttribute<ECOORD>( aModule, "dx" );
2091 dy = parseRequiredAttribute<ECOORD>( aModule, "dy" );
2092
2093 for( wxXmlNode* child = aModule->GetChildren(); child; child = child->GetNext() )
2094 {
2095 if( child->GetName() == "description" )
2096 {
2097 description = std::make_optional<EDESCRIPTION>( child, aIo );
2098 }
2099 else if( child->GetName() == "ports" )
2100 {
2101 for( wxXmlNode* port = child->GetChildren(); port; port = port->GetNext() )
2102 {
2103 if( port->GetName() == "port" )
2104 {
2105 std::unique_ptr<EPORT> tmp = std::make_unique<EPORT>( port, aIo );
2106 ports[ tmp->name ] = std::move( tmp );
2107 }
2108 }
2109
2111 }
2112 else if( child->GetName() == "variantdefs" )
2113 {
2114 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2115 variantdef = variantdef->GetNext() )
2116 {
2117 if( variantdef->GetName() == "variantdef" )
2118 {
2119 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2120 aIo );
2121 variantdefs[ tmp->name ] = std::move( tmp );
2122 }
2123 }
2124
2126 }
2127 else if( child->GetName() == "groups" )
2128 {
2129 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2130 {
2131 if( group->GetName() == "schematic_group" )
2132 {
2133 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2134 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2135 groups[ tmp->name ] = std::move( tmp );
2136 }
2137 }
2138
2140 }
2141 else if( child->GetName() == "parts" )
2142 {
2143 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2144 {
2145 if( part->GetName() == "part" )
2146 {
2147 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2148 parts[ tmp->name ] = std::move( tmp );
2149 }
2150 }
2151
2153 }
2154 else if( child->GetName() == "sheets" )
2155 {
2156 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2157 {
2158 if( sheet->GetName() == "sheet" )
2159 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2160 }
2161
2163 }
2164 }
2165
2167}
2168
2169
2170EPORT::EPORT( wxXmlNode* aPort, IO_BASE* aIo ) :
2171 EAGLE_BASE( aIo )
2172{
2173 /*
2174 * <!ELEMENT port EMPTY>
2175 * <!ATTLIST port
2176 * name %String; #REQUIRED
2177 * side %Int; #REQUIRED
2178 * coord %Coord; #REQUIRED
2179 * direction %PortDirection; "io"
2180 * >
2181 */
2182 name = parseRequiredAttribute<wxString>( aPort, "name" );
2183 side = parseRequiredAttribute<wxString>( aPort, "side" );
2184 coord = parseRequiredAttribute<ECOORD>( aPort, "coord" );
2185 direction = parseOptionalAttribute<wxString>( aPort, "direction" );
2186
2188}
2189
2190
2191EVARIANTDEF::EVARIANTDEF( wxXmlNode* aVariantDef, IO_BASE* aIo ) :
2192 EAGLE_BASE( aIo )
2193{
2194 /*
2195 * <!ELEMENT variantdef EMPTY>
2196 * <!ATTLIST variantdef
2197 * name %String; #REQUIRED
2198 * current %Bool; "no"
2199 * >
2200 */
2201 name = parseRequiredAttribute<wxString>( aVariantDef, "name" );
2202 current = parseOptionalAttribute<bool>( aVariantDef, "current" );
2203
2205}
2206
2207
2208ENOTE::ENOTE( wxXmlNode* aNote, IO_BASE* aIo ) :
2209 EAGLE_BASE( aIo )
2210{
2211 /*
2212 * <!ELEMENT note (#PCDATA)>
2213 * <!ATTLIST note
2214 * version %Real; #REQUIRED
2215 * severity %Severity; #REQUIRED
2216 * >
2217 * <!-- version: The EAGLE program version that introduced this compatibility note -->
2218 */
2219 version = parseRequiredAttribute<double>( aNote, "version" );
2220 severity = parseRequiredAttribute<wxString>( aNote, "severity" );
2221
2222 note = aNote->GetNodeContent();
2223
2225}
2226
2227
2228ECOMPATIBILITY::ECOMPATIBILITY( wxXmlNode* aCompatibility, IO_BASE* aIo ) :
2229 EAGLE_BASE( aIo )
2230{
2231 /*
2232 * <!ELEMENT compatibility (note)*>
2233 */
2234 for( wxXmlNode* child = aCompatibility->GetNext(); child; child = child->GetNext() )
2235 {
2236 if( child->GetName() == "note" )
2237 notes.emplace_back( std::make_unique<ENOTE>( child ) );
2238 }
2239
2241}
2242
2243
2244ESETTING::ESETTING( wxXmlNode* aSetting, IO_BASE* aIo ) :
2245 EAGLE_BASE( aIo )
2246{
2247 /*
2248 * <!ELEMENT setting EMPTY>
2249 * <!ATTLIST setting
2250 * alwaysvectorfont %Bool; #IMPLIED
2251 * verticaltext %VerticalText; "up"
2252 * keepoldvectorfont %Bool; "no"
2253 * >
2254 */
2255 alwaysvectorfont = parseOptionalAttribute<bool>( aSetting, "alwaysvectorfont" );
2256 verticaltext = parseOptionalAttribute<wxString>( aSetting, "verticaltext" );
2257 keepoldvectorfont = parseOptionalAttribute<bool>( aSetting, "keepoldvectorfont" );
2258
2260}
2261
2262
2263EGRID::EGRID( wxXmlNode* aGrid, IO_BASE* aIo ) :
2264 EAGLE_BASE( aIo )
2265{
2266 /*
2267 * <!ELEMENT grid EMPTY>
2268 * <!ATTLIST grid
2269 * distance %Real; #IMPLIED
2270 * unitdist %GridUnit; #IMPLIED
2271 * unit %GridUnit; #IMPLIED
2272 * style %GridStyle; "lines"
2273 * multiple %Int; "1"
2274 * display %Bool; "no"
2275 * altdistance %Real; #IMPLIED
2276 * altunitdist %GridUnit; #IMPLIED
2277 * altunit %GridUnit; #IMPLIED
2278 * >
2279 */
2280 distance = parseOptionalAttribute<double>( aGrid, "distance" );
2281 unitdist = parseOptionalAttribute<wxString>( aGrid, "unitdist" );
2282 unit = parseOptionalAttribute<wxString>( aGrid, "unit" );
2283 style = parseOptionalAttribute<wxString>( aGrid, "style" );
2284 multiple = parseOptionalAttribute<int>( aGrid, "multiple" );
2285 display = parseOptionalAttribute<bool>( aGrid, "display" );
2286 altdistance = parseOptionalAttribute<double>( aGrid, "altdistance" );
2287 altunitdist = parseOptionalAttribute<wxString>( aGrid, "altunitdist" );
2288 altunit = parseOptionalAttribute<wxString>( aGrid, "altunit" );
2289
2291}
2292
2293
2294EFILTER::EFILTER( wxXmlNode* aFilter, IO_BASE* aIo ) :
2295 EAGLE_BASE( aIo )
2296{
2297 /*
2298 * <!ELEMENT filter EMPTY>
2299 * <!ATTLIST filter
2300 * name %String; #REQUIRED
2301 * expression %String; #REQUIRED
2302 * >
2303 */
2304 name = parseRequiredAttribute<wxString>( aFilter, "name" );
2305 expression = parseRequiredAttribute<wxString>( aFilter, "expression" );
2306
2308};
2309
2310
2311EPACKAGE::EPACKAGE( wxXmlNode* aPackage, IO_BASE* aIo ) :
2312 EAGLE_BASE( aIo )
2313{
2314 /*
2315 * <!ELEMENT package (description?, (polygon | wire | text | dimension | circle |
2316 * rectangle | frame | hole | pad | smd)*)>
2317 * <!ATTLIST package
2318 * name %String; #REQUIRED
2319 * urn %Urn; ""
2320 * locally_modified %Bool; "no"
2321 * library_version %Int; ""
2322 * library_locally_modified %Bool; "no"
2323 * >
2324 * <!-- library_version and library_locally_modified: Only in managed libraries
2325 * inside boards or schematics -->
2326 */
2327 name = parseRequiredAttribute<wxString>( aPackage, "name" );
2328 urn = parseOptionalAttribute<EURN>( aPackage, "urn" );
2329 locally_modified = parseOptionalAttribute<bool>( aPackage, "locally_modified" );
2330 library_version = parseOptionalAttribute<int>( aPackage, "library_version" );
2331 library_locally_modified = parseOptionalAttribute<bool>( aPackage, "library_locally_modified" );
2332
2333 for( wxXmlNode* child = aPackage->GetChildren(); child; child = child->GetNext() )
2334 {
2335 if( child->GetName() == "description" )
2336 {
2337 description = std::make_optional<EDESCRIPTION>( child, aIo );
2338 }
2339 else if( child->GetName() == "polygon" )
2340 {
2341 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2342 }
2343 else if( child->GetName() == "wire" )
2344 {
2345 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2346 }
2347 else if( child->GetName() == "text" )
2348 {
2349 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2350 }
2351 else if( child->GetName() == "dimension" )
2352 {
2353 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2354 }
2355 else if( child->GetName() == "circle" )
2356 {
2357 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2358 }
2359 else if( child->GetName() == "rectangle" )
2360 {
2361 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2362 }
2363 else if( child->GetName() == "frame" )
2364 {
2365 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2366 }
2367 else if( child->GetName() == "hole" )
2368 {
2369 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
2370 }
2371 else if( child->GetName() == "pad" )
2372 {
2373 thtpads.emplace_back( std::make_unique<EPAD>( child, aIo ) );
2374 }
2375 else if( child->GetName() == "smd" )
2376 {
2377 smdpads.emplace_back( std::make_unique<ESMD>( child, aIo ) );
2378 }
2379 }
2380
2382}
2383
2384
2385EPACKAGEINSTANCE::EPACKAGEINSTANCE( wxXmlNode* aPackageInstance, IO_BASE* aIo ) :
2386 EAGLE_BASE( aIo )
2387{
2388 /*
2389 * <!ELEMENT packageinstance EMPTY>
2390 * <!ATTLIST packageinstance
2391 * name %String; #REQUIRED
2392 * >
2393 */
2394 name = parseRequiredAttribute<wxString>( aPackageInstance, "name" );
2395
2397}
2398
2399
2400EPACKAGE3D::EPACKAGE3D( wxXmlNode* aPackage3d, IO_BASE* aIo ) :
2401 EAGLE_BASE( aIo )
2402{
2403 /*
2404 * <!ELEMENT package3d (description?, packageinstances?)>
2405 * <!ATTLIST package3d
2406 * name %String; ""
2407 * urn %Urn; #REQUIRED
2408 * type %Package3dType; #REQUIRED
2409 * library_version %Int; ""
2410 * library_locally_modified %Bool; "no"
2411 * >
2412 * <!-- library_version and library_locally_modified: Only in managed libraries
2413 * inside boards or schematics -->
2414 */
2415 name = parseRequiredAttribute<wxString>( aPackage3d, "name" );
2416 urn = parseRequiredAttribute<wxString>( aPackage3d, "urn" );
2417 type = parseRequiredAttribute<wxString>( aPackage3d, "type" );
2418 library_version = parseOptionalAttribute<int>( aPackage3d, "library_version" );
2419 library_locally_modified = parseOptionalAttribute<bool>( aPackage3d, "library_locally_modified" );
2420
2421 for( wxXmlNode* child = aPackage3d->GetChildren(); child; child = child->GetNext() )
2422 {
2423 if( child->GetName() == "description" )
2424 {
2425 description = std::make_optional<EDESCRIPTION>( child, aIo );
2426 }
2427 else if( child->GetName() == "packageinstances" )
2428 {
2429 for( wxXmlNode* instance = child->GetChildren(); instance;
2430 instance = instance->GetNext() )
2431 packageinstances.emplace_back( std::make_unique<EPACKAGEINSTANCE>( instance, aIo ) );
2432
2434 }
2435 }
2436
2438}
2439
2440
2441ESYMBOL::ESYMBOL( wxXmlNode* aSymbol, IO_BASE* aIo ) :
2442 EAGLE_BASE( aIo )
2443{
2444 /*
2445 * <!ELEMENT symbol (description?, (polygon | wire | text | dimension | pin | circle |
2446 * rectangle | frame)*)>
2447 * <!ATTLIST symbol
2448 * name %String; #REQUIRED
2449 * urn %Urn; ""
2450 * locally_modified %Bool; "no"
2451 * library_version %Int; ""
2452 * library_locally_modified %Bool; "no"
2453 * >
2454 * <!-- library_version and library_locally_modified: Only in managed libraries
2455 * inside boards or schematics -->
2456 */
2457
2458 name = parseRequiredAttribute<wxString>( aSymbol, "name" );
2459 urn = parseOptionalAttribute<EURN>( aSymbol, "urn" );
2460 locally_modified = parseOptionalAttribute<bool>( aSymbol, "locally_modified" );
2461 library_version = parseOptionalAttribute<int>( aSymbol, "library_version" );
2462 library_locally_modified = parseOptionalAttribute<bool>( aSymbol, "library_locally_modified" );
2463
2464 for( wxXmlNode* child = aSymbol->GetChildren(); child; child = child->GetNext() )
2465 {
2466 if( child->GetName() == "description" )
2467 {
2468 description = std::make_optional<EDESCRIPTION>( child, aIo );
2469 }
2470 else if( child->GetName() == "polygon" )
2471 {
2472 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2473 }
2474 else if( child->GetName() == "wire" )
2475 {
2476 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2477 }
2478 else if( child->GetName() == "text" )
2479 {
2480 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2481 }
2482 else if( child->GetName() == "dimension" )
2483 {
2484 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2485 }
2486 else if( child->GetName() == "pin" )
2487 {
2488 pins.emplace_back( std::make_unique<EPIN>( child, aIo ) );
2489 }
2490 else if( child->GetName() == "circle" )
2491 {
2492 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2493 }
2494 else if( child->GetName() == "rectangle" )
2495 {
2496 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2497 }
2498 else if( child->GetName() == "frame" )
2499 {
2500 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2501 }
2502 }
2503
2505}
2506
2507
2508ELIBRARY::ELIBRARY( wxXmlNode* aLibrary, IO_BASE* aIo ) :
2509 EAGLE_BASE( aIo )
2510{
2511 /*
2512 * <!ELEMENT library (description?, packages?, packages3d?, symbols?, devicesets?)>
2513 * <!ATTLIST library
2514 * name %String; #REQUIRED
2515 * urn %Urn; ""
2516 * >
2517 * <!-- name: Only in libraries used inside boards or schematics -->
2518 * <!-- urn: Only in online libraries used inside boards or schematics -->
2519 */
2520
2521 // The name and urn attributes are only valid in schematic and board files.
2522 wxString parentNodeName;
2523
2524 if( aLibrary->GetParent() )
2525 parentNodeName = aLibrary->GetParent()->GetName();
2526
2527 if( parentNodeName == "libraries" )
2528 {
2529 name = parseRequiredAttribute<wxString>( aLibrary, "name" );
2530 urn = parseOptionalAttribute<EURN>( aLibrary, "urn" );
2531 }
2532
2533 for( wxXmlNode* child = aLibrary->GetChildren(); child; child = child->GetNext() )
2534 {
2535 if( child->GetName() == "description" )
2536 {
2537 description = std::make_optional<EDESCRIPTION>( child, aIo );
2538 }
2539 else if( child->GetName() == "packages" )
2540 {
2541 for( wxXmlNode* package = child->GetChildren(); package; package = package->GetNext() )
2542 {
2543 if( package->GetName() == "package" )
2544 {
2545 std::unique_ptr<EPACKAGE> tmp = std::make_unique<EPACKAGE>( package, aIo );
2546 packages[ tmp->name ] = std::move( tmp );
2547 }
2548 }
2549
2551 }
2552 else if( child->GetName() == "packages3d" )
2553 {
2554 for( wxXmlNode* package3d = child->GetChildren(); package3d;
2555 package3d = package3d->GetNext() )
2556 {
2557 if( package3d->GetName() == "package3d" )
2558 {
2559 std::unique_ptr<EPACKAGE3D> tmp = std::make_unique<EPACKAGE3D>( package3d,
2560 aIo );
2561 packages3d[ tmp->name ] = std::move( tmp );
2562 }
2563 }
2564
2565 AdvanceProgressPhase();
2566 }
2567 else if( child->GetName() == "symbols" )
2568 {
2569 for( wxXmlNode* symbol = child->GetChildren(); symbol; symbol = symbol->GetNext() )
2570 {
2571 if( symbol->GetName() == "symbol" )
2572 {
2573 std::unique_ptr<ESYMBOL> tmp = std::make_unique<ESYMBOL>( symbol, aIo );
2574 symbols[ tmp->name ] = std::move( tmp );
2575 }
2576 }
2577
2578 AdvanceProgressPhase();
2579 }
2580 else if( child->GetName() == "devicesets" )
2581 {
2582 for( wxXmlNode* deviceset = child->GetChildren(); deviceset;
2583 deviceset = deviceset->GetNext() )
2584 {
2585 if( deviceset->GetName() == "deviceset" )
2586 {
2587 std::unique_ptr<EDEVICE_SET> tmp = std::make_unique<EDEVICE_SET>( deviceset,
2588 aIo );
2589 devicesets[ tmp->name ] = std::move( tmp );
2590 }
2591 }
2592
2593 AdvanceProgressPhase();
2594 }
2595 }
2596
2597 AdvanceProgressPhase();
2598}
2599
2600
2601wxString ELIBRARY::GetName() const
2602{
2603 wxString libName = name;
2604
2605 // Use the name when no library urn exists.
2606 if( !urn.has_value() )
2607 return libName;
2608
2609 // Suffix the library name with the urn library identifier. Eagle schematics can have
2610 // mulitple libraries with the same name. The urn library identifier is used to prevent
2611 // library name clashes.
2612 if( urn.value().IsValid() )
2613 libName += wxS( "_" ) + urn.value().assetId;
2614
2615 return libName;
2616}
2617
2618
2619EAPPROVED::EAPPROVED( wxXmlNode* aApproved, IO_BASE* aIo ) :
2620 EAGLE_BASE( aIo )
2621{
2622 /*
2623 * <!ELEMENT approved EMPTY>
2624 * <!ATTLIST approved
2625 * hash %String; #REQUIRED
2626 * >
2627 */
2628 hash = parseRequiredAttribute<wxString>( aApproved, "hash" );
2629
2631}
2632
2633
2634ESCHEMATIC::ESCHEMATIC( wxXmlNode* aSchematic, IO_BASE* aIo ) :
2635 EAGLE_BASE( aIo )
2636{
2637 /*
2638 * <!ELEMENT schematic (description?, libraries?, attributes?, variantdefs?, classes?,
2639 * modules?, groups?, parts?, sheets?, errors?)>
2640 * <!ATTLIST schematic
2641 * xreflabel %String; #IMPLIED
2642 * xrefpart %String; #IMPLIED
2643 * >
2644 */
2645 xreflabel = parseOptionalAttribute<wxString>( aSchematic, "xreflabel" );
2646 xrefpart = parseOptionalAttribute<wxString>( aSchematic, "xrefpart" );
2647
2648 for( wxXmlNode* child = aSchematic->GetChildren(); child; child = child->GetNext() )
2649 {
2650 if( child->GetName() == "description" )
2651 {
2652 description = std::make_optional<EDESCRIPTION>( child, aIo );
2653 }
2654 else if( child->GetName() == "libraries" )
2655 {
2656 for( wxXmlNode* library = child->GetChildren(); library; library = library->GetNext() )
2657 {
2658 if( library->GetName() == "library" )
2659 {
2660 std::unique_ptr<ELIBRARY> tmp = std::make_unique<ELIBRARY>( library, aIo );
2661
2662 wxString libName = tmp->GetName();
2663
2664 // Prevent duplicate library names. This should only happen if the Eagle
2665 // file has an invalid format.
2666 if( libraries.find( libName ) != libraries.end() )
2667 {
2668 wxString uniqueName;
2669 std::set<wxString> usedNames;
2670
2671 for( const auto& [setName, setLibrary] : libraries )
2672 usedNames.emplace( setName );
2673
2674 // One of _1.._N+1 is always free (pigeonhole); the bound also
2675 // stops an infinite loop on malformed names (e.g. embedded
2676 // NULs) whose suffixed variants all compare equal.
2677 for( int i = 1; i <= (int) usedNames.size() + 1; i++ )
2678 {
2679 uniqueName.Format( wxS( "%s_%d" ), libName, i );
2680
2681 if( usedNames.find( uniqueName ) == usedNames.end() )
2682 break;
2683 }
2684
2685 libName = uniqueName;
2686 }
2687
2688 libraries[ libName ] = std::move( tmp );
2689 }
2690 }
2691
2693 }
2694 else if( child->GetName() == "attributes" )
2695 {
2696 for( wxXmlNode* attribute = child->GetChildren(); attribute;
2697 attribute = attribute->GetNext() )
2698 {
2699 if( attribute->GetName() == "attribute" )
2700 {
2701 std::unique_ptr<EATTR> tmp = std::make_unique<EATTR>( attribute, aIo );
2702 attributes[ tmp->name ] = std::move( tmp );
2703 }
2704 }
2705
2707 }
2708 else if( child->GetName() == "variantdefs" )
2709 {
2710 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2711 variantdef = variantdef->GetNext() )
2712 {
2713 if( variantdef->GetName() == "variantdef" )
2714 {
2715 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2716 aIo );
2717 variantdefs[ tmp->name ] = std::move( tmp );
2718 }
2719 }
2720
2722 }
2723 else if( child->GetName() == "classes" )
2724 {
2725 for( wxXmlNode* eclass = child->GetChildren(); eclass; eclass = eclass->GetNext() )
2726 {
2727 if( eclass->GetName() == "class" )
2728 {
2729 std::unique_ptr<ECLASS> tmp = std::make_unique<ECLASS>( eclass, aIo );
2730 classes[ tmp->number ] = std::move( tmp );
2731 }
2732 }
2733
2735 }
2736 else if( child->GetName() == "modules" )
2737 {
2738 for( wxXmlNode* mod = child->GetChildren(); mod; mod = mod->GetNext() )
2739 {
2740 if( mod->GetName() == "module" )
2741 {
2742 std::unique_ptr<EMODULE> tmp = std::make_unique<EMODULE>( mod, aIo );
2743 modules[ tmp->name ] = std::move( tmp );
2744 }
2745 }
2746
2748 }
2749 else if( child->GetName() == "groups" )
2750 {
2751 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2752 {
2753 if( group->GetName() == "schematic_group" )
2754 {
2755 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2756 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2757 groups[ tmp->name ] = std::move( tmp );
2758 }
2759 }
2760
2762 }
2763 else if( child->GetName() == "parts" )
2764 {
2765 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2766 {
2767 if( part->GetName() == "part" )
2768 {
2769 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2770 parts[ tmp->name ] = std::move( tmp );
2771 }
2772 }
2773
2775 }
2776 else if( child->GetName() == "sheets" )
2777 {
2778 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2779 {
2780 if( sheet->GetName() == "sheet" )
2781 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2782 }
2783
2785 }
2786 else if( child->GetName() == "errors" )
2787 {
2788 for( wxXmlNode* error = child->GetChildren(); error; error = error->GetNext() )
2789 {
2790 if( error->GetName() == "approved" )
2791 errors.emplace_back( std::make_unique<EAPPROVED>( error, aIo ) );
2792 }
2793
2795 }
2796 }
2797
2799}
2800
2801
2802EDRAWING::EDRAWING( wxXmlNode* aDrawing, IO_BASE* aIo ) :
2803 EAGLE_BASE( aIo )
2804{
2805 /*
2806 * <!ELEMENT drawing (settings?, grid?, filters?, layers, (library | schematic | board))>
2807 */
2808 for( wxXmlNode* child = aDrawing->GetChildren(); child; child = child->GetNext() )
2809 {
2810 if( child->GetName() == "settings" )
2811 {
2812 for( wxXmlNode* setting = child->GetChildren(); setting; setting = setting->GetNext() )
2813 settings.emplace_back( std::make_unique<ESETTING>( setting, aIo ) );
2814
2815 AdvanceProgressPhase();
2816 }
2817 else if( child->GetName() == "grid" )
2818 {
2819 grid = std::make_optional<EGRID>( child, aIo );
2820 }
2821 else if( child->GetName() == "filters" )
2822 {
2823 for( wxXmlNode* filter = child->GetChildren(); filter; filter = filter->GetNext() )
2824 {
2825 if( filter->GetName() == "filter" )
2826 filters.emplace_back( std::make_unique<EFILTER>( filter, aIo ) );
2827 }
2828
2830 }
2831 else if( child->GetName() == "layers" )
2832 {
2833 for( wxXmlNode* layer = child->GetChildren(); layer; layer = layer->GetNext() )
2834 {
2835 if( layer->GetName() == "layer" )
2836 layers.emplace_back( std::make_unique<ELAYER>( layer, aIo ) );
2837 }
2838
2839 AdvanceProgressPhase();
2840 }
2841 else if( child->GetName() == "schematic" )
2842 {
2843 schematic = std::make_optional<ESCHEMATIC>( child, aIo );
2844 }
2845 else if( child->GetName() == "library" )
2846 {
2847 library = std::make_optional<ELIBRARY>( child, aIo );
2848 }
2849 }
2850
2851 // std::optional<std::unique_ptr<EBOARD>> board;
2852
2853 AdvanceProgressPhase();
2854}
2855
2856
2857EAGLE_DOC::EAGLE_DOC( wxXmlNode* aEagleDoc, IO_BASE* aIo ) :
2858 EAGLE_BASE( aIo )
2859{
2860 /*
2861 * <!ELEMENT eagle (compatibility?, drawing, compatibility?)>
2862 * <!ATTLIST eagle
2863 * version %Real; #REQUIRED
2864 * >
2865 * <!-- version: The EAGLE program version that generated this file, in the
2866 * form V.RR -->
2867 */
2868
2869 version = parseRequiredAttribute<wxString>( aEagleDoc, "version" );
2870
2871 for( wxXmlNode* child = aEagleDoc->GetChildren(); child; child = child->GetNext() )
2872 {
2873 if( child->GetName() == "compitibility" )
2874 compatibility = std::make_optional<ECOMPATIBILITY>( child, aIo );
2875 else if( child->GetName() == "drawing" )
2876 drawing = std::make_unique<EDRAWING>( child, aIo );
2877 }
2878
2880}
A small class to help profiling.
Definition profile.h:46
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:86
double msecs(bool aSinceLast=false)
Definition profile.h:147
EURN Convert< EURN >(const wxString &aUrn)
std::string Convert< std::string >(const wxString &aValue)
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)
Translates Eagle special characters to their counterparts in KiCad.
wxString interpretText(const wxString &aText)
Interprets special characters in Eagle text and converts them to KiCAD notation.
bool substituteVariable(wxString *aText)
Translates Eagle special text reference to a KiCad variable reference.
constexpr auto DEFAULT_ALIGNMENT
int Convert< int >(const wxString &aValue)
wxString Convert< wxString >(const wxString &aValue)
size_t GetNodeCount(const wxXmlNode *aNode)
Fetch the number of XML nodes within aNode.
std::optional< T > parseOptionalAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Parse option aAttribute of the XML node aNode.
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)
VECTOR2I ConvertEagleTextSize(const std::optional< wxString > &font, const ECOORD &size)
Converts Eagle's text size to KiCad text size depending on the font used.
VECTOR2I ConvertArcCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC.
wxString convertDescription(wxString aDescr)
Converts Eagle's HTML description into KiCad description format.
T Convert(const wxString &aValue)
Convert a wxString to a generic type T.
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
VECTOR2I ConvertEagleTextSize(const std::optional< wxString > &font, const ECOORD &size)
Converts Eagle's text size to KiCad text size depending on the font used.
#define _(s)
const wxChar *const traceEagleIo
#define THROW_IO_ERRORF(msg,...)
SEVERITY
wxString RemoveHTMLTags(const wxString &aInput)
Removes HTML tags from a string.
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.
EAGLE_BASE(IO_BASE *aIo=nullptr)
IO_BASE * io
void AdvanceProgressPhase()
void Report(const wxString &aMsg, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Send a message to the IO_BASE REPORTER object if one exists.
EAGLE_DOC(wxXmlNode *aEagleDoc, IO_BASE *aIo=nullptr)
std::optional< ECOMPATIBILITY > compatibility
wxString version
The Eagle XML file version.
std::unique_ptr< EDRAWING > drawing
EAPPROVED(wxXmlNode *aApproved, IO_BASE *aIo=nullptr)
wxString hash
std::optional< int > layer
std::optional< ECOORD > y
std::optional< wxString > value
wxString name
std::optional< ECOORD > size
std::optional< int > align
std::optional< EROT > rot
std::optional< double > ratio
std::optional< int > display
std::optional< ECOORD > x
EBUS(wxXmlNode *aBus, IO_BASE *aIo=nullptr)
wxString name
std::vector< std::unique_ptr< ESEGMENT > > segments
ECOORD x
ECOORD radius
ECOORD y
ECIRCLE(wxXmlNode *aCircle, IO_BASE *aIo=nullptr)
ECOORD width
wxString number
std::optional< ECOORD > width
std::map< wxString, ECOORD > clearanceMap
std::optional< ECOORD > drill
ECLASS(wxXmlNode *aClass, IO_BASE *aIo=nullptr)
wxString name
ECOMPATIBILITY(wxXmlNode *aCompatibility, IO_BASE *aIo=nullptr)
std::optional< wxString > contactroute
wxString pad
ECONNECT(wxXmlNode *aConnect, IO_BASE *aIo=nullptr)
wxString gate
wxString pin
@ EU_NM
nanometers
@ EU_MM
millimeters
@ EU_MIL
mils/thous
@ EU_INCH
inches
int ToSchUnits() const
long long int value
Value expressed in nanometers.
static long long int ConvertToNm(int aValue, enum EAGLE_UNIT aUnit)
Converts a size expressed in a certain unit to nanometers.
wxString text
std::optional< wxString > language
EDESCRIPTION(wxXmlNode *aDescription, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< EDEVICE > > devices
std::optional< wxString > prefix
std::optional< EURN > urn
std::optional< EDESCRIPTION > description
EDEVICE_SET(wxXmlNode *aDeviceSet, IO_BASE *aIo=nullptr)
std::optional< bool > locally_modified
std::map< wxString, std::unique_ptr< EGATE > > gates
std::optional< int > library_version
std::optional< ESPICE > spice
std::optional< bool > uservalue
std::optional< bool > library_locally_modified
wxString name
wxString name
std::vector< std::unique_ptr< EPACKAGE3DINST > > package3dinstances
std::vector< std::unique_ptr< ECONNECT > > connects
EDEVICE(wxXmlNode *aDevice, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< ETECHNOLOGY > > technologies
std::optional< wxString > dimensionType
std::optional< ECOORD > textsize
EDIMENSION(wxXmlNode *aDimension, IO_BASE *aIo=nullptr)
EDRAWING(wxXmlNode *aDrawing, IO_BASE *aIo=nullptr)
EELEMENT(wxXmlNode *aElement, IO_BASE *aIo=nullptr)
wxString name
std::optional< bool > locked
std::optional< bool > smashed
wxString library
std::optional< EROT > rot
wxString value
std::optional< EURN > library_urn
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::map< wxString, std::unique_ptr< EVARIANT > > variants
wxString expression
EFILTER(wxXmlNode *aGrid, IO_BASE *aIo=nullptr)
wxString name
std::optional< bool > border_bottom
ECOORD x1
std::optional< bool > border_top
ECOORD y1
int columns
ECOORD y2
EFRAME(wxXmlNode *aFrameNode, IO_BASE *aIo=nullptr)
std::optional< bool > border_left
std::optional< bool > border_right
ECOORD x2
ECOORD x
ECOORD y
wxString symbol
std::optional< int > addlevel
std::optional< int > swaplevel
EGATE(wxXmlNode *aGate, IO_BASE *aIo=nullptr)
wxString name
std::optional< double > distance
std::optional< int > multiple
std::optional< bool > display
std::optional< wxString > altunitdist
EGRID(wxXmlNode *aGrid, IO_BASE *aIo=nullptr)
std::optional< wxString > unit
std::optional< wxString > altunit
std::optional< double > altdistance
std::optional< wxString > unitdist
std::optional< wxString > style
ECOORD y
ECOORD drill
ECOORD x
EHOLE(wxXmlNode *aHole, IO_BASE *aIo=nullptr)
std::optional< EROT > rot
wxString part
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::optional< bool > smashed
wxString gate
EINSTANCE(wxXmlNode *aInstance, IO_BASE *aIo=nullptr)
EJUNCTION(wxXmlNode *aJunction, IO_BASE *aIo=nullptr)
std::optional< EROT > rot
std::optional< int > ratio
std::optional< bool > xref
ELABEL(wxXmlNode *aLabel, IO_BASE *aIo=nullptr)
ECOORD size
std::optional< wxString > font
std::optional< wxString > align
ECOORD y
ECOORD x
wxString name
std::optional< bool > active
std::optional< bool > visible
ELAYER(wxXmlNode *aLayer, IO_BASE *aIo=nullptr)
wxString GetName() const
Fetch the fully unique library name.
std::optional< EURN > urn
wxString name
ELIBRARY(wxXmlNode *aLibrary, IO_BASE *aIo=nullptr)
wxString name
wxString model
EMODEL(wxXmlNode *aModel, IO_BASE *aIo=nullptr)
wxString name
EMODULEINST(wxXmlNode *aModuleInst, IO_BASE *aIo=nullptr)
std::optional< wxString > moduleVariant
std::optional< int > offset
std::optional< EROT > rotation
std::optional< bool > smashed
wxString moduleinst
std::map< wxString, std::unique_ptr< EPART > > parts
std::optional< wxString > prefix
ECOORD dy
std::map< wxString, std::unique_ptr< ESCHEMATIC_GROUP > > groups
std::vector< std::unique_ptr< ESHEET > > sheets
std::optional< EDESCRIPTION > description
EMODULE(wxXmlNode *aModule, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< EVARIANTDEF > > variantdefs
ECOORD dx
wxString name
std::map< wxString, std::unique_ptr< EPORT > > ports
int netcode
wxString netname
std::vector< std::unique_ptr< ESEGMENT > > segments
ENOTE(wxXmlNode *aNote, IO_BASE *aIo=nullptr)
wxString note
double version
wxString severity
EPACKAGE3DINST(wxXmlNode *aPackage3dInst, IO_BASE *aIo=nullptr)
wxString package3d_urn
wxString name
std::optional< bool > library_locally_modified
std::optional< EDESCRIPTION > description
std::vector< std::unique_ptr< EPACKAGEINSTANCE > > packageinstances
std::optional< int > library_version
wxString type
EPACKAGE3D(wxXmlNode *aPackage3d, IO_BASE *aIo=nullptr)
EPACKAGEINSTANCE(wxXmlNode *aPackageInstance, IO_BASE *aIo=nullptr)
std::vector< std::unique_ptr< EPOLYGON > > polygons
std::optional< int > library_version
std::vector< std::unique_ptr< EPAD > > thtpads
std::vector< std::unique_ptr< ECIRCLE > > circles
std::vector< std::unique_ptr< ESMD > > smdpads
std::optional< bool > library_locally_modified
std::vector< std::unique_ptr< EDIMENSION > > dimensions
std::optional< EURN > urn
std::vector< std::unique_ptr< EHOLE > > holes
wxString name
std::vector< std::unique_ptr< EFRAME > > frames
std::vector< std::unique_ptr< ERECT > > rectangles
std::vector< std::unique_ptr< ETEXT > > texts
std::vector< std::unique_ptr< EWIRE > > wires
std::optional< EDESCRIPTION > description
EPACKAGE(wxXmlNode *aPackage, IO_BASE *aIo=nullptr)
std::optional< bool > locally_modified
EPAD_COMMON(wxXmlNode *aPad, IO_BASE *aIo=nullptr)
std::optional< bool > thermals
wxString name
std::optional< EROT > rot
std::optional< bool > stop
std::optional< bool > first
std::optional< ECOORD > diameter
std::optional< int > shape
EPAD(wxXmlNode *aPad, IO_BASE *aIo=nullptr)
std::optional< ECOORD > drill
wxString device
std::optional< wxString > technology
std::optional< wxString > value
std::unique_ptr< ESPICE > spice
wxString library
std::optional< bool > override_locally_modified
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::optional< EURN > libraryUrn
EPART(wxXmlNode *aPart, IO_BASE *aIo=nullptr)
wxString deviceset
std::optional< wxString > override_package_urn
std::optional< wxString > override_package3d_urn
std::optional< wxString > package3d_urn
std::map< wxString, std::unique_ptr< EVARIANT > > variants
wxString name
EPINMAPPING(wxXmlNode *aPinMap, IO_BASE *aIo=nullptr)
std::optional< bool > iddevicewide
std::optional< wxString > spiceprefix
std::vector< std::unique_ptr< EPINMAP > > pinmaps
std::optional< bool > isusermap
wxString pinorder
wxString gate
wxString pin
EPINMAP(wxXmlNode *aPinMap, IO_BASE *aIo=nullptr)
wxString gate
EPINREF(wxXmlNode *aPinRef, IO_BASE *aIo=nullptr)
wxString pin
wxString part
std::optional< wxString > length
std::optional< wxString > function
std::optional< wxString > visible
EPIN(wxXmlNode *aPin, IO_BASE *aIo=nullptr)
ECOORD x
std::optional< int > swaplevel
wxString name
std::optional< EROT > rot
std::optional< wxString > direction
ECOORD y
EPLAIN(wxXmlNode *aPlain, IO_BASE *aIo=nullptr)
std::optional< ECOORD > isolate
std::vector< std::unique_ptr< EVERTEX > > vertices
EPOLYGON(wxXmlNode *aPolygon, IO_BASE *aIo=nullptr)
ECOORD width
std::optional< int > rank
std::optional< ECOORD > spacing
std::optional< bool > thermals
std::optional< bool > orphans
wxString port
EPORTREF(wxXmlNode *aPortRef, IO_BASE *aIo=nullptr)
wxString moduleinst
wxString name
std::optional< wxString > direction
EPORT(wxXmlNode *aPort, IO_BASE *aIo=nullptr)
wxString side
ECOORD coord
double size
ECOORD y
std::optional< int > ratio
std::optional< EROT > rot
std::optional< bool > xref
std::optional< wxString > font
ECOORD x
EPROBE(wxXmlNode *aProbe, IO_BASE *aIo=nullptr)
std::optional< EROT > rot
ECOORD x2
ECOORD y1
int layer
ERECT(wxXmlNode *aRect, IO_BASE *aIo=nullptr)
ECOORD y2
ECOORD x1
Eagle rotation.
double degrees
bool spin
bool mirror
std::optional< ECOORD > width
std::vector< std::unique_ptr< EATTR > > attributes
ESCHEMATIC_GROUP(wxXmlNode *aSchematicGroup, IO_BASE *aIo=nullptr)
std::optional< ECOORD > titleSize
std::optional< bool > selectable
std::optional< EDESCRIPTION > description
std::optional< wxString > wireStyle
std::optional< int > layer
std::optional< bool > showAnnotations
std::optional< wxString > grouprefs
std::optional< wxString > titleFont
std::optional< wxString > xreflabel
std::map< wxString, std::unique_ptr< EMODULE > > modules
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::vector< std::unique_ptr< EAPPROVED > > errors
std::optional< EDESCRIPTION > description
std::map< wxString, std::unique_ptr< ECLASS > > classes
std::vector< std::unique_ptr< ESHEET > > sheets
std::map< wxString, std::unique_ptr< EPART > > parts
ESCHEMATIC(wxXmlNode *aSchematic, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< ELIBRARY > > libraries
std::map< wxString, std::unique_ptr< EVARIANTDEF > > variantdefs
std::optional< wxString > xrefpart
std::map< wxString, std::unique_ptr< ESCHEMATIC_GROUP > > groups
ESEGMENT(wxXmlNode *aSegment, IO_BASE *aIo=nullptr)
std::optional< bool > alwaysvectorfont
std::optional< bool > keepoldvectorfont
std::optional< wxString > verticaltext
ESETTING(wxXmlNode *aSetting, IO_BASE *aIo=nullptr)
ESHEET(wxXmlNode *aSheet, IO_BASE *aIo=nullptr)
std::optional< bool > cream
ECOORD dx
int layer
ECOORD dy
ESMD(wxXmlNode *aSMD, IO_BASE *aIo=nullptr)
std::optional< int > roundness
ESPICE(wxXmlNode *aSpice, IO_BASE *aIo=nullptr)
std::unique_ptr< EMODEL > model
std::unique_ptr< EPINMAPPING > pinmapping
std::vector< std::unique_ptr< EVERTEX > > vertices
double width
ESPLINE(wxXmlNode *aSpline, IO_BASE *aIo=nullptr)
std::vector< std::unique_ptr< EFRAME > > frames
std::optional< EDESCRIPTION > description
std::optional< bool > locally_modified
std::optional< bool > library_locally_modified
std::optional< int > library_version
std::vector< std::unique_ptr< EPIN > > pins
std::vector< std::unique_ptr< ECIRCLE > > circles
std::vector< std::unique_ptr< ETEXT > > texts
std::vector< std::unique_ptr< EPOLYGON > > polygons
std::vector< std::unique_ptr< ERECT > > rectangles
std::vector< std::unique_ptr< EWIRE > > wires
ESYMBOL(wxXmlNode *aSymbol, IO_BASE *aIo=nullptr)
std::optional< EURN > urn
wxString name
std::vector< std::unique_ptr< EDIMENSION > > dimensions
wxString name
std::vector< std::unique_ptr< EATTR > > attributes
ETECHNOLOGY(wxXmlNode *aTechnology, IO_BASE *aIo=nullptr)
wxString text
@ BOTTOM_CENTER
@ BOTTOM_RIGHT
@ CENTER_RIGHT
@ CENTER_LEFT
@ BOTTOM_LEFT
ECOORD y
std::optional< wxString > font
ECOORD size
ETEXT(wxXmlNode *aText, IO_BASE *aIo=nullptr)
std::optional< EROT > rot
ECOORD x
std::optional< int > align
VECTOR2I ConvertSize() const
Calculate text size based on font type and size.
std::optional< double > ratio
int layer
Container that parses Eagle library file "urn" definitions.
bool IsValid() const
Check if the string passed to the ctor was a valid Eagle urn.
wxString host
Should always be "urn".
void Parse(const wxString &aUrn)
wxString assetVersion
May be empty depending on the asset type.
wxString assetId
The unique asset identifier for the asset type.
wxString assetType
Must be "symbol", "footprint", "package", "component", or "library".
wxString path
Path to the asset type below.
EVARIANTDEF(wxXmlNode *aVariantDef, IO_BASE *aIo=nullptr)
std::optional< bool > current
wxString name
EVARIANT(wxXmlNode *aVariant, IO_BASE *aIo=nullptr)
wxString name
std::optional< bool > populate
std::optional< wxString > technology
std::optional< wxString > value
EVERTEX(wxXmlNode *aVertex, IO_BASE *aIo=nullptr)
std::optional< double > curve
range is -359.9..359.9
ECOORD y
ECOORD x
ECOORD drill
< inclusive
std::optional< wxString > shape
ECOORD y
EVIA(wxXmlNode *aVia, IO_BASE *aIo=nullptr)
int layer_front_most
std::optional< ECOORD > diam
int layer_back_most
< extent
ECOORD x
ECOORD width
int layer
EWIRE(wxXmlNode *aWire, IO_BASE *aIo=nullptr)
std::optional< int > cap
std::optional< int > style
ECOORD x2
ECOORD y2
ECOORD x1
ECOORD y1
std::optional< double > curve
range is -359.9..359.9
Implement a simple wrapper around runtime_error to isolate the errors thrown by the Eagle XML parser.
VECTOR2I center
wxLogTrace helper definitions.
double DEG2RAD(double deg)
Definition trigo.h:172
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683