Commit 67ebe29b authored by dickelbeck's avatar dickelbeck

more free specctra work

parent 7878ba27
Change Log for Kicad Change Log for Kicad
Started 2007-June-11 Started 2007-June-11
...@@ -16,7 +15,6 @@ email address. ...@@ -16,7 +15,6 @@ email address.
the new track takes the width of the existing track the new track takes the width of the existing track
2008-Jan-27 UPDATE Dick Hollenbeck <dick@softplc.com> 2008-Jan-27 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================ ================================================================================
+all: +all:
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
#include <wx/ffile.h> #include <wx/ffile.h>
// To build the DSN beautifier and unit tester, simply uncomment this and then
// use CMake's makefile to build target "specctra_test".
//#define STANDALONE // define "stand alone, i.e. unit testing" //#define STANDALONE // define "stand alone, i.e. unit testing"
...@@ -861,24 +863,32 @@ void SPECCTRA_DB::doWINDOW( WINDOW* growth ) throw( IOError ) ...@@ -861,24 +863,32 @@ void SPECCTRA_DB::doWINDOW( WINDOW* growth ) throw( IOError )
switch( tok ) switch( tok )
{ {
case T_rect: case T_rect:
growth->rectangle = new RECTANGLE( growth ); if( growth->shape )
doRECTANGLE( growth->rectangle ); unexpected( tok );
growth->shape = new RECTANGLE( growth );
doRECTANGLE( (RECTANGLE*) growth->shape );
break; break;
case T_circle: case T_circle:
growth->circle = new CIRCLE( growth ); if( growth->shape )
doCIRCLE( growth->circle ); unexpected( tok );
growth->shape = new CIRCLE( growth );
doCIRCLE( (CIRCLE*) growth->shape );
break; break;
case T_path: case T_path:
case T_polygon: case T_polygon:
growth->path = new PATH( growth, tok ); if( growth->shape )
doPATH( growth->path ); unexpected( tok );
growth->shape = new PATH( growth, tok );
doPATH( (PATH*) growth->shape );
break; break;
case T_qarc: case T_qarc:
growth->qarc = new QARC( growth ); if( growth->shape )
doQARC( growth->qarc ); unexpected( tok );
growth->shape = new QARC( growth );
doQARC( (QARC*) growth->shape );
break; break;
default: default:
...@@ -3353,18 +3363,19 @@ int SPECCTRA_DB::Print( int nestLevel, const char* fmt, ... ) throw( IOError ) ...@@ -3353,18 +3363,19 @@ int SPECCTRA_DB::Print( int nestLevel, const char* fmt, ... ) throw( IOError )
return total; return total;
} }
// factor out a common GetQuoteChar
const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
{ {
// I include '#' so a symbol is not confused with a comment. We intend // I include '#' so a symbol is not confused with a comment. We intend
// to wrap any symbol starting with a '#'. // to wrap any symbol starting with a '#'.
// Our LEXER class handles comments, and comments appear to be an extension // Our LEXER class handles comments, and comments appear to be an extension
// to the SPECCTRA DSN specification. // to the SPECCTRA DSN specification.
if( *wrapee == '#' ) if( *wrapee == '#' )
return quote_char.c_str(); return quote_char;
if( strlen(wrapee)==0 ) if( strlen(wrapee)==0 )
return quote_char.c_str(); return quote_char;
bool isNumber = true; bool isNumber = true;
...@@ -3373,19 +3384,25 @@ const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) ...@@ -3373,19 +3384,25 @@ const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee )
// if the string to be wrapped (wrapee) has a delimiter in it, // if the string to be wrapped (wrapee) has a delimiter in it,
// return the quote_char so caller wraps the wrapee. // return the quote_char so caller wraps the wrapee.
if( strchr( "\t ()", *wrapee ) ) if( strchr( "\t ()", *wrapee ) )
return quote_char.c_str(); return quote_char;
if( !strchr( "01234567890.-+", *wrapee ) ) if( !strchr( "01234567890.-+", *wrapee ) )
isNumber = false; isNumber = false;
} }
if( isNumber ) if( isNumber )
return quote_char.c_str(); return quote_char;
return ""; // can use an unwrapped string. return ""; // can use an unwrapped string.
} }
const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee )
{
return OUTPUTFORMATTER::GetQuoteChar( wrapee, quote_char.c_str() );
}
void SPECCTRA_DB::ExportPCB( wxString filename, bool aNameChange ) throw( IOError ) void SPECCTRA_DB::ExportPCB( wxString filename, bool aNameChange ) throw( IOError )
{ {
fp = wxFopen( filename, wxT("w") ); fp = wxFopen( filename, wxT("w") );
...@@ -3438,6 +3455,8 @@ PCB* SPECCTRA_DB::MakePCB() ...@@ -3438,6 +3455,8 @@ PCB* SPECCTRA_DB::MakePCB()
pcb->structure = new STRUCTURE( pcb ); pcb->structure = new STRUCTURE( pcb );
pcb->structure->boundary = new BOUNDARY( pcb->structure ); pcb->structure->boundary = new BOUNDARY( pcb->structure );
pcb->structure->via = new VIA( pcb->structure );
pcb->structure->rules = new RULE( pcb->structure, T_rule );
pcb->placement = new PLACEMENT( pcb ); pcb->placement = new PLACEMENT( pcb );
...@@ -3451,6 +3470,87 @@ PCB* SPECCTRA_DB::MakePCB() ...@@ -3451,6 +3470,87 @@ PCB* SPECCTRA_DB::MakePCB()
} }
//-----<STRINGFORMATTER>----------------------------------------------------
const char* STRINGFORMATTER::GetQuoteChar( const char* wrapee )
{
// for what we are using STRINGFORMATTER for at this time, we can return the nul string
// always.
return "";
// return OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, "\"" );
}
int STRINGFORMATTER::vprint( const char* fmt, va_list ap )
{
int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
if( ret >= (int) buffer.size() )
{
buffer.reserve( ret+200 );
ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
}
if( ret > 0 )
mystring.append( (const char*) &buffer[0] );
return ret;
}
int STRINGFORMATTER::sprint( const char* fmt, ... )
{
va_list args;
va_start( args, fmt );
int ret = vprint( fmt, args);
va_end( args );
return ret;
}
int STRINGFORMATTER::Print( int nestLevel, const char* fmt, ... ) throw( IOError )
{
va_list args;
va_start( args, fmt );
int result = 0;
int total = 0;
for( int i=0; i<nestLevel; ++i )
{
result = sprint( "%*c", NESTWIDTH, ' ' );
if( result < 0 )
break;
total += result;
}
if( result<0 || (result=vprint( fmt, args ))<0 )
{
throw IOError( _("Error writing to STRINGFORMATTER") );
}
va_end( args );
total += result;
return total;
}
void STRINGFORMATTER::StripUseless()
{
for( std::string::iterator i=mystring.begin(); i!=mystring.end(); )
{
if( isspace( *i ) || *i==')' || *i=='(' )
mystring.erase(i);
else
++i;
}
}
//-----<ELEM>--------------------------------------------------------------- //-----<ELEM>---------------------------------------------------------------
ELEM::ELEM( DSN_T aType, ELEM* aParent ) : ELEM::ELEM( DSN_T aType, ELEM* aParent ) :
...@@ -3500,8 +3600,40 @@ int ELEM_HOLDER::FindElem( DSN_T aType, int instanceNum ) ...@@ -3500,8 +3600,40 @@ int ELEM_HOLDER::FindElem( DSN_T aType, int instanceNum )
} }
//-----<PARSER>----------------------------------------------------------- //-----<PADSTACK>---------------------------------------------------------
int PADSTACK::Compare( PADSTACK* lhs, PADSTACK* rhs )
{
if( !lhs->hash.size() )
lhs->hash = lhs->makeHash();
if( !rhs->hash.size() )
rhs->hash = rhs->makeHash();
int result = lhs->hash.compare( rhs->hash );
return result;
}
//-----<IMAGE>------------------------------------------------------------
int IMAGE::Compare( IMAGE* lhs, IMAGE* rhs )
{
if( !lhs->hash.size() )
lhs->hash = lhs->makeHash();
if( !rhs->hash.size() )
rhs->hash = rhs->makeHash();
int result = lhs->hash.compare( rhs->hash );
// printf("\"%s\" \"%s\" ret=%d\n", lhs->hash.c_str(), rhs->hash.c_str(), result );
return result;
}
//-----<PARSER>-----------------------------------------------------------
PARSER::PARSER( ELEM* aParent ) : PARSER::PARSER( ELEM* aParent ) :
ELEM( T_parser, aParent ) ELEM( T_parser, aParent )
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include "fctsys.h" #include "fctsys.h"
#include "dsn.h" #include "dsn.h"
class TYPE_COLLECTOR; // outside the DSN namespace
/** /**
...@@ -101,9 +103,86 @@ public: ...@@ -101,9 +103,86 @@ public:
* if the wrapee does not need to be wrapped. * if the wrapee does not need to be wrapped.
*/ */
virtual const char* GetQuoteChar( const char* wrapee ) = 0; virtual const char* GetQuoteChar( const char* wrapee ) = 0;
virtual ~OUTPUTFORMATTER() {}
/**
* Function GetQuoteChar
* factor may be used by derived classes to perform quote character selection.
* @param wrapee A string that might need wrapping on each end.
* @param quote_char A single character C string which hold the current quote character.
* @return const char* - the quote_char as a single character string, or ""
* if the wrapee does not need to be wrapped.
*/
static const char* GetQuoteChar( const char* wrapee, const char* quote_char );
}; };
/**
* Class STRINGFORMATTER
* implements OUTPUTFORMATTER to a memory buffer. After Print()ing the
* string is available through GetString()
*/
class STRINGFORMATTER : public OUTPUTFORMATTER
{
std::vector<char> buffer;
std::string mystring;
int sprint( const char* fmt, ... );
int vprint( const char* fmt, va_list ap );
public:
/**
* Constructor STRINGFORMATTER
* reserves space in the buffer
*/
STRINGFORMATTER( int aReserve = 300 ) :
buffer( aReserve, '\0' )
{
}
/**
* Function Clear
* clears the buffer and empties the internal string.
*/
void Clear()
{
mystring.clear();
}
/**
* Function StripUseless
* removes whitespace, '(', and ')' from the mystring.
*/
void StripUseless();
/*
const char* c_str()
{
return mystring.c_str();
}
*/
std::string GetString()
{
return mystring;
}
//-----<OUTPUTFORMATTER>------------------------------------------------
int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) throw( IOError );
const char* GetQuoteChar( const char* wrapee );
//-----</OUTPUTFORMATTER>-----------------------------------------------
};
/**
* Class POINT
* is a holder for a point in the SPECCTRA DSN coordinate system. It can also
* be used to hold a distance (vector really) from some origin.
*/
struct POINT struct POINT
{ {
double x; double x;
...@@ -136,14 +215,23 @@ struct POINT ...@@ -136,14 +215,23 @@ struct POINT
POINT& operator=( const POINT& other ) POINT& operator=( const POINT& other )
{ {
x = other.x; x = other.x;
if( x == -0.0 ) // correct -0.0 so output looks nice.
x = 0.0;
y = other.y; y = other.y;
if( y == -0.0 )
y = 0.0;
return *this; return *this;
} }
/**
* Function FixNegativeZero
* will change negative zero to positive zero in the IEEE floating point
* storage format. Basically turns off the sign bit if the mantiss and exponent
* would say the value is zero.
*/
void FixNegativeZero()
{
if( x == -0.0 )
x = 0.0;
if( y == -0.0 )
y = 0.0;
}
/** /**
* Function Format * Function Format
...@@ -196,10 +284,33 @@ typedef std::vector<PROPERTY> PROPERTIES; ...@@ -196,10 +284,33 @@ typedef std::vector<PROPERTY> PROPERTIES;
class ELEM class ELEM
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
protected: protected:
DSN_T type; DSN_T type;
ELEM* parent; ELEM* parent;
/**
* Function makeHash
* returns a string which uniquely represents this ELEM amoung other
* ELEMs of the same derived class as "this" one.
* It is not useable for all derived classes, only those which plan for
* it by implementing a FormatContents() function that captures all info
* which will be used in the subsequent string compare. THIS SHOULD
* NORMALLY EXCLUDE THE TYPENAME, AND INSTANCE NAME OR ID AS WELL.
*/
std::string makeHash()
{
STRINGFORMATTER sf;
FormatContents( &sf, 0 );
sf.StripUseless();
return sf.GetString();
}
public: public:
...@@ -207,7 +318,7 @@ public: ...@@ -207,7 +318,7 @@ public:
virtual ~ELEM(); virtual ~ELEM();
DSN_T Type() { return type; } DSN_T Type() const { return type; }
/** /**
...@@ -216,7 +327,7 @@ public: ...@@ -216,7 +327,7 @@ public:
* to check for section specific overrides. * to check for section specific overrides.
* @return DSN_T - one of the allowed values to &lt;unit_descriptor&gt; * @return DSN_T - one of the allowed values to &lt;unit_descriptor&gt;
*/ */
virtual DSN_T GetUnits() virtual DSN_T GetUnits() const
{ {
if( parent ) if( parent )
return parent->GetUnits(); return parent->GetUnits();
...@@ -324,14 +435,14 @@ public: ...@@ -324,14 +435,14 @@ public:
kids.insert( kids.begin()+aIndex, aElem ); kids.insert( kids.begin()+aIndex, aElem );
} }
ELEM* At( int aIndex ) ELEM* At( int aIndex ) const
{ {
// we have varying sized objects and are using polymorphism, so we // we have varying sized objects and are using polymorphism, so we
// must return a pointer not a reference. // must return a pointer not a reference.
return &kids[aIndex]; return (ELEM*) &kids[aIndex];
} }
ELEM* operator[]( int aIndex ) ELEM* operator[]( int aIndex ) const
{ {
return At( aIndex ); return At( aIndex );
} }
...@@ -408,7 +519,7 @@ public: ...@@ -408,7 +519,7 @@ public:
LEXER::GetTokenText(units), value ); LEXER::GetTokenText(units), value );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
return units; return units;
} }
...@@ -439,7 +550,10 @@ public: ...@@ -439,7 +550,10 @@ public:
void SetCorners( const POINT& aPoint0, const POINT& aPoint1 ) void SetCorners( const POINT& aPoint0, const POINT& aPoint1 )
{ {
point0 = aPoint0; point0 = aPoint0;
point0.FixNegativeZero();
point1 = aPoint1; point1 = aPoint1;
point1.FixNegativeZero();
} }
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
...@@ -581,7 +695,6 @@ public: ...@@ -581,7 +695,6 @@ public:
out->Print( nestLevel, ")\n" ); out->Print( nestLevel, ")\n" );
} }
}; };
typedef boost::ptr_vector<LAYER_RULE> LAYER_RULES; typedef boost::ptr_vector<LAYER_RULE> LAYER_RULES;
...@@ -780,15 +893,21 @@ public: ...@@ -780,15 +893,21 @@ public:
} }
void SetStart( const POINT& aStart ) void SetStart( const POINT& aStart )
{ {
vertex[0] = aStart; vertex[0] = aStart;
// no -0.0 on the printouts!
vertex[0].FixNegativeZero();
} }
void SetEnd( const POINT& aEnd ) void SetEnd( const POINT& aEnd )
{ {
vertex[1] = aEnd; vertex[1] = aEnd;
// no -0.0 on the printouts!
vertex[1].FixNegativeZero();
} }
void SetCenter( const POINT& aCenter ) void SetCenter( const POINT& aCenter )
{ {
vertex[2] = aCenter; vertex[2] = aCenter;
// no -0.0 on the printouts!
vertex[2].FixNegativeZero();
} }
}; };
...@@ -797,49 +916,53 @@ class WINDOW : public ELEM ...@@ -797,49 +916,53 @@ class WINDOW : public ELEM
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
//----- only one of these is used, like a union ----- protected:
/* shape holds one of these
PATH* path; ///< used for both path and polygon PATH* path; ///< used for both path and polygon
RECTANGLE* rectangle; RECTANGLE* rectangle;
CIRCLE* circle; CIRCLE* circle;
QARC* qarc; QARC* qarc;
//--------------------------------------------------- */
ELEM* shape;
public: public:
WINDOW( ELEM* aParent ) : WINDOW( ELEM* aParent, DSN_T aType = T_window ) :
ELEM( T_window, aParent ) ELEM( aType, aParent )
{ {
path = 0; shape = 0;
rectangle = 0;
circle = 0;
qarc = 0;
} }
~WINDOW() ~WINDOW()
{ {
delete path; delete shape;
delete rectangle;
delete circle;
delete qarc;
} }
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void SetShape( ELEM* aShape )
{ {
// these are mutually exclusive delete shape;
if( rectangle ) shape = aShape;
rectangle->Format( out, nestLevel );
else if( path )
path->Format( out, nestLevel );
else if( circle ) if( aShape )
circle->Format( out, nestLevel ); {
wxASSERT(aShape->Type()==T_rect || aShape->Type()==T_circle
|| aShape->Type()==T_qarc || aShape->Type()==T_path
|| aShape->Type()==T_polygon);
aShape->SetParent( this );
}
}
else if( qarc ) void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
qarc->Format( out, nestLevel ); {
out->Print( nestLevel, "(%s ", LEXER::GetTokenText( Type() ) );
if( shape )
shape->Format( out, 0 );
out->Print( 0, ")\n" );
} }
}; };
typedef boost::ptr_vector<WINDOW> WINDOWS; typedef boost::ptr_vector<WINDOW> WINDOWS;
...@@ -956,6 +1079,11 @@ public: ...@@ -956,6 +1079,11 @@ public:
ELEM( T_via, aParent ) ELEM( T_via, aParent )
{ {
} }
void AppendVia( const char* aViaName )
{
padstacks.push_back( aViaName );
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
...@@ -1217,13 +1345,13 @@ public: ...@@ -1217,13 +1345,13 @@ public:
layer_weight ); layer_weight );
} }
}; };
typedef boost::ptr_vector<LAYER_PAIR> LAYER_PAIRS;
class LAYER_NOISE_WEIGHT : public ELEM class LAYER_NOISE_WEIGHT : public ELEM
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
typedef boost::ptr_vector<LAYER_PAIR> LAYER_PAIRS;
LAYER_PAIRS layer_pairs; LAYER_PAIRS layer_pairs;
public: public:
...@@ -1542,7 +1670,7 @@ public: ...@@ -1542,7 +1670,7 @@ public:
i->Format( out, nestLevel ); i->Format( out, nestLevel );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -1693,7 +1821,7 @@ public: ...@@ -1693,7 +1821,7 @@ public:
i->Format( out, nestLevel ); i->Format( out, nestLevel );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -1710,7 +1838,7 @@ public: ...@@ -1710,7 +1838,7 @@ public:
* elements contains, i.e. in its "shape" field. This class also implements * elements contains, i.e. in its "shape" field. This class also implements
* the "(outline ...)" element as a dual personality. * the "(outline ...)" element as a dual personality.
*/ */
class SHAPE : public ELEM class SHAPE : public WINDOW
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
...@@ -1722,38 +1850,18 @@ class SHAPE : public ELEM ...@@ -1722,38 +1850,18 @@ class SHAPE : public ELEM
<polygon_descriptor> | <polygon_descriptor> |
<path_descriptor> | <path_descriptor> |
<qarc_descriptor> ] <qarc_descriptor> ]
ELEM* shape; // inherited from WINDOW
*/ */
ELEM* shape;
WINDOWS windows; WINDOWS windows;
public: public:
SHAPE( ELEM* aParent, DSN_T aType = T_shape ) : SHAPE( ELEM* aParent, DSN_T aType = T_shape ) :
ELEM( aType, aParent ) WINDOW( aParent, aType )
{ {
connect = T_on; connect = T_on;
shape = 0;
}
~SHAPE()
{
delete shape;
} }
void SetShape( ELEM* aShape )
{
delete shape;
shape = aShape;
if( aShape )
{
wxASSERT(aShape->Type()==T_rect || aShape->Type()==T_circle
|| aShape->Type()==T_qarc || aShape->Type()==T_path
|| aShape->Type()==T_polygon);
aShape->SetParent( this );
}
}
void SetConnect( DSN_T aConnect ) void SetConnect( DSN_T aConnect )
{ {
connect = aConnect; connect = aConnect;
...@@ -1808,6 +1916,12 @@ public: ...@@ -1808,6 +1916,12 @@ public:
isRotated = (aRotation != 0.0); isRotated = (aRotation != 0.0);
} }
void SetVertex( const POINT& aPoint )
{
vertex = aPoint;
vertex.FixNegativeZero();
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
const char* quote = out->GetQuoteChar( padstack_id.c_str() ); const char* quote = out->GetQuoteChar( padstack_id.c_str() );
...@@ -1830,6 +1944,8 @@ class IMAGE : public ELEM_HOLDER ...@@ -1830,6 +1944,8 @@ class IMAGE : public ELEM_HOLDER
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
std::string hash; ///< a hash string used by Compare(), not Format()ed/exported.
std::string image_id; std::string image_id;
DSN_T side; DSN_T side;
UNIT_RES* unit; UNIT_RES* unit;
...@@ -1864,42 +1980,53 @@ public: ...@@ -1864,42 +1980,53 @@ public:
delete place_rules; delete place_rules;
} }
/**
* Function Compare
* compares two objects of this type and returns <0, 0, or >0.
*/
static int Compare( IMAGE* lhs, IMAGE* rhs );
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
const char* quote = out->GetQuoteChar( image_id.c_str() ); const char* quote = out->GetQuoteChar( image_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ), out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ),
quote, image_id.c_str(), quote ); quote, image_id.c_str(), quote );
FormatContents( out, nestLevel+1 );
out->Print( nestLevel, ")\n" );
}
// this is here for makeHash()
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
if( side != T_both ) if( side != T_both )
out->Print( 0, " (side %s)", LEXER::GetTokenText( side ) ); out->Print( 0, " (side %s)", LEXER::GetTokenText( side ) );
out->Print( 0, "\n"); out->Print( 0, "\n");
if( unit ) if( unit )
unit->Format( out, nestLevel+1 ); unit->Format( out, nestLevel );
// format the kids, which in this class are the shapes // format the kids, which in this class are the shapes
ELEM_HOLDER::FormatContents( out, nestLevel+1 ); ELEM_HOLDER::FormatContents( out, nestLevel );
for( PINS::iterator i=pins.begin(); i!=pins.end(); ++i ) for( PINS::iterator i=pins.begin(); i!=pins.end(); ++i )
i->Format( out, nestLevel+1 ); i->Format( out, nestLevel );
if( rules ) if( rules )
rules->Format( out, nestLevel+1 ); rules->Format( out, nestLevel );
if( place_rules ) if( place_rules )
place_rules->Format( out, nestLevel+1 ); place_rules->Format( out, nestLevel );
for( KEEPOUTS::iterator i=keepouts.begin(); i!=keepouts.end(); ++i ) for( KEEPOUTS::iterator i=keepouts.begin(); i!=keepouts.end(); ++i )
i->Format( out, nestLevel+1 ); i->Format( out, nestLevel );
out->Print( nestLevel, ")\n" );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -1907,12 +2034,20 @@ public: ...@@ -1907,12 +2034,20 @@ public:
return ELEM::GetUnits(); return ELEM::GetUnits();
} }
}; };
typedef boost::ptr_vector<IMAGE> IMAGES;
/**
* Class PADSTACK
* holds either a via or a pad definition.
*/
class PADSTACK : public ELEM_HOLDER class PADSTACK : public ELEM_HOLDER
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
std::string hash; ///< a hash string used by Compare(), not Format()ed/exported.
std::string padstack_id; std::string padstack_id;
UNIT_RES* unit; UNIT_RES* unit;
...@@ -1942,6 +2077,13 @@ public: ...@@ -1942,6 +2077,13 @@ public:
delete rules; delete rules;
} }
/**
* Function Compare
* compares two objects of this type and returns <0, 0, or >0.
*/
static int Compare( PADSTACK* lhs, PADSTACK* rhs );
void SetPadstackId( const char* aPadstackId ) void SetPadstackId( const char* aPadstackId )
{ {
padstack_id = aPadstackId; padstack_id = aPadstackId;
...@@ -1954,11 +2096,20 @@ public: ...@@ -1954,11 +2096,20 @@ public:
out->Print( nestLevel, "(%s %s%s%s\n", LEXER::GetTokenText( Type() ), out->Print( nestLevel, "(%s %s%s%s\n", LEXER::GetTokenText( Type() ),
quote, padstack_id.c_str(), quote ); quote, padstack_id.c_str(), quote );
FormatContents( out, nestLevel+1 );
out->Print( nestLevel, ")\n" );
}
// this factored out for use by Compare()
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
if( unit ) if( unit )
unit->Format( out, nestLevel+1 ); unit->Format( out, nestLevel );
// format the kids, which in this class are the shapes // format the kids, which in this class are the shapes
ELEM_HOLDER::FormatContents( out, nestLevel+1 ); ELEM_HOLDER::FormatContents( out, nestLevel );
out->Print( nestLevel+1, "%s", "" ); out->Print( nestLevel+1, "%s", "" );
...@@ -1982,12 +2133,11 @@ public: ...@@ -1982,12 +2133,11 @@ public:
out->Print( 0, "\n" ); out->Print( 0, "\n" );
if( rules ) if( rules )
rules->Format( out, nestLevel+1 ); rules->Format( out, nestLevel );
out->Print( nestLevel, ")\n" );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -2007,25 +2157,68 @@ typedef boost::ptr_vector<PADSTACK> PADSTACKS; ...@@ -2007,25 +2157,68 @@ typedef boost::ptr_vector<PADSTACK> PADSTACKS;
class LIBRARY : public ELEM class LIBRARY : public ELEM
{ {
friend class SPECCTRA_DB; friend class SPECCTRA_DB;
UNIT_RES* unit;
typedef boost::ptr_vector<IMAGE> IMAGES; UNIT_RES* unit;
IMAGES images; IMAGES images;
PADSTACKS padstacks; PADSTACKS padstacks;
/// The start of the vias within the padstacks, which trail the pads.
/// This field is not Format()ed.
int via_start_index;
public: public:
LIBRARY( ELEM* aParent, DSN_T aType = T_library ) : LIBRARY( ELEM* aParent, DSN_T aType = T_library ) :
ELEM( aType, aParent ) ELEM( aType, aParent )
{ {
unit = 0; unit = 0;
via_start_index = -1; // 0 or greater means there is at least one via
} }
~LIBRARY() ~LIBRARY()
{ {
delete unit; delete unit;
} }
void AddPadstack( PADSTACK* aPadstack )
{
padstacks.push_back( aPadstack );
}
void SetViaStartIndex( int aIndex )
{
via_start_index = aIndex;
}
int GetViaStartIndex()
{
return via_start_index;
}
int FindIMAGE( IMAGE* aImage )
{
for( unsigned i=0; i<images.size(); ++i )
{
if( 0 == IMAGE::Compare( aImage, &images[i] ) )
return (int) i;
}
return -1;
}
void AppendIMAGE( IMAGE* aImage )
{
aImage->SetParent( this );
images.push_back( aImage );
}
bool LookupIMAGE( IMAGE* aImage )
{
int ndx = FindIMAGE( aImage );
if( ndx == -1 )
{
AppendIMAGE( aImage );
return false;
}
return true;
}
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
...@@ -2039,18 +2232,13 @@ public: ...@@ -2039,18 +2232,13 @@ public:
i->Format( out, nestLevel ); i->Format( out, nestLevel );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
return ELEM::GetUnits(); return ELEM::GetUnits();
} }
void AddPadstack( PADSTACK* aPadstack )
{
padstacks.push_back( aPadstack );
}
}; };
...@@ -2422,6 +2610,8 @@ public: ...@@ -2422,6 +2610,8 @@ public:
class CONNECT : public ELEM class CONNECT : public ELEM
{ {
// @todo not completed.
public: public:
CONNECT( ELEM* parent ) : CONNECT( ELEM* parent ) :
ELEM( T_connect, parent ) {} ELEM( T_connect, parent ) {}
...@@ -2695,7 +2885,7 @@ public: ...@@ -2695,7 +2885,7 @@ public:
i->Format( out, nestLevel ); i->Format( out, nestLevel );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -2780,7 +2970,7 @@ public: ...@@ -2780,7 +2970,7 @@ public:
out->Print( nestLevel, ")\n" ); out->Print( nestLevel, ")\n" );
} }
DSN_T GetUnits() DSN_T GetUnits() const
{ {
if( unit ) if( unit )
return unit->GetUnits(); return unit->GetUnits();
...@@ -3179,6 +3369,8 @@ class SPECCTRA_DB : public OUTPUTFORMATTER ...@@ -3179,6 +3369,8 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
wxString filename; wxString filename;
std::string quote_char; std::string quote_char;
STRINGFORMATTER sf;
/** /**
...@@ -3321,6 +3513,22 @@ class SPECCTRA_DB : public OUTPUTFORMATTER ...@@ -3321,6 +3513,22 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
void doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IOError ); void doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IOError );
/**
* Function makeIMAGE
* allocates an IMAGE on the heap and creates all the PINs according
* to the PADs in the MODULE.
*/
IMAGE* makeIMAGE( MODULE* aModule );
/**
* Function makePADSTACKs
* makes all the PADSTACKs, and marks each D_PAD with the index into the
* LIBRARY::padstacks list that it matches.
*/
void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads );
public: public:
SPECCTRA_DB() SPECCTRA_DB()
...@@ -3332,7 +3540,7 @@ public: ...@@ -3332,7 +3540,7 @@ public:
quote_char += '"'; quote_char += '"';
} }
~SPECCTRA_DB() virtual ~SPECCTRA_DB()
{ {
delete lexer; delete lexer;
delete pcb; delete pcb;
......
...@@ -234,14 +234,43 @@ static QARC* makeArc( const POINT& aStart, const POINT& aEnd, ...@@ -234,14 +234,43 @@ static QARC* makeArc( const POINT& aStart, const POINT& aEnd,
qarc->SetLayerId( aLayerName.c_str() ); qarc->SetLayerId( aLayerName.c_str() );
return qarc; return qarc;
} }
/**
* Function makePADSTACKs IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
* makes all the PADSTACKs, and marks each D_PAD with the index into the {
* LIBRARY::padstacks list that it matches. TYPE_COLLECTOR items;
*/
static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibrary ) static const KICAD_T scanPADs[] = { TYPEPAD, EOT };
PADSTACKS& padstacks = pcb->library->padstacks;
// get all the MODULE's pads.
items.Collect( aModule, scanPADs );
IMAGE* image = new IMAGE( 0 );
image->image_id = CONV_TO_UTF8( aModule->m_LibRef );
// collate all the pads, and make a component.
for( int p=0; p<items.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) items[p];
PADSTACK* padstack = &padstacks[pad->m_logical_connexion];
PIN* pin = new PIN(image);
image->pins.push_back( pin );
pin->padstack_id = padstack->padstack_id;
pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
pin->SetVertex( mapPt( pad->m_Pos0 ) );
}
return image;
}
void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
{ {
char name[80]; // padstack name builder char name[80]; // padstack name builder
...@@ -251,7 +280,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -251,7 +280,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
} }
D_PAD* old_pad = NULL; D_PAD* old_pad = NULL;
int padstackNdx = 0;
#define COPPER_LAYERS 2 // top and bottom #define COPPER_LAYERS 2 // top and bottom
...@@ -262,7 +290,7 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -262,7 +290,7 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
// within a pad's padstack. this is usually correct, but not rigorous. We could do // within a pad's padstack. this is usually correct, but not rigorous. We could do
// better if there was actually a "layer type" field within Kicad which would // better if there was actually a "layer type" field within Kicad which would
// hold one of: T_signal, T_power, T_mixed, T_jumper // hold one of: T_signal, T_power, T_mixed, T_jumper
// See page bottom of page 74 of the SECCTRA Design Language Reference, May 2000. // See bottom of page 74 of the SECCTRA Design Language Reference, May 2000.
std::string layerId[COPPER_LAYERS] = { std::string layerId[COPPER_LAYERS] = {
CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )), CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )),
...@@ -270,8 +298,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -270,8 +298,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
}; };
#if 1 #if 1
// late breaking news, we can use "signal" as the layer name and report the // Late breaking news: we can use the reserved layer name "signal" and report the
// padstack as a single layer. // padstack as a single layer. See <reserved_layer_name> in the spec.
// But this probably gives problems for a "power" layer or power pin, we'll see.
reportedLayers = 1; reportedLayers = 1;
layerId[0] = "signal"; layerId[0] = "signal";
#endif #endif
...@@ -280,8 +309,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -280,8 +309,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
{ {
D_PAD* pad = (D_PAD*) aPads[i]; D_PAD* pad = (D_PAD*) aPads[i];
pad->m_logical_connexion = padstackNdx;
bool doLayer[COPPER_LAYERS] = { bool doLayer[COPPER_LAYERS] = {
pad->IsOnLayer( LAYER_CMP_N ), pad->IsOnLayer( LAYER_CMP_N ),
pad->IsOnLayer( COPPER_LAYER_N ) pad->IsOnLayer( COPPER_LAYER_N )
...@@ -289,6 +316,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -289,6 +316,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
if( old_pad && 0==D_PAD::Compare( old_pad, pad ) ) if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
{ {
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
// this is the same as the last pad, so do not add it to the padstack list.
continue; continue;
} }
...@@ -296,6 +327,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -296,6 +327,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
// an "image->keepout" later. No copper pad here, it is probably a hole. // an "image->keepout" later. No copper pad here, it is probably a hole.
if( !doLayer[0] && !doLayer[1] ) if( !doLayer[0] && !doLayer[1] )
{ {
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
continue; continue;
} }
...@@ -305,11 +339,11 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -305,11 +339,11 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
old_pad = pad; old_pad = pad;
// this is the index into the library->padstacks, be careful. PADSTACK* padstack = new PADSTACK( pcb->library );
pad->m_logical_connexion = padstackNdx++; pcb->library->AddPadstack( padstack );
PADSTACK* padstack = new PADSTACK( aLibrary ); // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
aLibrary->AddPadstack( padstack ); pad->m_logical_connexion = pcb->library->padstacks.size()-1;
// paddOfset is the offset of copper shape relative to hole position, // paddOfset is the offset of copper shape relative to hole position,
// and pad->m_Pos is hole position. All shapes must be shifted by // and pad->m_Pos is hole position. All shapes must be shifted by
...@@ -331,12 +365,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -331,12 +365,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
{ {
if( doLayer[layer] ) if( doLayer[layer] )
{ {
CIRCLE* circle;
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
circle = new CIRCLE( shape ); CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle ); shape->SetShape( circle );
circle->SetLayerId( layerId[layer].c_str() ); circle->SetLayerId( layerId[layer].c_str() );
...@@ -347,7 +379,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -347,7 +379,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
} }
snprintf( name, sizeof(name), "Round%dPad_%.6g_mil", coppers, scale(pad->m_Size.x) ); snprintf( name, sizeof(name), "Round%dPad_%.6g_mil", coppers, scale(pad->m_Size.x) );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name)-1 ] = 0;
// @todo verify that all pad names are unique, there is a chance that // @todo verify that all pad names are unique, there is a chance that
...@@ -536,9 +567,13 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -536,9 +567,13 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize; int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize ) if( defaultViaSize )
{ {
PADSTACK* padstack = new PADSTACK( aLibrary ); PADSTACK* padstack = new PADSTACK( pcb->library );
aLibrary->AddPadstack( padstack ); pcb->library->AddPadstack( padstack );
padstackNdx++; // remember this index, it is the default via
// remember this index, it is the default via and also the start of the
// vias within the padstack list. Before this index are the pads.
// At this index and later are the vias.
pcb->library->SetViaStartIndex( pcb->library->padstacks.size()-1 );
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
...@@ -560,9 +595,8 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -560,9 +595,8 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
if( viaSize == defaultViaSize ) if( viaSize == defaultViaSize )
continue; continue;
PADSTACK* padstack = new PADSTACK( aLibrary ); PADSTACK* padstack = new PADSTACK( pcb->library );
aLibrary->AddPadstack( padstack ); pcb->library->AddPadstack( padstack );
padstackNdx++; // remember this index, it is the default via
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
...@@ -575,10 +609,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra ...@@ -575,10 +609,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra
snprintf( name, sizeof(name), "Via_%.6g_mil", scale(viaSize) ); snprintf( name, sizeof(name), "Via_%.6g_mil", scale(viaSize) );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name)-1 ] = 0;
// @todo verify that all pad names are unique, there is a chance that
// D_PAD::Compare() could say two pads are different, yet they get the same
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name ); padstack->SetPadstackId( name );
} }
} }
...@@ -593,7 +623,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -593,7 +623,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
if( !pcb ) if( !pcb )
pcb = SPECCTRA_DB::MakePCB(); pcb = SPECCTRA_DB::MakePCB();
// DSN Images (=Kicad MODULES and pads) must be presented from the // DSN Images (=Kicad MODULES and pads) must be presented from the
// top view. So we temporarily flip any modules which are on the back // top view. So we temporarily flip any modules which are on the back
// side of the board to the front, and record this in the MODULE's flag field. // side of the board to the front, and record this in the MODULE's flag field.
...@@ -661,8 +690,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -661,8 +690,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
rect->layer_id = "pcb"; rect->layer_id = "pcb";
// opposite corners // opposite corners
rect->point0 = ppairs[0].p1; rect->SetCorners( ppairs[0].p1, ppairs[2].p1 );
rect->point1 = ppairs[2].p1;
boundary->rectangle = rect; boundary->rectangle = rect;
} }
...@@ -763,54 +791,60 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -763,54 +791,60 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
// but in that case they are WINDOWs within the COPPER_PLANEs. // but in that case they are WINDOWs within the COPPER_PLANEs.
//-----<build the padstack list here, no output>------------------------ //-----<build the initial padstack list>--------------------------------
{ {
static const KICAD_T scanPADs[] = { TYPEPAD, EOT };
TYPE_COLLECTOR pads; TYPE_COLLECTOR pads;
static const KICAD_T scanPADs[] = { TYPEPAD, EOT };
// get all the D_PADs into pads.
// get all the D_PADs into 'pads'.
pads.Collect( aBoard, scanPADs ); pads.Collect( aBoard, scanPADs );
makePADSTACKs( aBoard, pads, pcb->library ); makePADSTACKs( aBoard, pads );
#if 0 && defined(DEBUG) #if 0 && defined(DEBUG)
for( int p=0; p<pads.GetCount(); ++p ) for( int p=0; p<pads.GetCount(); ++p )
pads[p]->Show( 0, std::cout ); pads[p]->Show( 0, std::cout );
#endif #endif
} }
//-----<via_descriptor>-------------------------------------------------
{
// Output the vias in the padstack list here, by name
}
//-----<build the images>---------------------------------------------- //-----<build the images>----------------------------------------------
{ {
/*
static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT }; static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT };
items.Collect( aBoard, scanMODULEs ); items.Collect( aBoard, scanMODULEs );
for( int m=0; m<items.GetCount(); ++m ) for( int m=0; m<items.GetCount(); ++m )
{ {
MODULE* module = (MODULE*) items[m]; MODULE* module = (MODULE*) items[m];
// collate all the pads, and make a component. IMAGE* image = makeIMAGE( module );
for( int p=0; p<pads.GetCount(); ++p )
if( pcb->library->LookupIMAGE( image ) )
{ {
D_PAD* pad = (D_PAD*) pads[p]; delete image;
}
D(pad->Show( 0, std::cout );) }
}
// lookup and maybe add this pad to the padstack.
wxString padName = lookupPad( pcb->library->padstacks, pad );
//-----<via_descriptor>-------------------------------------------------
{
// Output the vias in the padstack list here, by name
VIA* vias = pcb->structure->via;
PADSTACKS& padstacks = pcb->library->padstacks;
int viaNdx = pcb->library->via_start_index;
if( viaNdx != -1 )
{
for( ; viaNdx < (int)padstacks.size(); ++viaNdx )
{
vias->AppendVia( padstacks[viaNdx].padstack_id.c_str() );
} }
} }
*/
} }
//-----<restore MODULEs>------------------------------------------------
// DSN Images (=Kicad MODULES and pads) must be presented from the // DSN Images (=Kicad MODULES and pads) must be presented from the
// top view. Restore those that were flipped. // top view. Restore those that were flipped.
...@@ -822,6 +856,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -822,6 +856,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
module->flag = 0; module->flag = 0;
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment