Eeschema plugin to import Eagle XML schematics

This commit is contained in:
Maciej Suminski 2017-10-20 09:34:49 +02:00
commit b3cbfdb7ba
61 changed files with 20922 additions and 524 deletions

View File

@ -42,6 +42,7 @@ Cheng Sheng <chengsheng[at]google-dot-com> Google Inc.
Kristoffer Ödmark <kristoffer.odmark90[at]gmail-dot-com>
Oliver Walters <oliver.henry.walters[at]gmail-dot-com>
Jon Evans <jon[at]craftyjon-dot-com>
Russell Oliver <roliver8143[at]gmail-dot-com>
See also CHANGELOG.txt for contributors.

View File

@ -0,0 +1,39 @@
Eagle Plugin Implementation Notes. 2017 Russell Oliver
Below is some notes on the correspondence between Eagle schematics and symbols libraries and the
KiCad equivalent.
Eagle libraries are a many to many listing of symbols and footprints connected by a device set and
device definitions. They are embedded in the schematic and board files if there are used, and
therefore the schematic symbols and footprints can be recovered from either file.
An Eagle device set definition is the information needed to represent a physical part at the
schematic level including the functional gates of the device. Each gate is lists the symbol to be
displayed for that gate. This is equivalent to a KiCad symbol unit. Since the symbol is defined
outside of the device set, multiple devices sets in the library can use the same symbol for a gate.
Lower to a device set, is the device definition. This establishes the link between the schematic
symbols and a physical part through the 'connect' elements. These map the symbol pins for each gate
to the physical pins provided by the package (footprint) definition. An Eagle Symbol outlines the
layout of graphical of items including pins. Pins for multi gate symbols are generally labelled
per their function, i.e. input / output. An Eagle symbol pin is not numbered but merely labelled. A
connect element gives the pad number for each pin found in that gate. Therefore the equivalent
KiCad pin number is read from the connect element pad number. Since an Eagle gate is equivalent to
a KiCad symbol unit, the graphical items for that unit will be copied from the Eagle symbol for
that gate and will be unique for that unit. This will yield duplication of the graphical elements
if the same symbol is used for multiple gates but the conversion will be complete.
An Eagle sheet contains a list of instances, which are equivalent to KiCad schematic component
entries. An instance describes the part, the gate used and its location on the sheet. This is
translated into the equivalent KiCad symbol with the given unit number.
Eagle 'plain' items describe graphical items with no electrical connection, such as note text,
lines etc. Of importance is the use of wire elements to describe both electrical connections and
graphical items. A wire element will act as an electrical connection when defined within a net and
segment. Anywhere else it is a graphical line. The layer for the wire element will change the
displayed colour for the wire. Connections between regular wires and busses occur when a wire ends
on a bus segment. When translated to KiCad a bus connection symbol is created. Within an Eagle
schematic there can be multiple sheets in a flat hierarchy. For each sheet, there is a list of
electrically connected nets. Each net is broken up into graphically connected segments, defined by
a list of wires and labels. Labels remain associate with wires of that net segment, even if they
are not located on a wire element. This necessitates the movement of such a label to the nearest
wire segment within KiCad.

View File

@ -26,13 +26,71 @@
#include <eagle_parser.h>
#include <wx/xml/xml.h>
#include <wx/string.h>
#include <wx/filename.h>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <convert_to_biu.h>
constexpr auto DEFAULT_ALIGNMENT = ETEXT::BOTTOM_LEFT;
ECOORD::ECOORD( const wxString& aValue, enum ECOORD::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 = ToNanoMeters( 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 = ToNanoMeters( fraction, aUnit ) / DIVIDERS[digits];
// keep the sign in mind
value = negative ? value - frac_value : value + frac_value;
}
}
long long int ECOORD::ToNanoMeters( int aValue, enum UNIT aUnit )
{
long long int ret;
switch( aUnit )
{
case NM: ret = aValue; break;
case MM: ret = (long long) aValue * 1000000; break;
case INCH: ret = (long long) aValue * 25400000; break;
case MIL: ret = (long long) aValue * 25400; break;
}
wxASSERT( ( ret > 0 ) == ( aValue > 0 ) ); // check for overflow
return ret;
}
using std::string;
// Template specializations below parse wxString to the used types:
// - string
@ -40,12 +98,12 @@ using std::string;
// - int
// - bool
// - EROT
// - ECOORD
template<>
string Convert<string>( const wxString& aValue )
{
return aValue.ToStdString();
return string( aValue.ToUTF8() );
}
@ -102,6 +160,15 @@ EROT Convert<EROT>( const wxString& aRot )
return value;
}
template<>
ECOORD Convert<ECOORD>( const wxString& aCoord )
{
// Eagle uses millimeters as the default unit
return ECOORD( aCoord, ECOORD::UNIT::MM );
}
/**
* Function parseRequiredAttribute
* parsese the aAttribute of the XML node aNode.
@ -111,7 +178,7 @@ EROT Convert<EROT>( const wxString& aRot )
* @return T - the attributed parsed as the specified type.
*/
template<typename T>
T parseRequiredAttribute( wxXmlNode* aNode, string aAttribute )
T parseRequiredAttribute( wxXmlNode* aNode, const string& aAttribute )
{
wxString value;
@ -130,12 +197,101 @@ T parseRequiredAttribute( wxXmlNode* aNode, string aAttribute )
* found.
*/
template<typename T>
OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, string aAttribute )
OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const string& 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().ToStdString()] = aCurrentNode;
// Get next child
aCurrentNode = aCurrentNode->GetNext();
}
return nodesMap;
}
unsigned long EagleTimeStamp( wxXmlNode* aTree )
{
// in this case from a unique tree memory location
return (unsigned long)(void*) aTree;
}
time_t EagleModuleTstamp( const string& aName, const string& aValue, int aUnit )
{
std::size_t h1 = std::hash<string>{}( aName );
std::size_t h2 = std::hash<string>{}( aValue );
std::size_t h3 = std::hash<int>{}( aUnit );
return 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 )
{
/*
@ -154,11 +310,11 @@ EWIRE::EWIRE( wxXmlNode* aWire )
>
*/
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" );
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" );
@ -182,6 +338,47 @@ EWIRE::EWIRE( wxXmlNode* aWire )
}
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<string>( aLabel, "xref" );
netname = aNetName;
}
EVIA::EVIA( wxXmlNode* aVia )
{
/*
@ -197,15 +394,15 @@ EVIA::EVIA( wxXmlNode* aVia )
>
*/
x = parseRequiredAttribute<double>( aVia, "x" );
y = parseRequiredAttribute<double>( aVia, "y" );
x = parseRequiredAttribute<ECOORD>( aVia, "x" );
y = parseRequiredAttribute<ECOORD>( 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" );
drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
shape = parseOptionalAttribute<string>( aVia, "shape" );
}
@ -223,10 +420,10 @@ ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
>
*/
x = parseRequiredAttribute<double>( aCircle, "x" );
y = parseRequiredAttribute<double>( aCircle, "y" );
radius = parseRequiredAttribute<double>( aCircle, "radius" );
width = parseRequiredAttribute<double>( aCircle, "width" );
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" );
}
@ -245,10 +442,10 @@ ERECT::ERECT( wxXmlNode* aRect )
>
*/
x1 = parseRequiredAttribute<double>( aRect, "x1" );
y1 = parseRequiredAttribute<double>( aRect, "y1" );
x2 = parseRequiredAttribute<double>( aRect, "x2" );
y2 = parseRequiredAttribute<double>( aRect, "y2" );
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" );
}
@ -276,9 +473,9 @@ EATTR::EATTR( wxXmlNode* aTree )
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" );
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.
@ -297,6 +494,10 @@ EATTR::EATTR( wxXmlNode* aTree )
display = EATTR::NAME;
else if( stemp == "both" )
display = EATTR::BOTH;
stemp = parseOptionalAttribute<string>( aTree, "align" );
align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
}
@ -316,20 +517,14 @@ EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
>
*/
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" );
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" );
opt_string dimType = parseOptionalAttribute<string>( aDimension, "dtype" );
if( !dimType )
{
// default type is parallel
}
dimensionType = parseOptionalAttribute<string>( aDimension, "dtype" );
}
@ -350,9 +545,9 @@ ETEXT::ETEXT( wxXmlNode* aText )
*/
text = aText->GetNodeContent();
x = parseRequiredAttribute<double>( aText, "x" );
y = parseRequiredAttribute<double>( aText, "y" );
size = parseRequiredAttribute<double>( aText, "size" );
x = parseRequiredAttribute<ECOORD>( aText, "x" );
y = parseRequiredAttribute<ECOORD>( aText, "y" );
size = parseRequiredAttribute<ECOORD>( aText, "size" );
layer = parseRequiredAttribute<int>( aText, "layer" );
font = parseOptionalAttribute<string>( aText, "font" );
@ -361,26 +556,38 @@ ETEXT::ETEXT( wxXmlNode* aText )
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;
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;
}
@ -404,12 +611,12 @@ EPAD::EPAD( wxXmlNode* aPad )
// #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" );
x = parseRequiredAttribute<ECOORD>( aPad, "x" );
y = parseRequiredAttribute<ECOORD>( aPad, "y" );
drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
// Optional attributes
diameter = parseOptionalAttribute<double>( aPad, "diameter" );
diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
opt_string s = parseOptionalAttribute<string>( aPad, "shape" );
@ -452,10 +659,10 @@ ESMD::ESMD( wxXmlNode* aSMD )
// 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" );
x = parseRequiredAttribute<ECOORD>( aSMD, "x" );
y = parseRequiredAttribute<ECOORD>( aSMD, "y" );
dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
layer = parseRequiredAttribute<int>( aSMD, "layer" );
roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
@ -467,6 +674,37 @@ ESMD::ESMD( wxXmlNode* aSMD )
}
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<string>( aPin, "name" );
x = parseRequiredAttribute<ECOORD>( aPin, "x" );
y = parseRequiredAttribute<ECOORD>( aPin, "y" );
visible = parseOptionalAttribute<string>( aPin, "visible" );
length = parseOptionalAttribute<string>( aPin, "length" );
direction = parseOptionalAttribute<string>( aPin, "direction" );
function = parseOptionalAttribute<string>( aPin, "function" );
swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
rot = parseOptionalAttribute<EROT>( aPin, "rot" );
}
EVERTEX::EVERTEX( wxXmlNode* aVertex )
{
/*
@ -478,8 +716,8 @@ EVERTEX::EVERTEX( wxXmlNode* aVertex )
>
*/
x = parseRequiredAttribute<double>( aVertex, "x" );
y = parseRequiredAttribute<double>( aVertex, "y" );
x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
}
@ -498,11 +736,11 @@ EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
>
*/
width = parseRequiredAttribute<double>( aPolygon, "width" );
width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
layer = parseRequiredAttribute<int>( aPolygon, "layer" );
spacing = parseOptionalAttribute<double>( aPolygon, "spacing" );
isolate = parseOptionalAttribute<double>( aPolygon, "isolate" );
spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
opt_string s = parseOptionalAttribute<string>( aPolygon, "pour" );
// default pour to solid fill
@ -532,9 +770,9 @@ EHOLE::EHOLE( wxXmlNode* aHole )
*/
// #REQUIRED:
x = parseRequiredAttribute<double>( aHole, "x" );
y = parseRequiredAttribute<double>( aHole, "y" );
drill = parseRequiredAttribute<double>( aHole, "drill" );
x = parseRequiredAttribute<ECOORD>( aHole, "x" );
y = parseRequiredAttribute<ECOORD>( aHole, "y" );
drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
}
@ -562,8 +800,8 @@ EELEMENT::EELEMENT( wxXmlNode* aElement )
package = parseRequiredAttribute<string>( aElement, "package" );
ReplaceIllegalFileNameChars( &package );
x = parseRequiredAttribute<double>( aElement, "x" );
y = parseRequiredAttribute<double>( aElement, "y" );
x = parseRequiredAttribute<ECOORD>( aElement, "x" );
y = parseRequiredAttribute<ECOORD>( aElement, "y" );
// optional
locked = parseOptionalAttribute<bool>( aElement, "locked" );
@ -595,56 +833,169 @@ ELAYER::ELAYER( wxXmlNode* aLayer )
}
NODE_MAP MapChildren( wxXmlNode* currentNode )
EPART::EPART( wxXmlNode* aPart )
{
// Map node_name -> node_pointer
NODE_MAP nodesMap;
/*
* <!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<string>( aPart, "name" );
library = parseRequiredAttribute<string>( aPart, "library" );
deviceset = parseRequiredAttribute<string>( aPart, "deviceset" );
device = parseRequiredAttribute<string>( aPart, "device" );
technology = parseOptionalAttribute<string>( aPart, "technology" );
value = parseOptionalAttribute<string>( aPart, "value" );
}
// 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();
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<string>( aInstance, "part" );
gate = parseRequiredAttribute<string>( 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<string>( aGate, "name" );
symbol = parseRequiredAttribute<string>( aGate, "symbol" );
x = parseRequiredAttribute<ECOORD>( aGate, "x" );
y = parseRequiredAttribute<ECOORD>( aGate, "y" );
opt_string stemp = parseOptionalAttribute<string>( 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<string>( aConnect, "gate" );
pin = parseRequiredAttribute<string>( aConnect, "pin" );
pad = parseRequiredAttribute<string>( aConnect, "pad" );
//TODO:
//int contactroute;
};
EDEVICE::EDEVICE( wxXmlNode* aDevice )
{
/*
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
name = parseRequiredAttribute<string>( aDevice, "name" );
package = parseOptionalAttribute<string>( aDevice, "package" );
NODE_MAP aDeviceChildren = MapChildren(aDevice);
wxXmlNode* connectNode = getChildrenNodes(aDeviceChildren, "connects");
while(connectNode){
connects.push_back(ECONNECT(connectNode));
connectNode = connectNode->GetNext();
}
return nodesMap;
}
};
string makeKey( const string& aFirst, const string& aSecond )
EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
{
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( 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 );
double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
wxPoint center(
mid.x + dist * ( dy / dlen ),
mid.y - dist * ( dx / dlen )
);
return center;
/*
<!ELEMENT deviceset (description?, gates, devices)>
<!ATTLIST deviceset
name %String; #REQUIRED
prefix %String; ""
uservalue %Bool; "no"
>
*/
name = parseRequiredAttribute<string>(aDeviceSet, "name");
prefix = parseOptionalAttribute<string>( 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();
}
*/
}

View File

@ -35,20 +35,7 @@
#include <class_drawpanel.h> // EDA_DRAW_PANEL
#include <basic_gal.h>
// Conversion to application internal units defined at build time.
#if defined( PCBNEW )
#include <class_board_item.h> // for FMT_IU
#elif defined( EESCHEMA )
#include <sch_item_struct.h> // for FMT_IU
#elif defined( GERBVIEW )
#elif defined( PL_EDITOR )
#include <base_units.h>
#define FMT_IU Double2Str
#else
#error "Cannot resolve units formatting due to no definition of EESCHEMA or PCBNEW."
#endif
#include <unit_format.h>
#include <convert_to_biu.h>
EDA_TEXT::EDA_TEXT( const wxString& text ) :

View File

@ -52,7 +52,7 @@ void FP_LIB_TABLE_ROW::SetType( const wxString& aType )
type = IO_MGR::EnumFromStr( aType );
if( IO_MGR::PCB_FILE_T( -1 ) == type )
type = IO_MGR::KICAD;
type = IO_MGR::KICAD_SEXP;
}

View File

@ -72,6 +72,8 @@ const wxString SchematicSymbolFileWildcard( _( "KiCad drawing symbol file (*.sym
const wxString SchematicLibraryFileWildcard( _( "KiCad component library file (*.lib)|*.lib" ) );
const wxString ProjectFileWildcard( _( "KiCad project files (*.pro)|*.pro" ) );
const wxString SchematicFileWildcard( _( "KiCad schematic files (*.sch)|*.sch" ) );
const wxString EagleSchematicFileWildcard( _( "Eagle XML schematic file (*.sch)|*.sch" ) );
const wxString EagleFilesWildcard( _( "Eagle XML files (*.sch *.brd)|*.sch;*.brd" ) );
const wxString NetlistFileWildcard( _( "KiCad netlist files (*.net)|*.net" ) );
const wxString GerberFileWildcard( _( "Gerber files (*.pho)|*.pho" ) );
const wxString LegacyPcbFileWildcard( _( "KiCad printed circuit board files (*.brd)|*.brd" ) );

View File

@ -168,6 +168,7 @@ set( EESCHEMA_SRCS
sch_bus_entry.cpp
sch_collectors.cpp
sch_component.cpp
sch_eagle_plugin.cpp
sch_field.cpp
sch_io_mgr.cpp
sch_item_struct.cpp
@ -299,7 +300,7 @@ target_link_libraries( eeschema
)
# the DSO (KIFACE) housing the main eeschema code:
add_library( eeschema_kiface MODULE
add_library( eeschema_kiface SHARED
${EESCHEMA_SRCS}
${EESCHEMA_COMMON_SRCS}
)
@ -437,3 +438,4 @@ add_custom_target(
add_dependencies( eeschema_kiface dialog_bom_cfg_lexer_source_files )
add_subdirectory( plugins )
add_subdirectory( qa )

View File

@ -433,7 +433,7 @@ void DIALOG_BOM::OnRunPlugin( wxCommandEvent& event )
m_parent->SetExecFlags( wxEXEC_SHOW_CONSOLE );
#endif
m_parent->CreateNetlist( -1, fullfilename, 0, &reporter );
m_parent->CreateNetlist( -1, fullfilename, 0, &reporter, false );
m_Messages->SetValue( reportmsg );
}

View File

@ -611,7 +611,7 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event )
else
m_Parent->SetNetListerCommand( wxEmptyString );
m_Parent->CreateNetlist( currPage->m_IdNetType, fullpath, netlist_opt );
m_Parent->CreateNetlist( currPage->m_IdNetType, fullpath, netlist_opt, NULL, false );
WriteCurrentNetlistSetup();
@ -689,7 +689,7 @@ void NETLIST_DIALOG::RunSimulator( wxCommandEvent& event )
netlist_opt |= NET_ADJUST_PASSIVE_VALS;
if( ! m_Parent->CreateNetlist( currPage->m_IdNetType, fn.GetFullPath(),
netlist_opt ) )
netlist_opt, NULL, false ) )
return;
ExecuteFile( this, ExecFile, CommandLine );
@ -878,4 +878,3 @@ int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller )
return dlg.ShowModal();
}

View File

@ -60,6 +60,7 @@ enum id_eeschema_frm
{
ID_UPDATE_ONE_SHEET = ID_END_LIST,
ID_SAVE_ONE_SHEET_UNDER_NEW_NAME,
ID_IMPORT_NON_KICAD_SCH,
/* Schematic editor main menubar IDs. */
ID_RESCUE_CACHED,

View File

@ -47,6 +47,7 @@
#include <project_rescue.h>
#include <eeschema_config.h>
#include <sch_legacy_plugin.h>
#include <sch_eagle_plugin.h>
//#define USE_SCH_LEGACY_IO_PLUGIN
@ -190,8 +191,6 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
{
// implement the pseudo code from KIWAY_PLAYER.h:
SCH_SCREENS screenList;
// This is for python:
if( aFileSet.size() != 1 )
{
@ -216,34 +215,8 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
return false;
}
// Save any currently open and modified project files.
for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
{
if( screen->IsModify() )
{
int response = YesNoCancelDialog( this, _(
"The current schematic has been modified. Do you wish to save the changes?" ),
wxEmptyString,
_( "Save and Load" ),
_( "Load Without Saving" )
);
if( response == wxID_CANCEL )
{
return false;
}
else if( response == wxID_YES )
{
wxCommandEvent dummy;
OnSaveProject( dummy );
}
else
{
// response == wxID_NO, fall thru
}
break;
}
}
if( !AskToSaveChanges() )
return false;
wxFileName pro = fullFileName;
pro.SetExt( ProjectFileExtension );
@ -314,7 +287,6 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
{
delete g_RootSheet; // Delete the current project.
g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure.
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
try
@ -399,7 +371,7 @@ bool SCH_EDIT_FRAME::AppendOneEEProject()
// open file chooser dialog
wxString path = wxPathOnly( Prj().GetProjectFullName() );
wxFileDialog dlg( this, _( "Import Schematic" ), path,
wxFileDialog dlg( this, _( "Append Schematic" ), path,
wxEmptyString, SchematicFileWildcard,
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
@ -533,6 +505,25 @@ void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
}
void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
{
if( !AskToSaveChanges() )
return;
wxString path = wxPathOnly( Prj().GetProjectFullName() );
wxFileDialog dlg( this, _( "Import Schematic" ), path,
wxEmptyString, EagleSchematicFileWildcard,
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if( dlg.ShowModal() == wxID_CANCEL )
return;
// For now there is only one import plugin
ImportFile( dlg.GetPath(), SCH_IO_MGR::SCH_EAGLE );
}
void SCH_EDIT_FRAME::OnSaveProject( wxCommandEvent& aEvent )
{
SCH_SCREEN* screen;
@ -606,3 +597,118 @@ bool SCH_EDIT_FRAME::doAutoSave()
return autoSaveOk;
}
bool SCH_EDIT_FRAME::ImportFile( const wxString& aFileName, int aFileType )
{
wxString fullFileName( aFileName );
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi;
wxString projectpath;
wxFileName newfilename;
SCH_SHEET_LIST sheetList( g_RootSheet );
SCH_SCREENS schematic;
switch( (SCH_IO_MGR::SCH_FILE_T) aFileType )
{
case SCH_IO_MGR::SCH_EAGLE:
// We insist on caller sending us an absolute path, if it does not, we say it's a bug.
wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(),
wxT( "Import eagle schematic caller didn't send full filename" ) );
if( !LockFile( fullFileName ) )
{
wxString msg = wxString::Format( _( "Schematic file '%s' is already open." ),
GetChars( fullFileName ) );
DisplayError( this, msg );
return false;
}
try
{
pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE ) );
g_RootSheet = pi->Load( fullFileName, &Kiway() );
projectpath = Kiway().Prj().GetProjectPath();
newfilename = Prj().AbsolutePath( Prj().GetProjectName() );
newfilename.SetExt( SchematicFileExtension );
m_CurrentSheet->clear();
m_CurrentSheet->push_back( g_RootSheet );
SetScreen( m_CurrentSheet->LastScreen() );
g_RootSheet->SetFileName( newfilename.GetFullPath() );
GetScreen()->SetFileName( newfilename.GetFullPath() );
GetScreen()->SetModify();
UpdateFileHistory( fullFileName );
schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId );
Zoom_Automatique( false );
SetSheetNumberAndCount();
m_canvas->Refresh( true );
UpdateTitle();
}
catch( const IO_ERROR& ioe )
{
// Do not leave g_RootSheet == NULL because it is expected to be
// a valid sheet. Therefore create a dummy empty root sheet and screen.
CreateScreens();
Zoom_Automatique( false );
wxString msg;
msg.Printf( _( "Error loading schematic file '%s'.\n%s" ),
GetChars( fullFileName ), GetChars( ioe.What() ) );
DisplayError( this, msg );
msg.Printf( _( "Failed to load '%s'" ), GetChars( fullFileName ) );
AppendMsgPanel( wxEmptyString, msg, CYAN );
return false;
}
return true;
default:
return false;
}
return false;
}
bool SCH_EDIT_FRAME::AskToSaveChanges()
{
SCH_SCREENS screenList;
// Save any currently open and modified project files.
for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
{
if( screen->IsModify() )
{
int response = YesNoCancelDialog( m_parent, _(
"The current schematic has been modified. Do you wish to save the changes?" ),
wxEmptyString,
_( "Save and Load" ),
_( "Load Without Saving" )
);
if( response == wxID_CANCEL )
{
return false;
}
else if( response == wxID_YES )
{
wxCommandEvent dummy;
OnSaveProject( dummy );
}
// else wxID_NO, so do not save
break;
}
}
return true;
}

View File

@ -745,7 +745,7 @@ void LIB_ARC::calcEdit( const wxPoint& aPosition )
}
m_Pos = newCenterPoint;
calcRadiusAngles();
CalcRadiusAngles();
}
else if( m_Flags == IS_NEW )
{
@ -781,7 +781,7 @@ void LIB_ARC::calcEdit( const wxPoint& aPosition )
cY += m_ArcStart.y;
m_Pos.x = cX;
m_Pos.y = cY;
calcRadiusAngles();
CalcRadiusAngles();
SetEraseLastDrawItem();
}
@ -792,7 +792,7 @@ void LIB_ARC::calcEdit( const wxPoint& aPosition )
}
void LIB_ARC::calcRadiusAngles()
void LIB_ARC::CalcRadiusAngles()
{
wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart );
wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd );

View File

@ -78,10 +78,6 @@ class LIB_ARC : public LIB_ITEM
*/
void calcEdit( const wxPoint& aPosition ) override;
/**
* Calculate the radius and angle of an arc using the start, end, and center points.
*/
void calcRadiusAngles();
public:
LIB_ARC( LIB_PART * aParent );
@ -153,6 +149,12 @@ public:
void SetEnd( const wxPoint& aPoint ) { m_ArcEnd = aPoint; }
/**
* Calculate the radius and angle of an arc using the start, end, and center points.
*/
void CalcRadiusAngles();
wxString GetSelectMenuText() const override;
BITMAP_DEF GetMenuImage() const override;

View File

@ -130,7 +130,8 @@ static const wxString getPinOrientationName( unsigned aPinOrientationCode )
static int InternalPinDecoSize( const LIB_PIN &aPin )
{
return aPin.GetNameTextSize() / 2;
return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
}
/// Utility for getting the size of the 'external' pin decorators (as a radius)

View File

@ -37,6 +37,7 @@ class SCH_COMPONENT;
#include "pin_shape.h"
#include "pin_type.h"
#include "class_libentry.h"
// Circle diameter drawn at the active end of pins:
#define TARGET_PIN_RADIUS 12
@ -362,7 +363,13 @@ public:
* Return whether this pin forms an implicit power connection: i.e., is hidden
* and of type POWER_IN.
*/
bool IsPowerConnection() const { return !IsVisible() && GetType() == PIN_POWER_IN; }
bool IsPowerConnection() const {
return (
( !IsVisible() && GetType() == PIN_POWER_IN )
||
( (LIB_PART*)GetParent()->IsPower() && GetType() == PIN_POWER_IN )
) ; }
int GetPenSize() const override;

View File

@ -338,10 +338,15 @@ void prepareFilesMenu( wxMenu* aParentMenu, bool aIsOutsideProject )
}
AddMenuItem( aParentMenu,
ID_APPEND_PROJECT, _( "Imp&ort Schematic Sheet Content" ),
_( "Import schematic sheet content from other project in current sheet" ),
ID_APPEND_PROJECT, _( "App&end Schematic Sheet" ),
_( "Import schematic sheet content from another project to current sheet" ),
KiBitmap( open_document_xpm ) );
AddMenuItem( aParentMenu,
ID_IMPORT_NON_KICAD_SCH, _( "&Import Non-Kicad Schematic File" ),
_( "Import schematic file from other applications" ),
KiBitmap( open_document_xpm ) ); // TODO needs a different icon
aParentMenu->AppendSeparator();
text = AddHotkeyName( _( "&Save Schematic Project" ),

View File

@ -110,15 +110,26 @@ void SCH_EDIT_FRAME::sendNetlist()
bool SCH_EDIT_FRAME::CreateNetlist( int aFormat, const wxString& aFullFileName,
unsigned aNetlistOptions, REPORTER* aReporter )
unsigned aNetlistOptions, REPORTER* aReporter, bool aSilent )
{
if( !prepareForNetlist() )
return false;
if( !aSilent ) // checks for errors and invokes annotation dialog as neccessary
{
if( !prepareForNetlist() )
return false;
}
else // performs similar function as prepareForNetlist but without a dialog.
{
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks();
SCH_SHEET_LIST sheets( g_RootSheet );
sheets.AnnotatePowerSymbols( Prj().SchLibs() );
schematic.SchematicCleanUp();
}
std::unique_ptr<NETLIST_OBJECT_LIST> connectedItemsList( BuildNetListBase() );
bool success = WriteNetListFile( connectedItemsList.release(), aFormat,
aFullFileName, aNetlistOptions, aReporter );
aFullFileName, aNetlistOptions, aReporter );
return success;
}

View File

@ -0,0 +1,44 @@
#
# This program source code file is part of KiCad, a free EDA CAD application.
#
# 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
find_package( Boost COMPONENTS unit_test_framework REQUIRED )
include_directories( BEFORE ${INC_BEFORE} )
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${INC_AFTER}
)
add_executable( qa_eagle_plugin
test_module.cpp
test_basic.cpp
)
add_dependencies( qa_eagle_plugin common eeschema_kiface )
target_link_libraries( qa_eagle_plugin
common
eeschema_kiface
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
${wxWidgets_LIBRARIES}
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,49 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* 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 <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <sch_io_mgr.h>
#include <kiway.h>
#include <data/fixtures_eagle_plugin.h>
/**
* Checks that the SCH_IO manager finds the Eagle plugin
*/
BOOST_AUTO_TEST_CASE( FindPlugin )
{
BOOST_CHECK( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE ) != NULL );
}
/**
*
*/
BOOST_AUTO_TEST_CASE( Load )
{
SCH_PLUGIN* pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE );
pi->Load("/home/alejandro/Proyectos/kicad/kicad-alejandro/eeschema/qa/data/eagle_schematics/empty.sch",
NULL);
}

View File

@ -0,0 +1,32 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* 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
*/
/**
* Main file for the schematic eagle plugin tests to be compiled
*/
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "Schematic Eagle plugin"
#include <boost/test/unit_test.hpp>

File diff suppressed because it is too large Load Diff

189
eeschema/sch_eagle_plugin.h Normal file
View File

@ -0,0 +1,189 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 CERN
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
* @author Maciej Suminski <maciej.suminski@cern.ch>
* @author Russell Oliver <roliver8143@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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SCH_EAGLE_PLUGIN_H_
#define _SCH_EAGLE_PLUGIN_H_
#include <wx/xml/xml.h>
#include <sch_line.h>
#include <sch_io_mgr.h>
#include <eagle_parser.h>
#include <lib_draw_item.h>
#include <dlist.h>
#include <boost/ptr_container/ptr_map.hpp>
class EDA_TEXT;
class KIWAY;
class LINE_READER;
class SCH_SCREEN;
class SCH_SHEET;
class SCH_BITMAP;
class SCH_JUNCTION;
class SCH_NO_CONNECT;
class SCH_LINE;
class SCH_BUS_ENTRY_BASE;
class SCH_TEXT;
class SCH_GLOBALLABEL;
class SCH_COMPONENT;
class SCH_FIELD;
class PROPERTIES;
class SCH_EAGLE_PLUGIN_CACHE;
class LIB_PART;
class PART_LIB;
class LIB_ALIAS;
class LIB_CIRCLE;
class LIB_FIELD;
class LIB_RECTANGLE;
class LIB_POLYLINE;
class LIB_PIN;
class LIB_TEXT;
typedef struct EAGLE_LIBRARY
{
std::string name;
boost::ptr_map<std::string, LIB_PART> KiCadSymbols;
std::unordered_map<std::string, wxXmlNode*> SymbolNodes;
std::unordered_map<std::string, int> GateUnit;
std::unordered_map<std::string, std::string> package;
} EAGLE_LIBRARY;
typedef boost::ptr_map<std::string, EPART> EPART_LIST;
/**
* Class SCH_EAGLE_PLUGIN
* is a #SCH_PLUGIN derivation for loading 6.x+ Eagle schematic files.
*
* As with all SCH_PLUGINs there is no UI dependencies i.e. windowing calls allowed.
*/
class SCH_EAGLE_PLUGIN : public SCH_PLUGIN
{
public:
SCH_EAGLE_PLUGIN();
~SCH_EAGLE_PLUGIN();
const wxString GetName() const override;
const wxString GetFileExtension() const override;
int GetModifyHash() const override;
SCH_SHEET* Load( const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* aAppendToMe = NULL,
const PROPERTIES* aProperties = NULL ) override;
bool CheckHeader( const wxString& aFileName ) override;
// unimplemented functions. Will trigger a not_implemented IO error.
//void SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties = NULL ) override;
//void Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY* aKiway,
// const PROPERTIES* aProperties = NULL ) override;
//size_t GetSymbolLibCount( const wxString& aLibraryPath,
// const PROPERTIES* aProperties = NULL ) override;
//void EnumerateSymbolLib( wxArrayString& aAliasNameList, const wxString& aLibraryPath,
// const PROPERTIES* aProperties = NULL ) override;
//LIB_ALIAS* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
// const PROPERTIES* aProperties = NULL ) override;
//void SaveSymbol( const wxString& aLibraryPath, const LIB_PART* aSymbol,
// const PROPERTIES* aProperties = NULL ) override;
//void DeleteAlias( const wxString& aLibraryPath, const wxString& aAliasName,
// const PROPERTIES* aProperties = NULL ) override;
//void DeleteSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
// const PROPERTIES* aProperties = NULL ) override;
//void CreateSymbolLib( const wxString& aLibraryPath,
// const PROPERTIES* aProperties = NULL ) override;
// bool DeleteSymbolLib( const wxString& aLibraryPath,
// const PROPERTIES* aProperties = NULL ) override;
//bool IsSymbolLibWritable( const wxString& aLibraryPath ) override;
//void SymbolLibOptions( PROPERTIES* aListToAppendTo ) const override;
private:
void loadDrawing( wxXmlNode* aDrawingNode );
void loadLayerDefs( wxXmlNode* aLayers );
void loadSchematic( wxXmlNode* aSchematicNode );
void loadSheet( wxXmlNode* aSheetNode, int sheetcount );
void loadInstance( wxXmlNode* aInstanceNode );
EAGLE_LIBRARY* loadLibrary( wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLib );
void countNets( wxXmlNode* aSchematicNode );
/// Moves any labels on the wire to the new end point of the wire.
void moveLabels( SCH_ITEM* aWire, const wxPoint& aNewEndPoint );
/// This function finds best way to place a bus entry symbol for when an Eagle wire segment
/// ends on an Eagle bus segment.
void addBusEntries();
///> Translates Eagle special characters to their counterparts in KiCad.
static wxString escapeName( const wxString& aNetName );
/// Return the matching layer or return LAYER_NOTES
SCH_LAYER_ID kiCadLayer( int aEagleLayer );
wxPoint findNearestLinePoint( const wxPoint& aPoint, const DLIST<SCH_LINE>& aLines );
void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName,
const wxString& aNetClass );
SCH_LINE* loadWire( wxXmlNode* aWireNode );
SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName, const DLIST< SCH_LINE >& segmentWires);
SCH_JUNCTION* loadJunction( wxXmlNode* aJunction );
SCH_TEXT* loadPlainText( wxXmlNode* aSchText );
bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_PART>& aPart, EDEVICE* aDevice, int aGateNumber, string aGateName );
LIB_CIRCLE* loadSymbolCircle( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aCircleNode, int aGateNumber );
LIB_RECTANGLE* loadSymbolRectangle( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aRectNode, int aGateNumber );
LIB_POLYLINE* loadSymbolPolyLine( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aPolygonNode, int aGateNumber );
LIB_ITEM* loadSymbolWire( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aWireNode, int aGateNumber );
LIB_PIN* loadPin( std::unique_ptr<LIB_PART>& aPart, wxXmlNode*, EPIN* epin, int aGateNumber );
LIB_TEXT* loadSymbolText( std::unique_ptr<LIB_PART>& aPart, wxXmlNode* aLibText, int aGateNumber );
void loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const;
void loadFieldAttributes( LIB_FIELD* aField, const LIB_TEXT* aText ) const;
KIWAY* m_kiway; ///< For creating sub sheets.
SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded..
SCH_SHEET* m_currentSheet; ///< The current sheet of the schematic being loaded..
wxString m_version; ///< Eagle file version.
wxFileName m_filename;
PART_LIB* m_partlib; ///< symbol library for imported file.
EPART_MAP m_partlist;
std::map<std::string, EAGLE_LIBRARY> m_eagleLibs;
std::map<std::string, int> m_netCounts;
std::map<int, SCH_LAYER_ID> m_layerMap;
};
#endif // _SCH_EAGLE_PLUGIN_H_

View File

@ -25,6 +25,7 @@
#include <sch_io_mgr.h>
#include <sch_legacy_plugin.h>
#include <sch_eagle_plugin.h>
#include <wildcards_and_files_ext.h>
@ -54,6 +55,8 @@ SCH_PLUGIN* SCH_IO_MGR::FindPlugin( SCH_FILE_T aFileType )
{
case SCH_LEGACY:
return new SCH_LEGACY_PLUGIN();
case SCH_EAGLE:
return new SCH_EAGLE_PLUGIN();
case SCH_KICAD:
return NULL;
}
@ -85,6 +88,9 @@ const wxString SCH_IO_MGR::ShowType( SCH_FILE_T aType )
case SCH_LEGACY:
return wxString( wxT( "Legacy" ) );
case SCH_EAGLE:
return wxString( wxT( "EAGLE" ) );
}
}
@ -97,6 +103,8 @@ SCH_IO_MGR::SCH_FILE_T SCH_IO_MGR::EnumFromStr( const wxString& aType )
if( aType == wxT( "Legacy" ) )
return SCH_LEGACY;
else if( aType == wxT( "EAGLE" ) )
return SCH_EAGLE;
// wxASSERT( blow up here )
@ -162,3 +170,6 @@ void SCH_IO_MGR::Save( SCH_FILE_T aFileType, const wxString& aFileName,
THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) );
}
DECLARE_ENUM_VECTOR( SCH_IO_MGR, SCH_FILE_T );

View File

@ -24,7 +24,9 @@
*/
#include <richio.h>
#include <import_export.h>
#include <map>
#include <enum_vector.h>
class SCH_SHEET;
@ -49,15 +51,16 @@ public:
* A set of file types that the #SCH_IO_MGR knows about, and for which there
* has been a plugin written.
*/
enum SCH_FILE_T
DEFINE_ENUM_VECTOR( SCH_FILE_T,
{
SCH_LEGACY, ///< Legacy Eeschema file formats prior to s-expression.
SCH_KICAD, ///< The s-expression version of the schematic file formats.
SCH_EAGLE, ///< Autodesk Eagle file format
// Add your schematic type here.
// ALTIUM,
// etc.
};
} );
/**
* Return a #SCH_PLUGIN which the caller can use to import, export, save, or load
@ -72,6 +75,7 @@ public:
* @return the plugin corresponding to aFileType or NULL if not found.
* Caller owns the returned object, and must call PluginRelease when done using it.
*/
APIEXPORT
static SCH_PLUGIN* FindPlugin( SCH_FILE_T aFileType );
/**
@ -481,6 +485,14 @@ public:
*/
virtual void SymbolLibOptions( PROPERTIES* aListToAppendTo ) const;
/**
* Function CheckHeader
* returns true if the first line in @a aFileName begins with the expected header
* @param aFileName is the name of the file to use as input
*
*/
virtual bool CheckHeader( const wxString& aFileName );
//-----</PUBLIC SCH_PLUGIN API>------------------------------------------------

View File

@ -51,8 +51,6 @@ typedef SCH_ITEMS::iterator SCH_ITEMS_ITR;
typedef std::vector< SCH_ITEMS_ITR > SCH_ITEMS_ITRS;
#define FMT_IU SCH_ITEM::FormatInternalUnits
#define FMT_ANGLE SCH_ITEM::FormatAngle
/**

View File

@ -3604,5 +3604,19 @@ void SCH_LEGACY_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERT
}
bool SCH_LEGACY_PLUGIN::CheckHeader( const wxString& aFileName )
{
// Open file and check first line
wxTextFile tempFile;
tempFile.Open( aFileName );
wxString firstline;
// read the first line
firstline = tempFile.GetFirstLine();
tempFile.Close();
return firstline.StartsWith( "EESchema" );
}
const char* SCH_LEGACY_PLUGIN::PropBuffering = "buffering";
const char* SCH_LEGACY_PLUGIN::PropNoDocFile = "no_doc_file";

View File

@ -124,6 +124,8 @@ public:
const PROPERTIES* aProperties = NULL ) override;
void SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL ) override;
bool CheckHeader( const wxString& aFileName ) override;
private:
void loadHierarchy( SCH_SHEET* aSheet );
void loadHeader( FILE_LINE_READER& aReader, SCH_SCREEN* aScreen );

View File

@ -598,3 +598,9 @@ void SCH_LINE::SetPosition( const wxPoint& aPosition )
m_end = m_end - ( m_start - aPosition );
m_start = aPosition;
}
wxPoint SCH_LINE::MidPoint()
{
return wxPoint( ( m_start.x + m_end.x ) / 2, ( m_start.y + m_end.y ) / 2 );
}

View File

@ -143,6 +143,8 @@ public:
void Plot( PLOTTER* aPlotter ) override;
wxPoint MidPoint();
EDA_ITEM* Clone() const override;
#if defined(DEBUG)

View File

@ -188,3 +188,11 @@ void SCH_PLUGIN::SymbolLibOptions( PROPERTIES* aListToAppendTo ) const
) );
#endif
}
bool SCH_PLUGIN::CheckHeader( const wxString& aFileName )
{
// not pure virtual so that plugins only have to implement subset of the SCH_PLUGIN interface.
not_implemented( this, __FUNCTION__ );
return NULL;
}

View File

@ -223,6 +223,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, SCH_EDIT_FRAME::OnLoadFile )
EVT_MENU( ID_APPEND_PROJECT, SCH_EDIT_FRAME::OnAppendProject )
EVT_MENU( ID_IMPORT_NON_KICAD_SCH, SCH_EDIT_FRAME::OnImportProject )
EVT_TOOL( ID_NEW_PROJECT, SCH_EDIT_FRAME::OnNewProject )
EVT_TOOL( ID_LOAD_PROJECT, SCH_EDIT_FRAME::OnLoadProject )

View File

@ -532,7 +532,8 @@ public:
bool CreateNetlist( int aFormat,
const wxString& aFullFileName,
unsigned aNetlistOptions,
REPORTER* aReporter = NULL );
REPORTER* aReporter = NULL,
bool silent = false ) override;
/**
* Function WriteNetListFile
@ -784,6 +785,21 @@ public:
bool IsSearchCacheObsolete( const SCH_FIND_REPLACE_DATA& aSearchCriteria );
/**
* Function ImportFile
* load the given filename but sets the path to the current project path.
* @param full filepath of file to be imported.
* @param aFileType SCH_FILE_T value for filetype
*/
bool ImportFile( const wxString& aFileName, int aFileType ) override;
/**
* Checks whether any of the screens has unsaved changes and asks the user
* whether to save or drop them.
* @return True if user decided to save or drop changes, false if the
* operation should be cancelled.
*/
bool AskToSaveChanges();
private:
@ -868,6 +884,7 @@ private:
void OnNewProject( wxCommandEvent& event );
void OnLoadProject( wxCommandEvent& event );
void OnAppendProject( wxCommandEvent& event );
void OnImportProject( wxCommandEvent& event );
void OnOpenPcbnew( wxCommandEvent& event );
void OnOpenPcbModuleEditor( wxCommandEvent& event );
void OnOpenCvpcb( wxCommandEvent& event );

View File

@ -35,9 +35,6 @@
#include <gr_basic.h>
#include <layers_id_colors_and_visibility.h>
/// Abbrevation for fomatting internal units to a string.
#define FMT_IU BOARD_ITEM::FormatInternalUnits
#define FMT_ANGLE BOARD_ITEM::FormatAngle
class BOARD;
class BOARD_ITEM_CONTAINER;

View File

@ -3,7 +3,7 @@
*
* 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.
* Copyright (C) 2017 CERN
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
*
* This program is free software; you can redistribute it and/or
@ -44,9 +44,20 @@
using std::string;
class MODULE;
struct EINSTANCE;
struct EPART;
struct ETEXT;
typedef std::unordered_map< string, wxXmlNode* > NODE_MAP;
typedef std::map< string, MODULE* > MODULE_MAP;
typedef std::unordered_map<string, wxXmlNode*> NODE_MAP;
typedef std::map<string, MODULE*> MODULE_MAP;
typedef std::map<string, EINSTANCE*> EINSTANCE_MAP;
typedef std::map<string, std::unique_ptr<EPART>> EPART_MAP;
static inline wxXmlNode* getChildrenNodes( NODE_MAP& aMap, const string& aName )
{
auto it = aMap.find( aName );
return it == aMap.end() ? nullptr : it->second->GetChildren();
}
/**
@ -98,7 +109,7 @@ struct TRIPLET
*/
class XPATH
{
std::vector<TRIPLET> p;
std::vector<TRIPLET> p;
public:
void push( const char* aPathSegment, const char* aAttribute="" )
@ -336,14 +347,34 @@ public:
}
};
/**
* 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* aCurrentNode );
/// Make a unique time stamp
unsigned long EagleTimeStamp( wxXmlNode* aTree );
/// Computes module timestamp basing on its name, value and unit
time_t EagleModuleTstamp( const string& aName, const string& aValue, int aUnit );
/// Convert an Eagle curve end to a KiCad center for S_ARC
wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle );
// Pre-declare for typedefs
struct EROT;
struct ECOORD;
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;
typedef OPTIONAL_XML_ATTRIBUTE<ECOORD> opt_ecoord;
// All of the 'E'STRUCTS below merely hold Eagle XML information verbatim, in binary.
@ -352,14 +383,78 @@ typedef OPTIONAL_XML_ATTRIBUTE<EROT> opt_erot;
// forms of information in these 'E'STRUCTS. They are only binary forms
// of the Eagle information in the corresponding Eagle XML nodes.
// Eagle coordinates
struct ECOORD
{
enum UNIT
{
NM, ///< nanometers
MM, ///< millimeters
INCH, ///< inches
MIL, ///< mils/thous
};
///> Value expressed in nanometers
long long int value;
///> Unit used for the value field
static constexpr UNIT ECOORD_UNIT = NM;
ECOORD()
: value( 0 )
{
}
ECOORD( int aValue, enum UNIT aUnit )
: value( ToNanoMeters( aValue, aUnit ) )
{
}
ECOORD( const wxString& aValue, enum UNIT aUnit );
int ToSchUnits() const
{
// mils
return value / 25400;
}
int ToPcbUnits() const
{
// nanometers
return value;
}
float ToMm() const
{
return value / 1000000.0;
}
ECOORD operator+( const ECOORD& aOther ) const
{
return ECOORD( value + aOther.value, ECOORD_UNIT );
}
ECOORD operator-( const ECOORD& aOther ) const
{
return ECOORD( value - aOther.value, ECOORD_UNIT );
}
bool operator==( const ECOORD& aOther ) const
{
return value == aOther.value;
}
static long long int ToNanoMeters( int aValue, enum UNIT aUnit );
};
/// Eagle net
struct ENET
{
int netcode;
std::string netname;
int netcode;
string netname;
ENET( int aNetCode, const std::string& aNetName ) :
ENET( int aNetCode, const string& aNetName ) :
netcode( aNetCode ),
netname( aNetName )
{}
@ -394,11 +489,11 @@ struct EROT
/// Eagle wire
struct EWIRE
{
double x1;
double y1;
double x2;
double y2;
double width;
ECOORD x1;
ECOORD y1;
ECOORD x2;
ECOORD y2;
ECOORD width;
LAYER_NUM layer;
// for style: (continuous | longdash | shortdash | dashdot)
@ -422,15 +517,40 @@ struct EWIRE
};
/// Eagle Junction
struct EJUNCTION
{
ECOORD x;
ECOORD y;
EJUNCTION( wxXmlNode* aJunction);
};
/// Eagle label
struct ELABEL
{
ECOORD x;
ECOORD y;
ECOORD size;
LAYER_NUM layer;
opt_erot rot;
opt_string xref;
wxString netname;
ELABEL( wxXmlNode* aLabel, const wxString& aNetName );
};
/// Eagle via
struct EVIA
{
double x;
double y;
ECOORD x;
ECOORD y;
int layer_front_most; /// < extent
int layer_back_most; /// < inclusive
double drill;
opt_double diam;
ECOORD drill;
opt_ecoord diam;
opt_string shape;
EVIA( wxXmlNode* aVia );
@ -440,10 +560,10 @@ struct EVIA
/// Eagle circle
struct ECIRCLE
{
double x;
double y;
double radius;
double width;
ECOORD x;
ECOORD y;
ECOORD radius;
ECOORD width;
LAYER_NUM layer;
ECIRCLE( wxXmlNode* aCircle );
@ -453,10 +573,10 @@ struct ECIRCLE
/// Eagle XML rectangle in binary
struct ERECT
{
double x1;
double y1;
double x2;
double y2;
ECOORD x1;
ECOORD y1;
ECOORD x2;
ECOORD y2;
int layer;
opt_erot rot;
@ -474,9 +594,9 @@ struct EATTR
{
string name;
opt_string value;
opt_double x;
opt_double y;
opt_double size;
opt_ecoord x;
opt_ecoord y;
opt_ecoord size;
opt_int layer;
opt_double ratio;
opt_erot rot;
@ -488,6 +608,7 @@ struct EATTR
BOTH,
};
opt_int display;
opt_int align;
EATTR( wxXmlNode* aTree );
EATTR() {}
@ -497,12 +618,12 @@ struct EATTR
/// Eagle dimension element
struct EDIMENSION
{
double x1;
double y1;
double x2;
double y2;
double x3;
double y3;
ECOORD x1;
ECOORD y1;
ECOORD x2;
ECOORD y2;
ECOORD x3;
ECOORD y3;
int layer;
opt_string dimensionType;
@ -515,9 +636,9 @@ struct EDIMENSION
struct ETEXT
{
string text;
double x;
double y;
double size;
ECOORD x;
ECOORD y;
ECOORD size;
int layer;
opt_string font;
opt_double ratio;
@ -537,9 +658,12 @@ struct ETEXT
BOTTOM_RIGHT = -TOP_LEFT,
};
opt_int align;
opt_int align;
ETEXT( wxXmlNode* aText );
/// Calculate text size based on font type and size
wxSize ConvertSize() const;
};
@ -547,10 +671,10 @@ struct ETEXT
struct EPAD
{
string name;
double x;
double y;
double drill;
opt_double diameter;
ECOORD x;
ECOORD y;
ECOORD drill;
opt_ecoord diameter;
// for shape: (square | round | octagon | long | offset)
enum {
@ -574,10 +698,10 @@ struct EPAD
struct ESMD
{
string name;
double x;
double y;
double dx;
double dy;
ECOORD x;
ECOORD y;
ECOORD dx;
ECOORD dy;
int layer;
opt_int roundness;
opt_erot rot;
@ -589,11 +713,29 @@ struct ESMD
};
/// Eagle pin element
struct EPIN
{
string name;
ECOORD x;
ECOORD y;
opt_string visible;
opt_string length;
opt_string direction;
opt_string function;
opt_int swaplevel;
opt_erot rot;
EPIN( wxXmlNode* aPin );
};
/// Eagle vertex
struct EVERTEX
{
double x;
double y;
ECOORD x;
ECOORD y;
EVERTEX( wxXmlNode* aVertex );
};
@ -602,9 +744,9 @@ struct EVERTEX
/// Eagle polygon, without vertices which are parsed as needed
struct EPOLYGON
{
double width;
ECOORD width;
int layer;
opt_double spacing;
opt_ecoord spacing;
// KiCad priority is opposite of Eagle rank, that is:
// - Eagle Low rank drawn first
@ -619,7 +761,7 @@ struct EPOLYGON
CUTOUT,
};
int pour;
opt_double isolate;
opt_ecoord isolate;
opt_bool orphans;
opt_bool thermals;
opt_int rank;
@ -631,9 +773,9 @@ struct EPOLYGON
/// Eagle hole element
struct EHOLE
{
double x;
double y;
double drill;
ECOORD x;
ECOORD y;
ECOORD drill;
EHOLE( wxXmlNode* aHole );
};
@ -646,8 +788,8 @@ struct EELEMENT
string library;
string package;
string value;
double x;
double y;
ECOORD x;
ECOORD y;
opt_bool locked;
opt_bool smashed;
opt_erot rot;
@ -738,23 +880,151 @@ struct EAGLE_LAYER
};
};
/**
* 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 );
struct EPART
{
/*
* <!ELEMENT part (attribute*, variant*)>
* <!ATTLIST part
* name %String; #REQUIRED
* library %String; #REQUIRED
* deviceset %String; #REQUIRED
* device %String; #REQUIRED
* technology %String; ""
* value %String; #IMPLIED
* >
*/
/// Make a unique time stamp
unsigned long timeStamp( wxXmlNode* aTree );
string name;
string library;
string deviceset;
string device;
opt_string technology;
opt_string value;
EPART( wxXmlNode* aPart );
};
struct EINSTANCE
{
/*
* <!ELEMENT instance (attribute)*>
* <!ATTLIST instance
* part %String; #REQUIRED
* gate %String; #REQUIRED
* x %Coord; #REQUIRED
* y %Coord; #REQUIRED
* smashed %Bool; "no"
* rot %Rotation; "R0"
* >
*/
string part;
string gate;
ECOORD x;
ECOORD y;
opt_bool smashed;
opt_erot rot;
EINSTANCE( wxXmlNode* aInstance );
};
struct EGATE
{
/*
* <!ELEMENT gate EMPTY>
* <!ATTLIST gate
* name %String; #REQUIRED
* symbol %String; #REQUIRED
* x %Coord; #REQUIRED
* y %Coord; #REQUIRED
* addlevel %GateAddLevel; "next"
* swaplevel %Int; "0"
* >
*/
string name;
string symbol;
ECOORD x;
ECOORD y;
opt_int addlevel;
opt_int swaplevel;
enum
{
MUST,
CAN,
NEXT,
REQUEST,
ALWAYS
};
EGATE( wxXmlNode* aGate );
};
struct ECONNECT
{
/*
* <!ELEMENT connect EMPTY>
* <!ATTLIST connect
* gate %String; #REQUIRED
* pin %String; #REQUIRED
* pad %String; #REQUIRED
* route %ContactRoute; "all"
* >
*/
string gate;
string pin;
string pad;
int contactroute;
ECONNECT( wxXmlNode* aConnect );
};
struct EDEVICE
{
/*
<!ELEMENT device (connects?, technologies?)>
<!ATTLIST device
name %String; ""
package %String; #IMPLIED
>
*/
string name;
opt_string package;
std::vector<ECONNECT> connects;
EDEVICE( wxXmlNode* aDevice );
};
struct EDEVICE_SET
{
/*
<!ELEMENT deviceset (description?, gates, devices)>
<!ATTLIST deviceset
name %String; #REQUIRED
prefix %String; ""
uservalue %Bool; "no"
>
*/
string name;
opt_string prefix;
opt_bool uservalue;
//std::vector<EDEVICE> devices;
//std::vector<EGATE> gates;
EDEVICE_SET( wxXmlNode* aDeviceSet );
};
/// Convert an Eagle curve end to a KiCad center for S_ARC
wxPoint kicad_arc_center( const wxPoint& aStart, const wxPoint& aEnd, double aAngle );
#endif // _EAGLE_PARSER_H_

46
include/enum_vector.h Normal file
View File

@ -0,0 +1,46 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEFINE_ENUM_VECTOR
/**
* Macro to create const vectors containing enum values to enable easy iteration.
*
* Usage:
* [header]
* class A {
* DEFINE_ENUM_VECTOR( COLORS, { RED, GREEN, BLUE } );
* };
*
* [source]
* for( auto color : A::COLORS_vector ) {
* // do sth with color
* }
*
* DECLARE_ENUM_VECTOR( COLORS );
*/
#define DEFINE_ENUM_VECTOR(enum_name, ...) \
enum enum_name __VA_ARGS__; \
static constexpr enum_name enum_name##_vector[] = __VA_ARGS__;
#define DECLARE_ENUM_VECTOR(class_name, enum_name) \
constexpr class_name::enum_name class_name::enum_name##_vector[];
#endif

View File

@ -54,7 +54,7 @@ public:
}
FP_LIB_TABLE_ROW() :
type( IO_MGR::KICAD )
type( IO_MGR::KICAD_SEXP )
{
}

View File

@ -179,6 +179,49 @@ public:
return false;
}
/**
* Function ImportFile
* load the given filename but sets the path to the current project path.
* @param full filepath of file to be imported.
* @param aFileType enum value for filetype
*/
VTBL_ENTRY bool ImportFile( const wxString& aFileName, int aFileType )
{
// overload me for your wxFrame type.
return false;
}
/**
* Function ReadPcbNetlist
* provides access to PcbNew's function ReadPcbNetlist.
*/
VTBL_ENTRY void ReadPcbNetlist( const wxString& aNetlistFileName,
const wxString& aCmpFileName,
REPORTER* aReporter,
bool aChangeFootprint,
bool aDeleteBadTracks,
bool aDeleteExtraFootprints,
bool aSelectByTimestamp,
bool aDeleteSinglePadNets,
bool aIsDryRun )
{
};
/**
* Function ReadPcbNetlist
* provides access to Eeschema's function CreateNetlist.
*/
VTBL_ENTRY bool CreateNetlist( int aFormat,
const wxString& aFullFileName,
unsigned aNetlistOptions,
REPORTER* aReporter = NULL,
bool silent = false )
{
return false;
};
/**
* Function ShowModal
* puts up this wxFrame as if it were a modal dialog, with all other instantiated

44
include/unit_format.h Normal file
View File

@ -0,0 +1,44 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see change_log.txt for contributors.
*
* 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 UNIT_FORMAT_H
#define UNIT_FORMAT_H
// Conversion to application internal units defined at build time.
#if defined( PCBNEW )
#include <class_board_item.h>
#define FMT_IU BOARD_ITEM::FormatInternalUnits
#define FMT_ANGLE BOARD_ITEM::FormatAngle
#elif defined( EESCHEMA )
#include <sch_item_struct.h>
#define FMT_IU SCH_ITEM::FormatInternalUnits
#define FMT_ANGLE SCH_ITEM::FormatAngle
#elif defined( GERBVIEW )
#elif defined( PL_EDITOR )
#include <base_units.h>
#define FMT_IU Double2Str
#else
#error "Cannot resolve units formatting due to no definition of EESCHEMA or PCBNEW."
#endif
#endif /* UNIT_FORMAT_H */

View File

@ -88,6 +88,8 @@ extern const wxString CsvFileWildcard;
extern const wxString LegacyPcbFileWildcard;
extern const wxString PcbFileWildcard;
extern const wxString EaglePcbFileWildcard;
extern const wxString EagleSchematicFileWildcard;
extern const wxString EagleFilesWildcard;
extern const wxString PCadPcbFileWildcard;
extern const wxString PdfFileWildcard;
extern const wxString PSFileWildcard;

View File

@ -7,6 +7,8 @@ add_definitions( -DKICAD )
include_directories( BEFORE ${INC_BEFORE} )
include_directories(
../pcbnew
../eeschema
${INC_AFTER}
)
@ -25,6 +27,7 @@ set( KICAD_SRCS
prjconfig.cpp
project_template.cpp
tree_project_frame.cpp
import_project.cpp
)
if( MINGW )

212
kicad/import_project.cpp Normal file
View File

@ -0,0 +1,212 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
* @author Russell Oliver <roliver8143@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
*/
/**
* @file import_project.cpp
* @brief routines for importing an eagle project
*/
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <wx/string.h>
#include <common.h>
#include <confirm.h>
#include <hotkeys_basic.h>
#include <kiway.h>
#include <richio.h>
#include <wildcards_and_files_ext.h>
#include <systemdirsappend.h>
#include <kiway_player.h>
#include <stdexcept>
#include "pgm_kicad.h"
#include <io_mgr.h>
#include <sch_io_mgr.h>
#include <wxPcbStruct.h>
#include <schframe.h>
#include <netlist.h>
class PCB_EDIT_FRAME;
#include "kicad.h"
void KICAD_MANAGER_FRAME::OnImportEagleFiles( wxCommandEvent& event )
{
// Close other windows.
if( !Kiway.PlayersClose( false ) )
return;
wxString title = _( "Import Eagle Project Files" );
int style = wxFD_OPEN | wxFD_FILE_MUST_EXIST;
wxString default_dir = GetMruPath();
ClearMsg();
wxFileDialog schdlg( this, title, default_dir, wxEmptyString,
EagleFilesWildcard, style );
if( schdlg.ShowModal() == wxID_CANCEL )
return;
wxFileName sch( schdlg.GetPath() );
sch.SetExt( SchematicFileExtension );
wxString protitle = _( "Kicad Project Destination" );
wxFileDialog prodlg( this, protitle, sch.GetPath(), sch.GetName(),
ProjectFileWildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if( prodlg.ShowModal() == wxID_CANCEL )
return;
wxFileName pro( prodlg.GetPath() );
// Check if the project directory is empty
wxDir directory( pro.GetPath() );
if( directory.HasFiles() )
{
wxString msg = _( "The selected directory is not empty. We recommend you "
"create projects in their own clean directory.\n\nDo you "
"want to create a new empty directory for the project?" );
if( IsOK( this, msg ) )
{
// Append a new directory with the same name of the project file
// and try to create it
pro.AppendDir( pro.GetName() );
if( !wxMkdir( pro.GetPath() ) )
// There was a problem, undo
pro.RemoveLastDir();
}
}
wxFileName pcb( sch );
wxFileName netlist( pro );
pro.SetExt( ProjectFileExtension ); // enforce extension
pcb.SetExt( LegacyPcbFileExtension ); // enforce extension
netlist.SetExt( NetlistFileExtension );
if( !pro.IsAbsolute() )
pro.MakeAbsolute();
SetProjectFileName( pro.GetFullPath() );
wxString prj_filename = GetProjectFileName();
wxString sch_filename = sch.GetFullPath();
if( sch.FileExists() )
{
SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway.Player( FRAME_SCH, false );
if( !schframe )
{
try
{
schframe = (SCH_EDIT_FRAME*) Kiway.Player( FRAME_SCH, true );
}
catch( IO_ERROR err )
{
wxMessageBox( _( "Eeschema failed to load:\n" ) + err.What(),
_( "KiCad Error" ), wxOK | wxICON_ERROR, this );
return;
}
}
schframe->ImportFile( sch_filename, SCH_IO_MGR::SCH_EAGLE );
if( !schframe->IsShown() ) // the frame exists, (created by the dialog field editor)
// but no project loaded.
{
schframe->Show( true );
}
if( schframe->IsIconized() )
schframe->Iconize( false );
schframe->Raise();
schframe->CreateNetlist( NET_TYPE_PCBNEW, netlist.GetFullPath(), 0, NULL, true );
}
if( pcb.FileExists() )
{
PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Kiway.Player( FRAME_PCB, false );
if( !pcbframe )
{
try
{
pcbframe = (PCB_EDIT_FRAME*) Kiway.Player( FRAME_PCB, true );
}
catch( IO_ERROR err )
{
wxMessageBox( _( "Pcbnew failed to load:\n" ) + err.What(), _( "KiCad Error" ),
wxOK | wxICON_ERROR, this );
return;
}
}
// a pcb frame can be already existing, but not yet used.
// this is the case when running the footprint editor, or the footprint viewer first
// if the frame is not visible, the board is not yet loaded
if( !pcbframe->IsVisible() )
{
pcbframe->ImportFile( pcb.GetFullPath(), IO_MGR::EAGLE );
pcbframe->Show( true );
}
// On Windows, Raise() does not bring the window on screen, when iconized
if( pcbframe->IsIconized() )
pcbframe->Iconize( false );
pcbframe->Raise();
if( netlist.FileExists() )
{
pcbframe->ReadPcbNetlist( netlist.GetFullPath(),
wxEmptyString,
NULL,
false,
false,
false,
false,
false,
false );
}
}
ReCreateTreePrj();
}

View File

@ -123,6 +123,7 @@ enum id_kicad_frm {
ID_SAVE_AND_ZIP_FILES,
ID_READ_ZIP_ARCHIVE,
ID_INIT_WATCHED_PATHS,
ID_IMPORT_EAGLE_PROJECT,
// Please, verify: the number of items in this list should be
// less than ROOM_FOR_KICADMANAGER (see id.h)
@ -194,6 +195,11 @@ public:
void ReCreateMenuBar() override;
void RecreateBaseHToolbar();
/**
* Open dialog to import Eagle schematic and board files.
*/
void OnImportEagleFiles( wxCommandEvent& event );
/**
* Displays \a aText in the text panel.
*

View File

@ -66,6 +66,7 @@ BEGIN_EVENT_TABLE( KICAD_MANAGER_FRAME, EDA_BASE_FRAME )
EVT_MENU( wxID_INDEX, KICAD_MANAGER_FRAME::GetKicadHelp )
EVT_MENU( ID_HELP_GET_INVOLVED, KICAD_MANAGER_FRAME::GetKicadContribute )
EVT_MENU( wxID_ABOUT, KICAD_MANAGER_FRAME::GetKicadAbout )
EVT_MENU( ID_IMPORT_EAGLE_PROJECT, KICAD_MANAGER_FRAME::OnImportEagleFiles )
// Range menu events
EVT_MENU_RANGE( ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END,
@ -265,7 +266,21 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar()
KiBitmap( save_project_xpm ) );
#endif
// Separator
fileMenu->AppendSeparator();
wxMenu* importprjSubMenu = new wxMenu();
AddMenuItem( importprjSubMenu, ID_IMPORT_EAGLE_PROJECT, _( "Eagle CAD" ),
_( "Import Eagle CAD XML schematic and board" ),
KiBitmap( new_project_xpm ) );
AddMenuItem( fileMenu, importprjSubMenu,
wxID_ANY,
_( "Import Project" ),
_( "Import project files from other software" ),
KiBitmap( new_project_xpm ) );
fileMenu->AppendSeparator();
// Archive

View File

@ -33,6 +33,10 @@
#include <class_board.h>
#include <class_netclass.h>
/// Abbrevation for fomatting internal units to a string.
#define FMT_IU BOARD_ITEM::FormatInternalUnits
#define FMT_ANGLE BOARD_ITEM::FormatAngle
// This will get mapped to "kicad_default" in the specctra_export.
const char NETCLASS::Default[] = "Default";

View File

@ -185,7 +185,7 @@ public:
wxArrayString choices;
choices.Add( IO_MGR::ShowType( IO_MGR::KICAD ) );
choices.Add( IO_MGR::ShowType( IO_MGR::KICAD_SEXP ) );
choices.Add( IO_MGR::ShowType( IO_MGR::GITHUB ) );
choices.Add( IO_MGR::ShowType( IO_MGR::LEGACY ) );
choices.Add( IO_MGR::ShowType( IO_MGR::EAGLE ) );

View File

@ -37,6 +37,7 @@
#include <macros.h>
#include <wxBasePcbFrame.h>
#include <base_units.h>
#include <unit_format.h>
#include <gr_basic.h>
#include <class_board.h>

View File

@ -38,6 +38,7 @@
#include <pcbnew.h>
#include <wxBasePcbFrame.h>
#include <base_units.h>
#include <unit_format.h>
#include <board_commit.h>
#include <class_board.h>

View File

@ -65,7 +65,7 @@ static const struct
IO_MGR::PCB_FILE_T m_Plugin;
} fileFilters[FILTER_COUNT] =
{
{ "KiCad (folder with .kicad_mod files)", "kicad_mod", false, IO_MGR::KICAD },
{ "KiCad (folder with .kicad_mod files)", "kicad_mod", false, IO_MGR::KICAD_SEXP },
{ "Eagle 6.x (*.lbr)", "lbr", true, IO_MGR::EAGLE },
{ "KiCad legacy (*.mod)", "mod", true, IO_MGR::LEGACY },
{ "Geda (folder with *.fp files)", "fp", false, IO_MGR::GEDA_PCB },
@ -206,7 +206,7 @@ wxString WIZARD_FPLIB_TABLE::LIBRARY::GetPluginName() const
case IO_MGR::LEGACY:
return wxT( "Legacy" );
case IO_MGR::KICAD:
case IO_MGR::KICAD_SEXP:
return wxT( "KiCad" );
case IO_MGR::EAGLE:
@ -544,7 +544,7 @@ void WIZARD_FPLIB_TABLE::OnWizardFinished( wxWizardEvent& aEvent )
wxString path = it->GetAbsolutePath();
path.Replace( GetGithubURL(), getDownloadDir() );
it->setPath( path );
it->setPluginType( IO_MGR::KICAD );
it->setPluginType( IO_MGR::KICAD_SEXP );
}
}
}
@ -654,7 +654,7 @@ bool WIZARD_FPLIB_TABLE::downloadGithubLibsFromList( wxArrayString& aUrlList,
try
{
PLUGIN::RELEASER src( IO_MGR::PluginFind( IO_MGR::GITHUB ) );
PLUGIN::RELEASER dst( IO_MGR::PluginFind( IO_MGR::KICAD ) );
PLUGIN::RELEASER dst( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
wxArrayString footprints;

View File

@ -83,15 +83,23 @@ typedef MODULE_MAP::const_iterator MODULE_CITER;
/// Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
/// Return is in BIU.
static double parseEagle( const wxString& aDistance )
static int parseEagle( const wxString& aDistance )
{
double ret = strtod( aDistance.c_str(), NULL );
if( aDistance.npos != aDistance.find( "mil" ) )
ret = IU_PER_MILS * ret;
else
ret = IU_PER_MM * ret;
ECOORD::UNIT unit = ( aDistance.npos != aDistance.find( "mil" ) )
? ECOORD::UNIT::MIL : ECOORD::UNIT::MM;
return ret;
ECOORD coord( aDistance, unit );
return coord.ToPcbUnits();
}
/// Assemble a two part key as a simple concatenation of aFirst and aSecond parts,
/// using a separator.
static string makeKey( const string& aFirst, const string& aSecond )
{
string key = aFirst + '\x02' + aSecond;
return key;
}
@ -137,7 +145,6 @@ EAGLE_PLUGIN::EAGLE_PLUGIN() :
m_mod_time( wxDateTime::Now() )
{
init( NULL );
clear_cu_map();
}
@ -162,16 +169,10 @@ const wxString EAGLE_PLUGIN::GetFileExtension() const
}
int inline EAGLE_PLUGIN::kicad( double d ) const
{
return KiROUND( biu_per_mm * d );
}
wxSize inline EAGLE_PLUGIN::kicad_fontz( double d ) const
wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d ) const
{
// texts seem to better match eagle when scaled down by 0.95
int kz = kicad( d ) * 95 / 100;
int kz = d.ToPcbUnits() * 95 / 100;
return wxSize( kz, kz );
}
@ -277,8 +278,6 @@ void EAGLE_PLUGIN::init( const PROPERTIES* aProperties )
m_board = NULL;
m_props = aProperties;
mm_per_biu = 1/IU_PER_MM;
biu_per_mm = IU_PER_MM;
delete m_rules;
m_rules = new ERULES();
@ -354,19 +353,19 @@ void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
{
typedef std::vector<ELAYER> ELAYERS;
typedef ELAYERS::const_iterator EITER;
ELAYERS cu; // copper layers
ELAYERS cu; // copper layers
// Get the first layer and iterate
wxXmlNode* layerNode = aLayers->GetChildren();
// find the subset of layers that are copper, and active
m_eagleLayers.clear();
while( layerNode )
{
ELAYER elayer( layerNode );
ELAYER elayer( layerNode );
m_eagleLayers.insert( std::make_pair( elayer.number, elayer ) );
// find the subset of layers that are copper and active
if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
{
cu.push_back( elayer );
@ -457,7 +456,7 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
}
else
{
wxPoint center = kicad_arc_center( start, end, *w.curve);
wxPoint center = ConvertArcCenter( start, end, *w.curve );
dseg->SetShape( S_ARC );
dseg->SetStart( center );
@ -465,7 +464,7 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
}
dseg->SetTimeStamp( timeStamp( gr ) );
dseg->SetTimeStamp( EagleTimeStamp( gr ) );
dseg->SetLayer( layer );
dseg->SetWidth( Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ) );
}
@ -484,15 +483,15 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
m_board->Add( pcbtxt, ADD_APPEND );
pcbtxt->SetLayer( layer );
pcbtxt->SetTimeStamp( timeStamp( gr ) );
pcbtxt->SetTimeStamp( EagleTimeStamp( gr ) );
pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
pcbtxt->SetTextSize( kicad_fontz( t.size ) );
double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
pcbtxt->SetThickness( kicad( t.size * ratio / 100 ) );
pcbtxt->SetThickness( t.size.ToPcbUnits() * ratio / 100 );
int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT;
@ -592,11 +591,11 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
m_board->Add( dseg, ADD_APPEND );
dseg->SetShape( S_CIRCLE );
dseg->SetTimeStamp( timeStamp( gr ) );
dseg->SetTimeStamp( EagleTimeStamp( gr ) );
dseg->SetLayer( layer );
dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
dseg->SetEnd( wxPoint( kicad_x( c.x + c.radius ), kicad_y( c.y ) ) );
dseg->SetWidth( kicad( c.width ) );
dseg->SetWidth( c.width.ToPcbUnits() );
}
m_xpath->pop();
}
@ -615,7 +614,7 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
m_board->Add( zone, ADD_APPEND );
zone->SetTimeStamp( timeStamp( gr ) );
zone->SetTimeStamp( EagleTimeStamp( gr ) );
zone->SetLayer( layer );
zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
@ -667,7 +666,7 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
pad->SetPosition( padpos + module->GetPosition() );
*/
wxSize sz( kicad( e.drill ), kicad( e.drill ) );
wxSize sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
pad->SetDrillSize( sz );
pad->SetSize( sz );
@ -694,6 +693,24 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
DIMENSION* dimension = new DIMENSION( m_board );
m_board->Add( dimension, ADD_APPEND );
if( d.dimensionType )
{
// Eagle dimension graphic arms may have different lengths, but they look
// incorrect in KiCad (the graphic is tilted). Make them even lenght in such case.
if( *d.dimensionType == "horizontal" )
{
int newY = ( d.y1.ToPcbUnits() + d.y2.ToPcbUnits() ) / 2;
d.y1 = ECOORD( newY, ECOORD::UNIT::NM );
d.y2 = ECOORD( newY, ECOORD::UNIT::NM );
}
else if( *d.dimensionType == "vertical" )
{
int newX = ( d.x1.ToPcbUnits() + d.x2.ToPcbUnits() ) / 2;
d.x1 = ECOORD( newX, ECOORD::UNIT::NM );
d.x2 = ECOORD( newX, ECOORD::UNIT::NM );
}
}
dimension->SetLayer( layer );
// The origin and end are assumed to always be in this order from eagle
dimension->SetOrigin( wxPoint( kicad_x( d.x1 ), kicad_y( d.y1 ) ) );
@ -713,8 +730,8 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
// because the "height" of the dimension is perpendicular to that axis
// Note the check is just if two axes are close enough to each other
// Eagle appears to have some rounding errors
if( fabs( d.x1 - d.x2 ) < 0.05 )
dimension->SetHeight( kicad_x( d.x1 - d.x3 ) );
if( abs( ( d.x1 - d.x2 ).ToPcbUnits() ) < 50000 ) // 50000 nm = 0.05 mm
dimension->SetHeight( kicad_x( d.x3 - d.x1 ) );
else
dimension->SetHeight( kicad_y( d.y3 - d.y1 ) );
@ -871,18 +888,21 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
refanceNamePresetInPackageLayout = true;
valueNamePresetInPackageLayout = true;
m->SetPosition( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
// Is >NAME field set in package layout ?
if( m->GetReference().size() == 0 )
{
m->Reference().SetVisible( false ); // No so no show
refanceNamePresetInPackageLayout = false;
}
// Is >VALUE field set in package layout
if( m->GetValue().size() == 0 )
{
m->Value().SetVisible( false ); // No so no show
valueNamePresetInPackageLayout = false;
}
m->SetReference( FROM_UTF8( e.name.c_str() ) );
m->SetValue( FROM_UTF8( e.value.c_str() ) );
@ -890,6 +910,7 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
{ // Not smashed so show NAME & VALUE
if( valueNamePresetInPackageLayout )
m->Value().SetVisible( true ); // Only if place holder in package layout
if( refanceNamePresetInPackageLayout )
m->Reference().SetVisible( true ); // Only if place holder in package layout
}
@ -1084,7 +1105,7 @@ void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e,
ratio = *a.ratio;
}
int lw = int( fontz.y * ratio / 100.0 );
int lw = int( fontz.y * ratio / 100 );
txt->SetThickness( lw );
int align = ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
@ -1163,9 +1184,9 @@ void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e,
MODULE* EAGLE_PLUGIN::makeModule( wxXmlNode* aPackage, const string& aPkgName ) const
{
std::unique_ptr<MODULE> m( new MODULE( m_board ) );
std::unique_ptr<MODULE> m( new MODULE( m_board ) );
m->SetFPID( LIB_ID( UTF8(aPkgName) ) );
m->SetFPID( LIB_ID( UTF8( aPkgName ) ) );
// Get the first package item and iterate
wxXmlNode* packageItem = aPackage->GetChildren();
@ -1213,37 +1234,46 @@ void EAGLE_PLUGIN::packageWire( MODULE* aModule, wxXmlNode* aTree ) const
EWIRE w( aTree );
PCB_LAYER_ID layer = kicad_layer( w.layer );
if( IsNonCopperLayer( layer ) ) // only valid non-copper wires, skip copper package wires
if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
{
wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
int width = kicad( w.width );
// FIXME: the cap attribute is ignored because kicad can't create lines
// with flat ends.
EDGE_MODULE* dwg;
if( !w.curve )
{
dwg = new EDGE_MODULE( aModule, S_SEGMENT );
dwg->SetStart0( start );
dwg->SetEnd0( end );
}
else
{
dwg = new EDGE_MODULE( aModule, S_ARC );
wxPoint center = kicad_arc_center( start, end, *w.curve);
dwg->SetStart0( center );
dwg->SetEnd0( start );
dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
}
dwg->SetLayer( layer );
dwg->SetWidth( width );
aModule->GraphicalItemsList().PushBack( dwg );
wxLogMessage( wxString::Format(
"Line on copper layer in package %s (%f mm, %f mm) (%f mm, %f mm)."
"\nMoving to Dwgs.User layer",
aModule->GetFPID().GetLibItemName().c_str(), w.x1.ToMm(), w.y1.ToMm(),
w.x2.ToMm(), w.y2.ToMm() ) );
layer = Dwgs_User;
}
wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
int width = w.width.ToPcbUnits();
// FIXME: the cap attribute is ignored because kicad can't create lines
// with flat ends.
EDGE_MODULE* dwg;
if( !w.curve )
{
dwg = new EDGE_MODULE( aModule, S_SEGMENT );
dwg->SetStart0( start );
dwg->SetEnd0( end );
}
else
{
dwg = new EDGE_MODULE( aModule, S_ARC );
wxPoint center = ConvertArcCenter( start, end, *w.curve );
dwg->SetStart0( center );
dwg->SetEnd0( start );
dwg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
}
dwg->SetLayer( layer );
dwg->SetWidth( width );
dwg->SetDrawCoord();
aModule->GraphicalItemsList().PushBack( dwg );
}
@ -1267,9 +1297,7 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, wxXmlNode* aTree ) const
RotatePoint( &padpos, aModule->GetOrientation() );
pad->SetPosition( padpos + aModule->GetPosition() );
pad->SetDrillSize( wxSize( kicad( e.drill ), kicad( e.drill ) ) );
pad->SetDrillSize( wxSize( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() ) );
pad->SetLayerSet( LSET::AllCuMask().set( B_Mask ).set( F_Mask ) );
if( e.shape )
@ -1305,7 +1333,7 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, wxXmlNode* aTree ) const
if( e.diameter )
{
int diameter = kicad( *e.diameter );
int diameter = e.diameter->ToPcbUnits();
pad->SetSize( wxSize( diameter, diameter ) );
}
else
@ -1340,6 +1368,14 @@ void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
ETEXT t( aTree );
PCB_LAYER_ID layer = kicad_layer( t.layer );
if( IsCopperLayer( layer ) ) // skip copper texts
{
wxLogMessage( wxString::Format(
"Unsupported text on copper layer in package %s.\nMoving to Dwgs.User layer.",
aModule->GetFPID().GetLibItemName().c_str() ) );
layer = Dwgs_User;
}
if( layer == UNDEFINED_LAYER )
{
layer = Cmts_User;
@ -1358,7 +1394,7 @@ void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
aModule->GraphicalItemsList().PushBack( txt );
}
txt->SetTimeStamp( timeStamp( aTree ) );
txt->SetTimeStamp( EagleTimeStamp( aTree ) );
txt->SetText( FROM_UTF8( t.text.c_str() ) );
wxPoint pos( kicad_x( t.x ), kicad_y( t.y ) );
@ -1371,7 +1407,7 @@ void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
double ratio = t.ratio ? *t.ratio : 8; // DTD says 8 is default
txt->SetThickness( kicad( t.size * ratio / 100 ) );
txt->SetThickness( t.size.ToPcbUnits() * ratio / 100 );
int align = t.align ? *t.align : ETEXT::BOTTOM_LEFT; // bottom-left is eagle default
@ -1446,31 +1482,44 @@ void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const
ERECT r( aTree );
PCB_LAYER_ID layer = kicad_layer( r.layer );
if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
// Rectangles are not supported yet in footprints as they are not editable.
wxLogMessage( wxString::Format( "Unsupported rectangle in package %s"
" (%f mm, %f mm) (%f mm, %f mm), layer: %s",
aModule->GetFPID().GetLibItemName().c_str(), r.x1.ToMm(), r.y1.ToMm(),
r.x2.ToMm(), r.y2.ToMm(), eagle_layer_name( r.layer ) ) );
return;
if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
{
EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
aModule->GraphicalItemsList().PushBack( dwg );
dwg->SetLayer( layer );
dwg->SetWidth( 0 );
dwg->SetTimeStamp( timeStamp( aTree ) );
std::vector<wxPoint> pts;
wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
pts.push_back( start );
pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
pts.push_back( end );
dwg->SetPolyPoints( pts );
dwg->SetStart0( start );
dwg->SetEnd0( end );
wxLogMessage( wxString::Format(
"Unsupported rectangle on copper layer in package %s.\nMoving to Dwgs.User layer.",
aModule->GetFPID().GetLibItemName().c_str() ) );
layer = Dwgs_User;
}
EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
aModule->GraphicalItemsList().PushBack( dwg );
dwg->SetLayer( layer );
dwg->SetWidth( 0 );
dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
std::vector<wxPoint> pts;
wxPoint start( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) );
wxPoint end( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) );
pts.push_back( start );
pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) );
pts.push_back( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) );
pts.push_back( end );
dwg->SetPolyPoints( pts );
dwg->SetStart0( start );
dwg->SetEnd0( end );
}
@ -1479,53 +1528,46 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
EPOLYGON p( aTree );
PCB_LAYER_ID layer = kicad_layer( p.layer );
if( IsNonCopperLayer( layer ) ) // skip copper "package.rectangle"s
if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
{
EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
aModule->GraphicalItemsList().PushBack( dwg );
dwg->SetWidth( 0 ); // it's filled, no need for boundary width
/*
switch( layer )
{
case Eco1_User: layer = F_SilkS; break;
case Eco2_User: layer = B_SilkS; break;
// all MODULE templates (created from eagle packages) are on front layer
// until cloned.
case Cmts_User: layer = F_SilkS; break;
}
*/
dwg->SetLayer( layer );
dwg->SetTimeStamp( timeStamp( aTree ) );
std::vector<wxPoint> pts;
// TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
// pts.reserve( aTree.size() );
// Get the first vertex and iterate
wxXmlNode* vertex = aTree->GetChildren();
while( vertex )
{
if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
continue;
EVERTEX v( vertex );
pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
vertex = vertex->GetNext();
}
dwg->SetPolyPoints( pts );
dwg->SetStart0( *pts.begin() );
dwg->SetEnd0( pts.back() );
wxLogMessage( wxString::Format(
"Unsupported polygon on copper layer in package %s.\nMoving to Dwgs.User layer.",
aModule->GetFPID().GetLibItemName().c_str() ) );
layer = Dwgs_User;
}
EDGE_MODULE* dwg = new EDGE_MODULE( aModule, S_POLYGON );
aModule->GraphicalItemsList().PushBack( dwg );
dwg->SetWidth( 0 ); // it's filled, no need for boundary width
dwg->SetLayer( layer );
dwg->SetTimeStamp( EagleTimeStamp( aTree ) );
std::vector<wxPoint> pts;
// TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
// pts.reserve( aTree.size() );
// Get the first vertex and iterate
wxXmlNode* vertex = aTree->GetChildren();
while( vertex )
{
if( vertex->GetName() != "vertex" ) // skip <xmlattr> node
continue;
EVERTEX v( vertex );
pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
vertex = vertex->GetNext();
}
dwg->SetPolyPoints( pts );
dwg->SetStart0( *pts.begin() );
dwg->SetEnd0( pts.back() );
dwg->SetDrawCoord();
}
@ -1533,11 +1575,20 @@ void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
{
ECIRCLE e( aTree );
PCB_LAYER_ID layer = kicad_layer( e.layer );
if( IsCopperLayer( layer ) ) // skip copper "package.circle"s
{
wxLogMessage( wxString::Format(
"Unsupported circle on copper layer in package %s.\nMoving to Dwgs.User layer.",
aModule->GetFPID().GetLibItemName().c_str() ) );
layer = Dwgs_User;
}
EDGE_MODULE* gr = new EDGE_MODULE( aModule, S_CIRCLE );
aModule->GraphicalItemsList().PushBack( gr );
gr->SetWidth( kicad( e.width ) );
gr->SetWidth( e.width.ToPcbUnits() );
switch( (int) layer )
{
@ -1551,10 +1602,10 @@ void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
}
gr->SetLayer( layer );
gr->SetTimeStamp( timeStamp( aTree ) );
gr->SetTimeStamp( EagleTimeStamp( aTree ) );
gr->SetStart0( wxPoint( kicad_x( e.x ), kicad_y( e.y ) ) );
gr->SetEnd0( wxPoint( kicad_x( e.x + e.radius ), kicad_y( e.y ) ) );
gr->SetDrawCoord();
}
@ -1579,7 +1630,7 @@ void EAGLE_PLUGIN::packageHole( MODULE* aModule, wxXmlNode* aTree ) const
pad->SetPos0( padpos );
pad->SetPosition( padpos + aModule->GetPosition() );
wxSize sz( kicad( e.drill ), kicad( e.drill ) );
wxSize sz( e.drill.ToPcbUnits(), e.drill.ToPcbUnits() );
pad->SetDrillSize( sz );
pad->SetSize( sz );
@ -1616,7 +1667,7 @@ void EAGLE_PLUGIN::packageSMD( MODULE* aModule, wxXmlNode* aTree ) const
pad->SetPosition( padpos + aModule->GetPosition() );
pad->SetSize( wxSize( kicad( e.dx ), kicad( e.dy ) ) );
pad->SetSize( wxSize( e.dx.ToPcbUnits(), e.dy.ToPcbUnits() ) );
pad->SetLayer( layer );
@ -1703,12 +1754,12 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
{
TRACK* t = new TRACK( m_board );
t->SetTimeStamp( timeStamp( netItem ) );
t->SetTimeStamp( EagleTimeStamp( netItem ) );
t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
int width = kicad( w.width );
int width = w.width.ToPcbUnits();
if( width < m_min_trace )
m_min_trace = width;
@ -1738,7 +1789,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
IsCopperLayer( layer_back_most ) )
{
int kidiam;
int drillz = kicad( v.drill );
int drillz = v.drill.ToPcbUnits();
VIA* via = new VIA( m_board );
m_board->m_Track.Insert( via, NULL );
@ -1746,7 +1797,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
if( v.diam )
{
kidiam = kicad( *v.diam );
kidiam = v.diam->ToPcbUnits();
via->SetWidth( kidiam );
}
else
@ -1781,7 +1832,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
else
via->SetViaType( VIA_BLIND_BURIED );
via->SetTimeStamp( timeStamp( netItem ) );
via->SetTimeStamp( EagleTimeStamp( netItem ) );
wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
@ -1827,7 +1878,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
m_board->Add( zone, ADD_APPEND );
zones.push_back( zone );
zone->SetTimeStamp( timeStamp( netItem ) );
zone->SetTimeStamp( EagleTimeStamp( netItem ) );
zone->SetLayer( layer );
zone->SetNetCode( netCode );
@ -1863,14 +1914,14 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
// clearances, etc.
zone->SetArcSegmentCount( 32 ); // @todo: should be a constructor default?
zone->SetMinThickness( kicad( p.width ) );
zone->SetMinThickness( p.width.ToPcbUnits() );
// FIXME: KiCad zones have very rounded corners compared to eagle.
// This means that isolation amounts that work well in eagle
// tend to make copper intrude in soldermask free areas around pads.
if( p.isolate )
{
zone->SetZoneClearance( kicad( *p.isolate ) );
zone->SetZoneClearance( p.isolate->ToPcbUnits() );
} else
{
zone->SetZoneClearance( 0 );
@ -1885,8 +1936,8 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
// based on what the zone is connecting to.
// (i.e. width of spoke is half of the smaller side of an smd pad)
// This is a basic workaround
zone->SetThermalReliefGap( kicad( p.width + 0.05 ) );
zone->SetThermalReliefCopperBridge( kicad( p.width + 0.05 ) );
zone->SetThermalReliefGap( p.width.ToPcbUnits() + 50000 ); // 50000nm == 0.05mm
zone->SetThermalReliefCopperBridge( p.width.ToPcbUnits() + 50000 );
}
int rank = p.rank ? (p.max_priority - *p.rank) : p.max_priority;
@ -1975,8 +2026,8 @@ PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
case EAGLE_LAYER::HOLES:
default:
// some layers do not map to KiCad
wxLogMessage( wxString::Format( "Unsupported Eagle layer %d. Use drawings layer",
aEagleLayer ) );
wxLogMessage( wxString::Format( "Unsupported Eagle layer '%s' (%d), converted to Dwgs.User layer",
eagle_layer_name( aEagleLayer ), aEagleLayer ) );
kiLayer = Dwgs_User; break;
}
}
@ -1985,6 +2036,14 @@ PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
}
const string& EAGLE_PLUGIN::eagle_layer_name( int aLayer ) const
{
static const string unknown( "unknown" );
auto it = m_eagleLayers.find( aLayer );
return it == m_eagleLayers.end() ? unknown : it->second.name;
}
void EAGLE_PLUGIN::centerBoard()
{
if( m_props )

View File

@ -125,8 +125,11 @@ public:
~EAGLE_PLUGIN();
private:
typedef std::vector<ELAYER> ELAYERS;
typedef ELAYERS::const_iterator EITER;
int m_cu_map[17]; ///< map eagle to kicad, cu layers only.
std::map<int, ELAYER> m_eagleLayers; ///< Eagle layers data stored by the layer number
ERULES* m_rules; ///< Eagle design rules.
XPATH* m_xpath; ///< keeps track of what we are working on within
@ -148,9 +151,6 @@ private:
int m_min_via; ///< smallest via we find on Load(), in BIU.
int m_min_via_hole; ///< smallest via diameter hole we find on Load(), in BIU.
double mm_per_biu; ///< how many mm in each BIU
double biu_per_mm; ///< how many bius in a mm
wxString m_lib_path;
wxDateTime m_mod_time;
@ -160,20 +160,17 @@ private:
void clear_cu_map();
/// Convert an Eagle distance to a KiCad distance.
int kicad( double d ) const;
int kicad_y( double y ) const { return -kicad( y ); }
int kicad_x( double x ) const { return kicad( x ); }
int kicad_y( const ECOORD& y ) const { return -y.ToPcbUnits(); }
int kicad_x( const ECOORD& x ) const { return x.ToPcbUnits(); }
/// create a font size (fontz) from an eagle font size scalar
wxSize kicad_fontz( double d ) const;
wxSize kicad_fontz( const ECOORD& d ) const;
/// Convert an Eagle layer to a KiCad layer.
PCB_LAYER_ID kicad_layer( int aLayer ) const;
/// Convert a KiCad distance to an Eagle distance.
double eagle( BIU d ) const { return mm_per_biu * d; }
double eagle_x( BIU x ) const { return eagle( x ); }
double eagle_y( BIU y ) const { return eagle( y ); }
/// Get Eagle layer name by its number
const std::string& eagle_layer_name( int aLayer ) const;
/// This PLUGIN only caches one footprint library, this determines which one.
void cacheLib( const wxString& aLibraryPath );

View File

@ -42,6 +42,8 @@
#include <msgpanel.h>
#include <fp_lib_table.h>
#include <ratsnest_data.h>
#include <kiway.h>
#include <kiway_player.h>
#include <pcbnew.h>
#include <pcbnew_id.h>
@ -94,10 +96,10 @@ bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bo
IO_MGR::PCB_FILE_T pluginType;
} loaders[] =
{
{ PcbFileWildcard, IO_MGR::KICAD }, // Current Kicad board files
{ LegacyPcbFileWildcard, IO_MGR::LEGACY }, // Old Kicad board files
{ EaglePcbFileWildcard, IO_MGR::EAGLE }, // Import board files
{ PCadPcbFileWildcard, IO_MGR::PCAD }, // Import board files
{ PcbFileWildcard, IO_MGR::KICAD_SEXP }, // Current Kicad board files
{ LegacyPcbFileWildcard, IO_MGR::LEGACY }, // Old Kicad board files
{ EaglePcbFileWildcard, IO_MGR::EAGLE }, // Import board files
{ PCadPcbFileWildcard, IO_MGR::PCAD }, // Import board files
};
wxFileName fileName( *aFileName );
@ -394,7 +396,7 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
}
else
{
pluginType = IO_MGR::KICAD;
pluginType = IO_MGR::KICAD_SEXP;
}
return pluginType;
@ -467,7 +469,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
IO_MGR::PCB_FILE_T pluginType = plugin_type( fullFileName, aCtl );
bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD;
bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP;
if( !converted )
{
@ -709,7 +711,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
try
{
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD ) );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
wxASSERT( pcbFileName.IsAbsolute() );
@ -788,7 +790,7 @@ bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
try
{
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD ) );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
wxASSERT( pcbFileName.IsAbsolute() );
@ -861,3 +863,34 @@ bool PCB_EDIT_FRAME::doAutoSave()
return false;
}
bool PCB_EDIT_FRAME::ImportFile( const wxString& aFileName, int aFileType )
{
switch( (IO_MGR::PCB_FILE_T) aFileType )
{
case IO_MGR::EAGLE:
if( OpenProjectFiles( std::vector<wxString>( 1, aFileName ),
KICTL_EAGLE_BRD ) )
{
wxString projectpath = Kiway().Prj().GetProjectPath();
wxFileName newfilename = Prj().AbsolutePath( Prj().GetProjectName() );
newfilename.SetExt( KiCadPcbFileExtension );
GetBoard()->SetFileName( newfilename.GetFullPath() );
UpdateTitle();
ArchiveModulesOnBoard( true, newfilename.GetName() );
return true;
}
return false;
default:
return false;
}
return false;
}

View File

@ -65,7 +65,7 @@ PLUGIN* IO_MGR::PluginFind( PCB_FILE_T aFileType )
case LEGACY:
return new LEGACY_PLUGIN();
case KICAD:
case KICAD_SEXP:
return new PCB_IO();
case EAGLE:
@ -116,7 +116,7 @@ const wxString IO_MGR::ShowType( PCB_FILE_T aType )
case LEGACY:
return wxString( wxT( "Legacy" ) );
case KICAD:
case KICAD_SEXP:
return wxString( wxT( "KiCad" ) );
case EAGLE:
@ -141,7 +141,7 @@ IO_MGR::PCB_FILE_T IO_MGR::EnumFromStr( const wxString& aType )
// library tables, so don't do change, only additions are ok.
if( aType == wxT( "KiCad" ) )
return KICAD;
return KICAD_SEXP;
if( aType == wxT( "Legacy" ) )
return LEGACY;
@ -181,7 +181,7 @@ const wxString IO_MGR::GetFileExtension( PCB_FILE_T aFileType )
IO_MGR::PCB_FILE_T IO_MGR::GuessPluginTypeFromLibPath( const wxString& aLibPath )
{
PCB_FILE_T ret = KICAD; // default guess, unless detected otherwise.
PCB_FILE_T ret = KICAD_SEXP; // default guess, unless detected otherwise.
wxFileName fn( aLibPath );
if( fn.GetExt() == LegacyFootprintLibPathExtension )
@ -209,7 +209,7 @@ IO_MGR::PCB_FILE_T IO_MGR::GuessPluginTypeFromLibPath( const wxString& aLibPath
else if( fn.GetExt() == KiCadFootprintLibPathExtension &&
!aLibPath.StartsWith( wxT( "http" ) ) )
{
ret = KICAD;
ret = KICAD_SEXP;
}
else
{
@ -254,4 +254,3 @@ void IO_MGR::Save( PCB_FILE_T aFileType, const wxString& aFileName, BOARD* aBoar
THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) );
}

View File

@ -51,7 +51,7 @@ public:
enum PCB_FILE_T
{
LEGACY, ///< Legacy Pcbnew file formats prior to s-expression.
KICAD, ///< S-expression Pcbnew file format.
KICAD_SEXP, ///< S-expression Pcbnew file format.
EAGLE,
PCAD,
GEDA_PCB, ///< Geda PCB file formats.

View File

@ -53,7 +53,8 @@
using namespace PCB_KEYS_T;
#define FMTIU BOARD_ITEM::FormatInternalUnits
#define FMT_IU BOARD_ITEM::FormatInternalUnits
#define FMT_ANGLE BOARD_ITEM::FormatAngle
/**
* @ingroup trace_env_vars
@ -538,105 +539,105 @@ void PCB_IO::formatSetup( BOARD* aBoard, int aNestLevel ) const
// Save current default track width, for compatibility with older Pcbnew version;
m_out->Print( aNestLevel+1, "(last_trace_width %s)\n",
FMTIU( dsnSettings.GetCurrentTrackWidth() ).c_str() );
FMT_IU( dsnSettings.GetCurrentTrackWidth() ).c_str() );
// Save custom tracks width list (the first is not saved here: this is the netclass value
for( unsigned ii = 1; ii < dsnSettings.m_TrackWidthList.size(); ii++ )
m_out->Print( aNestLevel+1, "(user_trace_width %s)\n",
FMTIU( dsnSettings.m_TrackWidthList[ii] ).c_str() );
FMT_IU( dsnSettings.m_TrackWidthList[ii] ).c_str() );
m_out->Print( aNestLevel+1, "(trace_clearance %s)\n",
FMTIU( dsnSettings.GetDefault()->GetClearance() ).c_str() );
FMT_IU( dsnSettings.GetDefault()->GetClearance() ).c_str() );
// ZONE_SETTINGS
m_out->Print( aNestLevel+1, "(zone_clearance %s)\n",
FMTIU( aBoard->GetZoneSettings().m_ZoneClearance ).c_str() );
FMT_IU( aBoard->GetZoneSettings().m_ZoneClearance ).c_str() );
m_out->Print( aNestLevel+1, "(zone_45_only %s)\n",
aBoard->GetZoneSettings().m_Zone_45_Only ? "yes" : "no" );
m_out->Print( aNestLevel+1, "(trace_min %s)\n",
FMTIU( dsnSettings.m_TrackMinWidth ).c_str() );
FMT_IU( dsnSettings.m_TrackMinWidth ).c_str() );
m_out->Print( aNestLevel+1, "(segment_width %s)\n",
FMTIU( dsnSettings.m_DrawSegmentWidth ).c_str() );
FMT_IU( dsnSettings.m_DrawSegmentWidth ).c_str() );
m_out->Print( aNestLevel+1, "(edge_width %s)\n",
FMTIU( dsnSettings.m_EdgeSegmentWidth ).c_str() );
FMT_IU( dsnSettings.m_EdgeSegmentWidth ).c_str() );
// Save current default via size, for compatibility with older Pcbnew version;
m_out->Print( aNestLevel+1, "(via_size %s)\n",
FMTIU( dsnSettings.GetDefault()->GetViaDiameter() ).c_str() );
FMT_IU( dsnSettings.GetDefault()->GetViaDiameter() ).c_str() );
m_out->Print( aNestLevel+1, "(via_drill %s)\n",
FMTIU( dsnSettings.GetDefault()->GetViaDrill() ).c_str() );
FMT_IU( dsnSettings.GetDefault()->GetViaDrill() ).c_str() );
m_out->Print( aNestLevel+1, "(via_min_size %s)\n",
FMTIU( dsnSettings.m_ViasMinSize ).c_str() );
FMT_IU( dsnSettings.m_ViasMinSize ).c_str() );
m_out->Print( aNestLevel+1, "(via_min_drill %s)\n",
FMTIU( dsnSettings.m_ViasMinDrill ).c_str() );
FMT_IU( dsnSettings.m_ViasMinDrill ).c_str() );
// Save custom vias diameters list (the first is not saved here: this is
// the netclass value
for( unsigned ii = 1; ii < dsnSettings.m_ViasDimensionsList.size(); ii++ )
m_out->Print( aNestLevel+1, "(user_via %s %s)\n",
FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Diameter ).c_str(),
FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Drill ).c_str() );
FMT_IU( dsnSettings.m_ViasDimensionsList[ii].m_Diameter ).c_str(),
FMT_IU( dsnSettings.m_ViasDimensionsList[ii].m_Drill ).c_str() );
// for old versions compatibility:
if( dsnSettings.m_BlindBuriedViaAllowed )
m_out->Print( aNestLevel+1, "(blind_buried_vias_allowed yes)\n" );
m_out->Print( aNestLevel+1, "(uvia_size %s)\n",
FMTIU( dsnSettings.GetDefault()->GetuViaDiameter() ).c_str() );
FMT_IU( dsnSettings.GetDefault()->GetuViaDiameter() ).c_str() );
m_out->Print( aNestLevel+1, "(uvia_drill %s)\n",
FMTIU( dsnSettings.GetDefault()->GetuViaDrill() ).c_str() );
FMT_IU( dsnSettings.GetDefault()->GetuViaDrill() ).c_str() );
m_out->Print( aNestLevel+1, "(uvias_allowed %s)\n",
( dsnSettings.m_MicroViasAllowed ) ? "yes" : "no" );
m_out->Print( aNestLevel+1, "(uvia_min_size %s)\n",
FMTIU( dsnSettings.m_MicroViasMinSize ).c_str() );
FMT_IU( dsnSettings.m_MicroViasMinSize ).c_str() );
m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n",
FMTIU( dsnSettings.m_MicroViasMinDrill ).c_str() );
FMT_IU( dsnSettings.m_MicroViasMinDrill ).c_str() );
m_out->Print( aNestLevel+1, "(pcb_text_width %s)\n",
FMTIU( dsnSettings.m_PcbTextWidth ).c_str() );
FMT_IU( dsnSettings.m_PcbTextWidth ).c_str() );
m_out->Print( aNestLevel+1, "(pcb_text_size %s %s)\n",
FMTIU( dsnSettings.m_PcbTextSize.x ).c_str(),
FMTIU( dsnSettings.m_PcbTextSize.y ).c_str() );
FMT_IU( dsnSettings.m_PcbTextSize.x ).c_str(),
FMT_IU( dsnSettings.m_PcbTextSize.y ).c_str() );
m_out->Print( aNestLevel+1, "(mod_edge_width %s)\n",
FMTIU( dsnSettings.m_ModuleSegmentWidth ).c_str() );
FMT_IU( dsnSettings.m_ModuleSegmentWidth ).c_str() );
m_out->Print( aNestLevel+1, "(mod_text_size %s %s)\n",
FMTIU( dsnSettings.m_ModuleTextSize.x ).c_str(),
FMTIU( dsnSettings.m_ModuleTextSize.y ).c_str() );
FMT_IU( dsnSettings.m_ModuleTextSize.x ).c_str(),
FMT_IU( dsnSettings.m_ModuleTextSize.y ).c_str() );
m_out->Print( aNestLevel+1, "(mod_text_width %s)\n",
FMTIU( dsnSettings.m_ModuleTextWidth ).c_str() );
FMT_IU( dsnSettings.m_ModuleTextWidth ).c_str() );
m_out->Print( aNestLevel+1, "(pad_size %s %s)\n",
FMTIU( dsnSettings.m_Pad_Master.GetSize().x ).c_str(),
FMTIU( dsnSettings.m_Pad_Master.GetSize().y ).c_str() );
FMT_IU( dsnSettings.m_Pad_Master.GetSize().x ).c_str(),
FMT_IU( dsnSettings.m_Pad_Master.GetSize().y ).c_str() );
m_out->Print( aNestLevel+1, "(pad_drill %s)\n",
FMTIU( dsnSettings.m_Pad_Master.GetDrillSize().x ).c_str() );
FMT_IU( dsnSettings.m_Pad_Master.GetDrillSize().x ).c_str() );
m_out->Print( aNestLevel+1, "(pad_to_mask_clearance %s)\n",
FMTIU( dsnSettings.m_SolderMaskMargin ).c_str() );
FMT_IU( dsnSettings.m_SolderMaskMargin ).c_str() );
if( dsnSettings.m_SolderMaskMinWidth )
m_out->Print( aNestLevel+1, "(solder_mask_min_width %s)\n",
FMTIU( dsnSettings.m_SolderMaskMinWidth ).c_str() );
FMT_IU( dsnSettings.m_SolderMaskMinWidth ).c_str() );
if( dsnSettings.m_SolderPasteMargin != 0 )
m_out->Print( aNestLevel+1, "(pad_to_paste_clearance %s)\n",
FMTIU( dsnSettings.m_SolderPasteMargin ).c_str() );
FMT_IU( dsnSettings.m_SolderPasteMargin ).c_str() );
if( dsnSettings.m_SolderPasteMarginRatio != 0 )
m_out->Print( aNestLevel+1, "(pad_to_paste_clearance_ratio %s)\n",
Double2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() );
m_out->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n",
FMTIU( aBoard->GetAuxOrigin().x ).c_str(),
FMTIU( aBoard->GetAuxOrigin().y ).c_str() );
FMT_IU( aBoard->GetAuxOrigin().x ).c_str(),
FMT_IU( aBoard->GetAuxOrigin().y ).c_str() );
if( aBoard->GetGridOrigin().x || aBoard->GetGridOrigin().y )
m_out->Print( aNestLevel+1, "(grid_origin %s %s)\n",
FMTIU( aBoard->GetGridOrigin().x ).c_str(),
FMTIU( aBoard->GetGridOrigin().y ).c_str() );
FMT_IU( aBoard->GetGridOrigin().x ).c_str(),
FMT_IU( aBoard->GetGridOrigin().y ).c_str() );
m_out->Print( aNestLevel+1, "(visible_elements %X)\n",
dsnSettings.GetVisibleElements() );
@ -655,7 +656,7 @@ void PCB_IO::formatGeneral( BOARD* aBoard, int aNestLevel ) const
m_out->Print( aNestLevel, "(general\n" );
// Write Bounding box info
m_out->Print( aNestLevel+1, "(thickness %s)\n",
FMTIU( dsnSettings.GetBoardThickness() ).c_str() );
FMT_IU( dsnSettings.GetBoardThickness() ).c_str() );
m_out->Print( aNestLevel+1, "(drawings %d)\n", aBoard->Drawings().Size() );
m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() );

View File

@ -144,7 +144,7 @@ static IO_MGR::PCB_FILE_T detect_file_type( FILE* aFile, const wxFileName& aFile
if( !strncasecmp( line, "(module", strlen( "(module" ) ) )
{
file_type = IO_MGR::KICAD;
file_type = IO_MGR::KICAD_SEXP;
*aName = aFileName.GetName();
}
else if( !strncasecmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) )
@ -240,7 +240,7 @@ MODULE* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFil
module = parse_module_with_plugin( aFileName, aFileType, aName );
break;
case IO_MGR::KICAD:
case IO_MGR::KICAD_SEXP:
module = parse_module_kicad( aFileName );
break;
@ -441,27 +441,47 @@ bool FOOTPRINT_EDIT_FRAME::SaveCurrentModule( const wxString* aLibPath )
return true;
}
wxString PCB_BASE_EDIT_FRAME::CreateNewLibrary()
wxString PCB_BASE_EDIT_FRAME::CreateNewLibrary(const wxString& aLibName )
{
// Kicad cannot write legacy format libraries, only .pretty new format
// because the legacy format cannot handle current features.
// The footprint library is actually a directory
// prompt user for footprint library name, ending by ".pretty"
// if a library name is not given, prompt user for footprint library name, ending by ".pretty"
// Because there are constraints for the directory name to create,
// (the name should have the extension ".pretty", and the folder cannot be inside
// a footprint library), we do not use the standard wxDirDialog.
wxString initialPath = wxPathOnly( Prj().GetProjectFullName() );
DIALOG_SELECT_PRETTY_LIB dlg( this, initialPath );
if( dlg.ShowModal() != wxID_OK )
return wxEmptyString;
wxString libPath;
wxString libPath = dlg.GetFullPrettyLibName();
if( aLibName.IsEmpty() )
{
DIALOG_SELECT_PRETTY_LIB dlg( this, initialPath );
// We can save fp libs only using IO_MGR::KICAD format (.pretty libraries)
IO_MGR::PCB_FILE_T piType = IO_MGR::KICAD;
if( dlg.ShowModal() != wxID_OK )
return wxEmptyString;
libPath = dlg.GetFullPrettyLibName();
}
else
{
wxFileName fn = aLibName;
if( !fn.IsAbsolute() )
fn.MakeAbsolute( initialPath );
// Enforce the extension:
fn.SetExt( KiCadFootprintLibPathExtension );
libPath = fn.GetFullPath();
}
// We can save fp libs only using IO_MGR::KICAD_SEXP format (.pretty libraries)
IO_MGR::PCB_FILE_T piType = IO_MGR::KICAD_SEXP;
try
{
@ -570,7 +590,7 @@ bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary()
}
void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aStoreInNewLib )
void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aStoreInNewLib, const wxString& aLibName )
{
if( GetBoard()->m_Modules == NULL )
{
@ -611,12 +631,12 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aStoreInNewLib )
{
// The footprints are saved in a new .pretty library.
// If this library already exists, all previous footprints will be deleted
wxString libPath = CreateNewLibrary();
wxString libPath = CreateNewLibrary( aLibName );
if( libPath.IsEmpty() ) // Aborted
return;
IO_MGR::PCB_FILE_T piType = IO_MGR::KICAD;
IO_MGR::PCB_FILE_T piType = IO_MGR::KICAD_SEXP;
PLUGIN::RELEASER pi( IO_MGR::PluginFind( piType ) );
for( MODULE* curr_fp = GetBoard()->m_Modules; curr_fp; curr_fp = curr_fp->Next() )

View File

@ -52,14 +52,16 @@ public:
/**
* Function CreateNewLibrary
* prompts user for a library path, then creates a new footprint library at that
* location. If library exists, user is warned about that, and is given a chance
* If a library name is given, creates a new footprint library in the project folder
* with the given name. If no library name is given it prompts user for a library path,
* then creates a new footprint library at that location.
* If library exists, user is warned about that, and is given a chance
* to abort the new creation, and in that case existing library is first deleted.
*
* @return wxString - the newly created library path if library was successfully
* created, else wxEmptyString because user aborted or error.
*/
wxString CreateNewLibrary();
wxString CreateNewLibrary(const wxString& aLibName = wxEmptyString);
/**
* Function OnEditItemRequest

View File

@ -60,7 +60,7 @@ void ScriptingSetPcbEditFrame( PCB_EDIT_FRAME* aPcbEditFrame )
BOARD* LoadBoard( wxString& aFileName )
{
if( aFileName.EndsWith( wxT( ".kicad_pcb" ) ) )
return LoadBoard( aFileName, IO_MGR::KICAD );
return LoadBoard( aFileName, IO_MGR::KICAD_SEXP );
else if( aFileName.EndsWith( wxT( ".brd" ) ) )
return LoadBoard( aFileName, IO_MGR::LEGACY );
@ -95,7 +95,7 @@ bool SaveBoard( wxString& aFileName, BOARD* aBoard, IO_MGR::PCB_FILE_T aFormat )
bool SaveBoard( wxString& aFileName, BOARD* aBoard )
{
return SaveBoard( aFileName, aBoard, IO_MGR::KICAD );
return SaveBoard( aFileName, aBoard, IO_MGR::KICAD_SEXP );
}

View File

@ -30,10 +30,10 @@
#define WXPCB_STRUCT_H_
#include <pcb_base_edit_frame.h>
#include <config_params.h>
#include <class_undoredo_container.h>
#include <zones.h>
#include "pcb_base_edit_frame.h"
#include "config_params.h"
#include "class_undoredo_container.h"
#include "zones.h"
/* Forward declarations of classes. */
@ -864,6 +864,14 @@ public:
*/
bool AppendBoardFile( const wxString& aFullFileName, int aCtl );
/**
* Function ImportFile
* load the given filename but sets the path to the current project path.
* @param full filepath of file to be imported.
* @param aFileType PCB_FILE_T value for filetype
*/
bool ImportFile( const wxString& aFileName, int aFileType ) override;
/**
* Function SavePcbFile
* writes the board data structures to \a a aFileName
@ -933,8 +941,12 @@ public:
* This lib should be in fp lib table, and is type is .pretty
* false: save modules in a new lib. It it is an existing lib,
* previous footprints will be removed
*
* @param aLibName:
* optional library name to create, stops dialog call.
* must be called with aStoreInNewLib as true
*/
void ArchiveModulesOnBoard( bool aStoreInNewLib );
void ArchiveModulesOnBoard( bool aStoreInNewLib, const wxString& aLibName = wxEmptyString );
/**
* Function RecreateBOMFileFromBoard
@ -1546,7 +1558,7 @@ public:
bool aDeleteExtraFootprints,
bool aSelectByTimestamp,
bool aDeleteSinglePadNets,
bool aIsDryRun );
bool aIsDryRun ) override;
/**
* Function RemoveMisConnectedTracks