kicad-source/common/eagle_parser.cpp
Mark van Doesburg 91e3d21d68 Eeschema: Copy attributes from eagle.
Eagle allows for variants of components to be listed in the schematic.
This patch copies the variant data into the imported schematic item,
prefixing the alternate variant names with "VARIANT_" and keeping the
alternate values.
2018-07-31 11:58:01 -07:00

1073 lines
33 KiB
C++

/*
* 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 <functional>
#include <sstream>
#include <iomanip>
#include <cstdio>
constexpr auto DEFAULT_ALIGNMENT = ETEXT::BOTTOM_LEFT;
wxString escapeName( const wxString& aNetName )
{
wxString ret( aNetName );
ret.Replace( "~", "~~" );
ret.Replace( "!", "~" );
return ret;
}
template<> template<>
OPTIONAL_XML_ATTRIBUTE<wxString>::OPTIONAL_XML_ATTRIBUTE( wxString aData )
{
m_isAvailable = !aData.IsEmpty();
if( m_isAvailable )
Set( aData );
}
ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
{
// this array is used to adjust the fraction part value basing on the number of digits in the fraction
constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
int integer, fraction, pre_fraction, post_fraction;
// the following check is needed to handle correctly negative fractions where the integer part == 0
bool negative = ( aValue[0] == '-' );
// %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 digits
int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction );
if( ret == 0 )
throw XML_PARSER_ERROR( "Invalid coordinate" );
// process the integer part
value = ConvertToNm( integer, aUnit );
// process the fraction part
if( ret == 2 )
{
int digits = post_fraction - pre_fraction;
// adjust the number of digits if necessary as we cannot handle anything smaller than nanometers (rounding)
if( (unsigned) digits > DIVIDERS_MAX_IDX )
{
int diff = digits - DIVIDERS_MAX_IDX;
digits = DIVIDERS_MAX_IDX;
fraction /= DIVIDERS[diff];
}
int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
// keep the sign in mind
value = negative ? value - frac_value : value + frac_value;
}
}
long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
{
long long int ret;
switch( aUnit )
{
default:
case EU_NM: ret = aValue; break;
case EU_MM: ret = (long long) aValue * 1000000; break;
case EU_INCH: ret = (long long) aValue * 25400000; break;
case EU_MIL: ret = (long long) aValue * 25400; break;
}
wxASSERT( ( ret > 0 ) == ( aValue > 0 ) ); // check for overflow
return ret;
}
// Template specializations below parse wxString to the used types:
// - wxString (preferred)
// - string
// - double
// - int
// - bool
// - EROT
// - ECOORD
template <>
wxString Convert<wxString>( const wxString& aValue )
{
return aValue;
}
template <>
std::string Convert<std::string>( const wxString& aValue )
{
return std::string( aValue.ToUTF8() );
}
template <>
double Convert<double>( const 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>( const wxString& aValue )
{
if( aValue.IsEmpty() )
throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
return wxAtoi( aValue );
}
template <>
bool Convert<bool>( const 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>( const 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;
}
template<>
ECOORD Convert<ECOORD>( const wxString& aCoord )
{
// Eagle uses millimeters as the default unit
return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
}
/**
* 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, const wxString& 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, const wxString& aAttribute )
{
return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
}
NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
{
// Map node_name -> node_pointer
NODE_MAP nodesMap;
// Loop through all children mapping them in nodesMap
if( aCurrentNode )
aCurrentNode = aCurrentNode->GetChildren();
while( aCurrentNode )
{
// Create a new pair in the map
// key: current node name
// value: current node pointer
nodesMap[aCurrentNode->GetName()] = aCurrentNode;
// Get next child
aCurrentNode = aCurrentNode->GetNext();
}
return nodesMap;
}
timestamp_t EagleTimeStamp( wxXmlNode* aTree )
{
// in this case from a unique tree memory location
return (timestamp_t) reinterpret_cast<uintptr_t>( aTree );
}
timestamp_t EagleModuleTstamp( const wxString& aName, const wxString& aValue, int aUnit )
{
std::size_t h1 = std::hash<wxString>{}( aName );
std::size_t h2 = std::hash<wxString>{}( aValue );
std::size_t h3 = std::hash<int>{}( aUnit );
return (timestamp_t)( h1 ^ (h2 << 1) ^ (h3 << 2) );
}
wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle )
{
// Eagle give us start and end.
// S_ARC wants start to give the center, and end to give the start.
double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
wxPoint mid = ( aStart + aEnd ) / 2;
double dlen = sqrt( dx*dx + dy*dy );
wxASSERT( dlen != 0 );
wxASSERT( aAngle != 0 );
double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
wxPoint center(
mid.x + dist * ( dy / dlen ),
mid.y - dist * ( dx / dlen )
);
return center;
}
static int parseAlignment( const wxString& aAlignment )
{
// (bottom-left | bottom-center | bottom-right | center-left |
// center | center-right | top-left | top-center | top-right)
if( aAlignment == "center" )
return ETEXT::CENTER;
else if( aAlignment == "center-right" )
return ETEXT::CENTER_RIGHT;
else if( aAlignment == "top-left" )
return ETEXT::TOP_LEFT;
else if( aAlignment == "top-center" )
return ETEXT::TOP_CENTER;
else if( aAlignment == "top-right" )
return ETEXT::TOP_RIGHT;
else if( aAlignment == "bottom-left" )
return ETEXT::BOTTOM_LEFT;
else if( aAlignment == "bottom-center" )
return ETEXT::BOTTOM_CENTER;
else if( aAlignment == "bottom-right" )
return ETEXT::BOTTOM_RIGHT;
else if( aAlignment == "center-left" )
return ETEXT::CENTER_LEFT;
return DEFAULT_ALIGNMENT;
}
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<ECOORD>( aWire, "x1" );
y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
width = parseRequiredAttribute<ECOORD>( aWire, "width" );
layer = parseRequiredAttribute<int>( aWire, "layer" );
curve = parseOptionalAttribute<double>( aWire, "curve" );
opt_wxString s = parseOptionalAttribute<wxString>( 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<wxString>( aWire, "cap" );
if( s == "round" )
cap = EWIRE::ROUND;
else if( s == "flat" )
cap = EWIRE::FLAT;
}
EJUNCTION::EJUNCTION( wxXmlNode* aJunction )
{
/*
<!ELEMENT junction EMPTY>
<!ATTLIST junction
x %Coord; #REQUIRED
y %Coord; #REQUIRED
>
*/
x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
}
ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName )
{
/*
<!ELEMENT label EMPTY>
<!ATTLIST label
x %Coord; #REQUIRED
y %Coord; #REQUIRED
size %Dimension; #REQUIRED
layer %Layer; #REQUIRED
font %TextFont; "proportional"
ratio %Int; "8"
rot %Rotation; "R0"
xref %Bool; "no"
>
*/
x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
layer = parseRequiredAttribute<int>( aLabel, "layer" );
rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
netname = aNetName;
}
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<ECOORD>( aVia, "x" );
y = parseRequiredAttribute<ECOORD>( aVia, "y" );
wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
shape = parseOptionalAttribute<wxString>( 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<ECOORD>( aCircle, "x" );
y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
width = parseRequiredAttribute<ECOORD>( 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<ECOORD>( aRect, "x1" );
y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
y2 = parseRequiredAttribute<ECOORD>( 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<wxString>( aTree, "name" );
value = parseOptionalAttribute<wxString>( aTree, "value" );
x = parseOptionalAttribute<ECOORD>( aTree, "x" );
y = parseOptionalAttribute<ECOORD>( aTree, "y" );
size = parseOptionalAttribute<ECOORD>( 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_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
// (off | value | name | both)
if( stemp == "off" )
display = EATTR::Off;
else if( stemp == "name" )
display = EATTR::NAME;
else if( stemp == "both" )
display = EATTR::BOTH;
else // "value" is the default
display = EATTR::VALUE;
stemp = parseOptionalAttribute<wxString>( aTree, "align" );
align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
}
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<ECOORD>( aDimension, "x1" );
y1 = parseRequiredAttribute<ECOORD>( aDimension, "y1" );
x2 = parseRequiredAttribute<ECOORD>( aDimension, "x2" );
y2 = parseRequiredAttribute<ECOORD>( aDimension, "y2" );
x3 = parseRequiredAttribute<ECOORD>( aDimension, "x3" );
y3 = parseRequiredAttribute<ECOORD>( aDimension, "y3" );
layer = parseRequiredAttribute<int>( aDimension, "layer" );
dimensionType = parseOptionalAttribute<wxString>( aDimension, "dtype" );
}
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<ECOORD>( aText, "x" );
y = parseRequiredAttribute<ECOORD>( aText, "y" );
size = parseRequiredAttribute<ECOORD>( aText, "size" );
layer = parseRequiredAttribute<int>( aText, "layer" );
font = parseOptionalAttribute<wxString>( aText, "font" );
ratio = parseOptionalAttribute<double>( aText, "ratio" );
rot = parseOptionalAttribute<EROT>( aText, "rot" );
opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
}
wxSize ETEXT::ConvertSize() const
{
wxSize textsize;
if( font )
{
const wxString& fontName = font.CGet();
if( fontName == "vector" )
{
textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
}
else if( fontName == "fixed" )
{
textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
}
else
{
wxASSERT( false );
textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
}
}
else
{
textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() );
}
return textsize;
}
EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
{
// #REQUIRED says DTD, throw exception if not found
name = parseRequiredAttribute<wxString>( aPad, "name" );
x = parseRequiredAttribute<ECOORD>( aPad, "x" );
y = parseRequiredAttribute<ECOORD>( aPad, "y" );
rot = parseOptionalAttribute<EROT>( aPad, "rot" );
stop = parseOptionalAttribute<bool>( aPad, "stop" );
thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
}
EPAD::EPAD( wxXmlNode* aPad )
: EPAD_COMMON( 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
drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
// Optional attributes
diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
opt_wxString s = parseOptionalAttribute<wxString>( 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;
first = parseOptionalAttribute<bool>( aPad, "first" );
}
ESMD::ESMD( wxXmlNode* aSMD )
: EPAD_COMMON( 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
dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
layer = parseRequiredAttribute<int>( aSMD, "layer" );
roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
cream = parseOptionalAttribute<bool>( aSMD, "cream" );
}
EPIN::EPIN( wxXmlNode* aPin )
{
/*
<!ELEMENT pin EMPTY>
<!ATTLIST pin
name %String; #REQUIRED
x %Coord; #REQUIRED
y %Coord; #REQUIRED
visible %PinVisible; "both"
length %PinLength; "long"
direction %PinDirection; "io"
function %PinFunction; "none"
swaplevel %Int; "0"
rot %Rotation; "R0"
>
*/
// DTD #REQUIRED, throw exception if not found
name = parseRequiredAttribute<wxString>( aPin, "name" );
x = parseRequiredAttribute<ECOORD>( aPin, "x" );
y = parseRequiredAttribute<ECOORD>( aPin, "y" );
visible = parseOptionalAttribute<wxString>( aPin, "visible" );
length = parseOptionalAttribute<wxString>( aPin, "length" );
direction = parseOptionalAttribute<wxString>( aPin, "direction" );
function = parseOptionalAttribute<wxString>( aPin, "function" );
swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
rot = parseOptionalAttribute<EROT>( aPin, "rot" );
}
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<ECOORD>( aVertex, "x" );
y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
curve = parseOptionalAttribute<double>( aVertex, "curve" );
}
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<ECOORD>( aPolygon, "width" );
layer = parseRequiredAttribute<int>( aPolygon, "layer" );
spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
opt_wxString s = parseOptionalAttribute<wxString>( 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<ECOORD>( aHole, "x" );
y = parseRequiredAttribute<ECOORD>( aHole, "y" );
drill = parseRequiredAttribute<ECOORD>( 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<wxString>( aElement, "name" );
library = parseRequiredAttribute<wxString>( aElement, "library" );
value = parseRequiredAttribute<wxString>( aElement, "value" );
std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
ReplaceIllegalFileNameChars( &p, '_' );
package = wxString::FromUTF8( p.c_str() );
x = parseRequiredAttribute<ECOORD>( aElement, "x" );
y = parseRequiredAttribute<ECOORD>( 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<wxString>( aLayer, "name" );
color = parseRequiredAttribute<int>( aLayer, "color" );
fill = 1; // Temporary value.
visible = parseOptionalAttribute<bool>( aLayer, "visible" );
active = parseOptionalAttribute<bool>( aLayer, "active" );
}
EPART::EPART( wxXmlNode* aPart )
{
/*
* <!ELEMENT part (attribute*, variant*)>
* <!ATTLIST part
* name %String; #REQUIRED
* library %String; #REQUIRED
* deviceset %String; #REQUIRED
* device %String; #REQUIRED
* technology %String; ""
* value %String; #IMPLIED
* >
*/
// #REQUIRED
name = parseRequiredAttribute<wxString>( aPart, "name" );
library = parseRequiredAttribute<wxString>( aPart, "library" );
deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
device = parseRequiredAttribute<wxString>( aPart, "device" );
technology = parseOptionalAttribute<wxString>( aPart, "technology" );
value = parseOptionalAttribute<wxString>( aPart, "value" );
for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
{
if( child->GetName() == "attribute" )
{
std::string aname, avalue;
for( auto x = child->GetAttributes(); x; x = x->GetNext() )
{
if( x->GetName() == "name" )
aname = x->GetValue();
else if( x->GetName() == "value" )
avalue = x->GetValue();
}
if( aname.size() && avalue.size() )
attribute[aname] = avalue;
}
else if( child->GetName() == "variant" )
{
std::string aname, avalue;
for( auto x = child->GetAttributes(); x; x = x->GetNext() )
{
if( x->GetName() == "name" )
aname = x->GetValue();
else if( x->GetName() == "value" )
avalue = x->GetValue();
}
if( aname.size() && avalue.size() )
variant[aname] = avalue;
}
}
}
EINSTANCE::EINSTANCE( wxXmlNode* aInstance )
{
/*
* <!ELEMENT instance (attribute)*>
* <!ATTLIST instance
* part %String; #REQUIRED
* gate %String; #REQUIRED
* x %Coord; #REQUIRED
* y %Coord; #REQUIRED
* smashed %Bool; "no"
* rot %Rotation; "R0"
* >
*/
part = parseRequiredAttribute<wxString>( aInstance, "part" );
gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
// optional
smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
}
EGATE::EGATE( wxXmlNode* aGate )
{
/*
* <!ELEMENT gate EMPTY>
* <!ATTLIST gate
* name %String; #REQUIRED
* symbol %String; #REQUIRED
* x %Coord; #REQUIRED
* y %Coord; #REQUIRED
* addlevel %GateAddLevel; "next"
* swaplevel %Int; "0"
* >
*/
name = parseRequiredAttribute<wxString>( aGate, "name" );
symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
x = parseRequiredAttribute<ECOORD>( aGate, "x" );
y = parseRequiredAttribute<ECOORD>( aGate, "y" );
opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
// (off | value | name | both)
if( stemp == "must" )
addlevel = EGATE::MUST;
else if( stemp == "can" )
addlevel = EGATE::CAN;
else if( stemp == "next" )
addlevel = EGATE::NEXT;
else if( stemp == "request" )
addlevel = EGATE::REQUEST;
else if( stemp == "always" )
addlevel = EGATE::ALWAYS;
else
addlevel = EGATE::NEXT;
}
ECONNECT::ECONNECT( wxXmlNode* aConnect )
{
/*
* <!ELEMENT connect EMPTY>
* <!ATTLIST connect
* gate %String; #REQUIRED
* pin %String; #REQUIRED
* pad %String; #REQUIRED
* route %ContactRoute; "all"
* >
*/
gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
}
EDEVICE::EDEVICE( wxXmlNode* aDevice )
{
/*
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
name = parseRequiredAttribute<wxString>( aDevice, "name" );
opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
if( pack )
{
std::string p( pack->c_str() );
ReplaceIllegalFileNameChars( &p, '_' );
package.Set( wxString::FromUTF8( p.c_str() ) );
}
NODE_MAP aDeviceChildren = MapChildren( aDevice );
wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, "connects" );
while( connectNode )
{
connects.push_back( ECONNECT( connectNode ) );
connectNode = connectNode->GetNext();
}
}
EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
{
/*
<!ELEMENT deviceset (description?, gates, devices)>
<!ATTLIST deviceset
name %String; #REQUIRED
prefix %String; ""
uservalue %Bool; "no"
>
*/
name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
/* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp
*
//TODO: description
NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet);
wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, "device");
while(deviceNode){
devices.push_back(EDEVICE(deviceNode));
deviceNode->GetNext();
}
wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, "gate");
while(gateNode){
gates.push_back(EGATE(gateNode));
gateNode->GetNext();
}
*/
}