Commit 1969a511 authored by dickelbeck's avatar dickelbeck

more free specctra dsn work

parent b8b0fc6e
......@@ -737,7 +737,7 @@ L_read:
goto exit;
}
// else it was something like +5V, reset head back
// else it was something like +5V, fall through below
}
// a quoted string
......
......@@ -212,7 +212,7 @@ void SPECCTRA_DB::readTIME( time_t* time_stamp ) throw( IOError )
const char* ptok = lexer->CurText();
mytime.tm_mon = 0; // remains of we don't find a month match.
mytime.tm_mon = 0; // remains if we don't find a month match.
for( int m=0; months[m]; ++m )
{
if( !stricmp( months[m], ptok ) )
......@@ -1985,7 +1985,7 @@ void SPECCTRA_DB::doSHAPE( SHAPE* growth ) throw( IOError )
case T_polygon:
case T_qarc:
L_done_that:
if( growth->rectangle || growth->circle || growth->path || growth->qarc )
if( growth->Length() )
unexpected( tok );
break;
default:
......@@ -2000,24 +2000,32 @@ L_done_that:
switch( tok )
{
case T_rect:
growth->rectangle = new RECTANGLE( growth );
doRECTANGLE( growth->rectangle );
RECTANGLE* rectangle;
rectangle = new RECTANGLE( growth );
growth->Append( rectangle );
doRECTANGLE( rectangle );
break;
case T_circle:
growth->circle = new CIRCLE( growth );
doCIRCLE( growth->circle );
CIRCLE* circle;
circle = new CIRCLE( growth );
growth->Append( circle );
doCIRCLE( circle );
break;
case T_path:
case T_polygon:
growth->path = new PATH( growth, tok );
doPATH( growth->path );
PATH* path;
path = new PATH( growth, tok );
growth->Append( path );
doPATH( path );
break;
case T_qarc:
growth->qarc = new QARC( growth );
doQARC( growth->qarc );
QARC* qarc;
qarc = new QARC( growth );
growth->Append( qarc );
doQARC( qarc );
break;
case T_connect:
......@@ -3650,16 +3658,16 @@ int main( int argc, char** argv )
{
// wxString filename( wxT("/tmp/fpcroute/Sample_1sided/demo_1sided.dsn") );
// wxString filename( wxT("/tmp/testdesigns/test.dsn") );
wxString filename( wxT("/tmp/testdesigns/test.ses") );
// wxString filename( wxT("/tmp/specctra_big.dsn") );
// wxString filename( wxT("/tmp/testdesigns/test.ses") );
wxString filename( wxT("/tmp/specctra_big.dsn") );
SPECCTRA_DB db;
bool failed = false;
try
{
// db.LoadPCB( filename );
db.LoadSESSION( filename );
db.LoadPCB( filename );
// db.LoadSESSION( filename );
}
catch( IOError ioe )
{
......@@ -3672,8 +3680,8 @@ int main( int argc, char** argv )
// export what we read in, making this test program basically a beautifier
db.ExportSESSION( wxT("/tmp/export.ses") );
// db.ExportPCB( wxT("/tmp/export.dsn") );
// db.ExportSESSION( wxT("/tmp/export.ses") );
db.ExportPCB( wxT("/tmp/export.dsn") );
}
......
......@@ -111,6 +111,11 @@ struct POINT
POINT() { x=0.0; y=0.0; }
POINT( double aX, double aY ) :
x(aX), y(aY)
{
}
bool operator==( const POINT& other ) const
{
return x==other.x && y==other.y;
......@@ -406,6 +411,17 @@ public:
ELEM( T_rect, aParent )
{
}
void SetLayerId( const char* aLayerId )
{
layer_id = aLayerId;
}
void SetCorners( const POINT& aPoint0, const POINT& aPoint1 )
{
point0 = aPoint0;
point1 = aPoint1;
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
......@@ -439,21 +455,22 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
out->Print( nestLevel, "(%s ", LEXER::GetTokenText( Type() ) );
out->Print( nestLevel, "(%s", LEXER::GetTokenText( Type() ) );
bool singleLine;
if( rules.size() == 1 )
{
singleLine = true;
out->Print( 0, "%s)", rules.begin()->c_str() );
out->Print( 0, " %s)", rules.begin()->c_str() );
}
else
{
out->Print( 0, "\n" );
singleLine = false;
for( STRINGS::const_iterator i = rules.begin(); i!=rules.end(); ++i )
out->Print( nestLevel, "%s\n", i->c_str() );
out->Print( nestLevel+1, "%s\n", i->c_str() );
out->Print( nestLevel, ")" );
}
......@@ -671,6 +688,16 @@ public:
quote, layer_id.c_str(), quote,
diameter, vertex.x, vertex.y );
}
void SetLayerId( const char* aLayerId )
{
layer_id = aLayerId;
}
void SetDiameter( double aDiameter )
{
diameter = aDiameter;
}
};
......@@ -870,28 +897,42 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
out->Print( nestLevel, "(%s\n", LEXER::GetTokenText( Type() ) );
const int RIGHTMARGIN = 80;
int perLine = out->Print( nestLevel, "(%s", LEXER::GetTokenText( Type() ) );
for( STRINGS::iterator i=padstacks.begin(); i!=padstacks.end(); ++i )
{
if( perLine > RIGHTMARGIN )
{
out->Print( 0, "\n" );
perLine = out->Print( nestLevel+1, "%s", "");
}
const char* quote = out->GetQuoteChar( i->c_str() );
out->Print( nestLevel+1, "%s%s%s\n", quote, i->c_str(), quote );
perLine += out->Print( 0, " %s%s%s", quote, i->c_str(), quote );
}
if( spares.size() )
{
out->Print( nestLevel+1, "(spare\n" );
out->Print( 0, "\n" );
perLine = out->Print( nestLevel+1, "(spare" );
for( STRINGS::iterator i=spares.begin(); i!=spares.end(); ++i )
{
if( perLine > RIGHTMARGIN )
{
out->Print( 0, "\n" );
perLine = out->Print( nestLevel+2, "%s", "");
}
const char* quote = out->GetQuoteChar( i->c_str() );
out->Print( nestLevel+2, "%s%s%s\n", quote, i->c_str(), quote );
perLine += out->Print( 0, " %s%s%s", quote, i->c_str(), quote );
}
out->Print( nestLevel+1, ")\n" );
out->Print( 0, ")" );
}
out->Print( nestLevel, ")\n" );
out->Print( 0, ")\n" );
}
};
......@@ -1600,55 +1641,34 @@ public:
};
class SHAPE : public ELEM
class SHAPE : public ELEM_HOLDER
{
friend class SPECCTRA_DB;
DSN_T connect;
//----- only one of these is used, like a union -----
/*----- 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;
//---------------------------------------------------
//--------------------------------------------------- */
WINDOWS windows;
public:
SHAPE( ELEM* aParent, DSN_T aType = T_shape ) :
ELEM( aType, aParent )
ELEM_HOLDER( aType, aParent )
{
connect = T_on;
path = 0;
rectangle = 0;
circle = 0;
qarc = 0;
}
~SHAPE()
{
delete path;
delete rectangle;
delete circle;
delete qarc;
}
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
if( path )
path->Format( out, nestLevel );
else if( rectangle )
rectangle->Format( out, nestLevel );
else if( circle )
circle->Format( out, nestLevel );
else if( qarc )
qarc->Format( out, nestLevel );
ELEM_HOLDER::FormatContents( out, nestLevel );
if( connect == T_off )
out->Print( nestLevel, "(connect %s)\n", LEXER::GetTokenText( connect ) );
......@@ -1817,6 +1837,11 @@ public:
delete rules;
}
void SetPadstackId( const char* aPadstackId )
{
padstack_id = aPadstackId;
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
const char* quote = out->GetQuoteChar( padstack_id.c_str() );
......@@ -1865,6 +1890,7 @@ public:
return ELEM::GetUnits();
}
};
typedef boost::ptr_vector<PADSTACK> PADSTACKS;
/**
......@@ -1882,7 +1908,6 @@ class LIBRARY : public ELEM
typedef boost::ptr_vector<IMAGE> IMAGES;
IMAGES images;
typedef boost::ptr_vector<PADSTACK> PADSTACKS;
PADSTACKS padstacks;
public:
......@@ -1916,6 +1941,11 @@ public:
return ELEM::GetUnits();
}
void AddPadstack( PADSTACK* aPadstack )
{
padstacks.push_back( aPadstack );
}
};
......@@ -2215,35 +2245,32 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
const int RIGHTMARGIN = 80;
const char* quote = out->GetQuoteChar( class_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ),
quote, class_id.c_str(), quote );
const int NETGAP = 2;
const int RIGHTMARGIN = 92;
int perRow=RIGHTMARGIN;
int perLine = out->Print( nestLevel, "(%s %s%s%s",
LEXER::GetTokenText( Type() ),
quote, class_id.c_str(), quote );
for( STRINGS::iterator i=net_ids.begin(); i!=net_ids.end(); ++i )
{
quote = out->GetQuoteChar( i->c_str() );
int slength = strlen( i->c_str() );
if( *quote!='\0' )
slength += 2;
if( perRow + slength + NETGAP > RIGHTMARGIN )
if( perLine > RIGHTMARGIN )
{
out->Print( 0, "\n" );
perRow = 0;
perRow += out->Print( nestLevel+1, "%s%s%s",
quote, i->c_str(), quote );
}
else
{
perRow += out->Print( 0, "%*c%s%s%s", NETGAP, ' ',
quote, i->c_str(), quote );
perLine = out->Print( nestLevel+1, "%s", "" );
}
quote = out->GetQuoteChar( i->c_str() );
perLine += out->Print( 0, " %s%s%s", quote, i->c_str(), quote );
}
bool newLine = false;
if( circuit.size() || layer_rules.size() || topology )
{
out->Print( 0, "\n" );
newLine = true;
}
out->Print( 0, "\n" );
for( STRINGS::iterator i=circuit.begin(); i!=circuit.end(); ++i )
out->Print( nestLevel+1, "%s\n", i->c_str() );
......@@ -2254,7 +2281,7 @@ public:
if( topology )
topology->Format( out, nestLevel+1 );
out->Print( nestLevel, ")\n" );
out->Print( newLine ? nestLevel : 0, ")\n" );
}
};
......@@ -2444,6 +2471,9 @@ public:
perLine += out->Print( 0, "%.6g %.6g", i->x, i->y );
}
if( net_id.size() || via_number!=-1 || type!=T_NONE || attr!=T_NONE || supply)
out->Print( 0, " " );
if( net_id.size() )
{
if( perLine > RIGHTMARGIN )
......@@ -3183,13 +3213,6 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
void doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IOError );
/**
* Function exportEdges
* exports the EDGES_N layer of the board.
*/
void exportEdges( BOARD* aBoard ) throw( IOError );
public:
SPECCTRA_DB()
......@@ -3288,7 +3311,17 @@ public:
/**
* Function FromBOARD
* adds the entire BOARD to the PCB but does not write it out.
* adds the entire BOARD to the PCB but does not write it out. Note that
* the BOARD given to this function must have all the MODULEs on the component
* side of the BOARD.
*
* See void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
* for how this can be done before calling this function.
* @todo
* I would have liked to put the flipping logic into the ExportToSPECCTRA()
* function directly, but for some strange reason,
* void Change_Side_Module( MODULE* Module, wxDC* DC ) is a member of
* 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
......
......@@ -34,6 +34,7 @@
#include "specctra.h"
#include "collectors.h"
#include "wxPcbStruct.h" // Change_Side_Module()
using namespace DSN;
......@@ -61,29 +62,61 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
SPECCTRA_DB db;
bool ok = true;
wxString errorText;
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 )
{
Change_Side_Module( module, NULL );
module->flag = 1;
}
}
try
{
db.FromBOARD( m_Pcb );
db.ExportPCB( fullFileName, true );
// if an exception is thrown by FromBOARD or Export(), then
// if an exception is thrown by FromBOARD or ExportPCB(), then
// ~SPECCTRA_DB() will close the file.
}
catch ( IOError ioe )
{
DisplayError( this, ioe.errorText );
return;
ok = false;
// display no messages until we flip back the modules below.
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 )
{
Change_Side_Module( module, NULL );
module->flag = 0;
}
}
// @todo display a message saying the export is complete.
if( ok )
{
// @todo display a message saying the export is complete.
}
else
DisplayError( this, errorText );
}
namespace DSN {
struct POINT_PAIR
......@@ -103,6 +136,22 @@ static inline void swap( POINT_PAIR& pair )
}
static inline double scale( int kicadDist )
{
return kicadDist/10.0;
}
static inline double mapX( int x )
{
return scale(x);
}
static inline double mapY( int y )
{
return -scale(y); // make y negative, since it is increasing going down.
}
/**
* Function mapPt
* converts a Kicad point into a DSN file point. Kicad's BOARD coordinates
......@@ -112,8 +161,8 @@ static inline void swap( POINT_PAIR& pair )
static POINT mapPt( const wxPoint& pt )
{
POINT ret;
ret.x = pt.x / 10.0;
ret.y = -pt.y /10.0; // make y negative, since it is increasing going down.
ret.x = mapX( pt.x );
ret.y = mapY( pt.y );
return ret;
}
......@@ -172,8 +221,199 @@ static bool isRectangle( POINT_PAIRS& aList )
}
void SPECCTRA_DB::exportEdges( BOARD* aBoard ) throw( IOError )
/**************************************************************************/
static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
/**************************************************************************/
{
const D_PAD* padref = *(D_PAD**)refptr;
const D_PAD* padcmp = *(D_PAD**)objptr;
return D_PAD::Compare( padref, padcmp );
}
/**
* Function makePADSTACKs
* makes all the PADSTACKs, and marks each D_PAD with the index into the
* LIBRARY::padstacks list that it matches.
*/
static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads,
LIBRARY* aLibrary, PADSTACKS& aPadstacks )
{
if( aPads.GetCount() )
{
qsort( (void*) aPads.BasePtr(), aPads.GetCount(), sizeof(D_PAD*), Pad_list_Sort_by_Shapes );
}
D_PAD* old_pad = NULL;
int padstackNdx = 0;
for( int i=0; i<aPads.GetCount(); ++i )
{
D_PAD* pad = (D_PAD*) aPads[i];
pad->m_logical_connexion = padstackNdx;
if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
{
continue;
}
old_pad = pad;
// this is the index into the library->padstacks, be careful.
pad->m_logical_connexion = padstackNdx++;
PADSTACK* padstack = new PADSTACK( aLibrary );
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
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 ) )
{
circle = new CIRCLE( shape );
circle->SetLayerId( CONV_TO_UTF8(aBoard->GetLayerName( COPPER_LAYER_N )) );
circle->SetDiameter( diameter );
shape->Append( circle );
++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];
snprintf( name, sizeof(name), "Round%dPad_%.6g_mil", coppers, scale(pad->m_Size.x) );
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
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name );
aLibrary->AddPadstack( padstack );
}
break;
case PAD_RECT:
{
double dx = scale( pad->m_Size.x ) / 2.0;
double dy = scale( pad->m_Size.y ) / 2.0;
RECTANGLE* rect;
int coppers = 0;
if( pad->IsOnLayer( COPPER_LAYER_N ) )
{
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( 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];
snprintf( name, sizeof(name), "Rect%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 the get the same
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name );
aLibrary->AddPadstack( padstack );
}
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
}
}
}
......@@ -223,13 +463,13 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
{
swapEnds( ppairs );
#if defined(DEBUG)
#if defined(DEBUG)
for( unsigned i=0; i<ppairs.size(); ++i )
{
POINT_PAIR* p = &ppairs[i];
p->item->Show( 0, std::cout );
}
#endif
#endif
BOUNDARY* boundary = new BOUNDARY(0);
......@@ -303,6 +543,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
pcb->structure->layers.push_back( layer );
}
}
//-----<zone containers become planes>--------------------------------------------
{
......@@ -333,21 +574,50 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
pcb->structure->planes.push_back( plane );
}
}
// keepouts could go here, there are none in Kicad at this time.
// although COPPER_PLANEs probably will need them for the thru holes, etc.
// but in that case they are WINDOWs within the COPPER_PLANEs.
//-----<build the padstack list here, no output>------------------------
{
// get all the DRAWSEGMENTS into 'items', then look for layer == EDGE_N,
// and those segments comprize the board's perimeter.
static const KICAD_T scanPADnVIAs[] = { TYPEPAD, TYPEVIA, EOT };
items.Collect( aBoard, scanPADnVIAs );
static const KICAD_T scanPADs[] = { TYPEPAD, EOT };
for( int i=0; i<items.GetCount(); ++i )
TYPE_COLLECTOR pads;
// get all the D_PADs into pads.
pads.Collect( aBoard, scanPADs );
makePADSTACKs( aBoard, pads, pcb->library, pcb->library->padstacks );
for( int p=0; p<pads.GetCount(); ++p )
pads[p]->Show( 0, std::cout );
/*
static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT };
items.Collect( aBoard, scanMODULEs );
for( int m=0; m<items.GetCount(); ++m )
{
// items[i]->Show( 0, std::cout );
MODULE* module = (MODULE*) items[m];
// collate all the pads, and make a component.
for( int p=0; p<pads.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) pads[p];
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
......
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