more free specctra work

This commit is contained in:
dickelbeck 2008-01-25 22:03:36 +00:00
parent 22affc6750
commit 501fb2c270
4 changed files with 405 additions and 181 deletions

View File

@ -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>
================================================================================ ================================================================================

View File

@ -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:

View File

@ -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* 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 %.6g)\n", 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 &lt;shape_descriptor&gt; 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 ) );
if( windows.size() )
{
out->Print( 0, "\n" );
for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i ) for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i )
i->Format( out, nestLevel ); 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 );
/** /**

View File

@ -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,37 +280,49 @@ 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 )
{ {
if( doLayer[i] )
{
CIRCLE* circle;
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
circle = new CIRCLE( shape ); circle = new CIRCLE( shape );
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) ); shape->SetShape( circle );
circle->SetLayerId( layerId[layer].c_str() );
circle->SetDiameter( diameter ); circle->SetDiameter( diameter );
shape->Append( circle ); circle->SetVertex( padOffset );
++coppers; ++coppers;
} }
if( pad->IsOnLayer( LAYER_CMP_N ) )
{
circle = new CIRCLE( shape );
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )) );
circle->SetDiameter( diameter );
shape->Append( circle );
++coppers;
} }
char name[50]; char name[80];
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) );
@ -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 );
RECTANGLE* rect = new RECTANGLE( shape );
shape->SetShape( rect );
rect->SetLayerId( layerId[layer].c_str() );
rect->SetCorners( lowerLeft, upperRight );
++coppers; ++coppers;
} }
if( pad->IsOnLayer( LAYER_CMP_N ) )
{
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]; char name[80];
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"; double dx = scale( pad->m_Size.x ) / 2.0;
fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x ); double dy = scale( pad->m_Size.y ) / 2.0;
int dr = dx - dy; double dr = dx - dy;
if( dr >= 0 ) // ovale horizontal
{
int rayon = dy;
fprintf( file, "LINE %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 );
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, for( int layer=0; layer<2; ++layer )
-dr + pad->m_Offset.x, -pad->m_Offset.y - rayon, {
-dr + pad->m_Offset.x, -pad->m_Offset.y ); // each oval is 2 lines and 4 (quarter circle) qarcs
SHAPE* shape;
PATH* path;
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 // ovale vertical }
else // oval is vertical
{ {
double radius = dx;
dr = -dr; 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 2 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( -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;
}
}
} }