From 300d50b1bc2638aa7f3177a915a33c01a12a7752 Mon Sep 17 00:00:00 2001 From: dickelbeck Date: Tue, 22 Jan 2008 20:48:02 +0000 Subject: [PATCH] more specctra dsn work --- change_log.txt | 10 ++ pcbnew/dsn.cpp | 8 ++ pcbnew/dsn.h | 3 +- pcbnew/specctra.cpp | 28 +++-- pcbnew/specctra.h | 106 +++++++++++++----- pcbnew/specctra_export.cpp | 219 ++++++++++++++++++++++++++++++++++++- 6 files changed, 329 insertions(+), 45 deletions(-) diff --git a/change_log.txt b/change_log.txt index 1f02da23c8..a6c05cd3a0 100644 --- a/change_log.txt +++ b/change_log.txt @@ -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 +================================================================================ ++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 ================================================================================ diff --git a/pcbnew/dsn.cpp b/pcbnew/dsn.cpp index 3e56e67879..4e52d560d9 100644 --- a/pcbnew/dsn.cpp +++ b/pcbnew/dsn.cpp @@ -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 { diff --git a/pcbnew/dsn.h b/pcbnew/dsn.h index 385e258600..17fbf6462f 100644 --- a/pcbnew/dsn.h +++ b/pcbnew/dsn.h @@ -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); diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp index e7bf4a5974..b064a518de 100644 --- a/pcbnew/specctra.cpp +++ b/pcbnew/specctra.cpp @@ -55,11 +55,10 @@ #include -#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") ); @@ -3334,10 +3333,18 @@ void SPECCTRA_DB::ExportPCB( wxString filename ) throw( IOError ) { ThrowIOError( _("Unable to open file \"%s\""), filename.GetData() ); } - - if( pcb ) - pcb->Format( this, 0 ); + 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; diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 03ad10e4b1..8abea8e053 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -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 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_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; iPrint( 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" ); @@ -2370,6 +2407,9 @@ public: const char* quote = out->GetQuoteChar( net_id.c_str() ); 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 ) { @@ -3070,6 +3106,14 @@ class SPECCTRA_DB : public OUTPUTFORMATTER void doWAS_IS( WAS_IS* growth ) throw( IOError ); 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: @@ -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 ); /** diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index f8abba6dc1..89c7f9bbe5 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -33,6 +33,7 @@ #include "specctra.h" +#include "collectors.h" using namespace DSN; @@ -40,32 +41,242 @@ using namespace DSN; // see wxPcbStruct.h void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event ) { - SPECCTRA_DB db; + 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() ); 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_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------------------------------------------------- + pcb->unit->units = T_mil; + pcb->resolution->units = T_mil; + pcb->resolution->value = 10; + + //------------------------------------------------------- + + // 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; iType() == 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; iitem->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; ipoints.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 ); + } + + //------------------------------------------------------------ + + } - + } // namespace DSN