From 67ebe29b60fd2d4345602aac9ebf679d27aca771 Mon Sep 17 00:00:00 2001 From: dickelbeck Date: Tue, 29 Jan 2008 16:45:14 +0000 Subject: [PATCH] more free specctra work --- change_log.txt | 2 - pcbnew/specctra.cpp | 160 +++++++++++++-- pcbnew/specctra.h | 404 ++++++++++++++++++++++++++++--------- pcbnew/specctra_export.cpp | 153 ++++++++------ 4 files changed, 546 insertions(+), 173 deletions(-) diff --git a/change_log.txt b/change_log.txt index 451ac85baa..091fe06074 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,5 +1,4 @@ - Change Log for Kicad Started 2007-June-11 @@ -16,7 +15,6 @@ email address. the new track takes the width of the existing track - 2008-Jan-27 UPDATE Dick Hollenbeck ================================================================================ +all: diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp index a458aa33f5..914e8037f9 100644 --- a/pcbnew/specctra.cpp +++ b/pcbnew/specctra.cpp @@ -55,6 +55,8 @@ #include +// 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" @@ -861,24 +863,32 @@ void SPECCTRA_DB::doWINDOW( WINDOW* growth ) throw( IOError ) switch( tok ) { case T_rect: - growth->rectangle = new RECTANGLE( growth ); - doRECTANGLE( growth->rectangle ); + if( growth->shape ) + unexpected( tok ); + growth->shape = new RECTANGLE( growth ); + doRECTANGLE( (RECTANGLE*) growth->shape ); break; case T_circle: - growth->circle = new CIRCLE( growth ); - doCIRCLE( growth->circle ); + if( growth->shape ) + unexpected( tok ); + growth->shape = new CIRCLE( growth ); + doCIRCLE( (CIRCLE*) growth->shape ); break; case T_path: case T_polygon: - growth->path = new PATH( growth, tok ); - doPATH( growth->path ); + if( growth->shape ) + unexpected( tok ); + growth->shape = new PATH( growth, tok ); + doPATH( (PATH*) growth->shape ); break; case T_qarc: - growth->qarc = new QARC( growth ); - doQARC( growth->qarc ); + if( growth->shape ) + unexpected( tok ); + growth->shape = new QARC( growth ); + doQARC( (QARC*) growth->shape ); break; default: @@ -3353,18 +3363,19 @@ int SPECCTRA_DB::Print( int nestLevel, const char* fmt, ... ) throw( IOError ) return total; } +// factor out a common GetQuoteChar -const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) +const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char ) { // I include '#' so a symbol is not confused with a comment. We intend // to wrap any symbol starting with a '#'. // Our LEXER class handles comments, and comments appear to be an extension // to the SPECCTRA DSN specification. if( *wrapee == '#' ) - return quote_char.c_str(); + return quote_char; if( strlen(wrapee)==0 ) - return quote_char.c_str(); + return quote_char; bool isNumber = true; @@ -3373,19 +3384,25 @@ const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) // if the string to be wrapped (wrapee) has a delimiter in it, // return the quote_char so caller wraps the wrapee. if( strchr( "\t ()", *wrapee ) ) - return quote_char.c_str(); + return quote_char; if( !strchr( "01234567890.-+", *wrapee ) ) isNumber = false; } if( isNumber ) - return quote_char.c_str(); + return quote_char; return ""; // can use an unwrapped string. } +const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) +{ + return OUTPUTFORMATTER::GetQuoteChar( wrapee, quote_char.c_str() ); +} + + void SPECCTRA_DB::ExportPCB( wxString filename, bool aNameChange ) throw( IOError ) { fp = wxFopen( filename, wxT("w") ); @@ -3438,6 +3455,8 @@ PCB* SPECCTRA_DB::MakePCB() pcb->structure = new STRUCTURE( pcb ); pcb->structure->boundary = new BOUNDARY( pcb->structure ); + pcb->structure->via = new VIA( pcb->structure ); + pcb->structure->rules = new RULE( pcb->structure, T_rule ); pcb->placement = new PLACEMENT( pcb ); @@ -3451,6 +3470,87 @@ PCB* SPECCTRA_DB::MakePCB() } +//--------------------------------------------------------- + +const char* STRINGFORMATTER::GetQuoteChar( const char* wrapee ) +{ + // for what we are using STRINGFORMATTER for at this time, we can return the nul string + // always. + + return ""; +// return OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, "\"" ); +} + +int STRINGFORMATTER::vprint( const char* fmt, va_list ap ) +{ + int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap ); + if( ret >= (int) buffer.size() ) + { + buffer.reserve( ret+200 ); + ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap ); + } + + if( ret > 0 ) + mystring.append( (const char*) &buffer[0] ); + + return ret; +} + + +int STRINGFORMATTER::sprint( const char* fmt, ... ) +{ + va_list args; + + va_start( args, fmt ); + int ret = vprint( fmt, args); + va_end( args ); + + return ret; +} + + +int STRINGFORMATTER::Print( int nestLevel, const char* fmt, ... ) throw( IOError ) +{ + va_list args; + + va_start( args, fmt ); + + int result = 0; + int total = 0; + + for( int i=0; i--------------------------------------------------------------- ELEM::ELEM( DSN_T aType, ELEM* aParent ) : @@ -3500,8 +3600,40 @@ int ELEM_HOLDER::FindElem( DSN_T aType, int instanceNum ) } -//---------------------------------------------------------------- +//-------------------------------------------------------------- +int PADSTACK::Compare( PADSTACK* lhs, PADSTACK* 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; +} + + +//----------------------------------------------------------------- + +int IMAGE::Compare( IMAGE* lhs, IMAGE* rhs ) +{ + if( !lhs->hash.size() ) + lhs->hash = lhs->makeHash(); + + if( !rhs->hash.size() ) + rhs->hash = rhs->makeHash(); + + int result = lhs->hash.compare( rhs->hash ); + + // printf("\"%s\" \"%s\" ret=%d\n", lhs->hash.c_str(), rhs->hash.c_str(), result ); + + return result; +} + + +//---------------------------------------------------------------- PARSER::PARSER( ELEM* aParent ) : ELEM( T_parser, aParent ) diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 296690be42..aaa468ef38 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -32,6 +32,8 @@ #include "fctsys.h" #include "dsn.h" +class TYPE_COLLECTOR; // outside the DSN namespace + /** @@ -101,9 +103,86 @@ public: * if the wrapee does not need to be wrapped. */ virtual const char* GetQuoteChar( const char* wrapee ) = 0; -}; - + virtual ~OUTPUTFORMATTER() {} + + /** + * Function GetQuoteChar + * factor may be used by derived classes to perform quote character selection. + * @param wrapee A string that might need wrapping on each end. + * @param quote_char A single character C string which hold the current quote character. + * @return const char* - the quote_char as a single character string, or "" + * if the wrapee does not need to be wrapped. + */ + static const char* GetQuoteChar( const char* wrapee, const char* quote_char ); +}; + + +/** + * Class STRINGFORMATTER + * implements OUTPUTFORMATTER to a memory buffer. After Print()ing the + * string is available through GetString() +*/ +class STRINGFORMATTER : public OUTPUTFORMATTER +{ + std::vector buffer; + std::string mystring; + + int sprint( const char* fmt, ... ); + int vprint( const char* fmt, va_list ap ); + +public: + + /** + * Constructor STRINGFORMATTER + * reserves space in the buffer + */ + STRINGFORMATTER( int aReserve = 300 ) : + buffer( aReserve, '\0' ) + { + } + + + /** + * Function Clear + * clears the buffer and empties the internal string. + */ + void Clear() + { + mystring.clear(); + } + + /** + * Function StripUseless + * removes whitespace, '(', and ')' from the mystring. + */ + void StripUseless(); + + /* + const char* c_str() + { + return mystring.c_str(); + } + */ + + std::string GetString() + { + return mystring; + } + + + //----------------------------------------------------- + int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) throw( IOError ); + const char* GetQuoteChar( const char* wrapee ); + //---------------------------------------------------- +}; + + +/** + * Class POINT + * is a holder for a point in the SPECCTRA DSN coordinate system. It can also + * be used to hold a distance (vector really) from some origin. + */ struct POINT { double x; @@ -136,14 +215,23 @@ struct POINT 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 FixNegativeZero + * will change negative zero to positive zero in the IEEE floating point + * storage format. Basically turns off the sign bit if the mantiss and exponent + * would say the value is zero. + */ + void FixNegativeZero() + { + if( x == -0.0 ) + x = 0.0; + if( y == -0.0 ) + y = 0.0; + } /** * Function Format @@ -196,10 +284,33 @@ typedef std::vector PROPERTIES; class ELEM { friend class SPECCTRA_DB; + + protected: DSN_T type; ELEM* parent; + + + /** + * Function makeHash + * returns a string which uniquely represents this ELEM amoung other + * ELEMs of the same derived class as "this" one. + * It is not useable for all derived classes, only those which plan for + * it by implementing a FormatContents() function that captures all info + * which will be used in the subsequent string compare. THIS SHOULD + * NORMALLY EXCLUDE THE TYPENAME, AND INSTANCE NAME OR ID AS WELL. + */ + std::string makeHash() + { + STRINGFORMATTER sf; + + FormatContents( &sf, 0 ); + sf.StripUseless(); + + return sf.GetString(); + } + public: @@ -207,7 +318,7 @@ public: virtual ~ELEM(); - DSN_T Type() { return type; } + DSN_T Type() const { return type; } /** @@ -216,7 +327,7 @@ public: * to check for section specific overrides. * @return DSN_T - one of the allowed values to <unit_descriptor> */ - virtual DSN_T GetUnits() + virtual DSN_T GetUnits() const { if( parent ) return parent->GetUnits(); @@ -324,14 +435,14 @@ public: kids.insert( kids.begin()+aIndex, aElem ); } - ELEM* At( int aIndex ) + ELEM* At( int aIndex ) const { // we have varying sized objects and are using polymorphism, so we // must return a pointer not a reference. - return &kids[aIndex]; + return (ELEM*) &kids[aIndex]; } - ELEM* operator[]( int aIndex ) + ELEM* operator[]( int aIndex ) const { return At( aIndex ); } @@ -408,7 +519,7 @@ public: LEXER::GetTokenText(units), value ); } - DSN_T GetUnits() + DSN_T GetUnits() const { return units; } @@ -439,7 +550,10 @@ public: void SetCorners( const POINT& aPoint0, const POINT& aPoint1 ) { point0 = aPoint0; + point0.FixNegativeZero(); + point1 = aPoint1; + point1.FixNegativeZero(); } void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) @@ -581,7 +695,6 @@ public: out->Print( nestLevel, ")\n" ); } }; - typedef boost::ptr_vector LAYER_RULES; @@ -780,15 +893,21 @@ public: } void SetStart( const POINT& aStart ) { - vertex[0] = aStart; + vertex[0] = aStart; + // no -0.0 on the printouts! + vertex[0].FixNegativeZero(); } void SetEnd( const POINT& aEnd ) { vertex[1] = aEnd; + // no -0.0 on the printouts! + vertex[1].FixNegativeZero(); } void SetCenter( const POINT& aCenter ) { vertex[2] = aCenter; + // no -0.0 on the printouts! + vertex[2].FixNegativeZero(); } }; @@ -797,49 +916,53 @@ class WINDOW : public ELEM { friend class SPECCTRA_DB; - //----- only one of these is used, like a union ----- +protected: + /* shape holds one of these PATH* path; ///< used for both path and polygon RECTANGLE* rectangle; CIRCLE* circle; QARC* qarc; - //--------------------------------------------------- - + */ + ELEM* shape; + public: - WINDOW( ELEM* aParent ) : - ELEM( T_window, aParent ) + WINDOW( ELEM* aParent, DSN_T aType = T_window ) : + ELEM( aType, aParent ) { - path = 0; - rectangle = 0; - circle = 0; - qarc = 0; + shape = 0; } ~WINDOW() { - delete path; - delete rectangle; - delete circle; - delete qarc; + delete shape; } - - void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) - { - // these are mutually exclusive - if( rectangle ) - rectangle->Format( out, nestLevel ); - - else if( path ) - path->Format( out, nestLevel ); - - else if( circle ) - circle->Format( out, nestLevel ); - else if( qarc ) - qarc->Format( out, nestLevel ); + 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 Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) + { + out->Print( nestLevel, "(%s ", LEXER::GetTokenText( Type() ) ); + + if( shape ) + shape->Format( out, 0 ); + + out->Print( 0, ")\n" ); } }; - typedef boost::ptr_vector WINDOWS; @@ -956,6 +1079,11 @@ public: ELEM( T_via, aParent ) { } + + void AppendVia( const char* aViaName ) + { + padstacks.push_back( aViaName ); + } void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) { @@ -1217,13 +1345,13 @@ public: layer_weight ); } }; +typedef boost::ptr_vector LAYER_PAIRS; class LAYER_NOISE_WEIGHT : public ELEM { friend class SPECCTRA_DB; - typedef boost::ptr_vector LAYER_PAIRS; LAYER_PAIRS layer_pairs; public: @@ -1542,7 +1670,7 @@ public: i->Format( out, nestLevel ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -1693,7 +1821,7 @@ public: i->Format( out, nestLevel ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -1710,7 +1838,7 @@ public: * elements contains, i.e. in its "shape" field. This class also implements * the "(outline ...)" element as a dual personality. */ -class SHAPE : public ELEM +class SHAPE : public WINDOW { friend class SPECCTRA_DB; @@ -1722,38 +1850,18 @@ class SHAPE : public ELEM | | ] + ELEM* shape; // inherited from WINDOW */ - ELEM* shape; - + WINDOWS windows; public: SHAPE( ELEM* aParent, DSN_T aType = T_shape ) : - ELEM( aType, aParent ) + WINDOW( aParent, aType ) { 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 SetConnect( DSN_T aConnect ) { connect = aConnect; @@ -1808,6 +1916,12 @@ public: isRotated = (aRotation != 0.0); } + void SetVertex( const POINT& aPoint ) + { + vertex = aPoint; + vertex.FixNegativeZero(); + } + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) { const char* quote = out->GetQuoteChar( padstack_id.c_str() ); @@ -1830,6 +1944,8 @@ class IMAGE : public ELEM_HOLDER { friend class SPECCTRA_DB; + std::string hash; ///< a hash string used by Compare(), not Format()ed/exported. + std::string image_id; DSN_T side; UNIT_RES* unit; @@ -1864,42 +1980,53 @@ public: delete place_rules; } - + /** + * 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", LEXER::GetTokenText( Type() ), quote, image_id.c_str(), quote ); + + FormatContents( out, nestLevel+1 ); + out->Print( nestLevel, ")\n" ); + } + + // this is here for makeHash() + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) + { if( side != T_both ) out->Print( 0, " (side %s)", LEXER::GetTokenText( side ) ); out->Print( 0, "\n"); if( unit ) - unit->Format( out, nestLevel+1 ); + unit->Format( out, nestLevel ); // format the kids, which in this class are the shapes - ELEM_HOLDER::FormatContents( out, nestLevel+1 ); + ELEM_HOLDER::FormatContents( out, nestLevel ); for( PINS::iterator i=pins.begin(); i!=pins.end(); ++i ) - i->Format( out, nestLevel+1 ); + i->Format( out, nestLevel ); if( rules ) - rules->Format( out, nestLevel+1 ); + rules->Format( out, nestLevel ); if( place_rules ) - place_rules->Format( out, nestLevel+1 ); + place_rules->Format( out, nestLevel ); for( KEEPOUTS::iterator i=keepouts.begin(); i!=keepouts.end(); ++i ) - i->Format( out, nestLevel+1 ); - - out->Print( nestLevel, ")\n" ); + i->Format( out, nestLevel ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -1907,12 +2034,20 @@ public: return ELEM::GetUnits(); } }; +typedef boost::ptr_vector IMAGES; +/** + * Class PADSTACK + * holds either a via or a pad definition. + */ class PADSTACK : public ELEM_HOLDER { friend class SPECCTRA_DB; + std::string hash; ///< a hash string used by Compare(), not Format()ed/exported. + + std::string padstack_id; UNIT_RES* unit; @@ -1942,6 +2077,13 @@ public: delete rules; } + + /** + * Function Compare + * compares two objects of this type and returns <0, 0, or >0. + */ + static int Compare( PADSTACK* lhs, PADSTACK* rhs ); + void SetPadstackId( const char* aPadstackId ) { padstack_id = aPadstackId; @@ -1954,11 +2096,20 @@ public: out->Print( nestLevel, "(%s %s%s%s\n", LEXER::GetTokenText( Type() ), quote, padstack_id.c_str(), quote ); + FormatContents( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + + + // this factored out for use by Compare() + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) + { if( unit ) - unit->Format( out, nestLevel+1 ); + unit->Format( out, nestLevel ); // format the kids, which in this class are the shapes - ELEM_HOLDER::FormatContents( out, nestLevel+1 ); + ELEM_HOLDER::FormatContents( out, nestLevel ); out->Print( nestLevel+1, "%s", "" ); @@ -1982,12 +2133,11 @@ public: out->Print( 0, "\n" ); if( rules ) - rules->Format( out, nestLevel+1 ); - - out->Print( nestLevel, ")\n" ); + rules->Format( out, nestLevel ); } + - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -2007,25 +2157,68 @@ typedef boost::ptr_vector PADSTACKS; class LIBRARY : public ELEM { friend class SPECCTRA_DB; - - UNIT_RES* unit; - typedef boost::ptr_vector IMAGES; + UNIT_RES* unit; IMAGES images; - PADSTACKS padstacks; + /// The start of the vias within the padstacks, which trail the pads. + /// This field is not Format()ed. + int via_start_index; + public: LIBRARY( ELEM* aParent, DSN_T aType = T_library ) : ELEM( aType, aParent ) { unit = 0; + via_start_index = -1; // 0 or greater means there is at least one via } ~LIBRARY() { delete unit; } + + void AddPadstack( PADSTACK* aPadstack ) + { + padstacks.push_back( aPadstack ); + } + + void SetViaStartIndex( int aIndex ) + { + via_start_index = aIndex; + } + int GetViaStartIndex() + { + return via_start_index; + } + + int FindIMAGE( IMAGE* aImage ) + { + for( unsigned i=0; iSetParent( this ); + images.push_back( aImage ); + } + + bool LookupIMAGE( IMAGE* aImage ) + { + int ndx = FindIMAGE( aImage ); + if( ndx == -1 ) + { + AppendIMAGE( aImage ); + return false; + } + return true; + } void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) { @@ -2039,18 +2232,13 @@ public: i->Format( out, nestLevel ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); return ELEM::GetUnits(); } - - void AddPadstack( PADSTACK* aPadstack ) - { - padstacks.push_back( aPadstack ); - } }; @@ -2422,6 +2610,8 @@ public: class CONNECT : public ELEM { + // @todo not completed. + public: CONNECT( ELEM* parent ) : ELEM( T_connect, parent ) {} @@ -2695,7 +2885,7 @@ public: i->Format( out, nestLevel ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -2780,7 +2970,7 @@ public: out->Print( nestLevel, ")\n" ); } - DSN_T GetUnits() + DSN_T GetUnits() const { if( unit ) return unit->GetUnits(); @@ -3179,6 +3369,8 @@ class SPECCTRA_DB : public OUTPUTFORMATTER wxString filename; std::string quote_char; + + STRINGFORMATTER sf; /** @@ -3321,6 +3513,22 @@ class SPECCTRA_DB : public OUTPUTFORMATTER void doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IOError ); + /** + * Function makeIMAGE + * allocates an IMAGE on the heap and creates all the PINs according + * to the PADs in the MODULE. + */ + IMAGE* makeIMAGE( MODULE* aModule ); + + + /** + * Function makePADSTACKs + * makes all the PADSTACKs, and marks each D_PAD with the index into the + * LIBRARY::padstacks list that it matches. + */ + void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ); + + public: SPECCTRA_DB() @@ -3332,7 +3540,7 @@ public: quote_char += '"'; } - ~SPECCTRA_DB() + virtual ~SPECCTRA_DB() { delete lexer; delete pcb; diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index 841aaf3a9a..3bbc0d8937 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -234,14 +234,43 @@ static QARC* makeArc( const POINT& aStart, const POINT& aEnd, qarc->SetLayerId( aLayerName.c_str() ); return qarc; } - -/** - * 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 ) + +IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) +{ + TYPE_COLLECTOR items; + + static const KICAD_T scanPADs[] = { TYPEPAD, EOT }; + + PADSTACKS& padstacks = pcb->library->padstacks; + + // get all the MODULE's pads. + items.Collect( aModule, scanPADs ); + + 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 ) ); + } + + return image; +} + + +void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) { char name[80]; // padstack name builder @@ -251,7 +280,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra } D_PAD* old_pad = NULL; - int padstackNdx = 0; #define COPPER_LAYERS 2 // top and bottom @@ -262,7 +290,7 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra // within a pad's 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. + // See bottom of page 74 of the SECCTRA Design Language Reference, May 2000. std::string layerId[COPPER_LAYERS] = { CONV_TO_UTF8(aBoard->GetLayerName( LAYER_CMP_N )), @@ -270,8 +298,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra }; #if 1 - // late breaking news, we can use "signal" as the layer name and report the - // padstack as a single layer. +// Late breaking news: we can use the reserved layer name "signal" and report the + // padstack as a single layer. See in the spec. + // But this probably gives problems for a "power" layer or power pin, we'll see. reportedLayers = 1; layerId[0] = "signal"; #endif @@ -280,8 +309,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra { D_PAD* pad = (D_PAD*) aPads[i]; - pad->m_logical_connexion = padstackNdx; - bool doLayer[COPPER_LAYERS] = { pad->IsOnLayer( LAYER_CMP_N ), pad->IsOnLayer( COPPER_LAYER_N ) @@ -289,6 +316,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra if( old_pad && 0==D_PAD::Compare( old_pad, pad ) ) { + // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks + pad->m_logical_connexion = pcb->library->padstacks.size()-1; + + // this is the same as the last pad, so do not add it to the padstack list. continue; } @@ -296,6 +327,9 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra // an "image->keepout" later. No copper pad here, it is probably a hole. if( !doLayer[0] && !doLayer[1] ) { + // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks + pad->m_logical_connexion = pcb->library->padstacks.size()-1; + continue; } @@ -305,11 +339,11 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra old_pad = pad; - // this is the index into the library->padstacks, be careful. - pad->m_logical_connexion = padstackNdx++; - - PADSTACK* padstack = new PADSTACK( aLibrary ); - aLibrary->AddPadstack( padstack ); + PADSTACK* padstack = new PADSTACK( pcb->library ); + pcb->library->AddPadstack( padstack ); + + // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks + pad->m_logical_connexion = pcb->library->padstacks.size()-1; // paddOfset is the offset of copper shape relative to hole position, // and pad->m_Pos is hole position. All shapes must be shifted by @@ -331,12 +365,10 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra { if( doLayer[layer] ) { - CIRCLE* circle; SHAPE* shape = new SHAPE( padstack ); - padstack->Append( shape ); - circle = new CIRCLE( shape ); + CIRCLE* circle = new CIRCLE( shape ); shape->SetShape( circle ); circle->SetLayerId( layerId[layer].c_str() ); @@ -347,7 +379,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra } 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 @@ -536,9 +567,13 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize; if( defaultViaSize ) { - PADSTACK* padstack = new PADSTACK( aLibrary ); - aLibrary->AddPadstack( padstack ); - padstackNdx++; // remember this index, it is the default via + PADSTACK* padstack = new PADSTACK( pcb->library ); + pcb->library->AddPadstack( padstack ); + + // remember this index, it is the default via and also the start of the + // vias within the padstack list. Before this index are the pads. + // At this index and later are the vias. + pcb->library->SetViaStartIndex( pcb->library->padstacks.size()-1 ); SHAPE* shape = new SHAPE( padstack ); padstack->Append( shape ); @@ -560,9 +595,8 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra if( viaSize == defaultViaSize ) continue; - PADSTACK* padstack = new PADSTACK( aLibrary ); - aLibrary->AddPadstack( padstack ); - padstackNdx++; // remember this index, it is the default via + PADSTACK* padstack = new PADSTACK( pcb->library ); + pcb->library->AddPadstack( padstack ); SHAPE* shape = new SHAPE( padstack ); padstack->Append( shape ); @@ -575,10 +609,6 @@ static void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads, LIBRARY* aLibra snprintf( name, sizeof(name), "Via_%.6g_mil", scale(viaSize) ); 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 ); } } @@ -593,7 +623,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) 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. @@ -661,8 +690,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) rect->layer_id = "pcb"; // opposite corners - rect->point0 = ppairs[0].p1; - rect->point1 = ppairs[2].p1; + rect->SetCorners( ppairs[0].p1, ppairs[2].p1 ); boundary->rectangle = rect; } @@ -763,55 +791,61 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) // but in that case they are WINDOWs within the COPPER_PLANEs. - //----------------------------- + //------------------------------------- { - static const KICAD_T scanPADs[] = { TYPEPAD, EOT }; - TYPE_COLLECTOR pads; - - // get all the D_PADs into pads. + static const KICAD_T scanPADs[] = { TYPEPAD, EOT }; + + // get all the D_PADs into 'pads'. pads.Collect( aBoard, scanPADs ); - makePADSTACKs( aBoard, pads, pcb->library ); - + makePADSTACKs( aBoard, pads ); #if 0 && defined(DEBUG) for( int p=0; pShow( 0, std::cout ); #endif } - - //------------------------------------------------------ - { - // Output the vias in the padstack list here, by name - } + //--------------------------------------------------- { -/* static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT }; - items.Collect( aBoard, scanMODULEs ); - + for( int m=0; mlibrary->LookupIMAGE( image ) ) { - 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 ); + delete image; } } -*/ } + //------------------------------------------------------ + { + // Output the vias in the padstack list here, by name + VIA* vias = pcb->structure->via; + PADSTACKS& padstacks = pcb->library->padstacks; + int viaNdx = pcb->library->via_start_index; + + if( viaNdx != -1 ) + { + for( ; viaNdx < (int)padstacks.size(); ++viaNdx ) + { + vias->AppendVia( padstacks[viaNdx].padstack_id.c_str() ); + } + } + } + + + //----------------------------------------------------- + // 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() ) @@ -822,6 +856,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) module->flag = 0; } } + }