From 1c294c33a52a95b19f6fc8b0886780cd96fcbb66 Mon Sep 17 00:00:00 2001 From: dickelbeck Date: Tue, 29 Jan 2008 22:09:09 +0000 Subject: [PATCH] more free specctra support, MODULE::GetValue() --- change_log.txt | 7 ++ pcbnew/class_module.h | 10 ++- pcbnew/dsn.h | 3 +- pcbnew/specctra.cpp | 50 +++++++++++-- pcbnew/specctra.h | 137 +++++++++++++++++++++--------------- pcbnew/specctra_export.cpp | 139 ++++++++++++++++++++++++++++++------- 6 files changed, 256 insertions(+), 90 deletions(-) diff --git a/change_log.txt b/change_log.txt index 091fe06074..85a7fc628a 100644 --- a/change_log.txt +++ b/change_log.txt @@ -5,6 +5,13 @@ Started 2007-June-11 Please add newer entries at the top, list the date and your name with email address. +2008-Jan-29 UPDATE Dick Hollenbeck +================================================================================ ++pcbnew: + SPECCTRA export does most items now, except existing tracks. Soon will + need testing. + + 2008-Jan-28 UPDATE Jean-Pierre Charras ================================================================================ +pcbnew: diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index f46236cd02..2cd49e48e1 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -180,13 +180,21 @@ public: /** * Function GetReference - * @return wxString - the reference designator text. + * @return const wxString& - the reference designator text. */ const wxString& GetReference() { return m_Reference->m_Text; } + /** + * Function GetValue + * @return const wxString& - the value text. + */ + const wxString& GetValue() + { + return m_Value->m_Text; + } /** * Function Visit diff --git a/pcbnew/dsn.h b/pcbnew/dsn.h index 4b2187d555..e2f875a052 100644 --- a/pcbnew/dsn.h +++ b/pcbnew/dsn.h @@ -617,7 +617,8 @@ public: /** * Function SetSpaceInQuotedTokens * changes the setting controlling whether a space in a quoted string is - * a terminator + * a terminator. + * @param val If true, means */ bool SetSpaceInQuotedTokens( bool val ) { diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp index 914e8037f9..1841392095 100644 --- a/pcbnew/specctra.cpp +++ b/pcbnew/specctra.cpp @@ -57,7 +57,7 @@ // To build the DSN beautifier and unit tester, simply uncomment this and then // use CMake's makefile to build target "specctra_test". -//#define STANDALONE // define "stand alone, i.e. unit testing" +#define STANDALONE // define "stand alone, i.e. unit testing" #if defined(STANDALONE) @@ -1707,6 +1707,10 @@ void SPECCTRA_DB::doPLACE( PLACE* growth ) throw( IOError ) while( (tok = nextTok()) != T_RIGHT ) { + if( tok != T_LEFT ) + expecting( T_LEFT ); + + tok = nextTok(); switch( tok ) { case T_mirror: @@ -1772,7 +1776,9 @@ void SPECCTRA_DB::doPLACE( PLACE* growth ) throw( IOError ) case T_pn: if( growth->part_number.size() ) unexpected( tok ); + needSYMBOL(); growth->part_number = lexer->CurText(); + needRIGHT(); break; default: @@ -3633,6 +3639,22 @@ int IMAGE::Compare( IMAGE* lhs, IMAGE* rhs ) } +//------------------------------------------------------------- + +/* +int COMPONENT::Compare( COMPONENT* lhs, COMPONENT* rhs ) +{ + if( !lhs->hash.size() ) + lhs->hash = lhs->makeHash(); + + if( !rhs->hash.size() ) + rhs->hash = rhs->makeHash(); + + int result = lhs->hash.compare( rhs->hash ); + return result; +} +*/ + //---------------------------------------------------------------- PARSER::PARSER( ELEM* aParent ) : @@ -3688,8 +3710,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) const char* quote = out->GetQuoteChar( component_id.c_str() ); - if( place_rules || properties.size() || lock_type!=T_NONE || rules - || region || part_number.size() ) + if( place_rules || properties.size() || rules || region ) { useMultiLine = true; @@ -3714,17 +3735,19 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) out->Print( 0, " %.6g", rotation ); } + + out->Print( 0, " " ); if( mirror != T_NONE ) - out->Print( 0, " (mirror %s)", LEXER::GetTokenText( mirror ) ); + out->Print( 0, "(mirror %s)", LEXER::GetTokenText( mirror ) ); if( status != T_NONE ) - out->Print( 0, " (status %s)", LEXER::GetTokenText( status ) ); + out->Print( 0, "(status %s)", LEXER::GetTokenText( status ) ); if( logical_part.size() ) { quote = out->GetQuoteChar( logical_part.c_str() ); - out->Print( 0, " (logical_part %s%s%s)", + out->Print( 0, "(logical_part %s%s%s)", quote, logical_part.c_str(), quote ); } @@ -3764,7 +3787,20 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) } } else - out->Print( 0, ")\n" ); + { + if( lock_type != T_NONE ) + out->Print( 0, "(lock_type %s)", + LEXER::GetTokenText(lock_type) ); + + if( part_number.size() ) + { + const char* quote = out->GetQuoteChar( part_number.c_str() ); + out->Print( 0, "(PN %s%s%s)", + quote, part_number.c_str(), quote ); + } + } + + out->Print( 0, ")\n" ); } diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index aaa468ef38..7cf4faff71 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -616,49 +616,6 @@ public: }; -#if 0 -class PLACE_RULE : public RULE -{ - friend class SPECCTRA_DB; - - DSN_T object_type; - DSN_T image_type; - - /* T_spacing, T_permit_orient, T_permit_side & T_opposite_side are - all stored in the kids list. - */ - -public: - - PLACE_RULE( ELEM* aParent ) : - RULE( aParent, T_place_rule ) - { - object_type = T_NONE; - image_type = T_NONE; - } - - void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) - { - if( object_type != T_NONE ) - { - if( object_type == T_pcb ) - out->Print( nestLevel, "(object_type %s", - LEXER::GetTokenText( object_type ) ); - else - out->Print( nestLevel, "(object_type image_set %s", - LEXER::GetTokenText( object_type ) ); - - if( image_type != T_NONE ) - out->Print( 0, " (image_type %s)", LEXER::GetTokenText( image_type ) ); - out->Print( 0, ")\n" ); - } - - RULE::FormatContents( out, nestLevel ); - } -}; -#endif - - class LAYER_RULE : public ELEM { friend class SPECCTRA_DB; @@ -1680,6 +1637,10 @@ public: }; +/** + * Class PLACE + * implements the <placement_reference> in the specctra dsn spec. + */ class PLACE : public ELEM { friend class SPECCTRA_DB; @@ -1688,7 +1649,6 @@ class PLACE : public ELEM DSN_T side; - bool isRotated; double rotation; bool hasVertex; @@ -1718,7 +1678,9 @@ public: ELEM( T_place, aParent ) { side = T_front; - isRotated = false; + + rotation = 0.0; + hasVertex = false; mirror = T_NONE; @@ -1740,26 +1702,31 @@ public: void SetVertex( const POINT& aVertex ) { vertex = aVertex; + vertex.FixNegativeZero(); hasVertex = true; } void SetRotation( double aRotation ) { rotation = aRotation; - isRotated = (aRotation != 0.0); } void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ); }; +typedef boost::ptr_vector PLACES; +/** + * Class COMPONENT + * implements the <component_descriptor> in the specctra dsn spec. + */ class COMPONENT : public ELEM { friend class SPECCTRA_DB; + +// std::string hash; ///< a hash string used by Compare(), not Format()ed/exported. std::string image_id; - - typedef boost::ptr_vector PLACES; PLACES places; public: @@ -1768,17 +1735,35 @@ public: { } + const std::string& GetImageId() const { return image_id; } + void SetImageId( const std::string& aImageId ) + { + image_id = aImageId; + } + + + /** + * Function Compare + * compares two objects of this type and returns <0, 0, or >0. + */ +// static int Compare( IMAGE* lhs, IMAGE* rhs ); + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) { const char* quote = out->GetQuoteChar( image_id.c_str() ); out->Print( nestLevel, "(%s %s%s%s\n", LEXER::GetTokenText( Type() ), quote, image_id.c_str(), quote ); - - for( PLACES::iterator i=places.begin(); i!=places.end(); ++i ) - i->Format( out, nestLevel+1 ); + FormatContents( out, nestLevel+1 ); + out->Print( nestLevel, ")\n" ); } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) + { + for( PLACES::iterator i=places.begin(); i!=places.end(); ++i ) + i->Format( out, nestLevel ); + } }; @@ -1805,6 +1790,27 @@ public: { delete unit; } + + /** + * Function LookupCOMPONENT + * looks up a COMPONENT by name. If the name is not found, a new + * COMPONENT is added to the components container. At any time the + * names in the component container should remain unique. + * @return COMPONENT* - an existing or new + */ + COMPONENT* LookupCOMPONENT( const std::string& imageName ) + { + for( unsigned i=0; iSetImageId( imageName ); + return added; + } void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) { @@ -2111,7 +2117,7 @@ public: // format the kids, which in this class are the shapes ELEM_HOLDER::FormatContents( out, nestLevel ); - out->Print( nestLevel+1, "%s", "" ); + out->Print( nestLevel, "%s", "" ); // spec for says default is on, so // print the off condition to override this. @@ -2193,6 +2199,12 @@ public: return via_start_index; } + + /** + * Function FindIMAGE + * searches this LIBRARY for an image which matches the argument. + * @return int - if found the index into the images list, else -1. + */ int FindIMAGE( IMAGE* aImage ) { for( unsigned i=0; iSetParent( this ); images.push_back( aImage ); } - - bool LookupIMAGE( IMAGE* aImage ) + + /** + * Function LookupIMAGE + * will add the image only if one exactly like it does not alread exist + * in the image list. + * @return IMAGE* - the IMAGE which is registered in the LIBRARY that + * matches the argument, and it will be either the argument or + * a previous image which is a duplicate. + */ + IMAGE* LookupIMAGE( IMAGE* aImage ) { int ndx = FindIMAGE( aImage ); if( ndx == -1 ) { AppendIMAGE( aImage ); - return false; + return aImage; } - return true; + return &images[ndx]; } void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index 3bbc0d8937..4fdda7fa98 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -76,11 +76,11 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event ) // if an exception is thrown by FromBOARD or ExportPCB(), then // ~SPECCTRA_DB() will close the file. } - catch ( IOError ioe ) + catch( IOError ioe ) { ok = false; - // display no messages until we flip back the modules below. + // copy the error string to safe place, ioe is in this scope only. errorText = ioe.errorText; } @@ -112,6 +112,11 @@ static inline void swap( POINT_PAIR& pair ) } +/** + * Function scale + * converts a distance from kicad units to our reported specctra dsn units: + * 1/10000 inches (deci-mils) to mils. So the factor of 10 comes in. + */ static inline double scale( int kicadDist ) { return kicadDist/10.0; @@ -139,6 +144,7 @@ static POINT mapPt( const wxPoint& pt ) POINT ret; ret.x = mapX( pt.x ); ret.y = mapY( pt.y ); + ret.FixNegativeZero(); return ret; } @@ -238,32 +244,55 @@ static QARC* makeArc( const POINT& aStart, const POINT& aEnd, IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) { - TYPE_COLLECTOR items; - - static const KICAD_T scanPADs[] = { TYPEPAD, EOT }; - PADSTACKS& padstacks = pcb->library->padstacks; + TYPE_COLLECTOR pads; + static const KICAD_T scanPADs[] = { TYPEPAD, EOT }; + // get all the MODULE's pads. - items.Collect( aModule, scanPADs ); + pads.Collect( aModule, scanPADs ); - IMAGE* image = new IMAGE( 0 ); + IMAGE* image = new IMAGE(0); image->image_id = CONV_TO_UTF8( aModule->m_LibRef ); - // collate all the pads, and make a component. - for( int p=0; pm_logical_connexion]; - - PIN* pin = new PIN(image); - image->pins.push_back( pin ); - - pin->padstack_id = padstack->padstack_id; - pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); - pin->SetVertex( mapPt( pad->m_Pos0 ) ); + // see if this pad is a through hole with no copper on its perimeter + if( !pad->IsOnLayer( LAYER_CMP_N ) && !pad->IsOnLayer( COPPER_LAYER_N ) ) + { + if( pad->m_Drill.x!=0 ) + { + KEEPOUT* keepout = new KEEPOUT(image, T_keepout); + image->keepouts.push_back( keepout ); + + WINDOW* window = new WINDOW(keepout); + keepout->windows.push_back( window ); + + CIRCLE* circle = new CIRCLE(window); + window->SetShape( circle ); + + circle->SetDiameter( scale(pad->m_Drill.x) ); + circle->SetVertex( POINT( mapPt( pad->m_Pos0 ) ) ); + circle->layer_id = "signal"; + + // ?? the keepout is not affecting the power layers? + } + } + else + { + PADSTACK* padstack = &padstacks[pad->m_logical_connexion]; + + PIN* pin = new PIN(image); + image->pins.push_back( pin ); + + pin->padstack_id = padstack->padstack_id; + pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); + pin->SetVertex( mapPt( pad->m_Pos0 ) ); + } } return image; @@ -562,7 +591,8 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) } } - // unique pads are now in the padstack. next we add the via's which may be used. + // unique pads are now in the padstack list. + // next we add the via's which may be used. int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize; if( defaultViaSize ) @@ -636,6 +666,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) } } + // a space in a quoted token is NOT a terminator, true establishes this. + pcb->parser->space_in_quoted_tokens = true; //----- & -------------------- { @@ -648,7 +680,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) //----------------------------------------------- { // get all the DRAWSEGMENTS into 'items', then look for layer == EDGE_N, - // and those segments comprize the board's perimeter. + // and those segments comprise the board's perimeter. static const KICAD_T scanDRAWSEGMENTS[] = { TYPEDRAWSEGMENT, EOT }; items.Collect( aBoard, scanDRAWSEGMENTS ); @@ -725,8 +757,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) bottomRight.x = aBoard->m_BoundaryBox.GetRight(); bottomRight.y = aBoard->m_BoundaryBox.GetBottom(); - rect->point0 = mapPt( aBoard->m_BoundaryBox.GetOrigin() ); - rect->point1 = mapPt( bottomRight ); + rect->SetCorners( mapPt( aBoard->m_BoundaryBox.GetOrigin() ), + mapPt( bottomRight ) ); boundary->rectangle = rect; @@ -808,7 +840,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) } - //--------------------------------------------------- + //-------------------------------------- { static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT }; items.Collect( aBoard, scanMODULEs ); @@ -819,10 +851,29 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) IMAGE* image = makeIMAGE( module ); - if( pcb->library->LookupIMAGE( image ) ) + IMAGE* registered = pcb->library->LookupIMAGE( image ); + if( registered != image ) { + // If our new 'image' is not a unique IMAGE, delete it. + // In either case, 'registered' is the one we'll work with henceforth. delete image; } + + const std::string& imageId = registered->image_id; + + COMPONENT* comp = pcb->placement->LookupCOMPONENT( imageId ); + + PLACE* place = new PLACE( comp ); + comp->places.push_back( place ); + + place->SetRotation( module->m_Orient/10.0 ); + place->SetVertex( mapPt( module->m_Pos ) ); + place->component_id = CONV_TO_UTF8( module->GetReference() ); + place->part_number = CONV_TO_UTF8( module->GetValue() ); + + // module is flipped from bottom side, set side to T_back + if( module->flag ) + place->side = T_back; } } @@ -844,6 +895,44 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) } + //----------------------------------------------------- + { + NETWORK* network = pcb->network; + static const KICAD_T scanNETs[] = { PCB_EQUIPOT_STRUCT_TYPE, EOT }; + + items.Collect( aBoard, scanNETs ); + + PIN_REF emptypin(0); + + for( int i=0; inets.push_back( net ); + + net->net_id = CONV_TO_UTF8( kinet->m_Netname ); + net->net_number = kinet->GetNet(); + + D_PAD** ppad = kinet->m_PadzoneStart; + for( ; ppad < kinet->m_PadzoneEnd; ++ppad ) + { + D_PAD* pad = *ppad; + + wxASSERT( pad->Type() == TYPEPAD ); + + // push on an empty one, then fill it via 'pin_ref' + net->pins.push_back( emptypin ); + PIN_REF* pin_ref = &net->pins.back(); + + pin_ref->SetParent( net ); + pin_ref->component_id = CONV_TO_UTF8( ((MODULE*)pad->m_Parent)->GetReference() );; + pin_ref->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); + } + } + } + + //----------------------------------------------------- // DSN Images (=Kicad MODULES and pads) must be presented from the