Moves Eagle XML parser to common, replacing boost with wx.
All E'STRUCTS' are moved to common except for ERULES (which is specific to pcbnew and needs its internal units), still in pcbnew/eagle_plugin.{h,cpp} In order to get rid of another boost dependency, this also changes the parsing of the XML from Boost.PropertyTree to wxXml. To replace boost::optional, an OPTIONAL_XML_ATTRIBUTE class has been implemented. This could be replaced with std::optional when C++17 is ready.
This commit is contained in:
parent
4f2ed1b05f
commit
9cf934ef17
|
@ -239,6 +239,7 @@ set( COMMON_SRCS
|
||||||
draw_panel.cpp
|
draw_panel.cpp
|
||||||
drawtxt.cpp
|
drawtxt.cpp
|
||||||
dsnlexer.cpp
|
dsnlexer.cpp
|
||||||
|
eagle_parser.cpp
|
||||||
eda_dde.cpp
|
eda_dde.cpp
|
||||||
eda_doc.cpp
|
eda_doc.cpp
|
||||||
eda_pattern_match.cpp
|
eda_pattern_match.cpp
|
||||||
|
|
|
@ -0,0 +1,649 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
* Copyright (C) 2017 CERN.
|
||||||
|
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <eagle_parser.h>
|
||||||
|
|
||||||
|
#include <wx/xml/xml.h>
|
||||||
|
#include <wx/string.h>
|
||||||
|
#include <wx/filename.h>
|
||||||
|
|
||||||
|
#include <convert_to_biu.h>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// Template specializations below parse wxString to the used types:
|
||||||
|
// - string
|
||||||
|
// - double
|
||||||
|
// - int
|
||||||
|
// - bool
|
||||||
|
// - EROT
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
string Convert<string>( wxString aValue )
|
||||||
|
{
|
||||||
|
return aValue.ToStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
double Convert<double>( wxString aValue )
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
|
||||||
|
if( aValue.ToDouble( &value ) )
|
||||||
|
return value;
|
||||||
|
else
|
||||||
|
throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
|
||||||
|
aValue.ToStdString() + "'." );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
int Convert<int>( wxString aValue )
|
||||||
|
{
|
||||||
|
if( aValue.IsEmpty() )
|
||||||
|
throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
|
||||||
|
|
||||||
|
return wxAtoi( aValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool Convert<bool>( wxString aValue )
|
||||||
|
{
|
||||||
|
if( aValue != "yes" && aValue != "no" )
|
||||||
|
throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
|
||||||
|
aValue.ToStdString() +
|
||||||
|
"', is neither 'yes' nor 'no'." );
|
||||||
|
|
||||||
|
return aValue == "yes";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// parse an Eagle XML "rot" field. Unfortunately the DTD seems not to explain
|
||||||
|
/// this format very well. [S][M]R<degrees>. Examples: "R90", "MR180", "SR180"
|
||||||
|
template<>
|
||||||
|
EROT Convert<EROT>( wxString aRot )
|
||||||
|
{
|
||||||
|
EROT value;
|
||||||
|
|
||||||
|
value.spin = aRot.find( 'S' ) != aRot.npos;
|
||||||
|
value.mirror = aRot.find( 'M' ) != aRot.npos;
|
||||||
|
value.degrees = strtod( aRot.c_str()
|
||||||
|
+ 1 // skip leading 'R'
|
||||||
|
+ int( value.spin ) // skip optional leading 'S'
|
||||||
|
+ int( value.mirror ), // skip optional leading 'M'
|
||||||
|
NULL );
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function parseRequiredAttribute
|
||||||
|
* parsese the aAttribute of the XML node aNode.
|
||||||
|
* @param aNode is the node whose attribute will be parsed.
|
||||||
|
* @param aAttribute is the attribute that will be parsed.
|
||||||
|
* @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing
|
||||||
|
* @return T - the attributed parsed as the specified type.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T parseRequiredAttribute( wxXmlNode* aNode, string aAttribute )
|
||||||
|
{
|
||||||
|
wxString value;
|
||||||
|
|
||||||
|
if( aNode->GetAttribute( aAttribute, &value ) )
|
||||||
|
return Convert<T>( value );
|
||||||
|
else
|
||||||
|
throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function parseOptionalAttribute
|
||||||
|
* parses the aAttribute of the XML node aNode.
|
||||||
|
* @param aNode is the node whose attribute will be parsed.
|
||||||
|
* @param aAttribute is the attribute that will be parsed.
|
||||||
|
* @return OPTIONAL_XML_ATTRIBUTE<T> - an optional XML attribute, parsed as the specified type if
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, string aAttribute )
|
||||||
|
{
|
||||||
|
return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EWIRE::EWIRE( wxXmlNode* aWire )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT wire EMPTY>
|
||||||
|
<!ATTLIST wire
|
||||||
|
x1 %Coord; #REQUIRED
|
||||||
|
y1 %Coord; #REQUIRED
|
||||||
|
x2 %Coord; #REQUIRED
|
||||||
|
y2 %Coord; #REQUIRED
|
||||||
|
width %Dimension; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
extent %Extent; #IMPLIED -- only applicable for airwires --
|
||||||
|
style %WireStyle; "continuous"
|
||||||
|
curve %WireCurve; "0"
|
||||||
|
cap %WireCap; "round" -- only applicable if 'curve' is not zero --
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x1 = parseRequiredAttribute<double>( aWire, "x1" );
|
||||||
|
y1 = parseRequiredAttribute<double>( aWire, "y1" );
|
||||||
|
x2 = parseRequiredAttribute<double>( aWire, "x2" );
|
||||||
|
y2 = parseRequiredAttribute<double>( aWire, "y2" );
|
||||||
|
width = parseRequiredAttribute<double>( aWire, "width" );
|
||||||
|
layer = parseRequiredAttribute<int>( aWire, "layer" );
|
||||||
|
curve = parseOptionalAttribute<double>( aWire, "curve" );
|
||||||
|
|
||||||
|
opt_string s = parseOptionalAttribute<string>( aWire, "style" );
|
||||||
|
|
||||||
|
if( s == "continuous" )
|
||||||
|
style = EWIRE::CONTINUOUS;
|
||||||
|
else if( s == "longdash" )
|
||||||
|
style = EWIRE::LONGDASH;
|
||||||
|
else if( s == "shortdash" )
|
||||||
|
style = EWIRE::SHORTDASH;
|
||||||
|
else if( s == "dashdot" )
|
||||||
|
style = EWIRE::DASHDOT;
|
||||||
|
|
||||||
|
s = parseOptionalAttribute<string>( aWire, "cap" );
|
||||||
|
|
||||||
|
if( s == "round" )
|
||||||
|
cap = EWIRE::ROUND;
|
||||||
|
else if( s == "flat" )
|
||||||
|
cap = EWIRE::FLAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EVIA::EVIA( wxXmlNode* aVia )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT via EMPTY>
|
||||||
|
<!ATTLIST via
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
extent %Extent; #REQUIRED
|
||||||
|
drill %Dimension; #REQUIRED
|
||||||
|
diameter %Dimension; "0"
|
||||||
|
shape %ViaShape; "round"
|
||||||
|
alwaysstop %Bool; "no"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x = parseRequiredAttribute<double>( aVia, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aVia, "y" );
|
||||||
|
|
||||||
|
string ext = parseRequiredAttribute<string>( aVia, "extent" );
|
||||||
|
|
||||||
|
sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
|
||||||
|
|
||||||
|
drill = parseRequiredAttribute<double>( aVia, "drill" );
|
||||||
|
diam = parseOptionalAttribute<double>( aVia, "diameter" );
|
||||||
|
shape = parseOptionalAttribute<string>( aVia, "shape" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT circle EMPTY>
|
||||||
|
<!ATTLIST circle
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
radius %Coord; #REQUIRED
|
||||||
|
width %Dimension; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x = parseRequiredAttribute<double>( aCircle, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aCircle, "y" );
|
||||||
|
radius = parseRequiredAttribute<double>( aCircle, "radius" );
|
||||||
|
width = parseRequiredAttribute<double>( aCircle, "width" );
|
||||||
|
layer = parseRequiredAttribute<int>( aCircle, "layer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ERECT::ERECT( wxXmlNode* aRect )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT rectangle EMPTY>
|
||||||
|
<!ATTLIST rectangle
|
||||||
|
x1 %Coord; #REQUIRED
|
||||||
|
y1 %Coord; #REQUIRED
|
||||||
|
x2 %Coord; #REQUIRED
|
||||||
|
y2 %Coord; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x1 = parseRequiredAttribute<double>( aRect, "x1" );
|
||||||
|
y1 = parseRequiredAttribute<double>( aRect, "y1" );
|
||||||
|
x2 = parseRequiredAttribute<double>( aRect, "x2" );
|
||||||
|
y2 = parseRequiredAttribute<double>( aRect, "y2" );
|
||||||
|
layer = parseRequiredAttribute<int>( aRect, "layer" );
|
||||||
|
rot = parseOptionalAttribute<EROT>( aRect, "rot" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EATTR::EATTR( wxXmlNode* aTree )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT attribute EMPTY>
|
||||||
|
<!ATTLIST attribute
|
||||||
|
name %String; #REQUIRED
|
||||||
|
value %String; #IMPLIED
|
||||||
|
x %Coord; #IMPLIED
|
||||||
|
y %Coord; #IMPLIED
|
||||||
|
size %Dimension; #IMPLIED
|
||||||
|
layer %Layer; #IMPLIED
|
||||||
|
font %TextFont; #IMPLIED
|
||||||
|
ratio %Int; #IMPLIED
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
display %AttributeDisplay; "value" -- only in <element> or <instance> context --
|
||||||
|
constant %Bool; "no" -- only in <device> context --
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
name = parseRequiredAttribute<string>( aTree, "name" );
|
||||||
|
value = parseOptionalAttribute<string>( aTree, "value" );
|
||||||
|
|
||||||
|
x = parseOptionalAttribute<double>( aTree, "x" );
|
||||||
|
y = parseOptionalAttribute<double>( aTree, "y" );
|
||||||
|
size = parseOptionalAttribute<double>( aTree, "size" );
|
||||||
|
|
||||||
|
// KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
|
||||||
|
// Eagle can it seems.
|
||||||
|
layer = parseOptionalAttribute<int>( aTree, "layer" );
|
||||||
|
ratio = parseOptionalAttribute<double>( aTree, "ratio" );
|
||||||
|
rot = parseOptionalAttribute<EROT>( aTree, "rot" );
|
||||||
|
|
||||||
|
opt_string stemp = parseOptionalAttribute<string>( aTree, "display" );
|
||||||
|
|
||||||
|
// (off | value | name | both)
|
||||||
|
if( stemp == "off" )
|
||||||
|
display = EATTR::Off;
|
||||||
|
else if( stemp == "value" )
|
||||||
|
display = EATTR::VALUE;
|
||||||
|
else if( stemp == "name" )
|
||||||
|
display = EATTR::NAME;
|
||||||
|
else if( stemp == "both" )
|
||||||
|
display = EATTR::BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT dimension EMPTY>
|
||||||
|
<!ATTLIST dimension
|
||||||
|
x1 %Coord; #REQUIRED
|
||||||
|
y1 %Coord; #REQUIRED
|
||||||
|
x2 %Coord; #REQUIRED
|
||||||
|
y2 %Coord; #REQUIRED
|
||||||
|
x3 %Coord; #REQUIRED
|
||||||
|
y3 %Coord; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
dtype %DimensionType; "parallel"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x1 = parseRequiredAttribute<double>( aDimension, "x1" );
|
||||||
|
y1 = parseRequiredAttribute<double>( aDimension, "y1" );
|
||||||
|
x2 = parseRequiredAttribute<double>( aDimension, "x2" );
|
||||||
|
y2 = parseRequiredAttribute<double>( aDimension, "y2" );
|
||||||
|
x3 = parseRequiredAttribute<double>( aDimension, "x3" );
|
||||||
|
y3 = parseRequiredAttribute<double>( aDimension, "y3" );
|
||||||
|
layer = parseRequiredAttribute<int>( aDimension, "layer" );
|
||||||
|
|
||||||
|
opt_string dimType = parseOptionalAttribute<string>( aDimension, "dtype" );
|
||||||
|
|
||||||
|
if( !dimType )
|
||||||
|
{
|
||||||
|
// default type is parallel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ETEXT::ETEXT( wxXmlNode* aText )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT text (#PCDATA)>
|
||||||
|
<!ATTLIST text
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
size %Dimension; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
font %TextFont; "proportional"
|
||||||
|
ratio %Int; "8"
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
align %Align; "bottom-left"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
text = aText->GetNodeContent();
|
||||||
|
x = parseRequiredAttribute<double>( aText, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aText, "y" );
|
||||||
|
size = parseRequiredAttribute<double>( aText, "size" );
|
||||||
|
layer = parseRequiredAttribute<int>( aText, "layer" );
|
||||||
|
|
||||||
|
font = parseOptionalAttribute<string>( aText, "font" );
|
||||||
|
ratio = parseOptionalAttribute<double>( aText, "ratio" );
|
||||||
|
rot = parseOptionalAttribute<EROT>( aText, "rot" );
|
||||||
|
|
||||||
|
opt_string stemp = parseOptionalAttribute<string>( aText, "align" );
|
||||||
|
|
||||||
|
// (bottom-left | bottom-center | bottom-right | center-left |
|
||||||
|
// center | center-right | top-left | top-center | top-right)
|
||||||
|
if( stemp == "center" )
|
||||||
|
align = ETEXT::CENTER;
|
||||||
|
else if( stemp == "center-right" )
|
||||||
|
align = ETEXT::CENTER_RIGHT;
|
||||||
|
else if( stemp == "top-left" )
|
||||||
|
align = ETEXT::TOP_LEFT;
|
||||||
|
else if( stemp == "top-center" )
|
||||||
|
align = ETEXT::TOP_CENTER;
|
||||||
|
else if( stemp == "top-right" )
|
||||||
|
align = ETEXT::TOP_RIGHT;
|
||||||
|
else if( stemp == "bottom-left" )
|
||||||
|
align = ETEXT::BOTTOM_LEFT;
|
||||||
|
else if( stemp == "bottom-center" )
|
||||||
|
align = ETEXT::BOTTOM_CENTER;
|
||||||
|
else if( stemp == "bottom-right" )
|
||||||
|
align = ETEXT::BOTTOM_RIGHT;
|
||||||
|
else if( stemp == "center-left" )
|
||||||
|
align = ETEXT::CENTER_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EPAD::EPAD( wxXmlNode* aPad )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT pad EMPTY>
|
||||||
|
<!ATTLIST pad
|
||||||
|
name %String; #REQUIRED
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
drill %Dimension; #REQUIRED
|
||||||
|
diameter %Dimension; "0"
|
||||||
|
shape %PadShape; "round"
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
stop %Bool; "yes"
|
||||||
|
thermals %Bool; "yes"
|
||||||
|
first %Bool; "no"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #REQUIRED says DTD, throw exception if not found
|
||||||
|
name = parseRequiredAttribute<string>( aPad, "name" );
|
||||||
|
x = parseRequiredAttribute<double>( aPad, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aPad, "y" );
|
||||||
|
drill = parseRequiredAttribute<double>( aPad, "drill" );
|
||||||
|
|
||||||
|
// Optional attributes
|
||||||
|
diameter = parseOptionalAttribute<double>( aPad, "diameter" );
|
||||||
|
|
||||||
|
opt_string s = parseOptionalAttribute<string>( aPad, "shape" );
|
||||||
|
|
||||||
|
// (square | round | octagon | long | offset)
|
||||||
|
if( s == "square" )
|
||||||
|
shape = EPAD::SQUARE;
|
||||||
|
else if( s == "round" )
|
||||||
|
shape = EPAD::ROUND;
|
||||||
|
else if( s == "octagon" )
|
||||||
|
shape = EPAD::OCTAGON;
|
||||||
|
else if( s == "long" )
|
||||||
|
shape = EPAD::LONG;
|
||||||
|
else if( s == "offset" )
|
||||||
|
shape = EPAD::OFFSET;
|
||||||
|
|
||||||
|
rot = parseOptionalAttribute<EROT>( aPad, "rot" );
|
||||||
|
stop = parseOptionalAttribute<bool>( aPad, "stop" );
|
||||||
|
thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
|
||||||
|
first = parseOptionalAttribute<bool>( aPad, "first" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ESMD::ESMD( wxXmlNode* aSMD )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ATTLIST smd
|
||||||
|
name %String; #REQUIRED
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
dx %Dimension; #REQUIRED
|
||||||
|
dy %Dimension; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
roundness %Int; "0"
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
stop %Bool; "yes"
|
||||||
|
thermals %Bool; "yes"
|
||||||
|
cream %Bool; "yes"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DTD #REQUIRED, throw exception if not found
|
||||||
|
name = parseRequiredAttribute<string>( aSMD, "name" );
|
||||||
|
x = parseRequiredAttribute<double>( aSMD, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aSMD, "y" );
|
||||||
|
dx = parseRequiredAttribute<double>( aSMD, "dx" );
|
||||||
|
dy = parseRequiredAttribute<double>( aSMD, "dy" );
|
||||||
|
layer = parseRequiredAttribute<int>( aSMD, "layer" );
|
||||||
|
|
||||||
|
roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
|
||||||
|
rot = parseOptionalAttribute<EROT>( aSMD, "rot" );
|
||||||
|
thermals = parseOptionalAttribute<bool>( aSMD, "thermals" );
|
||||||
|
stop = parseOptionalAttribute<bool>( aSMD, "stop" );
|
||||||
|
thermals = parseOptionalAttribute<bool>( aSMD, "thermals" );
|
||||||
|
cream = parseOptionalAttribute<bool>( aSMD, "cream" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EVERTEX::EVERTEX( wxXmlNode* aVertex )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT vertex EMPTY>
|
||||||
|
<!ATTLIST vertex
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
curve %WireCurve; "0" -- the curvature from this vertex to the next one --
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
x = parseRequiredAttribute<double>( aVertex, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aVertex, "y" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ATTLIST polygon
|
||||||
|
width %Dimension; #REQUIRED
|
||||||
|
layer %Layer; #REQUIRED
|
||||||
|
spacing %Dimension; #IMPLIED
|
||||||
|
pour %PolygonPour; "solid"
|
||||||
|
isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
|
||||||
|
orphans %Bool; "no" -- only in <signal> context --
|
||||||
|
thermals %Bool; "yes" -- only in <signal> context --
|
||||||
|
rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
width = parseRequiredAttribute<double>( aPolygon, "width" );
|
||||||
|
layer = parseRequiredAttribute<int>( aPolygon, "layer" );
|
||||||
|
|
||||||
|
spacing = parseOptionalAttribute<double>( aPolygon, "spacing" );
|
||||||
|
isolate = parseOptionalAttribute<double>( aPolygon, "isolate" );
|
||||||
|
opt_string s = parseOptionalAttribute<string>( aPolygon, "pour" );
|
||||||
|
|
||||||
|
// default pour to solid fill
|
||||||
|
pour = EPOLYGON::SOLID;
|
||||||
|
|
||||||
|
// (solid | hatch | cutout)
|
||||||
|
if( s == "hatch" )
|
||||||
|
pour = EPOLYGON::HATCH;
|
||||||
|
else if( s == "cutout" )
|
||||||
|
pour = EPOLYGON::CUTOUT;
|
||||||
|
|
||||||
|
orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
|
||||||
|
thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
|
||||||
|
rank = parseOptionalAttribute<int>( aPolygon, "rank" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EHOLE::EHOLE( wxXmlNode* aHole )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT hole EMPTY>
|
||||||
|
<!ATTLIST hole
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
drill %Dimension; #REQUIRED
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #REQUIRED:
|
||||||
|
x = parseRequiredAttribute<double>( aHole, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aHole, "y" );
|
||||||
|
drill = parseRequiredAttribute<double>( aHole, "drill" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EELEMENT::EELEMENT( wxXmlNode* aElement )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT element (attribute*, variant*)>
|
||||||
|
<!ATTLIST element
|
||||||
|
name %String; #REQUIRED
|
||||||
|
library %String; #REQUIRED
|
||||||
|
package %String; #REQUIRED
|
||||||
|
value %String; #REQUIRED
|
||||||
|
x %Coord; #REQUIRED
|
||||||
|
y %Coord; #REQUIRED
|
||||||
|
locked %Bool; "no"
|
||||||
|
smashed %Bool; "no"
|
||||||
|
rot %Rotation; "R0"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #REQUIRED
|
||||||
|
name = parseRequiredAttribute<string>( aElement, "name" );
|
||||||
|
library = parseRequiredAttribute<string>( aElement, "library" );
|
||||||
|
value = parseRequiredAttribute<string>( aElement, "value" );
|
||||||
|
package = parseRequiredAttribute<string>( aElement, "package" );
|
||||||
|
ReplaceIllegalFileNameChars( &package );
|
||||||
|
|
||||||
|
x = parseRequiredAttribute<double>( aElement, "x" );
|
||||||
|
y = parseRequiredAttribute<double>( aElement, "y" );
|
||||||
|
|
||||||
|
// optional
|
||||||
|
locked = parseOptionalAttribute<bool>( aElement, "locked" );
|
||||||
|
smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
|
||||||
|
rot = parseOptionalAttribute<EROT>( aElement, "rot" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ELAYER::ELAYER( wxXmlNode* aLayer )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
<!ELEMENT layer EMPTY>
|
||||||
|
<!ATTLIST layer
|
||||||
|
number %Layer; #REQUIRED
|
||||||
|
name %String; #REQUIRED
|
||||||
|
color %Int; #REQUIRED
|
||||||
|
fill %Int; #REQUIRED
|
||||||
|
visible %Bool; "yes"
|
||||||
|
active %Bool; "yes"
|
||||||
|
>
|
||||||
|
*/
|
||||||
|
|
||||||
|
number = parseRequiredAttribute<int>( aLayer, "number" );
|
||||||
|
name = parseRequiredAttribute<string>( aLayer, "name" );
|
||||||
|
color = parseRequiredAttribute<int>( aLayer, "color" );
|
||||||
|
fill = 1; // Temporary value.
|
||||||
|
visible = parseOptionalAttribute<bool>( aLayer, "visible" );
|
||||||
|
active = parseOptionalAttribute<bool>( aLayer, "active" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_MAP MapChildren( wxXmlNode* currentNode )
|
||||||
|
{
|
||||||
|
// Map node_name -> node_pointer
|
||||||
|
NODE_MAP nodesMap;
|
||||||
|
|
||||||
|
// Loop through all children mapping them in nodesMap
|
||||||
|
currentNode = currentNode->GetChildren();
|
||||||
|
while( currentNode )
|
||||||
|
{
|
||||||
|
// Create a new pair in the map
|
||||||
|
// key: current node name
|
||||||
|
// value: current node pointer
|
||||||
|
nodesMap[currentNode->GetName().ToStdString()] = currentNode;
|
||||||
|
|
||||||
|
// Get next child
|
||||||
|
currentNode = currentNode->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodesMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string makeKey( const string& aFirst, const string& aSecond )
|
||||||
|
{
|
||||||
|
string key = aFirst + '\x02' + aSecond;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long timeStamp( wxXmlNode* aTree )
|
||||||
|
{
|
||||||
|
// in this case from a unique tree memory location
|
||||||
|
return (unsigned long)(void*) aTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxPoint kicad_arc_center( wxPoint start, wxPoint end, double angle )
|
||||||
|
{
|
||||||
|
// Eagle give us start and end.
|
||||||
|
// S_ARC wants start to give the center, and end to give the start.
|
||||||
|
double dx = end.x - start.x, dy = end.y - start.y;
|
||||||
|
wxPoint mid = (start + end) / 2;
|
||||||
|
|
||||||
|
double dlen = sqrt( dx*dx + dy*dy );
|
||||||
|
double dist = dlen / ( 2 * tan( DEG2RAD( angle ) / 2 ) );
|
||||||
|
|
||||||
|
wxPoint center(
|
||||||
|
mid.x + dist * ( dy / dlen ),
|
||||||
|
mid.y - dist * ( dx / dlen )
|
||||||
|
);
|
||||||
|
|
||||||
|
return center;
|
||||||
|
}
|
|
@ -0,0 +1,690 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
* Copyright (C) 2017 CERN.
|
||||||
|
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _EAGLE_PARSER_H_
|
||||||
|
#define _EAGLE_PARSER_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <wx/xml/xml.h>
|
||||||
|
#include <wx/string.h>
|
||||||
|
#include <wx/filename.h>
|
||||||
|
|
||||||
|
#include <layers_id_colors_and_visibility.h>
|
||||||
|
#include <convert_to_biu.h>
|
||||||
|
#include <macros.h>
|
||||||
|
#include <trigo.h>
|
||||||
|
#include <kicad_string.h>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
class MODULE;
|
||||||
|
|
||||||
|
typedef std::unordered_map< string, wxXmlNode* > NODE_MAP;
|
||||||
|
typedef std::map< string, MODULE* > MODULE_MAP;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class XML_PARSER_ERROR
|
||||||
|
* implements a simple wrapper around runtime_error to isolate the errors thrown by the
|
||||||
|
* Eagle XML parser.
|
||||||
|
*/
|
||||||
|
struct XML_PARSER_ERROR : std::runtime_error
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor XML_PARSER_ERROR
|
||||||
|
* build an XML error by just calling its parent class constructor, std::runtime_error, with
|
||||||
|
* the passed message.
|
||||||
|
* @param aMessage is an explanatory error message.
|
||||||
|
*/
|
||||||
|
XML_PARSER_ERROR( const string& aMessage ) noexcept :
|
||||||
|
std::runtime_error( "XML parser failed - " + aMessage )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// segment (element) of our XPATH into the Eagle XML document tree in PTREE form.
|
||||||
|
struct TRIPLET
|
||||||
|
{
|
||||||
|
const char* element;
|
||||||
|
const char* attribute;
|
||||||
|
const char* value;
|
||||||
|
|
||||||
|
TRIPLET( const char* aElement, const char* aAttribute = "", const char* aValue = "" ) :
|
||||||
|
element( aElement ),
|
||||||
|
attribute( aAttribute ),
|
||||||
|
value( aValue )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class XPATH
|
||||||
|
* keeps track of what we are working on within a PTREE.
|
||||||
|
* Then if an exception is thrown, the place within the tree that gave us
|
||||||
|
* grief can be reported almost accurately. To minimally impact
|
||||||
|
* speed, merely assign const char* pointers during the tree walking
|
||||||
|
* expedition. The const char* pointers must be to C strings residing either in
|
||||||
|
* the data or code segment (i.e. "compiled in") or within the XML document, but
|
||||||
|
* not on the stack, since the stack is unwound during the throwing of the
|
||||||
|
* exception. The XML document will not immediately vanish since we capture
|
||||||
|
* the xpath (using function Contents()) before the XML document tree (PTREE)
|
||||||
|
* is destroyed.
|
||||||
|
*/
|
||||||
|
class XPATH
|
||||||
|
{
|
||||||
|
std::vector<TRIPLET> p;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void push( const char* aPathSegment, const char* aAttribute="" )
|
||||||
|
{
|
||||||
|
p.push_back( TRIPLET( aPathSegment, aAttribute ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() { p.clear(); }
|
||||||
|
|
||||||
|
void pop() { p.pop_back(); }
|
||||||
|
|
||||||
|
/// modify the last path node's value
|
||||||
|
void Value( const char* aValue )
|
||||||
|
{
|
||||||
|
p.back().value = aValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// modify the last path node's attribute
|
||||||
|
void Attribute( const char* aAttribute )
|
||||||
|
{
|
||||||
|
p.back().attribute = aAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the contents of the XPATH as a single string
|
||||||
|
string Contents()
|
||||||
|
{
|
||||||
|
typedef std::vector<TRIPLET>::const_iterator CITER_TRIPLET;
|
||||||
|
|
||||||
|
string ret;
|
||||||
|
|
||||||
|
for( CITER_TRIPLET it = p.begin(); it != p.end(); ++it )
|
||||||
|
{
|
||||||
|
if( it != p.begin() )
|
||||||
|
ret += '.';
|
||||||
|
|
||||||
|
ret += it->element;
|
||||||
|
|
||||||
|
if( it->attribute[0] && it->value[0] )
|
||||||
|
{
|
||||||
|
ret += '[';
|
||||||
|
ret += it->attribute;
|
||||||
|
ret += '=';
|
||||||
|
ret += it->value;
|
||||||
|
ret += ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Convert
|
||||||
|
* converts a wxString to a generic type T.
|
||||||
|
* @param aValue is a wxString containing the value that will be converted to type T.
|
||||||
|
* @throw XML_PARSER_ERROR - an exception is thrown if the parsing fails or if the conversion to
|
||||||
|
* type T is unknown.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T Convert( wxString aValue )
|
||||||
|
{
|
||||||
|
throw XML_PARSER_ERROR( "Conversion failed. Unknown type." );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class OPTIONAL_XML_ATTRIBUTE
|
||||||
|
* models an optional XML attribute.
|
||||||
|
* This was implemented as an alternative to boost::optional. This class should be replaced with a
|
||||||
|
* simple typedef per type using std::optional when C++17 is published.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class OPTIONAL_XML_ATTRIBUTE
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// A boolean indicating if the data is present or not.
|
||||||
|
bool m_isAvailable;
|
||||||
|
|
||||||
|
/// The actual data if m_isAvailable is true; otherwise, garbage.
|
||||||
|
T m_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor OPTIONAL_XML_ATTRIBUTE
|
||||||
|
* construct a default OPTIONAL_XML_ATTRIBUTE, whose data is not available.
|
||||||
|
*/
|
||||||
|
OPTIONAL_XML_ATTRIBUTE() :
|
||||||
|
m_isAvailable( false )
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor OPTIONAL_XML_ATTRIBUTE
|
||||||
|
* @param aData is a wxString containing the value that should be converted to type T. If
|
||||||
|
* aData is empty, the attribute is understood as unavailable; otherwise, the
|
||||||
|
* conversion to T is tried.
|
||||||
|
*/
|
||||||
|
OPTIONAL_XML_ATTRIBUTE( wxString aData )
|
||||||
|
{
|
||||||
|
m_isAvailable = !aData.IsEmpty();
|
||||||
|
|
||||||
|
if( m_isAvailable )
|
||||||
|
Set( aData );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor OPTIONAL_XML_ATTRIBUTE
|
||||||
|
* @param aData is the value of the XML attribute. If this constructor is called, the
|
||||||
|
* attribute is available.
|
||||||
|
*/
|
||||||
|
OPTIONAL_XML_ATTRIBUTE( T aData ) :
|
||||||
|
m_isAvailable( true ),
|
||||||
|
m_data( aData )
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator bool
|
||||||
|
* @return bool - the availability of the attribute.
|
||||||
|
*/
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return m_isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assignment operator
|
||||||
|
* to a string (optionally) containing the data.
|
||||||
|
* @param aData is a wxString that should be converted to T. If the string is empty, the
|
||||||
|
* attribute is set to unavailable.
|
||||||
|
*/
|
||||||
|
OPTIONAL_XML_ATTRIBUTE<T>& operator =( wxString aData )
|
||||||
|
{
|
||||||
|
m_isAvailable = !aData.IsEmpty();
|
||||||
|
|
||||||
|
if( m_isAvailable )
|
||||||
|
Set( aData );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assignment operator
|
||||||
|
* to an object of the base type containing the data.
|
||||||
|
* @param aData is the actual value of the attribute. Calling this assignment, the attribute
|
||||||
|
* is automatically made available.
|
||||||
|
*/
|
||||||
|
OPTIONAL_XML_ATTRIBUTE<T>& operator =( T aData )
|
||||||
|
{
|
||||||
|
m_data = aData;
|
||||||
|
m_isAvailable = true;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equal operator
|
||||||
|
* to an object of the base type.
|
||||||
|
* @param aOther is the object of the base type that should be compared with this one.
|
||||||
|
*/
|
||||||
|
bool operator ==( const T& aOther ) const
|
||||||
|
{
|
||||||
|
return m_isAvailable && ( aOther == m_data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Set
|
||||||
|
* tries to convert a string to the base type.
|
||||||
|
* @param aString is the string that will be converted to the base type.
|
||||||
|
*/
|
||||||
|
void Set( wxString aString )
|
||||||
|
{
|
||||||
|
m_data = Convert<T>( aString );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Get
|
||||||
|
* returns a reference to the value of the attribute assuming it is available.
|
||||||
|
* @return T& - the value of the attribute.
|
||||||
|
*/
|
||||||
|
T& Get()
|
||||||
|
{
|
||||||
|
assert( m_isAvailable );
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function CGet
|
||||||
|
* returns a constant reference to the value of the attribute assuming it is available.
|
||||||
|
* @return const T& - the value of the attribute.
|
||||||
|
*/
|
||||||
|
const T& CGet() const
|
||||||
|
{
|
||||||
|
assert( m_isAvailable );
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator *
|
||||||
|
* returns a reference to the value of the attribute assuming it is available.
|
||||||
|
* @return T& - the value of the attribute.
|
||||||
|
*/
|
||||||
|
T& operator*()
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator *
|
||||||
|
* returns a constant reference to the value of the attribute assuming it is available.
|
||||||
|
* @return const T& - the value of the attribute.
|
||||||
|
*/
|
||||||
|
const T& operator*() const
|
||||||
|
{
|
||||||
|
return CGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator ->
|
||||||
|
* returns a pointer to the value of the attribute assuming it is available.
|
||||||
|
* @return T* - the value of the attribute.
|
||||||
|
*/
|
||||||
|
T* operator->()
|
||||||
|
{
|
||||||
|
return &Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator ->
|
||||||
|
* returns a constant pointer to the value of the attribute assuming it is available.
|
||||||
|
* @return const T* - the value of the attribute.
|
||||||
|
*/
|
||||||
|
const T* operator->() const
|
||||||
|
{
|
||||||
|
return &CGet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pre-declare for typedefs
|
||||||
|
struct EROT;
|
||||||
|
|
||||||
|
typedef OPTIONAL_XML_ATTRIBUTE<string> opt_string;
|
||||||
|
typedef OPTIONAL_XML_ATTRIBUTE<int> opt_int;
|
||||||
|
typedef OPTIONAL_XML_ATTRIBUTE<double> opt_double;
|
||||||
|
typedef OPTIONAL_XML_ATTRIBUTE<bool> opt_bool;
|
||||||
|
typedef OPTIONAL_XML_ATTRIBUTE<EROT> opt_erot;
|
||||||
|
|
||||||
|
|
||||||
|
// All of the 'E'STRUCTS below merely hold Eagle XML information verbatim, in binary.
|
||||||
|
// For maintenance and troubleshooting purposes, it was thought that we'd need to
|
||||||
|
// separate the conversion process into distinct steps. There is no intent to have KiCad
|
||||||
|
// forms of information in these 'E'STRUCTS. They are only binary forms
|
||||||
|
// of the Eagle information in the corresponding Eagle XML nodes.
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle net
|
||||||
|
struct ENET
|
||||||
|
{
|
||||||
|
int netcode;
|
||||||
|
std::string netname;
|
||||||
|
|
||||||
|
ENET( int aNetCode, const std::string& aNetName ) :
|
||||||
|
netcode( aNetCode ),
|
||||||
|
netname( aNetName )
|
||||||
|
{}
|
||||||
|
|
||||||
|
ENET() :
|
||||||
|
netcode( 0 )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle rotation
|
||||||
|
struct EROT
|
||||||
|
{
|
||||||
|
bool mirror;
|
||||||
|
bool spin;
|
||||||
|
double degrees;
|
||||||
|
|
||||||
|
EROT() :
|
||||||
|
mirror( false ),
|
||||||
|
spin( false ),
|
||||||
|
degrees( 0 )
|
||||||
|
{}
|
||||||
|
|
||||||
|
EROT( double aDegrees ) :
|
||||||
|
mirror( false ),
|
||||||
|
spin( false ),
|
||||||
|
degrees( aDegrees )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle wire
|
||||||
|
struct EWIRE
|
||||||
|
{
|
||||||
|
double x1;
|
||||||
|
double y1;
|
||||||
|
double x2;
|
||||||
|
double y2;
|
||||||
|
double width;
|
||||||
|
LAYER_NUM layer;
|
||||||
|
|
||||||
|
// for style: (continuous | longdash | shortdash | dashdot)
|
||||||
|
enum {
|
||||||
|
CONTINUOUS,
|
||||||
|
LONGDASH,
|
||||||
|
SHORTDASH,
|
||||||
|
DASHDOT,
|
||||||
|
};
|
||||||
|
opt_int style;
|
||||||
|
opt_double curve; ///< range is -359.9..359.9
|
||||||
|
|
||||||
|
// for cap: (flat | round)
|
||||||
|
enum {
|
||||||
|
FLAT,
|
||||||
|
ROUND,
|
||||||
|
};
|
||||||
|
opt_int cap;
|
||||||
|
|
||||||
|
EWIRE( wxXmlNode* aWire );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle via
|
||||||
|
struct EVIA
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
int layer_front_most; /// < extent
|
||||||
|
int layer_back_most; /// < inclusive
|
||||||
|
double drill;
|
||||||
|
opt_double diam;
|
||||||
|
opt_string shape;
|
||||||
|
|
||||||
|
EVIA( wxXmlNode* aVia );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle circle
|
||||||
|
struct ECIRCLE
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double radius;
|
||||||
|
double width;
|
||||||
|
LAYER_NUM layer;
|
||||||
|
|
||||||
|
ECIRCLE( wxXmlNode* aCircle );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle XML rectangle in binary
|
||||||
|
struct ERECT
|
||||||
|
{
|
||||||
|
double x1;
|
||||||
|
double y1;
|
||||||
|
double x2;
|
||||||
|
double y2;
|
||||||
|
int layer;
|
||||||
|
opt_erot rot;
|
||||||
|
|
||||||
|
ERECT( wxXmlNode* aRect );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EATTR
|
||||||
|
* parses an Eagle "attribute" XML element. Note that an attribute element
|
||||||
|
* is different than an XML element attribute. The attribute element is a
|
||||||
|
* full XML node in and of itself, and has attributes of its own. Blame Eagle.
|
||||||
|
*/
|
||||||
|
struct EATTR
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
opt_string value;
|
||||||
|
opt_double x;
|
||||||
|
opt_double y;
|
||||||
|
opt_double size;
|
||||||
|
opt_int layer;
|
||||||
|
opt_double ratio;
|
||||||
|
opt_erot rot;
|
||||||
|
|
||||||
|
enum { // for 'display'
|
||||||
|
Off,
|
||||||
|
VALUE,
|
||||||
|
NAME,
|
||||||
|
BOTH,
|
||||||
|
};
|
||||||
|
opt_int display;
|
||||||
|
|
||||||
|
EATTR( wxXmlNode* aTree );
|
||||||
|
EATTR() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle dimension element
|
||||||
|
struct EDIMENSION
|
||||||
|
{
|
||||||
|
double x1;
|
||||||
|
double y1;
|
||||||
|
double x2;
|
||||||
|
double y2;
|
||||||
|
double x3;
|
||||||
|
double y3;
|
||||||
|
int layer;
|
||||||
|
|
||||||
|
opt_string dimensionType;
|
||||||
|
|
||||||
|
EDIMENSION( wxXmlNode* aDimension );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle text element
|
||||||
|
struct ETEXT
|
||||||
|
{
|
||||||
|
string text;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double size;
|
||||||
|
int layer;
|
||||||
|
opt_string font;
|
||||||
|
opt_double ratio;
|
||||||
|
opt_erot rot;
|
||||||
|
|
||||||
|
enum { // for align
|
||||||
|
CENTER,
|
||||||
|
CENTER_LEFT,
|
||||||
|
TOP_CENTER,
|
||||||
|
TOP_LEFT,
|
||||||
|
TOP_RIGHT,
|
||||||
|
|
||||||
|
// opposites are -1 x above, used by code tricks in here
|
||||||
|
CENTER_RIGHT = -CENTER_LEFT,
|
||||||
|
BOTTOM_CENTER = -TOP_CENTER,
|
||||||
|
BOTTOM_LEFT = -TOP_RIGHT,
|
||||||
|
BOTTOM_RIGHT = -TOP_LEFT,
|
||||||
|
};
|
||||||
|
|
||||||
|
opt_int align;
|
||||||
|
|
||||||
|
ETEXT( wxXmlNode* aText );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle thru hol pad
|
||||||
|
struct EPAD
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double drill;
|
||||||
|
opt_double diameter;
|
||||||
|
|
||||||
|
// for shape: (square | round | octagon | long | offset)
|
||||||
|
enum {
|
||||||
|
SQUARE,
|
||||||
|
ROUND,
|
||||||
|
OCTAGON,
|
||||||
|
LONG,
|
||||||
|
OFFSET,
|
||||||
|
};
|
||||||
|
opt_int shape;
|
||||||
|
opt_erot rot;
|
||||||
|
opt_bool stop;
|
||||||
|
opt_bool thermals;
|
||||||
|
opt_bool first;
|
||||||
|
|
||||||
|
EPAD( wxXmlNode* aPad );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle SMD pad
|
||||||
|
struct ESMD
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double dx;
|
||||||
|
double dy;
|
||||||
|
int layer;
|
||||||
|
opt_int roundness;
|
||||||
|
opt_erot rot;
|
||||||
|
opt_bool stop;
|
||||||
|
opt_bool thermals;
|
||||||
|
opt_bool cream;
|
||||||
|
|
||||||
|
ESMD( wxXmlNode* aSMD );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle vertex
|
||||||
|
struct EVERTEX
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
|
||||||
|
EVERTEX( wxXmlNode* aVertex );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle polygon, without vertices which are parsed as needed
|
||||||
|
struct EPOLYGON
|
||||||
|
{
|
||||||
|
double width;
|
||||||
|
int layer;
|
||||||
|
opt_double spacing;
|
||||||
|
|
||||||
|
// KiCad priority is opposite of Eagle rank, that is:
|
||||||
|
// - Eagle Low rank drawn first
|
||||||
|
// - KiCad high priority drawn first
|
||||||
|
// So since Eagle has an upper limit we define this, used for the cases
|
||||||
|
// where no rank is specified.
|
||||||
|
static const int max_priority = 6;
|
||||||
|
|
||||||
|
enum { // for pour
|
||||||
|
SOLID,
|
||||||
|
HATCH,
|
||||||
|
CUTOUT,
|
||||||
|
};
|
||||||
|
int pour;
|
||||||
|
opt_double isolate;
|
||||||
|
opt_bool orphans;
|
||||||
|
opt_bool thermals;
|
||||||
|
opt_int rank;
|
||||||
|
|
||||||
|
EPOLYGON( wxXmlNode* aPolygon );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle hole element
|
||||||
|
struct EHOLE
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double drill;
|
||||||
|
|
||||||
|
EHOLE( wxXmlNode* aHole );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Eagle element element
|
||||||
|
struct EELEMENT
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
string library;
|
||||||
|
string package;
|
||||||
|
string value;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
opt_bool locked;
|
||||||
|
opt_bool smashed;
|
||||||
|
opt_erot rot;
|
||||||
|
|
||||||
|
EELEMENT( wxXmlNode* aElement );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ELAYER
|
||||||
|
{
|
||||||
|
int number;
|
||||||
|
string name;
|
||||||
|
int color;
|
||||||
|
int fill;
|
||||||
|
opt_bool visible;
|
||||||
|
opt_bool active;
|
||||||
|
|
||||||
|
ELAYER( wxXmlNode* aLayer );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function MapChildren
|
||||||
|
* provides an easy access to the children of an XML node via their names.
|
||||||
|
* @param currentNode is a pointer to a wxXmlNode, whose children will be mapped.
|
||||||
|
* @return NODE_MAP - a map linking the name of each children to the children itself (via a
|
||||||
|
* wxXmlNode*)
|
||||||
|
*/
|
||||||
|
NODE_MAP MapChildren( wxXmlNode* currentNode );
|
||||||
|
|
||||||
|
/// Assemble a two part key as a simple concatenation of aFirst and aSecond parts,
|
||||||
|
/// using a separator.
|
||||||
|
string makeKey( const string& aFirst, const string& aSecond );
|
||||||
|
|
||||||
|
/// Make a unique time stamp
|
||||||
|
unsigned long timeStamp( wxXmlNode* aTree );
|
||||||
|
|
||||||
|
/// Convert an Eagle curve end to a KiCad center for S_ARC
|
||||||
|
wxPoint kicad_arc_center( wxPoint start, wxPoint end, double angle );
|
||||||
|
|
||||||
|
#endif // _EAGLE_PARSER_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -27,48 +27,54 @@
|
||||||
|
|
||||||
#include <io_mgr.h>
|
#include <io_mgr.h>
|
||||||
#include <layers_id_colors_and_visibility.h>
|
#include <layers_id_colors_and_visibility.h>
|
||||||
|
#include <eagle_parser.h>
|
||||||
|
|
||||||
|
|
||||||
// forward declaration on ptree template so we can confine use of big boost
|
|
||||||
// headers to only the implementation *.cpp file.
|
|
||||||
|
|
||||||
#include <boost/property_tree/ptree_fwd.hpp>
|
|
||||||
#include <boost/ptr_container/ptr_map.hpp>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <wx/xml/xml.h>
|
||||||
|
|
||||||
|
|
||||||
class MODULE;
|
typedef std::map< std::string, MODULE* > MODULE_MAP;
|
||||||
typedef boost::ptr_map< std::string, MODULE > MODULE_MAP;
|
typedef std::map< std::string, ENET > NET_MAP;
|
||||||
|
typedef NET_MAP::const_iterator NET_MAP_CITER;
|
||||||
|
|
||||||
|
|
||||||
struct ENET
|
/// subset of eagle.drawing.board.designrules in the XML document
|
||||||
|
struct ERULES
|
||||||
{
|
{
|
||||||
int netcode;
|
int psElongationLong; ///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall
|
||||||
std::string netname;
|
///< Goes into making a scaling factor for "long" pads.
|
||||||
|
|
||||||
ENET( int aNetCode, const std::string& aNetName ) :
|
int psElongationOffset; ///< the offset of the hole within the "long" pad.
|
||||||
netcode( aNetCode ),
|
|
||||||
netname( aNetName )
|
double rvPadTop; ///< top pad size as percent of drill size
|
||||||
|
// double rvPadBottom; ///< bottom pad size as percent of drill size
|
||||||
|
|
||||||
|
double rlMinPadTop; ///< minimum copper annulus on through hole pads
|
||||||
|
double rlMaxPadTop; ///< maximum copper annulus on through hole pads
|
||||||
|
|
||||||
|
double rvViaOuter; ///< copper annulus is this percent of via hole
|
||||||
|
double rlMinViaOuter; ///< minimum copper annulus on via
|
||||||
|
double rlMaxViaOuter; ///< maximum copper annulus on via
|
||||||
|
double mdWireWire; ///< wire to wire spacing I presume.
|
||||||
|
|
||||||
|
|
||||||
|
ERULES() :
|
||||||
|
psElongationLong ( 100 ),
|
||||||
|
psElongationOffset ( 0 ),
|
||||||
|
rvPadTop ( 0.25 ),
|
||||||
|
// rvPadBottom ( 0.25 ),
|
||||||
|
rlMinPadTop ( Mils2iu( 10 ) ),
|
||||||
|
rlMaxPadTop ( Mils2iu( 20 ) ),
|
||||||
|
|
||||||
|
rvViaOuter ( 0.25 ),
|
||||||
|
rlMinViaOuter ( Mils2iu( 10 ) ),
|
||||||
|
rlMaxViaOuter ( Mils2iu( 20 ) ),
|
||||||
|
mdWireWire ( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ENET() :
|
void parse( wxXmlNode* aRules );
|
||||||
netcode( 0 )
|
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map< std::string, ENET > NET_MAP;
|
|
||||||
typedef NET_MAP::const_iterator NET_MAP_CITER;
|
|
||||||
|
|
||||||
typedef boost::property_tree::ptree PTREE;
|
|
||||||
typedef const PTREE CPTREE;
|
|
||||||
|
|
||||||
struct EELEMENT;
|
|
||||||
class XPATH;
|
|
||||||
struct ERULES;
|
|
||||||
struct EATTR;
|
|
||||||
class TEXTE_MODULE;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class EAGLE_PLUGIN
|
* Class EAGLE_PLUGIN
|
||||||
* works with Eagle 6.x XML board files and footprints to implement the
|
* works with Eagle 6.x XML board files and footprints to implement the
|
||||||
|
@ -175,11 +181,11 @@ private:
|
||||||
|
|
||||||
// all these loadXXX() throw IO_ERROR or ptree_error exceptions:
|
// all these loadXXX() throw IO_ERROR or ptree_error exceptions:
|
||||||
|
|
||||||
void loadAllSections( CPTREE& aDocument );
|
void loadAllSections( wxXmlNode* aDocument );
|
||||||
void loadDesignRules( CPTREE& aDesignRules );
|
void loadDesignRules( wxXmlNode* aDesignRules );
|
||||||
void loadLayerDefs( CPTREE& aLayers );
|
void loadLayerDefs( wxXmlNode* aLayers );
|
||||||
void loadPlain( CPTREE& aPlain );
|
void loadPlain( wxXmlNode* aPlain );
|
||||||
void loadSignals( CPTREE& aSignals );
|
void loadSignals( wxXmlNode* aSignals );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function loadLibrary
|
* Function loadLibrary
|
||||||
|
@ -192,10 +198,10 @@ private:
|
||||||
* we are loading a *.lbr not a *.brd file and the key used in m_templates is to exclude
|
* we are loading a *.lbr not a *.brd file and the key used in m_templates is to exclude
|
||||||
* the library name.
|
* the library name.
|
||||||
*/
|
*/
|
||||||
void loadLibrary( CPTREE& aLib, const std::string* aLibName );
|
void loadLibrary( wxXmlNode* aLib, const std::string* aLibName );
|
||||||
|
|
||||||
void loadLibraries( CPTREE& aLibs );
|
void loadLibraries( wxXmlNode* aLibs );
|
||||||
void loadElements( CPTREE& aElements );
|
void loadElements( wxXmlNode* aElements );
|
||||||
|
|
||||||
void orientModuleAndText( MODULE* m, const EELEMENT& e, const EATTR* nameAttr, const EATTR* valueAttr );
|
void orientModuleAndText( MODULE* m, const EELEMENT& e, const EATTR* nameAttr, const EATTR* valueAttr );
|
||||||
void orientModuleText( MODULE* m, const EELEMENT& e, TEXTE_MODULE* txt, const EATTR* a );
|
void orientModuleText( MODULE* m, const EELEMENT& e, TEXTE_MODULE* txt, const EATTR* a );
|
||||||
|
@ -216,16 +222,16 @@ private:
|
||||||
* Function makeModule
|
* Function makeModule
|
||||||
* creates a MODULE from an Eagle package.
|
* creates a MODULE from an Eagle package.
|
||||||
*/
|
*/
|
||||||
MODULE* makeModule( CPTREE& aPackage, const std::string& aPkgName ) const;
|
MODULE* makeModule( wxXmlNode* aPackage, const std::string& aPkgName ) const;
|
||||||
|
|
||||||
void packageWire( MODULE* aModule, CPTREE& aTree ) const;
|
void packageWire( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packagePad( MODULE* aModule, CPTREE& aTree ) const;
|
void packagePad( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packageText( MODULE* aModule, CPTREE& aTree ) const;
|
void packageText( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packageRectangle( MODULE* aModule, CPTREE& aTree ) const;
|
void packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packagePolygon( MODULE* aModule, CPTREE& aTree ) const;
|
void packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packageCircle( MODULE* aModule, CPTREE& aTree ) const;
|
void packageCircle( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packageHole( MODULE* aModule, CPTREE& aTree ) const;
|
void packageHole( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
void packageSMD( MODULE* aModule, CPTREE& aTree ) const;
|
void packageSMD( MODULE* aModule, wxXmlNode* aTree ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EAGLE_PLUGIN_H_
|
#endif // EAGLE_PLUGIN_H_
|
||||||
|
|
Loading…
Reference in New Issue