From 709be4951855fe9d265e9835397a9ad4fe96b443 Mon Sep 17 00:00:00 2001 From: dickelbeck Date: Thu, 14 Feb 2008 01:07:52 +0000 Subject: [PATCH] more amazing free specctra work --- change_log.txt | 28 +- pcbnew/class_board_item.cpp | 95 ++-- pcbnew/specctra.cpp | 158 +++++-- pcbnew/specctra.h | 113 ++++- pcbnew/specctra_export.cpp | 844 ++++++++++++++++++------------------ 5 files changed, 685 insertions(+), 553 deletions(-) diff --git a/change_log.txt b/change_log.txt index 80f748f83c..b69eb0a364 100644 --- a/change_log.txt +++ b/change_log.txt @@ -5,20 +5,29 @@ Started 2007-June-11 Please add newer entries at the top, list the date and your name with email address. +2008-Feb-13 UPDATE Dick Hollenbeck +================================================================================ ++pcbnew + specctra export: now generate unique pin names from module padnames in the + case where there are non-unique pad names within a module. Tested with + Electra demo, and *.dsn files load OK in there as well as in freerouter. + Stopped using reserved layer name "signal" and instead output a full + padstack consisting of all pertinent layers for via, pads, and keepouts. + 2008-Feb-12 UPDATE Tim Hanson sideskate@gmail.com ================================================================================ +eeschema - * commiting my changes to allow multiple instances of a given schematic file within a hierarchy: - ** internally, m_currentScreen has been replaced with m_currentSheet, - which is a list or 'path' of screens. The path of screens is used to generate - a series of timestamps, which is converted to flat component reference via a look-up - table in the schematic files. - ** this means that m_currentScreen is no longer used -- use GetScreen(). - ** GetScreen is virtual, as some of the dialogs keep around a WinEDA_BaseScreen pointer. - ** all sub-sheets in a given schematic must have different names to generate a meaningful netlist. + * commiting my changes to allow multiple instances of a given schematic file within a hierarchy: + ** internally, m_currentScreen has been replaced with m_currentSheet, + which is a list or 'path' of screens. The path of screens is used to generate + a series of timestamps, which is converted to flat component reference via a look-up + table in the schematic files. + ** this means that m_currentScreen is no longer used -- use GetScreen(). + ** GetScreen is virtual, as some of the dialogs keep around a WinEDA_BaseScreen pointer. + ** all sub-sheets in a given schematic must have different names to generate a meaningful netlist. + -======= 2008-Feb-12 UPDATE Igor Plyatov ================================================================================ +eeschema @@ -26,6 +35,7 @@ email address. +all Russian translation update. + 2008-Feb-11 UPDATE Dick Hollenbeck ================================================================================ +pcbnew diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp index fc28512721..17b4eab527 100644 --- a/pcbnew/class_board_item.cpp +++ b/pcbnew/class_board_item.cpp @@ -27,7 +27,7 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const wxString text, msg; const BOARD_ITEM* item = this; EQUIPOT* net; - D_PAD * pad; + D_PAD * pad; switch( item->Type() ) { @@ -42,17 +42,17 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const break; case TYPEPAD: - pad = (D_PAD *) this; + pad = (D_PAD *) this; text << _( "Pad" ) << wxT( " \"" ) << pad->ReturnStringPadName() - << wxT( "\" (" ); - if ( (pad->m_Masque_Layer & ALL_CU_LAYERS) == ALL_CU_LAYERS ) - text << _("all copper layers"); - else if( (pad->m_Masque_Layer & CUIVRE_LAYER) == CUIVRE_LAYER ) - text << _("copper layer"); - else if( (pad->m_Masque_Layer & CMP_LAYER) == CMP_LAYER ) - text << _("cmp layer"); - else text << _("???"); - text << _( ") of " ) << ( (MODULE*) GetParent() )->GetReference(); + << wxT( "\" (" ); + if ( (pad->m_Masque_Layer & ALL_CU_LAYERS) == ALL_CU_LAYERS ) + text << _("all copper layers"); + else if( (pad->m_Masque_Layer & CUIVRE_LAYER) == CUIVRE_LAYER ) + text << _("copper layer"); + else if( (pad->m_Masque_Layer & CMP_LAYER) == CMP_LAYER ) + text << _("cmp layer"); + else text << _("???"); + text << _( ") of " ) << ( (MODULE*) GetParent() )->GetReference(); break; case TYPEDRAWSEGMENT: @@ -89,7 +89,7 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const break; case TYPEEDGEMODULE: - { + { text << _( "Graphic" ) << wxT( " " ); wxString cp; @@ -129,23 +129,23 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const text << cp; text << wxT( " (" ) << ReturnPcbLayerName( ((EDGE_MODULE*) item )->m_Layer ).Trim() << wxT( ")" ); - text << _( " of " ) + text << _( " of " ) << ( (MODULE*) GetParent() )->GetReference(); break; - } + } case TYPETRACK: - // deleting tracks requires all the information we can get to + // deleting tracks requires all the information we can get to // disambiguate all the crap under the cursor! { wxString txt; - + text << _( "Track" ) << wxT( " " ) << ((TRACK*)item)->ShowWidth(); net = aPcb->FindNet( ((TRACK*)item)->GetNet() ); if( net ) { text << wxT( " [" ) << net->m_Netname << wxT( "]" ); } - text << _( " on " ) << ReturnPcbLayerName( item->GetLayer() ).Trim() + text << _( " on " ) << ReturnPcbLayerName( item->GetLayer() ).Trim() << wxT(" ") << _("Net:") << ((TRACK*)item)->GetNet() << wxT(" ") << _("Length:") << valeur_param( (int) ((TRACK*)item)->GetLength(), txt ); } @@ -153,36 +153,36 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const case TYPEZONE_CONTAINER: text = _( "Zone Outline" ); - { - ZONE_CONTAINER* area = (ZONE_CONTAINER*) this; - int ncont = area->m_Poly->GetContour(area->m_CornerSelection); - if ( ncont ) text << wxT(" ") << _("(Cutout)"); - } - text << wxT( " " ); + { + ZONE_CONTAINER* area = (ZONE_CONTAINER*) this; + int ncont = area->m_Poly->GetContour(area->m_CornerSelection); + if ( ncont ) text << wxT(" ") << _("(Cutout)"); + } + text << wxT( " " ); { wxString TimeStampText; TimeStampText.Printf( wxT( "(%8.8X)" ), item->m_TimeStamp ); text << TimeStampText; } - if ( ((ZONE_CONTAINER*) item)->GetNet() >= 0 ) - { - net = aPcb->FindNet( ( (ZONE_CONTAINER*) item )->GetNet() ); - if( net ) - { - text << wxT( " [" ) << net->m_Netname << wxT( "]" ); - } - } - else // A netcode < 0 is an error flag (Netname not found or area not initialised) - { - text << wxT( " [" ) << ( (ZONE_CONTAINER*) item )->m_Netname << wxT( "]" ); - text << wxT(" <") << _("Not Found") << wxT(">"); - } + if ( ((ZONE_CONTAINER*) item)->GetNet() >= 0 ) + { + net = aPcb->FindNet( ( (ZONE_CONTAINER*) item )->GetNet() ); + if( net ) + { + text << wxT( " [" ) << net->m_Netname << wxT( "]" ); + } + } + else // A netcode < 0 is an error flag (Netname not found or area not initialised) + { + text << wxT( " [" ) << ( (ZONE_CONTAINER*) item )->m_Netname << wxT( "]" ); + text << wxT(" <") << _("Not Found") << wxT(">"); + } text << _( " on " ) << ReturnPcbLayerName( item->GetLayer() ).Trim(); - break; + break; - case TYPEZONE: - text = _( "Zone" ); - text << wxT( " " ); + case TYPEZONE: + text = _( "Zone" ); + text << wxT( " " ); { wxString TimeStampText; TimeStampText.Printf( wxT( "(%8.8X)" ), item->m_TimeStamp ); @@ -200,34 +200,35 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const { SEGVIA* via = (SEGVIA*) item; text << _( "Via" ) << wxT( " " ) << via->ShowWidth(); - - int shape = via->Shape(); + + int shape = via->Shape(); if( shape == VIA_BLIND_BURIED ) text << wxT(" ") << _( "Blind/Buried" ); else if( shape == VIA_MICROVIA ) text << wxT(" ") << _("Micro Via"); // else say nothing about normal (through) vias - + net = aPcb->FindNet( via->GetNet() ); if( net ) { text << wxT( " [" ) << net->m_Netname << wxT( "]" ); } - + text << wxChar(' ') << _("Net:") << via->GetNet(); + if( shape != VIA_THROUGH ) { // say which layers, only two for now int topLayer; int botLayer; via->ReturnLayerPair( &topLayer, &botLayer ); - text << _( " on " ) << ReturnPcbLayerName( topLayer).Trim() << wxT(" <-> ") + text << _( " on " ) << ReturnPcbLayerName( topLayer).Trim() << wxT(" <-> ") << ReturnPcbLayerName( botLayer ).Trim(); } } break; case TYPEMARKER: - text << _( "Marker" ) << wxT( " @(" ) << ((MARKER*)item)->GetPos().x + text << _( "Marker" ) << wxT( " @(" ) << ((MARKER*)item)->GetPos().x << wxT(",") << ((MARKER*)item)->GetPos().y << wxT(")"); break; @@ -236,7 +237,7 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const break; case TYPEMIRE: - valeur_param( ((MIREPCB*)item)->m_Size, msg ); + valeur_param( ((MIREPCB*)item)->m_Size, msg ); text << _( "Target" ) << _( " on " ) << ReturnPcbLayerName( item->GetLayer() ).Trim() << wxT( " " ) << _( "size" ) << wxT( " " ) << msg ; diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp index 2aaa14bea2..79b0e856ad 100644 --- a/pcbnew/specctra.cpp +++ b/pcbnew/specctra.cpp @@ -76,6 +76,7 @@ namespace DSN { //------------------------------------------------------ +#if !defined(STANDALONE) void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard ) { @@ -100,6 +101,7 @@ void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard ) layerIds.push_back( CONV_TO_UTF8( aBoard->GetLayerName( kilayer ) ) ); } } +#endif int SPECCTRA_DB::findLayerName( const std::string& aLayerName ) const @@ -183,13 +185,21 @@ void SPECCTRA_DB::needRIGHT() throw( IOError ) expecting( T_RIGHT ); } -void SPECCTRA_DB::needSYMBOL() throw( IOError ) +DSN_T SPECCTRA_DB::needSYMBOL() throw( IOError ) { DSN_T tok = nextTok(); if( !isSymbol( tok ) ) expecting( T_SYMBOL ); + return tok; } +DSN_T SPECCTRA_DB::needSYMBOLorNUMBER() throw( IOError ) +{ + DSN_T tok = nextTok(); + if( !isSymbol( tok ) && tok!=T_NUMBER ) + expecting( "symbol|number" ); + return tok; +} void SPECCTRA_DB::readCOMPnPIN( std::string* component_id, std::string* pin_id ) throw( IOError ) { @@ -467,7 +477,9 @@ void SPECCTRA_DB::doPCB( PCB* growth ) throw( IOError ) void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IOError ) { - DSN_T tok; + DSN_T tok; + std::string const1; + std::string const2; /* ::= (parser @@ -519,17 +531,19 @@ void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IOError ) break; case T_host_version: - needSYMBOL(); + needSYMBOLorNUMBER(); growth->host_version = lexer->CurText(); needRIGHT(); break; case T_constant: - needSYMBOL(); - growth->const_id1 = lexer->CurText(); - needSYMBOL(); - growth->const_id2 = lexer->CurText(); + needSYMBOLorNUMBER(); + const1 = lexer->CurText(); + needSYMBOLorNUMBER(); + const2 = lexer->CurText(); needRIGHT(); + growth->constants.push_back( const1 ); + growth->constants.push_back( const2 ); break; case T_write_resolution: // [(writee_resolution { })] @@ -710,6 +724,8 @@ void SPECCTRA_DB::doSTRUCTURE( STRUCTURE* growth ) throw(IOError) break; case T_layer_noise_weight: + if( growth->layer_noise_weight ) + unexpected( tok ); growth->layer_noise_weight = new LAYER_NOISE_WEIGHT( growth ); doLAYER_NOISE_WEIGHT( growth->layer_noise_weight ); break; @@ -755,11 +771,15 @@ L_place: break; case T_via: + if( growth->via ) + unexpected( tok ); growth->via = new VIA( growth ); doVIA( growth->via ); break; case T_control: + if( growth->control ) + unexpected( tok ); growth->control = new CONTROL( growth ); doCONTROL( growth->control ); break; @@ -772,11 +792,15 @@ L_place: break; case T_rule: + if( growth->rules ) + unexpected( tok ); growth->rules = new RULE( growth, T_rule ); doRULE( growth->rules ); break; case T_place_rule: + if( growth->place_rules ) + unexpected( tok ); growth->place_rules = new RULE( growth, T_place_rule ); doRULE( growth->place_rules ); break; @@ -2219,35 +2243,35 @@ void SPECCTRA_DB::doPIN( PIN* growth ) throw( IOError ) growth->padstack_id = lexer->CurText(); - tok = nextTok(); - if( tok == T_LEFT ) + while( (tok = nextTok()) != T_RIGHT ) { - tok = nextTok(); - if( tok != T_rotate ) - expecting( T_rotate ); + if( tok == T_LEFT ) + { + tok = nextTok(); + if( tok != T_rotate ) + expecting( T_rotate ); - if( nextTok() != T_NUMBER ) - expecting( T_NUMBER ); - growth->SetRotation( strtod( lexer->CurText(), 0 ) ); - needRIGHT(); - tok = nextTok(); + if( nextTok() != T_NUMBER ) + expecting( T_NUMBER ); + growth->SetRotation( strtod( lexer->CurText(), 0 ) ); + needRIGHT(); + } + else + { + if( !isSymbol(tok) && tok!=T_NUMBER ) + expecting( "pin_id" ); + + growth->pin_id = lexer->CurText(); + + if( nextTok() != T_NUMBER ) + expecting( T_NUMBER ); + growth->vertex.x = strtod( lexer->CurText(), 0 ); + + if( nextTok() != T_NUMBER ) + expecting( T_NUMBER ); + growth->vertex.y = strtod( lexer->CurText(), 0 ); + } } - - if( !isSymbol(tok) && tok!=T_NUMBER ) - expecting( "pin_id" ); - - growth->pin_id = lexer->CurText(); - - if( nextTok() != T_NUMBER ) - expecting( T_NUMBER ); - growth->vertex.x = strtod( lexer->CurText(), 0 ); - - if( nextTok() != T_NUMBER ) - expecting( T_NUMBER ); - growth->vertex.y = strtod( lexer->CurText(), 0 ); - - if( nextTok() != T_RIGHT ) - unexpected( lexer->CurText() ); } @@ -2286,8 +2310,8 @@ void SPECCTRA_DB::doLIBRARY( LIBRARY* growth ) throw( IOError ) case T_padstack: PADSTACK* padstack; - padstack = new PADSTACK( growth ); - growth->padstacks.push_back( padstack ); + padstack = new PADSTACK(); + growth->AddPadstack( padstack ); doPADSTACK( padstack ); break; @@ -2307,7 +2331,8 @@ void SPECCTRA_DB::doLIBRARY( LIBRARY* growth ) throw( IOError ) void SPECCTRA_DB::doNET( NET* growth ) throw( IOError ) { - DSN_T tok = nextTok(); + DSN_T tok = nextTok(); + PIN_REFS* pin_refs; /* ::= (net @@ -2358,14 +2383,38 @@ void SPECCTRA_DB::doNET( NET* growth ) throw( IOError ) case T_pins: case T_order: growth->pins_type = tok; + pin_refs = &growth->pins; + goto L_pins; + + case T_expose: + pin_refs = &growth->expose; + goto L_pins; + + case T_noexpose: + pin_refs = &growth->noexpose; + goto L_pins; + + case T_source: + pin_refs = &growth->source; + goto L_pins; + + case T_load: + pin_refs = &growth->load; + goto L_pins; + + case T_terminator: + pin_refs = &growth->terminator; + //goto L_pins; + +L_pins: { PIN_REF empty( growth ); while( (tok = nextTok()) != T_RIGHT ) { // copy the empty one, then fill its copy later thru pin_ref. - growth->pins.push_back( empty ); + pin_refs->push_back( empty ); - PIN_REF* pin_ref = &growth->pins.back(); + PIN_REF* pin_ref = &pin_refs->back(); readCOMPnPIN( &pin_ref->component_id, &pin_ref->pin_id ); } @@ -3431,7 +3480,7 @@ const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote if( strlen(wrapee)==0 ) return quote_char; - bool isNumber = true; +// bool isNumber = true; for( ; *wrapee; ++wrapee ) { @@ -3444,12 +3493,12 @@ const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote if( strchr( quoteThese, *wrapee ) ) return quote_char; - if( !strchr( "01234567890.-+", *wrapee ) ) - isNumber = false; +// if( !strchr( "01234567890.-+", *wrapee ) ) +// isNumber = false; } - if( isNumber ) - return quote_char; +// if( isNumber ) +// return quote_char; return ""; // can use an unwrapped string. } @@ -3670,6 +3719,11 @@ int ELEM_HOLDER::FindElem( DSN_T aType, int instanceNum ) return -1; } + +// a reasonably small memory price to pay for improved performance +STRINGFORMATTER ELEM::sf; + + //-------------------------------------------------------------- UNIT_RES UNIT_RES::Default( NULL, T_resolution ); @@ -3679,6 +3733,8 @@ UNIT_RES UNIT_RES::Default( NULL, T_resolution ); int PADSTACK::Compare( PADSTACK* lhs, PADSTACK* rhs ) { + // printf( "PADSTACK::Compare( %p, %p)\n", lhs, rhs ); + if( !lhs->hash.size() ) lhs->hash = lhs->makeHash(); @@ -3725,7 +3781,6 @@ int COMPONENT::Compare( COMPONENT* lhs, COMPONENT* rhs ) */ //---------------------------------------------------------------- - PARSER::PARSER( ELEM* aParent ) : ELEM( T_parser, aParent ) { @@ -3752,10 +3807,17 @@ void PARSER::FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOErro out->Print( nestLevel, "(host_cad \"%s\")\n", host_cad.c_str() ); out->Print( nestLevel, "(host_version \"%s\")\n", host_version.c_str() ); - if( const_id1.length()>0 || const_id2.length()>0 ) - out->Print( nestLevel, "(constant %c%s%c %c%s%c)\n", - string_quote, const_id1.c_str(), string_quote, - string_quote, const_id2.c_str(), string_quote ); + for( STRINGS::iterator i=constants.begin(); i!=constants.end(); ) + { + const std::string& s1 = *i++; + const std::string& s2 = *i++; + + const char* q1 = out->GetQuoteChar( s1.c_str() ); + const char* q2 = out->GetQuoteChar( s2.c_str() ); + out->Print( nestLevel, "(constant %s%s%s %s%s%s)\n", + q1, s1.c_str(), q1, + q2, s2.c_str(), q2 ); + } if( routes_include_testpoint || routes_include_guides || routes_include_image_conductor ) out->Print( nestLevel, "(routes_include%s%s%s)\n", diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 61d1d45040..9f3fc631b0 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -29,6 +29,10 @@ // see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html #include +// see http://www.boost.org/libs/ptr_container/doc/ptr_set.html +#include +#include + #include "fctsys.h" #include "dsn.h" @@ -303,14 +307,16 @@ protected: */ std::string makeHash() { - STRINGFORMATTER sf; - + sf.Clear(); FormatContents( &sf, 0 ); sf.StripUseless(); return sf.GetString(); } + // avoid creating this for every compare, make static. + static STRINGFORMATTER sf; + public: @@ -466,8 +472,8 @@ class PARSER : public ELEM bool via_rotate_first; bool generated_by_freeroute; - std::string const_id1; - std::string const_id2; + /// This holds pairs of strings, one pair for each constant definition + STRINGS constants; std::string host_cad; std::string host_version; @@ -1924,12 +1930,16 @@ class PIN : public ELEM std::string pin_id; POINT vertex; + int kiNetCode; ///< kicad netcode + + public: PIN( ELEM* aParent ) : ELEM( T_pin, aParent ) { rotation = 0.0; isRotated = false; + kiNetCode = 0; } void SetRotation( double aRotation ) @@ -1960,6 +1970,8 @@ public: vertex.x, vertex.y ); } }; +typedef boost::ptr_vector PINS; + class LIBRARY; class IMAGE : public ELEM_HOLDER @@ -1978,7 +1990,6 @@ class IMAGE : public ELEM_HOLDER the kids list. */ - typedef boost::ptr_vector PINS; PINS pins; RULE* rules; @@ -2085,7 +2096,7 @@ typedef boost::ptr_vector IMAGES; * Class PADSTACK * holds either a via or a pad definition. */ -class PADSTACK : public ELEM_HOLDER +class PADSTACK : public ELEM_HOLDER, private boost::noncopyable { friend class SPECCTRA_DB; @@ -2105,8 +2116,14 @@ class PADSTACK : public ELEM_HOLDER public: - PADSTACK( ELEM* aParent ) : - ELEM_HOLDER( T_padstack, aParent ) + /** + * Constructor PADSTACK() + * cannot take ELEM* aParent because PADSTACKSET confuses this with a + * copy constructor and causes havoc. Instead set parent with + * LIBRARY::AddPadstack() + */ + PADSTACK() : + ELEM_HOLDER( T_padstack, NULL ) { unit = 0; rotate = T_on; @@ -2131,6 +2148,7 @@ public: */ static int Compare( PADSTACK* lhs, PADSTACK* rhs ); + void SetPadstackId( const char* aPadstackId ) { padstack_id = aPadstackId; @@ -2194,6 +2212,15 @@ public: }; typedef boost::ptr_vector PADSTACKS; +/** + * Function operator<() + * is used by the PADSTACKSET boost::ptr_set below + */ +inline bool operator<( const PADSTACK& lhs, const PADSTACK& rhs ) +{ + return PADSTACK::Compare( (PADSTACK*) &lhs, (PADSTACK*) &rhs ) < 0; +} + /** * Class LIBRARY @@ -2228,6 +2255,7 @@ public: void AddPadstack( PADSTACK* aPadstack ) { + aPadstack->SetParent( this ); padstacks.push_back( aPadstack ); } @@ -2537,10 +2565,15 @@ class NET : public ELEM bool unassigned; int net_number; - DSN_T pins_type; ///< T_pins | T_order - + DSN_T pins_type; ///< T_pins | T_order, type of field 'pins' below PIN_REFS pins; + PIN_REFS expose; + PIN_REFS noexpose; + PIN_REFS source; + PIN_REFS load; + PIN_REFS terminator; + DSN_T type; ///< T_fix | T_normal DSN_T supply; ///< T_power | T_ground @@ -3525,6 +3558,9 @@ public: }; +typedef boost::ptr_set PADSTACKSET; + + /** * Class SPECCTRA_DB * holds a DSN data tree, usually coming from a DSN file. @@ -3561,6 +3597,12 @@ class SPECCTRA_DB : public OUTPUTFORMATTER static const KICAD_T scanPADs[]; + PADSTACKSET padstackset; + + /// we don't want ownership here permanently, so we don't use boost::ptr_vector + std::vector nets; + + /** * Function buildLayerMaps * creates a few data translation structures for layer name and number @@ -3612,9 +3654,20 @@ class SPECCTRA_DB : public OUTPUTFORMATTER * calls nextTok() and then verifies that the token read in * satisfies bool isSymbol(). * If not, an IOError is thrown. + * @return DSN_T - the actual token read in. * @throw IOError, if the next token does not satisfy isSymbol() */ - void needSYMBOL() throw( IOError ); + DSN_T needSYMBOL() throw( IOError ); + + /** + * Function needSYMBOLorNUMBER + * calls nextTok() and then verifies that the token read in + * satisfies bool isSymbol() or tok==T_NUMBER. + * If not, an IOError is thrown. + * @return DSN_T - the actual token read in. + * @throw IOError, if the next token does not satisfy the above test + */ + DSN_T needSYMBOLorNUMBER() throw( IOError ); /** * Function readCOMPnPIN @@ -3718,28 +3771,35 @@ class SPECCTRA_DB : public OUTPUTFORMATTER /** * Function makeIMAGE * allocates an IMAGE on the heap and creates all the PINs according - * to the PADs in the MODULE. + * to the D_PADs in the MODULE. + * @param aBoard The owner of the MODULE. + * @param aModule The MODULE from which to build the IMAGE. + * @return IMAGE* - not tested for duplication yet. */ - IMAGE* makeIMAGE( MODULE* aModule ); + IMAGE* makeIMAGE( BOARD* aBoard, MODULE* aModule ); /** - * Function makePADSTACKs - * makes all the PADSTACKs, and marks each D_PAD with the index into the - * LIBRARY::padstacks list that it matches. + * Function makePADSTACK + * creates a PADSTACK which matches the given pad. Only pads which do not + * satisfy the function isKeepout() should be passed to this function. + * @param aPad The D_PAD which needs to be made into a PADSTACK. + * @return PADSTACK* - The created padstack, including its padstack_id. */ - void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ); - + PADSTACK* makePADSTACK( BOARD* aBoard, D_PAD* aPad ); /** * Function makeVia * makes a round through hole PADSTACK using the given Kicad diameter in deci-mils. * @param aCopperDiameter The diameter of the copper pad. * @param aDrillDiameter The drill diameter, used on re-import of the session file. + * @param aTopLayer The DSN::PCB top most layer index. + * @param aBotLayer The DSN::PCB bottom most layer index. * @return PADSTACK* - The padstack, which is on the heap only, user must save * or delete it. */ - PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter ); + PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter, + int aTopLayer, int aBotLayer ); /** * Function makeVia @@ -3751,6 +3811,19 @@ class SPECCTRA_DB : public OUTPUTFORMATTER PADSTACK* makeVia( const SEGVIA* aVia ); + /** + * Function deleteNETs + * deletes all the NETs that may be in here. + */ + void deleteNETs() + { + for( unsigned n=0; n----------------------------------------------------- /** @@ -3786,6 +3859,8 @@ public: delete pcb; delete session; + deleteNETs(); + if( fp ) fclose( fp ); } diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index a981c66bf9..0adc3bdcb8 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -40,7 +40,9 @@ #include "trigo.h" // RotatePoint() #include // std::set +#include // std::map +#include // boost::addressof() using namespace DSN; @@ -286,15 +288,15 @@ static bool isKeepout( D_PAD* aPad ) } -/**************************************************************************/ +/* 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 ); } +*/ /** @@ -312,11 +314,221 @@ static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string } -IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) +/** + * Struct wxString_less_than_ + * is used the std:set<> and std::map<> instantiations below. + * See STRINGSET typedef and PINMAP typedef below. + */ +struct wxString_less_than { - PADSTACKS& padstacks = pcb->library->padstacks; + // a "less than" test on two wxStrings, by pointer. + bool operator()( const wxString& s1, const wxString& s2) const + { + return s1.Cmp( s2 ) < 0; // case specific wxString compare + } +}; + +/** + * Function makePADSTACK + * creates a PADSTACK which matches the given pad. Only pads which do not + * satisfy the function isKeepout() should be passed to this function. + * @param aPad The D_PAD which needs to be made into a PADSTACK. + * @return PADSTACK* - The created padstack, including its padstack_id. + */ +PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) +{ + char name[80]; // padstack name builder + std::string uniqifier; + + bool doLayer[2] = { // top and bottom layers only + aPad->IsOnLayer( LAYER_CMP_N ), + aPad->IsOnLayer( COPPER_LAYER_N ) + }; + + // caller must do this screen before calling here. + wxASSERT( !isKeepout( aPad ) ); + + wxASSERT( doLayer[0] || doLayer[1] ); + + PADSTACK* padstack = new PADSTACK(); + + int reportedLayers = 0; // how many in reported padstack + const char* layerName[NB_COPPER_LAYERS]; + + if( aPad->m_Attribut==PAD_SMD || aPad->m_Attribut==PAD_CONN ) + { + // PAD_SMD and PAD_CONN are reported on each layer for which + // they are present. + uniqifier = '['; + + if( doLayer[0] ) + { + layerName[reportedLayers++] = layerIds[0].c_str(); + uniqifier += 'T'; // T for top, could have used a layer index here alternatively + } + if( doLayer[1] ) + { + int pcbLayerNdx = kicadLayer2pcb[COPPER_LAYER_N]; + layerName[reportedLayers++] = layerIds[ pcbLayerNdx ].c_str(); + uniqifier += 'B'; // B for bottom + } + + uniqifier += ']'; + } + + else // through hole pad + { +#if 0 + /* Through hole pads are reported on the + "signal". Reporting through hole pads on the special + "signal" layer may have problems when power layers are in the layer + stack. See bottom of page 74 of the SECCTRA Design Language + Reference, May 2000. 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. + */ + + reportedLayers = 1; + layerName[0] = signal; + uniqifier = "[A]"; // A for all + +#else + // Through hole pads are reported on *all* copper layers. + int copperLayers = aBoard->GetCopperLayerCount(); + + for( int layer=0; layerm_PadShape ) + { + default: + case PAD_CIRCLE: + { + double diameter = scale(aPad->m_Size.x); + + for( int ndx=0; ndxAppend( shape ); + + CIRCLE* circle = new CIRCLE( shape ); + shape->SetShape( circle ); + + circle->SetLayerId( layerName[ndx] ); + circle->SetDiameter( diameter ); + } + + snprintf( name, sizeof(name), "Round%sPad_%.6g_mil", + uniqifier.c_str(), scale(aPad->m_Size.x) ); + name[ sizeof(name)-1 ] = 0; + padstack->SetPadstackId( name ); + } + break; + + case PAD_RECT: + { + double dx = scale( aPad->m_Size.x ) / 2.0; + double dy = scale( aPad->m_Size.y ) / 2.0; + + POINT lowerLeft( -dx, -dy ); + POINT upperRight( dx, dy ); + + for( int ndx=0; ndxAppend( shape ); + + RECTANGLE* rect = new RECTANGLE( shape ); + shape->SetShape( rect ); + + rect->SetLayerId( layerName[ndx] ); + rect->SetCorners( lowerLeft, upperRight ); + } + + snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_mil", + uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) ); + name[ sizeof(name)-1 ] = 0; + + padstack->SetPadstackId( name ); + } + break; + + case PAD_OVAL: + { + double dx = scale( aPad->m_Size.x ) / 2.0; + double dy = scale( aPad->m_Size.y ) / 2.0; + double dr = dx - dy; + + if( dr >= 0 ) // oval is horizontal + { + double radius = dy; + + for( int ndx=0; ndxAppend( shape ); + path = makePath( POINT(-dr, 0.0), POINT(dr, 0.0), layerName[ndx] ); + shape->SetShape( path ); + path->aperture_width = 2.0 * radius; + } + } + else // oval is vertical + { + double radius = dx; + + dr = -dr; + + for( int ndx=0; ndxAppend( shape ); + path = makePath( POINT(0.0, -dr), POINT(0.0, dr), layerName[ndx] ); + shape->SetShape( path ); + path->aperture_width = 2.0 * radius; + } + } + + snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_mil", + uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) ); + name[ sizeof(name)-1 ] = 0; + + padstack->SetPadstackId( name ); + } + break; + +/* + case PAD_TRAPEZOID: + break; +*/ + } + + return padstack; +} + + +/// data type used to ensure unique-ness of pin names +typedef std::map PINMAP; +typedef std::pair PINMAP_PAIR; + + +IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) +{ + PINMAP pinmap; TYPE_COLLECTOR pads; + wxString padName; + // get all the MODULE's pads. pads.Collect( aModule, scanPADs ); @@ -333,25 +545,64 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) // see if this pad is a through hole with no copper on its perimeter if( isKeepout( pad ) ) { - KEEPOUT* keepout = new KEEPOUT(image, T_keepout); - image->keepouts.push_back( keepout ); + double diameter = scale( pad->m_Drill.x ); + POINT vertex = mapPt( pad->m_Pos0 ); - CIRCLE* circle = new CIRCLE(keepout); - keepout->SetShape( circle ); + int layerCount = aBoard->GetCopperLayerCount(); + for( int layer=0; layerkeepouts.push_back( keepout ); - circle->SetDiameter( scale(pad->m_Drill.x) ); - circle->SetVertex( mapPt( pad->m_Pos0 ) ); - circle->layer_id = "signal"; + CIRCLE* circle = new CIRCLE( keepout ); + keepout->SetShape( circle ); + + circle->SetDiameter( diameter ); + circle->SetVertex( vertex ); + circle->SetLayerId( layerIds[layer].c_str() ); + } } else { - PADSTACK* padstack = &padstacks[pad->m_logical_connexion]; + PADSTACK* padstack = makePADSTACK( aBoard, pad ); + + PADSTACKSET::iterator iter = padstackset.find( *padstack ); + if( iter != padstackset.end() ) + { + // padstack is a duplicate, delete it and use the original + delete padstack; + padstack = (PADSTACK*) *iter.base(); // folk lore, becareful here + } + else + { + padstackset.insert( padstack ); + } PIN* pin = new PIN(image); + + padName = pad->ReturnStringPadName(); + pin->pin_id = CONV_TO_UTF8( padName ); + + if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() ) + { + pinmap[ padName ] = 0; + } + else + { + char buf[32]; + + int duplicates = ++pinmap[ padName ]; + + sprintf( buf, "@%d", duplicates ); + + pin->pin_id += buf; // append "@1" or "@2", etc. to pin name + } + + pin->kiNetCode = pad->GetNet(); + image->pins.push_back( pin ); pin->padstack_id = padstack->padstack_id; - pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); wxPoint pos( pad->m_Pos0 ); wxPoint offset( pad->m_Offset.x, pad->m_Offset.y ); @@ -378,93 +629,31 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) } -PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia ) -{ - CIRCLE* circle; - SHAPE* shape; - double dsnDiameter; - char name[48]; - - PADSTACK* padstack = new PADSTACK( pcb->library ); - - switch( aVia->Shape() ) - { - case VIA_THROUGH: - shape = new SHAPE( padstack ); - padstack->Append( shape ); - - circle = new CIRCLE( shape ); - shape->SetShape( circle ); - - dsnDiameter = scale( aVia->m_Width ); - circle->SetDiameter( dsnDiameter ); - - circle->SetLayerId( "signal" ); - - snprintf( name, sizeof(name), "Via[A]%.6g:%.6g_mil", dsnDiameter, - // encode the drill value into the name for later import - scale( aVia->GetDrillValue() ) ); - name[ sizeof(name)-1 ] = 0; - padstack->SetPadstackId( name ); - break; - - case VIA_BLIND_BURIED: - case VIA_MICROVIA: - int topLayer; - int botLayer; - aVia->ReturnLayerPair( &topLayer, &botLayer ); - topLayer = kicadLayer2pcb[topLayer]; - botLayer = kicadLayer2pcb[botLayer]; - if( topLayer > botLayer ) - EXCHG( topLayer, botLayer ); - - dsnDiameter = scale( aVia->m_Width ); - - for( int layer=topLayer; layer<=botLayer; ++layer ) - { - shape = new SHAPE( padstack ); - padstack->Append( shape ); - - circle = new CIRCLE( shape ); - shape->SetShape( circle ); - - circle->SetDiameter( dsnDiameter ); - circle->SetLayerId( layerIds[layer].c_str() ); - } - - snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil", - topLayer, botLayer, dsnDiameter, - // encode the drill value into the name for later import - scale( aVia->GetDrillValue() ) - ); - name[ sizeof(name)-1 ] = 0; - padstack->SetPadstackId( name ); - break; - } - - return padstack; -} - - -PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter ) +PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter, + int aTopLayer, int aBotLayer ) { char name[48]; - PADSTACK* padstack = new PADSTACK( pcb->library ); - - SHAPE* shape = new SHAPE( padstack ); - padstack->Append( shape ); - - CIRCLE* circle = new CIRCLE( shape ); - shape->SetShape( circle ); + PADSTACK* padstack = new PADSTACK(); double dsnDiameter = scale(aCopperDiameter); - circle->SetDiameter( dsnDiameter ); - circle->SetLayerId( "signal" ); + for( int layer=aTopLayer; layer<=aBotLayer; ++layer ) + { + SHAPE* shape = new SHAPE( padstack ); + padstack->Append( shape ); - snprintf( name, sizeof(name), "Via[A]%.6g:%.6g_mil", dsnDiameter, - // encode the drill value into the name for later import - scale( aDrillDiameter ) ); + CIRCLE* circle = new CIRCLE( shape ); + shape->SetShape( circle ); + + circle->SetDiameter( dsnDiameter ); + circle->SetLayerId( layerIds[layer].c_str() ); + } + + snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil", + aTopLayer, aBotLayer, dsnDiameter, + // encode the drill value into the name for later import + scale( aDrillDiameter ) + ); name[ sizeof(name)-1 ] = 0; padstack->SetPadstackId( name ); @@ -472,262 +661,32 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter ) } -/** - * Struct ltWX - * is used secretly by the std:set<> class below. See STRINGSET typedef. - */ -struct ltWX +PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia ) { - // a "less than" test on two wxStrings, by pointer. - bool operator()( const wxString* s1, const wxString* s2) const - { - return s1->Cmp( *s2 ) < 0; // case specific wxString compare - } -}; + int topLayer; + int botLayer; + + aVia->ReturnLayerPair( &topLayer, &botLayer ); + + topLayer = kicadLayer2pcb[topLayer]; + botLayer = kicadLayer2pcb[botLayer]; + + if( topLayer > botLayer ) + EXCHG( topLayer, botLayer ); + + return makeVia( aVia->m_Width, aVia->GetDrillValue(), topLayer, botLayer ); +} +#if 0 void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) { - char name[80]; // padstack name builder - std::string uniqifier; - - if( aPads.GetCount() ) - { - qsort( (void*) aPads.BasePtr(), aPads.GetCount(), sizeof(D_PAD*), Pad_list_Sort_by_Shapes ); - } - - D_PAD* old_pad = NULL; - - for( int i=0; iIsOnLayer( LAYER_CMP_N ), - pad->IsOnLayer( COPPER_LAYER_N ) - }; - - 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; - } - - // if pad has no copper presence, then it will be made into - // an "image->keepout" later. No copper pad here, it is probably a hole. - if( (!doLayer[0] && !doLayer[1]) || isKeepout( pad ) ) - { - continue; - } - - old_pad = pad; - - 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; - - /* Through hole pads are reported on the - "signal". Reporting through hole pads on the special - "signal" layer may have problems when power layers are in the layer - stack. See bottom of page 74 of the SECCTRA Design Language - Reference, May 2000. 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. - - PAD_SMD and PAD_CONN are reported on each layer for which - they are present. - */ - - int reportedLayers; // how many in reported padstack - const char* layerName[NB_COPPER_LAYERS]; - - static const char signal[] = "signal"; - - if( pad->m_Attribut==PAD_SMD || pad->m_Attribut==PAD_CONN ) - { - reportedLayers = 0; - - uniqifier = '['; - - if( doLayer[0] ) - { - layerName[reportedLayers++] = layerIds[0].c_str(); - uniqifier += 'T'; // T for top, could have used a layer index here alternatively - } - if( doLayer[1] ) - { - int pcbLayerNdx = kicadLayer2pcb[COPPER_LAYER_N]; - layerName[reportedLayers++] = layerIds[ pcbLayerNdx ].c_str(); - uniqifier += 'B'; // B for bottom - } - - uniqifier += ']'; - } - else - { - reportedLayers = 1; - layerName[0] = signal; - uniqifier = "[A]"; // A for all - } - - switch( pad->m_PadShape ) - { - default: - case PAD_CIRCLE: - { - double diameter = scale(pad->m_Size.x); - - for( int ndx=0; ndxAppend( shape ); - - CIRCLE* circle = new CIRCLE( shape ); - shape->SetShape( circle ); - - circle->SetLayerId( layerName[ndx] ); - circle->SetDiameter( diameter ); - } - - snprintf( name, sizeof(name), "Round%sPad_%.6g_mil", - uniqifier.c_str(), 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 ); - } - break; - - case PAD_RECT: - { - 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 ); - - for( int ndx=0; ndxAppend( shape ); - - RECTANGLE* rect = new RECTANGLE( shape ); - shape->SetShape( rect ); - - rect->SetLayerId( layerName[ndx] ); - rect->SetCorners( lowerLeft, upperRight ); - } - - snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_mil", - uniqifier.c_str(), 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; - - 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 ndx=0; ndxAppend( shape ); - path = makePath( POINT(-dr, 0.0), POINT(dr, 0.0), layerName[ndx] ); - shape->SetShape( path ); - path->aperture_width = 2.0 * radius; - } - } - else // oval is vertical - { - double radius = dx; - - dr = -dr; - - for( int ndx=0; ndxAppend( shape ); - path = makePath( POINT(0.0, -dr), POINT(0.0, dr), layerName[ndx] ); - shape->SetShape( path ); - path->aperture_width = 2.0 * radius; - } - } - - snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_mil", - uniqifier.c_str(), 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; - -/* - case PAD_TRAPEZOID: - break; -*/ - } - } - - // 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 ) - { - PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill ); - 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 ); - - // padstack->SetPadstackId( "Via_Default" ); I like the padstack_id with the size in it. - } - - for( int i=0; im_BoardSettings->m_ViaSizeHistory[i]; - if( !viaSize ) - break; - - if( viaSize == defaultViaSize ) - continue; - - PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill ); - pcb->library->AddPadstack( padstack ); - } } +#endif + + +typedef std::set STRINGSET; +typedef std::pair STRINGSET_PAIR; void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) @@ -740,14 +699,15 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) // Not all boards are exportable. Check that all reference Ids are unique. // Unless they are unique, we cannot import the session file which comes - // back to us later from the router. + // back to us later from the router. Also check that all pad names within + // a part are unique, otherwise Electra and Freerouter will not draw the + // pads properly. { + TYPE_COLLECTOR padItems; + items.Collect( aBoard, scanMODULEs ); - typedef std::set STRINGSET; - typedef std::pair PAIR; - - STRINGSET references; // holds unique component references + STRINGSET refs; // holds module reference designators for( int i=0; iGetReference() ); - if( !pair.second ) // insert failed + STRINGSET_PAIR refpair = refs.insert( module->GetReference() ); + if( !refpair.second ) // insert failed { ThrowIOError( _("Multiple components have identical reference IDs of \"%s\"."), module->GetReference().GetData() ); @@ -785,11 +745,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } - // Since none of these statements cause any immediate output, the order - // of them is somewhat flexible. The outputting to disk is done at the - // end. We start by gathering all the layer information from the board. - - //---------------------------------------------------- { // specctra wants top physical layer first, then going down to the @@ -818,10 +773,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) } } - - // for now, report on only the top and bottom layers with respect to the copper - // within a pad's padstack. this is usually correct, but not rigorous. - // a space in a quoted token is NOT a terminator, true establishes this. pcb->parser->space_in_quoted_tokens = true; @@ -1004,49 +955,78 @@ 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. - - //------------------------------------- + //---------------------------- { - TYPE_COLLECTOR pads; + // find the highest numbered netCode within the board. + int highestNetCode = -1; + for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() ) + highestNetCode = MAX( highestNetCode, equipot->GetNet() ); - // get all the D_PADs into 'pads'. - pads.Collect( aBoard, scanPADs ); + deleteNETs(); - makePADSTACKs( aBoard, pads ); + // expand the net vector to highestNetCode+1, setting empty to NULL + nets.resize( highestNetCode+1, NULL ); -#if 0 && defined(DEBUG) - for( int p=0; pShow( 0, std::cout ); -#endif - } + // skip netcode = 0 + for( unsigned i=1; inetwork ); + for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() ) + { + int netcode = equipot->GetNet(); + if( netcode > 0 ) + nets[ netcode ]->net_id = CONV_TO_UTF8( equipot->m_Netname ); + } - //-------------------------------------- - { items.Collect( aBoard, scanMODULEs ); + padstackset.clear(); + for( int m=0; mnetwork ); + for( unsigned p=0; ppins.size(); ++p ) + { + PIN* pin = &image->pins[p]; + + int netcode = pin->kiNetCode; + if( netcode > 0 ) + { + NET* net = nets[netcode]; + + net->pins.push_back( empty ); + + PIN_REF& pin_ref = net->pins.back(); + + pin_ref.component_id = CONV_TO_UTF8( module->GetReference() ); + pin_ref.pin_id = pin->pin_id; + } + } + 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. + // and use the registered one, known as 'image' after this. delete image; + image = registered; } - // @todo: this only works if the user has not modified the MODULE within the PCB - // and made it different from what is in the PCBNEW library. Need to test - // each image for uniqueness, not just based on name as is done here: - - COMPONENT* comp = pcb->placement->LookupCOMPONENT( registered->GetImageId() ); + COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() ); PLACE* place = new PLACE( comp ); comp->places.push_back( place ); @@ -1060,69 +1040,73 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError ) if( module->flag ) { int angle = 1800 - module->m_Orient; - NORMALIZE_ANGLE_POS(angle); - place->SetRotation( angle/10.0 ); place->side = T_back; } } - } - - //----------------------------------------------------- - { - NETWORK* network = pcb->network; - TYPE_COLLECTOR nets; - TYPE_COLLECTOR pads; - - static const KICAD_T scanNETs[] = { PCB_EQUIPOT_STRUCT_TYPE, EOT }; - - nets.Collect( aBoard, scanNETs ); - - items.Collect( aBoard, scanMODULEs ); - - PIN_REF emptypin(0); - - for( int n=0; nGetNet() == 0 ) - continue; + pcb->library->AddPadstack( padstack ); + } - NET* net = new NET( network ); - network->nets.push_back( net ); - - net->net_id = CONV_TO_UTF8( kinet->m_Netname ); - net->net_number = kinet->GetNet(); - - for( int m=0; mnetwork + for( unsigned n=1; npins.size() ) { - MODULE* module = (MODULE*) items[m]; - - pads.Collect( module, scanPADs ); - - for( int p=0; pGetNet() == kinet->GetNet() ) - { - // 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->GetReference() ); - pin_ref->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); - } - } + // give ownership to pcb->network + pcb->network->nets.push_back( net ); + nets[n] = 0; } } } + + //-----< output the vias >----------------------------------------------- + { + // ASSUME: unique pads are now in the padstack list! i.e. this code + // must follow the initial padstack construction code. + // Next we add the via's which may be used. + + int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize; + if( defaultViaSize ) + { + PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill, + 0, aBoard->GetCopperLayerCount()-1 ); + 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 ); + } + + for( int i=0; im_BoardSettings->m_ViaSizeHistory[i]; + if( !viaSize ) + break; + + if( viaSize == defaultViaSize ) + continue; + + PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill, + 0, aBoard->GetCopperLayerCount()-1 ); + pcb->library->AddPadstack( padstack ); + } + } + + #if 1 // do existing wires and vias //----------------------------------------