From 501fb2c270fdaba56394a22f68d857402e590df8 Mon Sep 17 00:00:00 2001 From: dickelbeck Date: Fri, 25 Jan 2008 22:03:36 +0000 Subject: [PATCH] more free specctra work --- change_log.txt | 8 + pcbnew/specctra.cpp | 26 +-- pcbnew/specctra.h | 173 +++++++++++++---- pcbnew/specctra_export.cpp | 379 ++++++++++++++++++++++++------------- 4 files changed, 405 insertions(+), 181 deletions(-) diff --git a/change_log.txt b/change_log.txt index df4f71e0b7..6a22bde590 100644 --- a/change_log.txt +++ b/change_log.txt @@ -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 +================================================================================ ++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 ================================================================================ diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp index aadcd0c413..a458aa33f5 100644 --- a/pcbnew/specctra.cpp +++ b/pcbnew/specctra.cpp @@ -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: diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 5b9bf41364..ef458ea60d 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -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 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; - //--------------------------------------------------- */ + /* ::= + [ | + | + | + | + ] + */ + 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 ); /** diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index c3c0d7a6ee..40d904045e 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -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; im_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; + } + } + + //----- & -------------------- { 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; iname = 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; pShow( 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; + } + } }