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.
|
||||
|
||||
|
||||
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>
|
||||
================================================================================
|
||||
|
|
|
@ -1985,7 +1985,7 @@ void SPECCTRA_DB::doSHAPE( SHAPE* growth ) throw( IOError )
|
|||
case T_polygon:
|
||||
case T_qarc:
|
||||
L_done_that:
|
||||
if( growth->Length() )
|
||||
if( growth->shape )
|
||||
unexpected( tok );
|
||||
break;
|
||||
default:
|
||||
|
@ -2000,32 +2000,24 @@ L_done_that:
|
|||
switch( tok )
|
||||
{
|
||||
case T_rect:
|
||||
RECTANGLE* rectangle;
|
||||
rectangle = new RECTANGLE( growth );
|
||||
growth->Append( rectangle );
|
||||
doRECTANGLE( rectangle );
|
||||
growth->shape = new RECTANGLE( growth );
|
||||
doRECTANGLE( (RECTANGLE*) growth->shape );
|
||||
break;
|
||||
|
||||
case T_circle:
|
||||
CIRCLE* circle;
|
||||
circle = new CIRCLE( growth );
|
||||
growth->Append( circle );
|
||||
doCIRCLE( circle );
|
||||
growth->shape = new CIRCLE( growth );
|
||||
doCIRCLE( (CIRCLE*)growth->shape );
|
||||
break;
|
||||
|
||||
case T_path:
|
||||
case T_polygon:
|
||||
PATH* path;
|
||||
path = new PATH( growth, tok );
|
||||
growth->Append( path );
|
||||
doPATH( path );
|
||||
growth->shape = new PATH( growth, tok );
|
||||
doPATH( (PATH*)growth->shape );
|
||||
break;
|
||||
|
||||
case T_qarc:
|
||||
QARC* qarc;
|
||||
qarc = new QARC( growth );
|
||||
growth->Append( qarc );
|
||||
doQARC( qarc );
|
||||
growth->shape = new QARC( growth );
|
||||
doQARC( (QARC*)growth->shape );
|
||||
break;
|
||||
|
||||
case T_connect:
|
||||
|
|
|
@ -126,6 +126,25 @@ struct POINT
|
|||
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
|
||||
* 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 )
|
||||
{
|
||||
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() ),
|
||||
quote, layer_id.c_str(), quote,
|
||||
point0.x, point0.y,
|
||||
point1.x, point1.y );
|
||||
point1.x, point1.y,
|
||||
newline );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -587,12 +609,20 @@ public:
|
|||
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 )
|
||||
{
|
||||
const char* newline = nestLevel ? "\n" : "";
|
||||
|
||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||
|
||||
const int RIGHTMARGIN = 80;
|
||||
|
@ -607,6 +637,7 @@ public:
|
|||
{
|
||||
out->Print( 0, "\n" );
|
||||
perLine = out->Print( nestLevel+1, "%s", "" );
|
||||
newline = "\n";
|
||||
}
|
||||
else
|
||||
perLine += out->Print( 0, " " );
|
||||
|
@ -617,10 +648,10 @@ public:
|
|||
if( aperture_type == T_square )
|
||||
{
|
||||
out->Print( 0, "\n" );
|
||||
out->Print( nestLevel+1, "(aperture_type square)\n" );
|
||||
out->Print( nestLevel+1, "(aperture_type square))\n" );
|
||||
}
|
||||
|
||||
out->Print( 0, ")\n" );
|
||||
else
|
||||
out->Print( 0, ")%s", newline );
|
||||
}
|
||||
};
|
||||
typedef boost::ptr_vector<PATH> PATHS;
|
||||
|
@ -672,7 +703,7 @@ class CIRCLE : public ELEM
|
|||
std::string layer_id;
|
||||
|
||||
double diameter;
|
||||
POINT vertex;
|
||||
POINT vertex; // POINT's constructor sets to (0,0)
|
||||
|
||||
public:
|
||||
CIRCLE( ELEM* aParent ) :
|
||||
|
@ -683,10 +714,17 @@ public:
|
|||
|
||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||
{
|
||||
const char* newline = nestLevel ? "\n" : "";
|
||||
|
||||
const char* quote = out->GetQuoteChar( layer_id.c_str() );
|
||||
out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g)\n", LEXER::GetTokenText( Type() ) ,
|
||||
quote, layer_id.c_str(), quote,
|
||||
diameter, vertex.x, vertex.y );
|
||||
out->Print( nestLevel, "(%s %s%s%s %.6g", LEXER::GetTokenText( Type() ),
|
||||
quote, layer_id.c_str(), quote,
|
||||
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 )
|
||||
|
@ -698,6 +736,11 @@ public:
|
|||
{
|
||||
diameter = aDiameter;
|
||||
}
|
||||
|
||||
void SetVertex( const POINT& aVertex )
|
||||
{
|
||||
vertex = aVertex;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -718,15 +761,34 @@ public:
|
|||
|
||||
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||
{
|
||||
const char* newline = nestLevel ? "\n" : "";
|
||||
|
||||
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,
|
||||
aperture_width);
|
||||
|
||||
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;
|
||||
|
||||
DSN_T connect;
|
||||
|
||||
/*----- only one of these is used, like a union -----
|
||||
single item, but now in the kids list
|
||||
|
||||
PATH* path; ///< used for both path and polygon
|
||||
RECTANGLE* rectangle;
|
||||
CIRCLE* circle;
|
||||
QARC* qarc;
|
||||
//--------------------------------------------------- */
|
||||
/* <shape_descriptor >::=
|
||||
[<rectangle_descriptor> |
|
||||
<circle_descriptor> |
|
||||
<polygon_descriptor> |
|
||||
<path_descriptor> |
|
||||
<qarc_descriptor> ]
|
||||
*/
|
||||
ELEM* shape;
|
||||
|
||||
WINDOWS windows;
|
||||
|
||||
|
||||
public:
|
||||
SHAPE( ELEM* aParent, DSN_T aType = T_shape ) :
|
||||
ELEM_HOLDER( aType, aParent )
|
||||
ELEM( aType, aParent )
|
||||
{
|
||||
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 FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
|
||||
void SetConnect( DSN_T aConnect )
|
||||
{
|
||||
ELEM_HOLDER::FormatContents( out, nestLevel );
|
||||
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 )
|
||||
out->Print( nestLevel, "(connect %s)\n", LEXER::GetTokenText( connect ) );
|
||||
|
||||
for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i )
|
||||
i->Format( out, nestLevel );
|
||||
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 )
|
||||
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.
|
||||
*
|
||||
* @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() );
|
||||
|
||||
|
||||
// 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
|
||||
{
|
||||
db.FromBOARD( m_Pcb );
|
||||
|
@ -97,17 +83,6 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
|
|||
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 )
|
||||
{
|
||||
// @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
|
||||
* makes all the PADSTACKs, and marks each D_PAD with the index into the
|
||||
|
@ -247,7 +250,19 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
|||
|
||||
D_PAD* old_pad = NULL;
|
||||
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 )
|
||||
{
|
||||
D_PAD* pad = (D_PAD*) aPads[i];
|
||||
|
@ -265,39 +280,51 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
|||
pad->m_logical_connexion = padstackNdx++;
|
||||
|
||||
PADSTACK* padstack = new PADSTACK( aLibrary );
|
||||
SHAPE* shape = new SHAPE( padstack );
|
||||
padstack->Append( shape );
|
||||
aLibrary->AddPadstack( padstack );
|
||||
|
||||
// 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 )
|
||||
{
|
||||
default:
|
||||
case PAD_CIRCLE:
|
||||
{
|
||||
CIRCLE* circle;
|
||||
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 );
|
||||
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) );
|
||||
circle->SetDiameter( diameter );
|
||||
shape->Append( circle );
|
||||
++coppers;
|
||||
if( doLayer[i] )
|
||||
{
|
||||
CIRCLE* circle;
|
||||
SHAPE* shape = new SHAPE( padstack );
|
||||
|
||||
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 ) )
|
||||
{
|
||||
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) );
|
||||
|
||||
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.
|
||||
|
||||
padstack->SetPadstackId( name );
|
||||
|
||||
aLibrary->AddPadstack( padstack );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -315,29 +340,30 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
|
|||
{
|
||||
double dx = scale( pad->m_Size.x ) / 2.0;
|
||||
double dy = scale( pad->m_Size.y ) / 2.0;
|
||||
|
||||
POINT lowerLeft( -dx, -dy );
|
||||
POINT upperRight( dx, dy );
|
||||
|
||||
RECTANGLE* rect;
|
||||
int coppers = 0;
|
||||
lowerLeft += padOffset;
|
||||
upperRight += padOffset;
|
||||
|
||||
if( pad->IsOnLayer( COPPER_LAYER_N ) )
|
||||
for( int layer=0; layer<2; ++layer )
|
||||
{
|
||||
rect = new RECTANGLE( shape );
|
||||
rect->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) );
|
||||
rect->SetCorners( POINT(-dx,-dy), POINT(dx,dy) );
|
||||
shape->Append( rect );
|
||||
++coppers;
|
||||
if( doLayer[i] )
|
||||
{
|
||||
SHAPE* shape = new SHAPE( padstack );
|
||||
padstack->Append( shape );
|
||||
|
||||
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 ) )
|
||||
{
|
||||
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",
|
||||
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;
|
||||
|
||||
// @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.
|
||||
|
||||
padstack->SetPadstackId( name );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_OVAL:
|
||||
{
|
||||
double dx = scale( pad->m_Size.x ) / 2.0;
|
||||
double dy = scale( pad->m_Size.y ) / 2.0;
|
||||
double dr = dx - dy;
|
||||
|
||||
if( dr >= 0 ) // oval is horizontal
|
||||
{
|
||||
double radius = dy;
|
||||
|
||||
for( int layer=0; layer<2; ++layer )
|
||||
{
|
||||
// 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 // 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 );
|
||||
}
|
||||
}
|
||||
|
||||
aLibrary->AddPadstack( padstack );
|
||||
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;
|
||||
#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 */
|
||||
{
|
||||
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;
|
||||
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",
|
||||
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 );
|
||||
}
|
||||
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",
|
||||
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 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
case PAD_TRAPEZOID:
|
||||
pad_type = "POLYGON";
|
||||
break;
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
||||
void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
||||
{
|
||||
TYPE_COLLECTOR items;
|
||||
POINT_PAIRS ppairs;
|
||||
|
@ -426,6 +518,21 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
|||
if( !pcb )
|
||||
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>--------------------
|
||||
{
|
||||
pcb->unit->units = T_mil;
|
||||
|
@ -463,7 +570,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
|
|||
{
|
||||
swapEnds( ppairs );
|
||||
|
||||
#if defined(DEBUG)
|
||||
#if 0 && defined(DEBUG)
|
||||
for( unsigned i=0; i<ppairs.size(); ++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->type =
|
||||
// layer->type = @todo need this, the export would be better.
|
||||
|
||||
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.
|
||||
pads.Collect( aBoard, scanPADs );
|
||||
|
||||
|
||||
makePADSTACKs( aBoard, pads, pcb->library, pcb->library->padstacks );
|
||||
|
||||
#if defined(DEBUG)
|
||||
#if 0 && defined(DEBUG)
|
||||
for( int p=0; p<pads.GetCount(); ++p )
|
||||
pads[p]->Show( 0, std::cout );
|
||||
#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