Loading pcbnew/dsn.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading pcbnew/specctra.cpp +24 −16 Original line number Diff line number Diff line Loading @@ -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 ) ) Loading Loading @@ -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: Loading @@ -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: Loading Loading @@ -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 ) { Loading @@ -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") ); } Loading pcbnew/specctra.h +101 −68 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -407,6 +412,17 @@ public: { } 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 ) { const char* quote = out->GetQuoteChar( layer_id.c_str() ); Loading Loading @@ -451,9 +467,10 @@ public: 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, ")" ); } Loading Loading @@ -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; } }; Loading Loading @@ -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" ); } }; Loading Loading @@ -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 ) ); Loading Loading @@ -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() ); Loading Loading @@ -1865,6 +1890,7 @@ public: return ELEM::GetUnits(); } }; typedef boost::ptr_vector<PADSTACK> PADSTACKS; /** Loading @@ -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: Loading Loading @@ -1916,6 +1941,11 @@ public: return ELEM::GetUnits(); } void AddPadstack( PADSTACK* aPadstack ) { padstacks.push_back( aPadstack ); } }; Loading Loading @@ -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 perLine = out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ), quote, class_id.c_str(), quote ); int perRow=RIGHTMARGIN; 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; } for( STRINGS::iterator i=circuit.begin(); i!=circuit.end(); ++i ) out->Print( nestLevel+1, "%s\n", i->c_str() ); Loading @@ -2254,7 +2281,7 @@ public: if( topology ) topology->Format( out, nestLevel+1 ); out->Print( nestLevel, ")\n" ); out->Print( newLine ? nestLevel : 0, ")\n" ); } }; Loading Loading @@ -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 ) Loading Loading @@ -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() Loading Loading @@ -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 Loading pcbnew/specctra_export.cpp +289 −19 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "specctra.h" #include "collectors.h" #include "wxPcbStruct.h" // Change_Side_Module() using namespace DSN; Loading Loading @@ -61,27 +62,59 @@ 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; // @todo display a message saying the export is complete. // 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; } } if( ok ) { // @todo display a message saying the export is complete. } else DisplayError( this, errorText ); } namespace DSN { Loading @@ -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 Loading @@ -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; } Loading Loading @@ -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 } } } Loading Loading @@ -304,6 +544,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } //-----<zone containers become planes>-------------------------------------------- { static const KICAD_T scanZONEs[] = { TYPEZONE_CONTAINER, EOT }; Loading Loading @@ -334,19 +575,48 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } // 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>------------------------------------------------- { Loading Loading
pcbnew/dsn.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
pcbnew/specctra.cpp +24 −16 Original line number Diff line number Diff line Loading @@ -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 ) ) Loading Loading @@ -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: Loading @@ -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: Loading Loading @@ -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 ) { Loading @@ -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") ); } Loading
pcbnew/specctra.h +101 −68 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -407,6 +412,17 @@ public: { } 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 ) { const char* quote = out->GetQuoteChar( layer_id.c_str() ); Loading Loading @@ -451,9 +467,10 @@ public: 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, ")" ); } Loading Loading @@ -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; } }; Loading Loading @@ -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" ); } }; Loading Loading @@ -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 ) ); Loading Loading @@ -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() ); Loading Loading @@ -1865,6 +1890,7 @@ public: return ELEM::GetUnits(); } }; typedef boost::ptr_vector<PADSTACK> PADSTACKS; /** Loading @@ -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: Loading Loading @@ -1916,6 +1941,11 @@ public: return ELEM::GetUnits(); } void AddPadstack( PADSTACK* aPadstack ) { padstacks.push_back( aPadstack ); } }; Loading Loading @@ -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 perLine = out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ), quote, class_id.c_str(), quote ); int perRow=RIGHTMARGIN; 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; } for( STRINGS::iterator i=circuit.begin(); i!=circuit.end(); ++i ) out->Print( nestLevel+1, "%s\n", i->c_str() ); Loading @@ -2254,7 +2281,7 @@ public: if( topology ) topology->Format( out, nestLevel+1 ); out->Print( nestLevel, ")\n" ); out->Print( newLine ? nestLevel : 0, ")\n" ); } }; Loading Loading @@ -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 ) Loading Loading @@ -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() Loading Loading @@ -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 Loading
pcbnew/specctra_export.cpp +289 −19 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include "specctra.h" #include "collectors.h" #include "wxPcbStruct.h" // Change_Side_Module() using namespace DSN; Loading Loading @@ -61,27 +62,59 @@ 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; // @todo display a message saying the export is complete. // 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; } } if( ok ) { // @todo display a message saying the export is complete. } else DisplayError( this, errorText ); } namespace DSN { Loading @@ -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 Loading @@ -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; } Loading Loading @@ -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 } } } Loading Loading @@ -304,6 +544,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } //-----<zone containers become planes>-------------------------------------------- { static const KICAD_T scanZONEs[] = { TYPEZONE_CONTAINER, EOT }; Loading Loading @@ -334,19 +575,48 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } // 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>------------------------------------------------- { Loading