more specctra dsn work

This commit is contained in:
dickelbeck 2008-01-22 20:48:02 +00:00
parent 0f3b3ee2cb
commit 300d50b1bc
6 changed files with 329 additions and 45 deletions

View File

@ -5,6 +5,16 @@ Please add newer entries at the top, list the date and your name with
email address.
2008-Jan-22 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew:
* Actually able now to export a *.dsn file, but the contents of the file
is incomplete, not a complete input BOARD.
* Added DRAWSEGMENT::Show() for debugging.
* Changed specctra.h's POINT to use double for coordinates. Changed format
string for Format()ing a double.
* Changed specctra_export.cpp to actually output an incomplete file.
2008-Jan-21 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================

View File

@ -36,6 +36,14 @@
#include "pcbnew.h"
/**
* Class LEXER
* implements a lexical analyzer for the SPECCTRA DSN file format. It
* reads lexical tokens from the current LINE_READER through the NextTok()
* function. The NextTok() function returns one of the DSN_T values.
*/
namespace DSN {

View File

@ -535,6 +535,7 @@ public:
/**
* Class LEXER
* implements a lexical analyzer for the SPECCTRA DSN file format. It
* reads lexical tokens from the current LINE_READER through the NextTok()
* function. The NextTok() function returns one of the DSN_T values.
*/
@ -635,7 +636,7 @@ public:
/**
* Function ThrowIOError
* encapsulates the formatting of an error message which contains the exact
* location within the input file of a lexical error.
* location within the input file of something the caller is rejecting.
*/
void ThrowIOError( wxString aText, int charOffset ) throw (IOError);

View File

@ -55,11 +55,10 @@
#include <wx/ffile.h>
#define STANDALONE 0 // set to 1 for "stand alone, i.e. unit testing"
// set to 0 for component of pcbnew
//#define STANDALONE // define "stand alone, i.e. unit testing"
#if STANDALONE
#if defined(STANDALONE)
#define EDA_BASE // build_version.h behavior
#undef COMMON_GLOBL
#define COMMON_GLOBL // build_version.h behavior
@ -3326,7 +3325,7 @@ const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee )
}
void SPECCTRA_DB::ExportPCB( wxString filename ) throw( IOError )
void SPECCTRA_DB::ExportPCB( wxString filename, bool aNameChange ) throw( IOError )
{
fp = wxFopen( filename, wxT("w") );
@ -3336,7 +3335,15 @@ void SPECCTRA_DB::ExportPCB( wxString filename ) throw( IOError )
}
if( pcb )
{
if( aNameChange )
pcb->pcbname = CONV_TO_UTF8(filename);
pcb->Format( this, 0 );
}
// if an exception is thrown by Format, then ~SPECCTRA_DB() will close
// the file.
fclose( fp );
fp = 0;
@ -3369,6 +3376,7 @@ PCB* SPECCTRA_DB::MakePCB()
pcb->unit = new UNIT_RES( pcb, T_unit );
pcb->structure = new STRUCTURE( pcb );
pcb->structure->boundary = new BOUNDARY( pcb->structure );
pcb->placement = new PLACEMENT( pcb );
@ -3506,13 +3514,13 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
}
if( hasVertex )
out->Print( 0, " %f %f", vertex.x, vertex.y );
out->Print( 0, " %.6g %.6g", vertex.x, vertex.y );
if( side != T_NONE )
out->Print( 0, " %s", LEXER::GetTokenText( side ) );
if( isRotated )
out->Print( 0, " %f", rotation );
out->Print( 0, " %.6g", rotation );
if( mirror != T_NONE )
out->Print( 0, " (mirror %s)", LEXER::GetTokenText( mirror ) );
@ -3572,7 +3580,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
// unit test this source file
#if STANDALONE
#if defined(STANDALONE)
using namespace DSN;

View File

@ -106,11 +106,21 @@ public:
struct POINT
{
float x;
float y;
double x;
double y;
POINT() { x=0.0; y=0.0; }
bool operator==( const POINT& other ) const
{
return x==other.x && y==other.y;
}
bool operator!=( const POINT& other ) const
{
return !( *this == other );
}
/**
* Function Format
* writes this object as ASCII out to an OUTPUTFORMATTER according to the
@ -121,7 +131,7 @@ struct POINT
*/
void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IOError )
{
out->Print( nestLevel, " %f %f", x, y );
out->Print( nestLevel, " %.6g %.6g", x, y );
}
};
@ -161,6 +171,8 @@ typedef std::vector<PROPERTY> PROPERTIES;
*/
class ELEM
{
friend class SPECCTRA_DB;
protected:
DSN_T type;
ELEM* parent;
@ -213,6 +225,11 @@ public:
{
// overridden in ELEM_HOLDER
}
void SetParent( ELEM* aParent )
{
parent = aParent;
}
};
@ -223,7 +240,8 @@ public:
*/
class ELEM_HOLDER : public ELEM
{
// see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html
friend class SPECCTRA_DB;
typedef boost::ptr_vector<ELEM> ELEM_ARRAY;
ELEM_ARRAY kids; ///< ELEM pointers
@ -393,7 +411,7 @@ public:
{
const char* quote = out->GetQuoteChar( layer_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s %f %f %f %f)\n",
out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g %.6g)\n",
LEXER::GetTokenText( Type() ),
quote, layer_id.c_str(), quote,
point0.x, point0.y,
@ -546,7 +564,7 @@ class PATH : public ELEM
public:
PATH( ELEM* aParent, DSN_T aType ) :
PATH( ELEM* aParent, DSN_T aType = T_path ) :
ELEM( aType, aParent )
{
aperture_width = 0.0;
@ -561,13 +579,13 @@ public:
{
const char* quote = out->GetQuoteChar( layer_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s %f\n", LEXER::GetTokenText( Type() ),
out->Print( nestLevel, "(%s %s%s%s %.6g\n", LEXER::GetTokenText( Type() ),
quote, layer_id.c_str(), quote,
aperture_width );
for( unsigned i=0; i<points.size(); ++i )
{
out->Print( nestLevel+1, "%f %f\n", points[i].x, points[i].y );
out->Print( nestLevel+1, "%.6g %.6g\n", points[i].x, points[i].y );
}
if( aperture_type == T_square )
@ -587,6 +605,7 @@ class BOUNDARY : public ELEM
PATHS paths;
RECTANGLE* rectangle;
public:
BOUNDARY( ELEM* aParent, DSN_T aType = T_boundary ) :
@ -636,7 +655,7 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
const char* quote = out->GetQuoteChar( layer_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s %f %f %f)\n", LEXER::GetTokenText( Type() ) ,
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 );
}
@ -661,12 +680,12 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
const char* quote = out->GetQuoteChar( layer_id.c_str() );
out->Print( nestLevel, "(%s %s%s%s %f\n", LEXER::GetTokenText( Type() ) ,
out->Print( nestLevel, "(%s %s%s%s %.6g\n", LEXER::GetTokenText( Type() ) ,
quote, layer_id.c_str(), quote,
aperture_width);
for( int i=0; i<3; ++i )
out->Print( nestLevel+1, "%f %f\n", vertex[i].x, vertex[i].y );
out->Print( nestLevel+1, "%.6g %.6g\n", vertex[i].x, vertex[i].y );
out->Print( nestLevel, ")\n" );
}
@ -1072,7 +1091,7 @@ public:
const char* quote0 = out->GetQuoteChar( layer_id0.c_str() );
const char* quote1 = out->GetQuoteChar( layer_id1.c_str() );
out->Print( nestLevel, "(%s %s%s%s %s%s%s %f)\n", LEXER::GetTokenText( Type() ),
out->Print( nestLevel, "(%s %s%s%s %s%s%s %.6g)\n", LEXER::GetTokenText( Type() ),
quote0, layer_id0.c_str(), quote0,
quote1, layer_id1.c_str(), quote1,
layer_weight );
@ -1113,7 +1132,7 @@ class PLANE : public KEEPOUT
public:
PLANE( ELEM* aParent ) :
KEEPOUT( aParent, T_plane )
{}
{}
};
@ -1232,11 +1251,11 @@ class GRID : public ELEM
DSN_T grid_type; ///< T_via | T_wire | T_via_keepout | T_place | T_snap
float dimension;
double dimension;
DSN_T direction; ///< T_x | T_y | -1 for both
float offset;
double offset;
DSN_T image_type;
@ -1254,7 +1273,7 @@ public:
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
out->Print( nestLevel, "(%s %s %f",
out->Print( nestLevel, "(%s %s %.6g",
LEXER::GetTokenText( Type() ),
LEXER::GetTokenText( grid_type ), dimension );
@ -1270,7 +1289,7 @@ public:
}
if( offset != 0.0 )
out->Print( 0, " (offset %f)", offset );
out->Print( 0, " (offset %.6g)", offset );
out->Print( 0, ")\n");
}
@ -1335,6 +1354,24 @@ public:
delete place_rules;
}
void SetBOUNDARY( BOUNDARY *aBoundary )
{
delete boundary;
boundary = aBoundary;
if( boundary )
{
boundary->SetParent( this );
}
}
void SetPlaceBOUNDARY( BOUNDARY *aBoundary )
{
delete place_boundary;
place_boundary = aBoundary;
if( place_boundary )
place_boundary->SetParent( this );
}
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
if( unit )
@ -1401,7 +1438,7 @@ class PLACE : public ELEM
DSN_T side;
bool isRotated;
float rotation;
double rotation;
bool hasVertex;
POINT vertex;
@ -1457,7 +1494,7 @@ public:
void SetRotation( double aRotation )
{
rotation = (float) aRotation;
rotation = aRotation;
isRotated = (aRotation != 0.0);
}
@ -1607,7 +1644,7 @@ class PIN : public ELEM
friend class SPECCTRA_DB;
std::string padstack_id;
float rotation;
double rotation;
bool isRotated;
std::string pin_id;
POINT vertex;
@ -1622,7 +1659,7 @@ public:
void SetRotation( double aRotation )
{
rotation = (float) aRotation;
rotation = aRotation;
isRotated = (aRotation != 0.0);
}
@ -1630,7 +1667,7 @@ public:
{
const char* quote = out->GetQuoteChar( padstack_id.c_str() );
if( isRotated )
out->Print( nestLevel, "(pin %s%s%s (rotate %1.2f)",
out->Print( nestLevel, "(pin %s%s%s (rotate %.6g)",
quote, padstack_id.c_str(), quote,
rotation
);
@ -1638,7 +1675,7 @@ public:
out->Print( nestLevel, "(pin %s%s%s", quote, padstack_id.c_str(), quote );
quote = out->GetQuoteChar( pin_id.c_str() );
out->Print( 0, " %s%s%s %f %f)\n", quote, pin_id.c_str(), quote,
out->Print( 0, " %s%s%s %.6g %.6g)\n", quote, pin_id.c_str(), quote,
vertex.x, vertex.y );
}
};
@ -2356,11 +2393,11 @@ public:
{
out->Print( 0, "\n" );
perLine = 0;
perLine += out->Print( nestLevel+1, "%f %f", i->x, i->y );
perLine += out->Print( nestLevel+1, "%.6g %.6g", i->x, i->y );
}
else
{
perLine += out->Print( 0, " %f %f", i->x, i->y );
perLine += out->Print( 0, " %.6g %.6g", i->x, i->y );
}
}
out->Print( 0, "\n" );
@ -2371,6 +2408,9 @@ public:
out->Print( nestLevel+1, "(net %s%s%s)\n", quote, net_id.c_str(), quote );
}
if( via_number != -1 )
out->Print( nestLevel+1, "(via_number %d)\n", via_number );
if( type != T_NONE )
out->Print( nestLevel+1, "(type %s)\n", LEXER::GetTokenText( type ) );
@ -2599,10 +2639,6 @@ public:
{
time_stamp = time(NULL);
}
~HISTORY()
{
;
}
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
@ -3071,6 +3107,14 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
void doNET_OUT( NET_OUT* growth ) throw( IOError );
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()
@ -3160,9 +3204,11 @@ public:
* writes the internal PCB instance out as a SPECTRA DSN format file.
*
* @param aFilename The file to save to.
* @param aNameChange If true, causes the pcb's name to change to "aFilename"
* and also to to be changed in the output file.
* @throw IOError, if an i/o error occurs saving the file.
*/
void ExportPCB( wxString aFilename ) throw( IOError );
void ExportPCB( wxString aFilename, bool aNameChange=false ) throw( IOError );
/**

View File

@ -33,6 +33,7 @@
#include "specctra.h"
#include "collectors.h"
using namespace DSN;
@ -40,6 +41,25 @@ using namespace DSN;
// see wxPcbStruct.h
void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
{
wxString fullFileName = GetScreen()->m_FileName;
wxString std_ext = wxT( ".dsn" );
wxString mask = wxT( "*" ) + std_ext;
ChangeFileNameExt( fullFileName, std_ext );
fullFileName = EDA_FileSelector( _( "Specctra DSN file:" ),
wxEmptyString, /* Chemin par defaut */
fullFileName, /* nom fichier par defaut */
std_ext, /* extension par defaut */
mask, /* Masque d'affichage */
this,
wxFD_SAVE,
FALSE
);
if( fullFileName == wxEmptyString )
return;
SPECCTRA_DB db;
db.SetPCB( SPECCTRA_DB::MakePCB() );
@ -47,21 +67,212 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
try
{
db.FromBOARD( m_Pcb );
// db.Export( filename );
db.ExportPCB( fullFileName, true );
}
catch ( IOError ioe )
{
DisplayError( this, ioe.errorText );
}
// if an exception is thrown by FromBOARD or Export(), then
// ~SPECCTRA_DB() will close the file.
}
namespace DSN {
struct POINT_PAIR
{
POINT p1; ///< start
POINT p2; ///< end
BOARD_ITEM* item; ///< the item which has these points, TRACK or DRAWSEGMENT
};
typedef std::vector<POINT_PAIR> POINT_PAIRS;
static inline void swap( POINT_PAIR& pair )
{
POINT temp = pair.p1;
pair.p1 = pair.p2;
pair.p2 = temp;
}
static POINT mapPt( const wxPoint& pt )
{
POINT ret;
ret.x = pt.x;
ret.y = -pt.y; // make y negative, since it is increasing going down.
return ret;
}
/**
* Function swapEnds
* will swap ends of any POINT_PAIR in the POINT_PAIRS list in order to
* make the consecutive POINT_PAIRs be "connected" at their ends.
*/
static void swapEnds( POINT_PAIRS& aList )
{
POINT temp;
if( aList.size() <= 1 )
return;
for( unsigned i=0; i<aList.size(); ++i )
{
if( aList[i].p1 == aList[i+1].p1 )
swap( aList[i] );
else if( aList[i].p1 == aList[i+1].p2 )
{
swap( aList[i] );
swap( aList[i+1] );
++i; // skip next one, we swapped i+1 here
}
}
}
/**
* Function isRectangle
* tests to see if the POINT_PAIRS list make up a vertically/horizontally
* oriented rectangle.
* @return bool - true if there are 4 point pairs making a rectangle.
*/
static bool isRectangle( POINT_PAIRS& aList )
{
if( aList.size() == 4 )
{
for( unsigned i=0; i<aList.size(); ++i )
{
if( i < aList.size()-1 )
if( aList[i].p2 != aList[i+1].p1 )
return false;
if( aList[i].p1.x != aList[i].p2.x
&& aList[i].p1.y != aList[i].p2.y )
return false;
}
return ( aList[0].p1 == aList[3].p2 );
}
return false;
}
void SPECCTRA_DB::exportEdges( BOARD* aBoard ) throw( IOError )
{
}
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
{
TYPE_COLLECTOR items;
POINT_PAIRS ppairs;
POINT_PAIR pair;
if( !pcb )
pcb = SPECCTRA_DB::MakePCB();
//-----<header stuff>-------------------------------------------------
pcb->unit->units = T_mil;
pcb->resolution->units = T_mil;
pcb->resolution->value = 10;
//-----<board edges>--------------------------------------------------
// get all the DRAWSEGMENTS into 'items', then look for layer == EDGE_N,
// and those segments comprize the board's perimeter.
const KICAD_T scanDRAWSEGMENTS[] = { TYPEDRAWSEGMENT, EOT };
items.Collect( aBoard, scanDRAWSEGMENTS );
bool haveEdges = false;
ppairs.clear();
for( int i=0; i<items.GetCount(); ++i )
{
DRAWSEGMENT* item = (DRAWSEGMENT*) items[i];
wxASSERT( item->Type() == TYPEDRAWSEGMENT );
if( item->GetLayer() == EDGE_N )
{
pair.p1 = mapPt( item->m_Start );
pair.p2 = mapPt( item->m_End );
pair.item = item;
ppairs.push_back( pair );
haveEdges = true;
}
}
if( haveEdges )
{
swapEnds( ppairs );
#if defined(DEBUG)
for( unsigned i=0; i<ppairs.size(); ++i )
{
POINT_PAIR* p = &ppairs[i];
p->item->Show( 0, std::cout );
}
#endif
BOUNDARY* boundary = new BOUNDARY(0);
if( isRectangle( ppairs ) )
{
RECTANGLE* rect = new RECTANGLE( boundary );
rect->layer_id = "pcb";
// opposite corners
rect->point0 = ppairs[0].p1;
rect->point1 = ppairs[2].p1;
boundary->rectangle = rect;
}
else
{
PATH* path = new PATH( boundary );
path->layer_id = "pcb";
for( unsigned i=0; i<ppairs.size(); ++i )
{
// unless its a closed polygon, this probably won't work,
// otherwise it will.
path->points.push_back( ppairs[i].p1 );
}
boundary->paths.push_back( path );
}
pcb->structure->SetBOUNDARY( boundary );
}
else
{
aBoard->ComputeBoundaryBox();
BOUNDARY* boundary = new BOUNDARY(0);
RECTANGLE* rect = new RECTANGLE( boundary );
rect->layer_id = "pcb";
// opposite corners
wxPoint bottomRight;
bottomRight.x = aBoard->m_BoundaryBox.GetRight();
bottomRight.y = aBoard->m_BoundaryBox.GetBottom();
rect->point0 = mapPt( aBoard->m_BoundaryBox.GetOrigin() );
rect->point1 = mapPt( bottomRight );
boundary->rectangle = rect;
pcb->structure->SetBOUNDARY( boundary );
}
//-----<layers>-------------------------------------------------------
}