more free specctra work
This commit is contained in:
parent
22affc6750
commit
501fb2c270
|
@ -5,6 +5,14 @@ Please add newer entries at the top, list the date and your name with
|
||||||
email address.
|
email address.
|
||||||
|
|
||||||
|
|
||||||
|
2008-Jan-25 UPDATE Dick Hollenbeck <dick@softplc.com>
|
||||||
|
================================================================================
|
||||||
|
+pcbnew:
|
||||||
|
SPECCTRA export does padstacks ok, except that oval arcs need to be split
|
||||||
|
into quarter circle arcs, and no consideration is given to "layer types"
|
||||||
|
See page bottom of page 74 of the SECCTRA Design Language Reference, May 2000.
|
||||||
|
Still working today...
|
||||||
|
|
||||||
|
|
||||||
2008-Jan-25 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
|
2008-Jan-25 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
|
@ -1985,7 +1985,7 @@ void SPECCTRA_DB::doSHAPE( SHAPE* growth ) throw( IOError )
|
||||||
case T_polygon:
|
case T_polygon:
|
||||||
case T_qarc:
|
case T_qarc:
|
||||||
L_done_that:
|
L_done_that:
|
||||||
if( growth->Length() )
|
if( growth->shape )
|
||||||
unexpected( tok );
|
unexpected( tok );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2000,32 +2000,24 @@ L_done_that:
|
||||||
switch( tok )
|
switch( tok )
|
||||||
{
|
{
|
||||||
case T_rect:
|
case T_rect:
|
||||||
RECTANGLE* rectangle;
|
growth->shape = new RECTANGLE( growth );
|
||||||
rectangle = new RECTANGLE( growth );
|
doRECTANGLE( (RECTANGLE*) growth->shape );
|
||||||
growth->Append( rectangle );
|
|
||||||
doRECTANGLE( rectangle );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_circle:
|
case T_circle:
|
||||||
CIRCLE* circle;
|
growth->shape = new CIRCLE( growth );
|
||||||
circle = new CIRCLE( growth );
|
doCIRCLE( (CIRCLE*)growth->shape );
|
||||||
growth->Append( circle );
|
|
||||||
doCIRCLE( circle );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_path:
|
case T_path:
|
||||||
case T_polygon:
|
case T_polygon:
|
||||||
PATH* path;
|
growth->shape = new PATH( growth, tok );
|
||||||
path = new PATH( growth, tok );
|
doPATH( (PATH*)growth->shape );
|
||||||
growth->Append( path );
|
|
||||||
doPATH( path );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_qarc:
|
case T_qarc:
|
||||||
QARC* qarc;
|
growth->shape = new QARC( growth );
|
||||||
qarc = new QARC( growth );
|
doQARC( (QARC*)growth->shape );
|
||||||
growth->Append( qarc );
|
|
||||||
doQARC( qarc );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_connect:
|
case T_connect:
|
||||||
|
|
|
@ -126,6 +126,25 @@ struct POINT
|
||||||
return !( *this == other );
|
return !( *this == other );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POINT& operator+=( const POINT& other )
|
||||||
|
{
|
||||||
|
x += other.x;
|
||||||
|
y += other.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT& operator=( const POINT& other )
|
||||||
|
{
|
||||||
|
x = other.x;
|
||||||
|
if( x == -0.0 ) // correct -0.0 so output looks nice.
|
||||||
|
x = 0.0;
|
||||||
|
y = other.y;
|
||||||
|
if( y == -0.0 )
|
||||||
|
y = 0.0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Format
|
* Function Format
|
||||||
* writes this object as ASCII out to an OUTPUTFORMATTER according to the
|
* writes this object as ASCII out to an OUTPUTFORMATTER according to the
|
||||||
|
@ -425,13 +444,16 @@ public:
|
||||||
|
|
||||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||||
{
|
{
|
||||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
const char* newline = nestLevel ? "\n" : "";
|
||||||
|
|
||||||
out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g %.6g)\n",
|
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||||
|
|
||||||
|
out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g %.6g)%s",
|
||||||
LEXER::GetTokenText( Type() ),
|
LEXER::GetTokenText( Type() ),
|
||||||
quote, layer_id.c_str(), quote,
|
quote, layer_id.c_str(), quote,
|
||||||
point0.x, point0.y,
|
point0.x, point0.y,
|
||||||
point1.x, point1.y );
|
point1.x, point1.y,
|
||||||
|
newline );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -587,12 +609,20 @@ public:
|
||||||
aperture_type = T_round;
|
aperture_type = T_round;
|
||||||
}
|
}
|
||||||
|
|
||||||
~PATH()
|
void AppendPoint( const POINT& aPoint )
|
||||||
{
|
{
|
||||||
|
points.push_back( aPoint );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLayerId( const char* aLayerId )
|
||||||
|
{
|
||||||
|
layer_id = aLayerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||||
{
|
{
|
||||||
|
const char* newline = nestLevel ? "\n" : "";
|
||||||
|
|
||||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||||
|
|
||||||
const int RIGHTMARGIN = 80;
|
const int RIGHTMARGIN = 80;
|
||||||
|
@ -607,6 +637,7 @@ public:
|
||||||
{
|
{
|
||||||
out->Print( 0, "\n" );
|
out->Print( 0, "\n" );
|
||||||
perLine = out->Print( nestLevel+1, "%s", "" );
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
||||||
|
newline = "\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
perLine += out->Print( 0, " " );
|
perLine += out->Print( 0, " " );
|
||||||
|
@ -617,10 +648,10 @@ public:
|
||||||
if( aperture_type == T_square )
|
if( aperture_type == T_square )
|
||||||
{
|
{
|
||||||
out->Print( 0, "\n" );
|
out->Print( 0, "\n" );
|
||||||
out->Print( nestLevel+1, "(aperture_type square)\n" );
|
out->Print( nestLevel+1, "(aperture_type square))\n" );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
out->Print( 0, ")\n" );
|
out->Print( 0, ")%s", newline );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef boost::ptr_vector<PATH> PATHS;
|
typedef boost::ptr_vector<PATH> PATHS;
|
||||||
|
@ -672,7 +703,7 @@ class CIRCLE : public ELEM
|
||||||
std::string layer_id;
|
std::string layer_id;
|
||||||
|
|
||||||
double diameter;
|
double diameter;
|
||||||
POINT vertex;
|
POINT vertex; // POINT's constructor sets to (0,0)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CIRCLE( ELEM* aParent ) :
|
CIRCLE( ELEM* aParent ) :
|
||||||
|
@ -683,10 +714,17 @@ public:
|
||||||
|
|
||||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||||
{
|
{
|
||||||
|
const char* newline = nestLevel ? "\n" : "";
|
||||||
|
|
||||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||||
out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g)\n", LEXER::GetTokenText( Type() ) ,
|
out->Print( nestLevel, "(%s %s%s%s %.6g", LEXER::GetTokenText( Type() ),
|
||||||
quote, layer_id.c_str(), quote,
|
quote, layer_id.c_str(), quote,
|
||||||
diameter, vertex.x, vertex.y );
|
diameter );
|
||||||
|
|
||||||
|
if( vertex.x!=0.0 || vertex.y!=0.0 )
|
||||||
|
out->Print( 0, " %.6g %.6g)%s", vertex.x, vertex.y, newline );
|
||||||
|
else
|
||||||
|
out->Print( 0, ")%s", newline );
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLayerId( const char* aLayerId )
|
void SetLayerId( const char* aLayerId )
|
||||||
|
@ -698,6 +736,11 @@ public:
|
||||||
{
|
{
|
||||||
diameter = aDiameter;
|
diameter = aDiameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetVertex( const POINT& aVertex )
|
||||||
|
{
|
||||||
|
vertex = aVertex;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,15 +761,34 @@ public:
|
||||||
|
|
||||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||||
{
|
{
|
||||||
|
const char* newline = nestLevel ? "\n" : "";
|
||||||
|
|
||||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||||
out->Print( nestLevel, "(%s %s%s%s %.6g\n", LEXER::GetTokenText( Type() ) ,
|
out->Print( nestLevel, "(%s %s%s%s %.6g", LEXER::GetTokenText( Type() ) ,
|
||||||
quote, layer_id.c_str(), quote,
|
quote, layer_id.c_str(), quote,
|
||||||
aperture_width);
|
aperture_width);
|
||||||
|
|
||||||
for( int i=0; i<3; ++i )
|
for( int i=0; i<3; ++i )
|
||||||
out->Print( nestLevel+1, "%.6g %.6g\n", vertex[i].x, vertex[i].y );
|
out->Print( 0, " %.6g %.6g", vertex[i].x, vertex[i].y );
|
||||||
|
|
||||||
out->Print( nestLevel, ")\n" );
|
out->Print( 0, ")%s", newline );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLayerId( const char* aLayerId )
|
||||||
|
{
|
||||||
|
layer_id = aLayerId;
|
||||||
|
}
|
||||||
|
void SetStart( const POINT& aStart )
|
||||||
|
{
|
||||||
|
vertex[0] = aStart;
|
||||||
|
}
|
||||||
|
void SetEnd( const POINT& aEnd )
|
||||||
|
{
|
||||||
|
vertex[1] = aEnd;
|
||||||
|
}
|
||||||
|
void SetCenter( const POINT& aCenter )
|
||||||
|
{
|
||||||
|
vertex[2] = aCenter;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1641,40 +1703,85 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SHAPE : public ELEM_HOLDER
|
/**
|
||||||
|
* Class SHAPE
|
||||||
|
* corresponds to the "(shape ..)" element in the specctra dsn spec.
|
||||||
|
* It is not a <shape_descriptor> which is one of things that this
|
||||||
|
* elements contains, i.e. in its "shape" field. This class also implements
|
||||||
|
* the "(outline ...)" element as a dual personality.
|
||||||
|
*/
|
||||||
|
class SHAPE : public ELEM
|
||||||
{
|
{
|
||||||
friend class SPECCTRA_DB;
|
friend class SPECCTRA_DB;
|
||||||
|
|
||||||
DSN_T connect;
|
DSN_T connect;
|
||||||
|
|
||||||
/*----- only one of these is used, like a union -----
|
/* <shape_descriptor >::=
|
||||||
single item, but now in the kids list
|
[<rectangle_descriptor> |
|
||||||
|
<circle_descriptor> |
|
||||||
PATH* path; ///< used for both path and polygon
|
<polygon_descriptor> |
|
||||||
RECTANGLE* rectangle;
|
<path_descriptor> |
|
||||||
CIRCLE* circle;
|
<qarc_descriptor> ]
|
||||||
QARC* qarc;
|
*/
|
||||||
//--------------------------------------------------- */
|
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_HOLDER( aType, aParent )
|
ELEM( aType, aParent )
|
||||||
{
|
{
|
||||||
connect = T_on;
|
connect = T_on;
|
||||||
|
shape = 0;
|
||||||
|
}
|
||||||
|
~SHAPE()
|
||||||
|
{
|
||||||
|
delete shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
|
||||||
|
void SetShape( ELEM* aShape )
|
||||||
{
|
{
|
||||||
ELEM_HOLDER::FormatContents( out, nestLevel );
|
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 )
|
||||||
|
{
|
||||||
|
connect = aConnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||||
|
{
|
||||||
|
out->Print( nestLevel, "(%s ", LEXER::GetTokenText( Type() ) );
|
||||||
|
|
||||||
|
if( shape )
|
||||||
|
shape->Format( out, 0 );
|
||||||
|
|
||||||
if( connect == T_off )
|
if( connect == T_off )
|
||||||
out->Print( nestLevel, "(connect %s)\n", LEXER::GetTokenText( connect ) );
|
out->Print( 0, "(connect %s)", LEXER::GetTokenText( connect ) );
|
||||||
|
|
||||||
for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i )
|
if( windows.size() )
|
||||||
i->Format( out, nestLevel );
|
{
|
||||||
|
out->Print( 0, "\n" );
|
||||||
|
|
||||||
|
for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i )
|
||||||
|
i->Format( out, nestLevel+1 );
|
||||||
|
|
||||||
|
out->Print( nestLevel, ")\n" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out->Print( 0, ")\n" );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3324,10 +3431,8 @@ public:
|
||||||
* of class WinEDA_BasePcbFrame rather than class BOARD.
|
* of class WinEDA_BasePcbFrame rather than class BOARD.
|
||||||
*
|
*
|
||||||
* @param aBoard The BOARD to convert to a PCB.
|
* @param aBoard The BOARD to convert to a PCB.
|
||||||
* @throw IOError, if the BOARD cannot be converted, and the text of the
|
|
||||||
* exception tells the error message.
|
|
||||||
*/
|
*/
|
||||||
void FromBOARD( BOARD* aBoard ) throw( IOError );
|
void FromBOARD( BOARD* aBoard );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -67,20 +67,6 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
|
||||||
|
|
||||||
db.SetPCB( SPECCTRA_DB::MakePCB() );
|
db.SetPCB( SPECCTRA_DB::MakePCB() );
|
||||||
|
|
||||||
|
|
||||||
// DSN Images (=Kicad MODULES and pads) must be presented from the
|
|
||||||
// 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.
|
|
||||||
for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
module->flag = 0;
|
|
||||||
if( module->GetLayer() == COPPER_LAYER_N )
|
|
||||||
{
|
|
||||||
m_Pcb->Change_Side_Module( module, NULL );
|
|
||||||
module->flag = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
db.FromBOARD( m_Pcb );
|
db.FromBOARD( m_Pcb );
|
||||||
|
@ -97,17 +83,6 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
|
||||||
errorText = ioe.errorText;
|
errorText = ioe.errorText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DSN Images (=Kicad MODULES and pads) must be presented from the
|
|
||||||
// top view. Restore those that were flipped.
|
|
||||||
for( MODULE* module = m_Pcb->m_Modules; module; module = module->Next() )
|
|
||||||
{
|
|
||||||
if( module->flag )
|
|
||||||
{
|
|
||||||
m_Pcb->Change_Side_Module( module, NULL );
|
|
||||||
module->flag = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ok )
|
if( ok )
|
||||||
{
|
{
|
||||||
// @todo display a message saying the export is complete.
|
// @todo display a message saying the export is complete.
|
||||||
|
@ -232,6 +207,34 @@ static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function makePath
|
||||||
|
* creates a PATH element with a single straight line, a pair of vertices.
|
||||||
|
*/
|
||||||
|
static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName )
|
||||||
|
{
|
||||||
|
PATH* path = new PATH( 0, T_path );
|
||||||
|
|
||||||
|
path->AppendPoint( aStart );
|
||||||
|
path->AppendPoint( aEnd );
|
||||||
|
path->SetLayerId( aLayerName.c_str() );
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static QARC* makeArc( const POINT& aStart, const POINT& aEnd,
|
||||||
|
const POINT& aCenter, const std::string& aLayerName )
|
||||||
|
{
|
||||||
|
QARC* qarc = new QARC(0);
|
||||||
|
|
||||||
|
qarc->SetStart( aStart );
|
||||||
|
qarc->SetEnd( aEnd );
|
||||||
|
qarc->SetCenter( aCenter );
|
||||||
|
qarc->SetLayerId( aLayerName.c_str() );
|
||||||
|
return qarc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function makePADSTACKs
|
* Function makePADSTACKs
|
||||||
* makes all the PADSTACKs, and marks each D_PAD with the index into the
|
* makes all the PADSTACKs, and marks each D_PAD with the index into the
|
||||||
|
@ -248,6 +251,18 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
||||||
D_PAD* old_pad = NULL;
|
D_PAD* old_pad = NULL;
|
||||||
int padstackNdx = 0;
|
int padstackNdx = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// for now, report on only the top and bottom layers with respect to the copper
|
||||||
|
// within a padstack. this is usually correct, but not rigorous. We could do
|
||||||
|
// better if there was actually a "layer type" field within Kicad which would
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
std::string layerId[2] = {
|
||||||
|
CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )),
|
||||||
|
CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )),
|
||||||
|
};
|
||||||
|
|
||||||
for( int i=0; i<aPads.GetCount(); ++i )
|
for( int i=0; i<aPads.GetCount(); ++i )
|
||||||
{
|
{
|
||||||
D_PAD* pad = (D_PAD*) aPads[i];
|
D_PAD* pad = (D_PAD*) aPads[i];
|
||||||
|
@ -265,39 +280,51 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
||||||
pad->m_logical_connexion = padstackNdx++;
|
pad->m_logical_connexion = padstackNdx++;
|
||||||
|
|
||||||
PADSTACK* padstack = new PADSTACK( aLibrary );
|
PADSTACK* padstack = new PADSTACK( aLibrary );
|
||||||
SHAPE* shape = new SHAPE( padstack );
|
aLibrary->AddPadstack( padstack );
|
||||||
padstack->Append( shape );
|
|
||||||
|
// paddOfset is the offset of copper shape relative to hole position,
|
||||||
|
// and pad->m_Pos is hole position. All shapes must be shifted by
|
||||||
|
// this distance, normally (0,0).
|
||||||
|
|
||||||
|
// Note that the y correction here is set negative.
|
||||||
|
POINT padOffset( scale(pad->m_Offset.x), -scale(pad->m_Offset.y) );
|
||||||
|
|
||||||
|
bool doLayer[2] = {
|
||||||
|
pad->IsOnLayer( LAYER_CMP_N ),
|
||||||
|
pad->IsOnLayer( COPPER_LAYER_N )
|
||||||
|
};
|
||||||
|
|
||||||
|
int coppers = 0;
|
||||||
|
|
||||||
switch( pad->m_PadShape )
|
switch( pad->m_PadShape )
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case PAD_CIRCLE:
|
case PAD_CIRCLE:
|
||||||
{
|
{
|
||||||
CIRCLE* circle;
|
|
||||||
double diameter = scale(pad->m_Size.x);
|
double diameter = scale(pad->m_Size.x);
|
||||||
int coppers = 0;
|
|
||||||
|
|
||||||
if( pad->IsOnLayer( COPPER_LAYER_N ) )
|
for( int layer=0; layer<2; ++layer )
|
||||||
{
|
{
|
||||||
circle = new CIRCLE( shape );
|
if( doLayer[i] )
|
||||||
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) );
|
{
|
||||||
circle->SetDiameter( diameter );
|
CIRCLE* circle;
|
||||||
shape->Append( circle );
|
SHAPE* shape = new SHAPE( padstack );
|
||||||
++coppers;
|
|
||||||
|
padstack->Append( shape );
|
||||||
|
|
||||||
|
circle = new CIRCLE( shape );
|
||||||
|
shape->SetShape( circle );
|
||||||
|
|
||||||
|
circle->SetLayerId( layerId[layer].c_str() );
|
||||||
|
circle->SetDiameter( diameter );
|
||||||
|
circle->SetVertex( padOffset );
|
||||||
|
++coppers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pad->IsOnLayer( LAYER_CMP_N ) )
|
char name[80];
|
||||||
{
|
|
||||||
circle = new CIRCLE( shape );
|
|
||||||
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )) );
|
|
||||||
circle->SetDiameter( diameter );
|
|
||||||
shape->Append( circle );
|
|
||||||
++coppers;
|
|
||||||
}
|
|
||||||
|
|
||||||
char name[50];
|
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;
|
||||||
|
|
||||||
|
@ -306,8 +333,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
||||||
// name here. If so, blend in the padNdx into the name.
|
// name here. If so, blend in the padNdx into the name.
|
||||||
|
|
||||||
padstack->SetPadstackId( name );
|
padstack->SetPadstackId( name );
|
||||||
|
|
||||||
aLibrary->AddPadstack( padstack );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -316,28 +341,29 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
||||||
double dx = scale( pad->m_Size.x ) / 2.0;
|
double dx = scale( pad->m_Size.x ) / 2.0;
|
||||||
double dy = scale( pad->m_Size.y ) / 2.0;
|
double dy = scale( pad->m_Size.y ) / 2.0;
|
||||||
|
|
||||||
RECTANGLE* rect;
|
POINT lowerLeft( -dx, -dy );
|
||||||
int coppers = 0;
|
POINT upperRight( dx, dy );
|
||||||
|
|
||||||
if( pad->IsOnLayer( COPPER_LAYER_N ) )
|
lowerLeft += padOffset;
|
||||||
|
upperRight += padOffset;
|
||||||
|
|
||||||
|
for( int layer=0; layer<2; ++layer )
|
||||||
{
|
{
|
||||||
rect = new RECTANGLE( shape );
|
if( doLayer[i] )
|
||||||
rect->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) );
|
{
|
||||||
rect->SetCorners( POINT(-dx,-dy), POINT(dx,dy) );
|
SHAPE* shape = new SHAPE( padstack );
|
||||||
shape->Append( rect );
|
padstack->Append( shape );
|
||||||
++coppers;
|
|
||||||
|
RECTANGLE* rect = new RECTANGLE( shape );
|
||||||
|
shape->SetShape( rect );
|
||||||
|
|
||||||
|
rect->SetLayerId( layerId[layer].c_str() );
|
||||||
|
rect->SetCorners( lowerLeft, upperRight );
|
||||||
|
++coppers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pad->IsOnLayer( LAYER_CMP_N ) )
|
char name[80];
|
||||||
{
|
|
||||||
rect = new RECTANGLE( shape );
|
|
||||||
rect->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )) );
|
|
||||||
rect->SetCorners( POINT(-dx,-dy), POINT(dx,dy) );
|
|
||||||
shape->Append( rect );
|
|
||||||
++coppers;
|
|
||||||
}
|
|
||||||
|
|
||||||
char name[50];
|
|
||||||
|
|
||||||
snprintf( name, sizeof(name), "Rect%dPad_%.6gx%.6g_mil",
|
snprintf( name, sizeof(name), "Rect%dPad_%.6gx%.6g_mil",
|
||||||
coppers, scale(pad->m_Size.x), scale(pad->m_Size.y) );
|
coppers, scale(pad->m_Size.x), scale(pad->m_Size.y) );
|
||||||
|
@ -345,79 +371,145 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
||||||
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
|
||||||
// D_PAD::Compare() could say two pads are different, yet the get the same
|
// 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.
|
// name here. If so, blend in the padNdx into the name.
|
||||||
|
|
||||||
padstack->SetPadstackId( name );
|
padstack->SetPadstackId( name );
|
||||||
|
|
||||||
aLibrary->AddPadstack( padstack );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
pad_type = "RECTANGULAR";
|
|
||||||
fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
|
|
||||||
fprintf( file, "RECTANGLE %d %d %d %d\n",
|
|
||||||
-dx + pad->m_Offset.x, -dy - pad->m_Offset.y,
|
|
||||||
dx + pad->m_Offset.x, -pad->m_Offset.y + dy );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAD_OVAL: /* description du contour par 2 linges et 2 arcs */
|
case PAD_OVAL:
|
||||||
{
|
|
||||||
pad_type = "FINGER";
|
|
||||||
fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
|
|
||||||
int dr = dx - dy;
|
|
||||||
if( dr >= 0 ) // ovale horizontal
|
|
||||||
{
|
{
|
||||||
int rayon = dy;
|
double dx = scale( pad->m_Size.x ) / 2.0;
|
||||||
fprintf( file, "LINE %d %d %d %d\n",
|
double dy = scale( pad->m_Size.y ) / 2.0;
|
||||||
-dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
|
double dr = dx - dy;
|
||||||
dr + pad->m_Offset.x, -pad->m_Offset.y - rayon );
|
|
||||||
fprintf( file, "ARC %d %d %d %d %d %d\n",
|
|
||||||
dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
|
|
||||||
dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
|
|
||||||
dr + pad->m_Offset.x, -pad->m_Offset.y );
|
|
||||||
|
|
||||||
fprintf( file, "LINE %d %d %d %d\n",
|
if( dr >= 0 ) // oval is horizontal
|
||||||
dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
|
{
|
||||||
-dr + pad->m_Offset.x, -pad->m_Offset.y + rayon );
|
double radius = dy;
|
||||||
fprintf( file, "ARC %d %d %d %d %d %d\n",
|
|
||||||
-dr + pad->m_Offset.x, -pad->m_Offset.y + rayon,
|
|
||||||
-dr + pad->m_Offset.x, -pad->m_Offset.y - rayon,
|
|
||||||
-dr + pad->m_Offset.x, -pad->m_Offset.y );
|
|
||||||
}
|
|
||||||
else // ovale vertical
|
|
||||||
{
|
|
||||||
dr = -dr;
|
|
||||||
int rayon = dx;
|
|
||||||
fprintf( file, "LINE %d %d %d %d\n",
|
|
||||||
-rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
|
|
||||||
-rayon + pad->m_Offset.x, -pad->m_Offset.y + dr );
|
|
||||||
fprintf( file, "ARC %d %d %d %d %d %d\n",
|
|
||||||
-rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
|
|
||||||
rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
|
|
||||||
pad->m_Offset.x, -pad->m_Offset.y + dr );
|
|
||||||
|
|
||||||
fprintf( file, "LINE %d %d %d %d\n",
|
for( int layer=0; layer<2; ++layer )
|
||||||
rayon + pad->m_Offset.x, -pad->m_Offset.y + dr,
|
{
|
||||||
rayon + pad->m_Offset.x, -pad->m_Offset.y - dr );
|
// each oval is 2 lines and 4 (quarter circle) qarcs
|
||||||
fprintf( file, "ARC %d %d %d %d %d %d\n",
|
|
||||||
rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
|
SHAPE* shape;
|
||||||
-rayon + pad->m_Offset.x, -pad->m_Offset.y - dr,
|
PATH* path;
|
||||||
pad->m_Offset.x, -pad->m_Offset.y - dr );
|
QARC* qarc;
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
path = makePath(
|
||||||
|
POINT( -dr + padOffset.x, padOffset.y - radius ), // aStart
|
||||||
|
POINT( dr + padOffset.x, padOffset.y - radius ), // aEnd
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( path );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
|
||||||
|
qarc = makeArc(
|
||||||
|
POINT( dr + padOffset.x, padOffset.y - radius), // aStart
|
||||||
|
POINT( dr + padOffset.x, padOffset.y + radius), // aEnd
|
||||||
|
POINT( dr + padOffset.x, padOffset.y ), // aCenter
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( qarc );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
path = makePath(
|
||||||
|
POINT( dr + padOffset.x, padOffset.y + radius ), // aStart
|
||||||
|
POINT( -dr + padOffset.x, padOffset.y + radius ), // aEnd
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( path );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
|
||||||
|
qarc = makeArc(
|
||||||
|
POINT( -dr + padOffset.x, padOffset.y + radius), // aStart
|
||||||
|
POINT( -dr + padOffset.x, padOffset.y - radius), // aEnd
|
||||||
|
POINT( -dr + padOffset.x, padOffset.y ), // aCenter
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( qarc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // oval is vertical
|
||||||
|
{
|
||||||
|
double radius = dx;
|
||||||
|
|
||||||
|
dr = -dr;
|
||||||
|
|
||||||
|
for( int layer=0; layer<2; ++layer )
|
||||||
|
{
|
||||||
|
// each oval is 2 lines and 2 qarcs
|
||||||
|
|
||||||
|
SHAPE* shape;
|
||||||
|
PATH* path;
|
||||||
|
QARC* qarc;
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
path = makePath(
|
||||||
|
POINT( -radius + padOffset.x, padOffset.y - dr ), // aStart
|
||||||
|
POINT( -radius + padOffset.x, padOffset.y + dr ), // aEnd
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( path );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
|
||||||
|
qarc = makeArc(
|
||||||
|
POINT( -radius + padOffset.x, padOffset.y + dr ), // aStart
|
||||||
|
POINT( radius + padOffset.x, padOffset.y + dr), // aEnd
|
||||||
|
POINT( padOffset.x, padOffset.y +dr ), // aCenter
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( qarc );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
path = makePath(
|
||||||
|
POINT( radius + padOffset.x, padOffset.y + dr ), // aStart
|
||||||
|
POINT( radius + padOffset.x, padOffset.y - dr ), // aEnd
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( path );
|
||||||
|
|
||||||
|
shape = new SHAPE( padstack );
|
||||||
|
padstack->Append( shape );
|
||||||
|
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
|
||||||
|
qarc = makeArc(
|
||||||
|
POINT( radius + padOffset.x, padOffset.y - dr), // aStart
|
||||||
|
POINT( -radius + padOffset.x, padOffset.y - dr), // aEnd
|
||||||
|
POINT( padOffset.x, padOffset.y - dr ), // aCenter
|
||||||
|
layerId[layer] );
|
||||||
|
shape->SetShape( qarc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[80];
|
||||||
|
|
||||||
|
snprintf( name, sizeof(name), "Oval%dPad_%.6gx%.6g_mil",
|
||||||
|
coppers, scale(pad->m_Size.x), scale(pad->m_Size.y) );
|
||||||
|
|
||||||
|
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 );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
case PAD_TRAPEZOID:
|
case PAD_TRAPEZOID:
|
||||||
pad_type = "POLYGON";
|
|
||||||
break;
|
break;
|
||||||
#endif
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
||||||
{
|
{
|
||||||
TYPE_COLLECTOR items;
|
TYPE_COLLECTOR items;
|
||||||
POINT_PAIRS ppairs;
|
POINT_PAIRS ppairs;
|
||||||
|
@ -426,6 +518,21 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||||
if( !pcb )
|
if( !pcb )
|
||||||
pcb = SPECCTRA_DB::MakePCB();
|
pcb = SPECCTRA_DB::MakePCB();
|
||||||
|
|
||||||
|
|
||||||
|
// DSN Images (=Kicad MODULES and pads) must be presented from the
|
||||||
|
// 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.
|
||||||
|
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
module->flag = 0;
|
||||||
|
if( module->GetLayer() == COPPER_LAYER_N )
|
||||||
|
{
|
||||||
|
aBoard->Change_Side_Module( module, NULL );
|
||||||
|
module->flag = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----<unit_descriptor> & <resolution_descriptor>--------------------
|
//-----<unit_descriptor> & <resolution_descriptor>--------------------
|
||||||
{
|
{
|
||||||
pcb->unit->units = T_mil;
|
pcb->unit->units = T_mil;
|
||||||
|
@ -463,7 +570,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||||
{
|
{
|
||||||
swapEnds( ppairs );
|
swapEnds( ppairs );
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if 0 && defined(DEBUG)
|
||||||
for( unsigned i=0; i<ppairs.size(); ++i )
|
for( unsigned i=0; i<ppairs.size(); ++i )
|
||||||
{
|
{
|
||||||
POINT_PAIR* p = &ppairs[i];
|
POINT_PAIR* p = &ppairs[i];
|
||||||
|
@ -539,7 +646,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||||
|
|
||||||
layer->name = CONV_TO_UTF8( layerName );
|
layer->name = CONV_TO_UTF8( layerName );
|
||||||
|
|
||||||
// layer->type =
|
// layer->type = @todo need this, the export would be better.
|
||||||
|
|
||||||
pcb->structure->layers.push_back( layer );
|
pcb->structure->layers.push_back( layer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,9 +697,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||||
// 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, pcb->library->padstacks );
|
makePADSTACKs( aBoard, pads, pcb->library, pcb->library->padstacks );
|
||||||
|
|
||||||
#if 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
|
||||||
|
@ -626,6 +735,16 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DSN Images (=Kicad MODULES and pads) must be presented from the
|
||||||
|
// top view. Restore those that were flipped.
|
||||||
|
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
|
||||||
|
{
|
||||||
|
if( module->flag )
|
||||||
|
{
|
||||||
|
aBoard->Change_Side_Module( module, NULL );
|
||||||
|
module->flag = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue