diff options
Diffstat (limited to 'pcbnew/specctra.h')
-rw-r--r-- | pcbnew/specctra.h | 4004 |
1 files changed, 4004 insertions, 0 deletions
diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h new file mode 100644 index 0000000..540fcf9 --- /dev/null +++ b/pcbnew/specctra.h @@ -0,0 +1,4004 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007-2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2007-2015 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SPECCTRA_H_ +#define SPECCTRA_H_ + + +// see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html +#include <boost/ptr_container/ptr_vector.hpp> + +// see http://www.boost.org/libs/ptr_container/doc/ptr_set.html +#include <boost/ptr_container/ptr_set.hpp> +#include <boost/shared_ptr.hpp> + +#include <fctsys.h> +#include <specctra_lexer.h> +#include <pcbnew.h> + +// all outside the DSN namespace: +class BOARD; +class TRACK; +class VIA; +class NETCLASS; +class MODULE; +class SHAPE_POLY_SET; + +typedef DSN::T DSN_T; + + +/** + This source file implements export and import capabilities to the + specctra dsn file format. The grammar for that file format is documented + fairly well. There are classes for each major type of descriptor in the + spec. + + Since there are so many classes in here, it may be helpful to generate + the Doxygen directory: + + $ cd <kicadSourceRoot> + $ doxygen + + Then you can view the html documentation in the <kicadSourceRoot>/doxygen + directory. The main class in this file is SPECCTRA_DB and its main + functions are LoadPCB(), LoadSESSION(), and ExportPCB(). + + Wide use is made of boost::ptr_vector<> and std::vector<> template classes. + If the contained object is small, then std::vector tends to be used. + If the contained object is large, variable size, or would require writing + an assignment operator() or copy constructore, then boost::ptr_vector + cannot be beat. +*/ +namespace DSN { + + +class SPECCTRA_DB; + + +/** + * Function GetTokenText + * is in the DSN namespace and returns the C string representing a + * SPECCTRA_DB::keyword. We needed a non-instanance function to get at + * the SPECCTRA_DB::keyword[] and class SPECCTRA_DB is not defined yet. + */ +const char* GetTokenText( T aTok ); + + +/** + * Struct 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; + double y; + + POINT() { x=0.0; y=0.0; } + + POINT( double aX, double aY ) : + x(aX), y(aY) + { + } + + bool operator==( const POINT& other ) const + { + return x==other.x && y==other.y; + } + + bool operator!=( const POINT& other ) const + { + return !( *this == other ); + } + + POINT& operator+=( const POINT& other ) + { + x += other.x; + y += other.y; + return *this; + } + + POINT& operator=( const POINT& other ) + { + x = other.x; + y = other.y; + 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 mantissa and + * exponent say the value is otherwise zero. + */ + void FixNegativeZero() + { + if( x == -0.0 ) + x = 0.0; + if( y == -0.0 ) + y = 0.0; + } + + /** + * Function Format + * writes this object as ASCII out to an OUTPUTFORMATTER according to the + * SPECCTRA DSN format. + * @param out The formatter to write to. + * @param nestLevel A multiple of the number of spaces to preceed the output with. + * @throw IO_ERROR if a system error writing the output, such as a full disk. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) + { + out->Print( nestLevel, " %.6g %.6g", x, y ); + } +}; + +typedef std::vector<std::string> STRINGS; +typedef std::vector<POINT> POINTS; + +struct PROPERTY +{ + std::string name; + std::string value; + + /** + * Function Format + * writes this object as ASCII out to an OUTPUTFORMATTER according to the + * SPECCTRA DSN format. + * @param out The formatter to write to. + * @param nestLevel A multiple of the number of spaces to preceed the output with. + * @throw IO_ERROR if a system error writing the output, such as a full disk. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) + { + const char* quoteName = out->GetQuoteChar( name.c_str() ); + const char* quoteValue = out->GetQuoteChar( value.c_str() ); + + out->Print( nestLevel, "(%s%s%s %s%s%s)\n", + quoteName, name.c_str(), quoteName, + quoteValue, value.c_str(), quoteValue ); + } +}; +typedef std::vector<PROPERTY> PROPERTIES; + + +class UNIT_RES; + +/** + * Class ELEM + * is a base class for any DSN element class. + * See class ELEM_HOLDER also. + */ +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() + { + sf.Clear(); + FormatContents( &sf, 0 ); + sf.StripUseless(); + + return sf.GetString(); + } + + // avoid creating this for every compare, make static. + static STRING_FORMATTER sf; + + +public: + + ELEM( DSN_T aType, ELEM* aParent = 0 ); + + virtual ~ELEM(); + + DSN_T Type() const { return type; } + + const char* Name() const; + + + /** + * Function GetUnits + * returns the units for this section. Derived classes may override this + * to check for section specific overrides. + * @return UNIT_RES* - from a local or parent scope + */ + virtual UNIT_RES* GetUnits() const; + + /** + * Function Format + * writes this object as ASCII out to an OUTPUTFORMATTER according to the + * SPECCTRA DSN format. + * @param out The formatter to write to. + * @param nestLevel A multiple of the number of spaces to preceed the output with. + * @throw IO_ERROR if a system error writing the output, such as a full disk. + */ + virtual void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ); + + + /** + * Function FormatContents + * writes the contents as ASCII out to an OUTPUTFORMATTER according to the + * SPECCTRA DSN format. This is the same as Format() except that the outer + * wrapper is not included. + * @param out The formatter to write to. + * @param nestLevel A multiple of the number of spaces to preceed the output with. + * @throw IO_ERROR if a system error writing the output, such as a full disk. + */ + virtual void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + // overridden in ELEM_HOLDER + } + + void SetParent( ELEM* aParent ) + { + parent = aParent; + } +}; + + +/** + * Class ELEM_HOLDER + * is a holder for any DSN class. It can contain other + * class instances, including classes derived from this class. + */ +class ELEM_HOLDER : public ELEM +{ + friend class SPECCTRA_DB; + + typedef boost::ptr_vector<ELEM> ELEM_ARRAY; + + ELEM_ARRAY kids; ///< ELEM pointers + +public: + + ELEM_HOLDER( DSN_T aType, ELEM* aParent = 0 ) : + ELEM( aType, aParent ) + { + } + + virtual void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ); + + + //-----< list operations >-------------------------------------------- + + /** + * Function FindElem + * finds a particular instance number of a given type of ELEM. + * @param aType The type of ELEM to find + * @param instanceNum The instance number of to find: 0 for first, 1 for second, etc. + * @return int - The index into the kids array or -1 if not found. + */ + int FindElem( DSN_T aType, int instanceNum = 0 ); + + + /** + * Function Length + * returns the number of ELEMs in this ELEM. + * @return int - the count of children + */ + int Length() const + { + return kids.size(); + } + + void Append( ELEM* aElem ) + { + kids.push_back( aElem ); + } + + ELEM* Replace( int aIndex, ELEM* aElem ) + { + ELEM_ARRAY::auto_type ret = kids.replace( aIndex, aElem ); + return ret.release(); + } + + ELEM* Remove( int aIndex ) + { + ELEM_ARRAY::auto_type ret = kids.release( kids.begin()+aIndex ); + return ret.release(); + } + + void Insert( int aIndex, ELEM* aElem ) + { + kids.insert( kids.begin()+aIndex, aElem ); + } + + ELEM* At( int aIndex ) const + { + // we have varying sized objects and are using polymorphism, so we + // must return a pointer not a reference. + return (ELEM*) &kids[aIndex]; + } + + ELEM* operator[]( int aIndex ) const + { + return At( aIndex ); + } + + void Delete( int aIndex ) + { + kids.erase( kids.begin()+aIndex ); + } +}; + + +/** + * Class PARSER + * is simply a configuration record per the SPECCTRA DSN file spec. + * It is not actually a parser, but rather corresponds to <parser_descriptor> + */ +class PARSER : public ELEM +{ + friend class SPECCTRA_DB; + + char string_quote; + bool space_in_quoted_tokens; + bool case_sensitive; + bool wires_include_testpoint; + bool routes_include_testpoint; + bool routes_include_guides; + bool routes_include_image_conductor; + bool via_rotate_first; + bool generated_by_freeroute; + + /// This holds pairs of strings, one pair for each constant definition + STRINGS constants; + + std::string host_cad; + std::string host_version; + + +public: + + PARSER( ELEM* aParent ); + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ); +}; + + +/** + * Class UNIT_RES + * is a holder for either a T_unit or T_resolution object which are usually + * mutually exclusive in the dsn grammar, except within the T_pcb level. + */ +class UNIT_RES : public ELEM +{ + friend class SPECCTRA_DB; + + DSN_T units; + int value; + +public: + + /** + * A static instance which holds the default units of T_inch and 2540000. + * See page 108 of the specctra spec, May 2000. + */ + static UNIT_RES Default; + + UNIT_RES( ELEM* aParent, DSN_T aType ) : + ELEM( aType, aParent ) + { + units = T_inch; + value = 2540000; + } + + DSN_T GetEngUnits() const { return units; } + int GetValue() const { return value; } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( type == T_unit ) + out->Print( nestLevel, "(%s %s)\n", Name(), + GetTokenText(units) ); + + else // T_resolution + out->Print( nestLevel, "(%s %s %d)\n", Name(), + GetTokenText(units), value ); + } +}; + + +class RECTANGLE : public ELEM +{ + friend class SPECCTRA_DB; + + std::string layer_id; + + POINT point0; ///< one of two opposite corners + POINT point1; + +public: + + RECTANGLE( ELEM* aParent ) : + ELEM( T_rect, aParent ) + { + } + + void SetLayerId( const char* aLayerId ) + { + layer_id = aLayerId; + } + + void SetCorners( const POINT& aPoint0, const POINT& aPoint1 ) + { + point0 = aPoint0; + point0.FixNegativeZero(); + + point1 = aPoint1; + point1.FixNegativeZero(); + } + + POINT GetOrigin() { return point0; } + POINT GetEnd() { return point1; } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* newline = nestLevel ? "\n" : ""; + + const char* quote = out->GetQuoteChar( layer_id.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s %.6g %.6g %.6g %.6g)%s", + Name(), + quote, layer_id.c_str(), quote, + point0.x, point0.y, + point1.x, point1.y, + newline ); + } +}; + + +/** + * Class RULE + * corresponds to the <rule_descriptor> in the specctra dsn spec. + */ +class RULE : public ELEM +{ + friend class SPECCTRA_DB; + + STRINGS rules; ///< rules are saved in std::string form. + +public: + + RULE( ELEM* aParent, DSN_T aType ) : + ELEM( aType, aParent ) + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s", Name() ); + + bool singleLine; + + if( rules.size() == 1 ) + { + singleLine = true; + out->Print( 0, " %s)", rules.begin()->c_str() ); + } + + else + { + out->Print( 0, "\n" ); + singleLine = false; + for( STRINGS::const_iterator i = rules.begin(); i!=rules.end(); ++i ) + out->Print( nestLevel+1, "%s\n", i->c_str() ); + out->Print( nestLevel, ")" ); + } + + if( nestLevel || !singleLine ) + out->Print( 0, "\n" ); + } +}; + + +class LAYER_RULE : public ELEM +{ + friend class SPECCTRA_DB; + + STRINGS layer_ids; + RULE* rule; + +public: + + LAYER_RULE( ELEM* aParent ) : + ELEM( T_layer_rule, aParent ) + { + rule = 0; + } + ~LAYER_RULE() + { + delete rule; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s", Name() ); + + for( STRINGS::const_iterator i=layer_ids.begin(); i!=layer_ids.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( 0, " %s%s%s", quote, i->c_str(), quote ); + } + out->Print( 0 , "\n" ); + + if( rule ) + rule->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } +}; +typedef boost::ptr_vector<LAYER_RULE> LAYER_RULES; + + +/** + * Class PATH + * supports both the <path_descriptor> and the <polygon_descriptor> per + * the specctra dsn spec. + */ +class PATH : public ELEM +{ + friend class SPECCTRA_DB; + + std::string layer_id; + double aperture_width; + + POINTS points; + DSN_T aperture_type; + +public: + + PATH( ELEM* aParent, DSN_T aType = T_path ) : + ELEM( aType, aParent ) + { + aperture_width = 0.0; + aperture_type = T_round; + } + + void AppendPoint( const POINT& aPoint ) + { + points.push_back( aPoint ); + } + + POINTS& GetPoints() {return points; } + + void SetLayerId( const char* aLayerId ) + { + layer_id = aLayerId; + } + + void SetAperture( double aWidth ) + { + aperture_width = aWidth; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* newline = nestLevel ? "\n" : ""; + + const char* quote = out->GetQuoteChar( layer_id.c_str() ); + + const int RIGHTMARGIN = 70; + int perLine = out->Print( nestLevel, "(%s %s%s%s %.6g", + Name(), + quote, layer_id.c_str(), quote, + aperture_width ); + + int wrapNest = std::max( nestLevel+1, 6 ); + for( unsigned i=0; i<points.size(); ++i ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( wrapNest, "%s", "" ); + } + else + perLine += out->Print( 0, " " ); + + perLine += out->Print( 0, "%.6g %.6g", points[i].x, points[i].y ); + } + + if( aperture_type == T_square ) + { + out->Print( 0, "(aperture_type square)" ); + } + + out->Print( 0, ")%s", newline ); + } +}; +typedef boost::ptr_vector<PATH> PATHS; + + +class BOUNDARY : public ELEM +{ + friend class SPECCTRA_DB; + + // only one or the other of these two is used, not both + PATHS paths; + RECTANGLE* rectangle; + + +public: + + BOUNDARY( ELEM* aParent, DSN_T aType = T_boundary ) : + ELEM( aType, aParent ) + { + rectangle = 0; + } + + ~BOUNDARY() + { + delete rectangle; + } + + /** + * GetCorners fills aBuffer with a list of coordinates (x,y) of corners + */ + void GetCorners( std::vector<double>& aBuffer ) + { + if( rectangle ) + { + aBuffer.push_back( rectangle->GetOrigin().x ); + aBuffer.push_back( rectangle->GetOrigin().y ); + + aBuffer.push_back( rectangle->GetOrigin().x ); + aBuffer.push_back( rectangle->GetEnd().y ); + + aBuffer.push_back( rectangle->GetEnd().x ); + aBuffer.push_back( rectangle->GetEnd().y ); + + aBuffer.push_back( rectangle->GetEnd().x ); + aBuffer.push_back( rectangle->GetOrigin().y ); + } + else + { + for( PATHS::iterator i=paths.begin(); i!=paths.end(); ++i ) + { + POINTS& plist = i->GetPoints(); + for( unsigned jj = 0; jj < plist.size(); jj++ ) + { + aBuffer.push_back( plist[jj].x ); + aBuffer.push_back( plist[jj].y ); + } + } + } + } + + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s\n", Name() ); + + if( rectangle ) + rectangle->Format( out, nestLevel+1 ); + else + { + for( PATHS::iterator i=paths.begin(); i!=paths.end(); ++i ) + i->Format( out, nestLevel+1 ); + } + + out->Print( nestLevel, ")\n" ); + } +}; + + +class CIRCLE : public ELEM +{ + friend class SPECCTRA_DB; + + std::string layer_id; + + double diameter; + POINT vertex; // POINT's constructor sets to (0,0) + +public: + CIRCLE( ELEM* aParent ) : + ELEM( T_circle, aParent ) + { + diameter = 0.0; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* newline = nestLevel ? "\n" : ""; + + const char* quote = out->GetQuoteChar( layer_id.c_str() ); + out->Print( nestLevel, "(%s %s%s%s %.6g", Name(), + quote, layer_id.c_str(), quote, + diameter ); + + if( vertex.x!=0.0 || vertex.y!=0.0 ) + out->Print( 0, " %.6g %.6g)%s", vertex.x, vertex.y, newline ); + else + out->Print( 0, ")%s", newline ); + } + + void SetLayerId( const char* aLayerId ) + { + layer_id = aLayerId; + } + + void SetDiameter( double aDiameter ) + { + diameter = aDiameter; + } + + void SetVertex( const POINT& aVertex ) + { + vertex = aVertex; + } +}; + + +class QARC : public ELEM +{ + friend class SPECCTRA_DB; + + std::string layer_id; + double aperture_width; + POINT vertex[3]; + +public: + QARC( ELEM* aParent ) : + ELEM( T_qarc, aParent ) + { + aperture_width = 0.0; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* newline = nestLevel ? "\n" : ""; + + const char* quote = out->GetQuoteChar( layer_id.c_str() ); + out->Print( nestLevel, "(%s %s%s%s %.6g", Name() , + quote, layer_id.c_str(), quote, + aperture_width); + + for( int i=0; i<3; ++i ) + out->Print( 0, " %.6g %.6g", vertex[i].x, vertex[i].y ); + + out->Print( 0, ")%s", newline ); + } + + void SetLayerId( const char* aLayerId ) + { + layer_id = aLayerId; + } + void SetStart( const POINT& 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(); + } +}; + + +class WINDOW : public ELEM +{ + friend class SPECCTRA_DB; + +protected: + /* <shape_descriptor >::= + [<rectangle_descriptor> | + <circle_descriptor> | + <polygon_descriptor> | + <path_descriptor> | + <qarc_descriptor> ] + */ + ELEM* shape; + +public: + + WINDOW( ELEM* aParent, DSN_T aType = T_window ) : + ELEM( aType, aParent ) + { + shape = 0; + } + + ~WINDOW() + { + 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 Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s ", Name() ); + + if( shape ) + shape->Format( out, 0 ); + + out->Print( 0, ")\n" ); + } +}; +typedef boost::ptr_vector<WINDOW> WINDOWS; + + +/** + * Class KEEPOUT + * is used for <keepout_descriptor> and <plane_descriptor>. + */ +class KEEPOUT : public ELEM +{ + friend class SPECCTRA_DB; + +protected: + std::string name; + int sequence_number; + RULE* rules; + RULE* place_rules; + + WINDOWS windows; + + /* <shape_descriptor >::= + [<rectangle_descriptor> | + <circle_descriptor> | + <polygon_descriptor> | + <path_descriptor> | + <qarc_descriptor> ] + */ + ELEM* shape; + +public: + + /** + * Constructor KEEPOUT + * requires a DSN_T because this class is used for T_place_keepout, T_via_keepout, + * T_wire_keepout, T_bend_keepout, and T_elongate_keepout as well as T_keepout. + */ + KEEPOUT( ELEM* aParent, DSN_T aType ) : + ELEM( aType, aParent ) + { + rules = 0; + place_rules = 0; + shape = 0; + + sequence_number = -1; + } + + ~KEEPOUT() + { + delete rules; + delete place_rules; + 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 AddWindow( WINDOW* aWindow ) + { + aWindow->SetParent( this ); + windows.push_back( aWindow ); + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* newline = "\n"; + + out->Print( nestLevel, "(%s", Name() ); + + if( name.size() ) + { + const char* quote = out->GetQuoteChar( name.c_str() ); + out->Print( 0, " %s%s%s", quote, name.c_str(), quote ); + } + else + out->Print( 0, " \"\"" ); // the zone with no name or net_code == 0 + + if( sequence_number != -1 ) + out->Print( 0, " (sequence_number %d)", sequence_number ); + + if( shape ) + { + out->Print( 0, " " ); + shape->Format( out, 0 ); + } + + if( rules ) + { + out->Print( 0, "%s", newline ); + newline = ""; + rules->Format( out, nestLevel+1 ); + } + + if( place_rules ) + { + out->Print( 0, "%s", newline ); + newline = ""; + place_rules->Format( out, nestLevel+1 ); + } + + if( windows.size() ) + { + out->Print( 0, "%s", newline ); + newline = ""; + + for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + else + out->Print( 0, ")\n" ); + } +}; +typedef boost::ptr_vector<KEEPOUT> KEEPOUTS; + + +/** + * Class VIA + * corresponds to the <via_descriptor> in the specctra dsn spec. + */ +class VIA : public ELEM +{ + friend class SPECCTRA_DB; + + STRINGS padstacks; + STRINGS spares; + +public: + + VIA( ELEM* aParent ) : + ELEM( T_via, aParent ) + { + } + + void AppendVia( const char* aViaName ) + { + padstacks.push_back( aViaName ); + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const int RIGHTMARGIN = 80; + int perLine = out->Print( nestLevel, "(%s", Name() ); + + for( STRINGS::iterator i=padstacks.begin(); i!=padstacks.end(); ++i ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", ""); + } + + const char* quote = out->GetQuoteChar( i->c_str() ); + perLine += out->Print( 0, " %s%s%s", quote, i->c_str(), quote ); + } + + if( spares.size() ) + { + out->Print( 0, "\n" ); + + perLine = out->Print( nestLevel+1, "(spare" ); + + for( STRINGS::iterator i=spares.begin(); i!=spares.end(); ++i ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+2, "%s", ""); + } + const char* quote = out->GetQuoteChar( i->c_str() ); + perLine += out->Print( 0, " %s%s%s", quote, i->c_str(), quote ); + } + + out->Print( 0, ")" ); + } + + out->Print( 0, ")\n" ); + } +}; + + +class CLASSES : public ELEM +{ + friend class SPECCTRA_DB; + + STRINGS class_ids; + +public: + CLASSES( ELEM* aParent ) : + ELEM( T_classes, aParent ) + { + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( STRINGS::iterator i=class_ids.begin(); i!=class_ids.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( nestLevel, "%s%s%s\n", quote, i->c_str(), quote ); + } + } +}; + + +class CLASS_CLASS : public ELEM_HOLDER +{ + friend class SPECCTRA_DB; + + CLASSES* classes; + + /* rule | layer_rule are put into the kids container. + */ + + +public: + + /** + * Constructor CLASS_CLASS + * @param aParent - Parent element of the object. + * @param aType May be either T_class_class or T_region_class_class + */ + CLASS_CLASS( ELEM* aParent, DSN_T aType ) : + ELEM_HOLDER( aType, aParent ) + { + classes = 0; + } + + ~CLASS_CLASS() + { + delete classes; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( classes ) + classes->Format( out, nestLevel ); + + // format the kids + ELEM_HOLDER::FormatContents( out, nestLevel ); + } +}; + + +class CONTROL : public ELEM_HOLDER +{ + friend class SPECCTRA_DB; + + bool via_at_smd; + bool via_at_smd_grid_on; + +public: + CONTROL( ELEM* aParent ) : + ELEM_HOLDER( T_control, aParent ) + { + via_at_smd = false; + via_at_smd_grid_on = false; + } + + ~CONTROL() + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s\n", Name() ); + + //if( via_at_smd ) + { + out->Print( nestLevel+1, "(via_at_smd %s", via_at_smd ? "on" : "off" ); + if( via_at_smd_grid_on ) + out->Print( 0, " grid %s", via_at_smd_grid_on ? "on" : "off" ); + + out->Print( 0, ")\n" ); + } + + for( int i=0; i<Length(); ++i ) + { + At(i)->Format( out, nestLevel+1 ); + } + + out->Print( nestLevel, ")\n" ); + } +}; + + +class LAYER : public ELEM +{ + friend class SPECCTRA_DB; + + std::string name; + DSN_T layer_type; ///< one of: T_signal, T_power, T_mixed, T_jumper + int direction; + int cost; ///< [forbidden | high | medium | low | free | \<positive_integer\> | -1] + int cost_type; ///< T_length | T_way + RULE* rules; + STRINGS use_net; + + PROPERTIES properties; + +public: + + LAYER( ELEM* aParent ) : + ELEM( T_layer, aParent ) + { + layer_type = T_signal; + direction = -1; + cost = -1; + cost_type = -1; + + rules = 0; + } + + ~LAYER() + { + delete rules; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( name.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + quote, name.c_str(), quote ); + + out->Print( nestLevel+1, "(type %s)\n", GetTokenText( layer_type ) ); + + if( properties.size() ) + { + out->Print( nestLevel+1, "(property\n" ); + + for( PROPERTIES::iterator i = properties.begin(); i != properties.end(); ++i ) + { + i->Format( out, nestLevel+2 ); + } + out->Print( nestLevel+1, ")\n" ); + } + + if( direction != -1 ) + out->Print( nestLevel+1, "(direction %s)\n", + GetTokenText( (DSN_T)direction ) ); + + if( rules ) + rules->Format( out, nestLevel+1 ); + + if( cost != -1 ) + { + if( cost < 0 ) + out->Print( nestLevel+1, "(cost %d", -cost ); // positive integer, stored as negative + else + out->Print( nestLevel+1, "(cost %s", GetTokenText( (DSN_T)cost ) ); + + if( cost_type != -1 ) + out->Print( 0, " (type %s)", GetTokenText( (DSN_T)cost_type ) ); + + out->Print( 0, ")\n" ); + } + + if( use_net.size() ) + { + out->Print( nestLevel+1, "(use_net" ); + for( STRINGS::const_iterator i = use_net.begin(); i!=use_net.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( 0, " %s%s%s", quote, i->c_str(), quote ); + } + out->Print( 0, ")\n" ); + } + + out->Print( nestLevel, ")\n" ); + } +}; + +typedef boost::ptr_vector<LAYER> LAYERS; + + +class LAYER_PAIR : public ELEM +{ + friend class SPECCTRA_DB; + + std::string layer_id0; + std::string layer_id1; + + double layer_weight; + +public: + LAYER_PAIR( ELEM* aParent ) : + ELEM( T_layer_pair, aParent ) + { + layer_weight = 0.0; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote0 = out->GetQuoteChar( layer_id0.c_str() ); + const char* quote1 = out->GetQuoteChar( layer_id1.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s %s%s%s %.6g)\n", Name(), + quote0, layer_id0.c_str(), quote0, + quote1, layer_id1.c_str(), quote1, + layer_weight ); + } +}; +typedef boost::ptr_vector<LAYER_PAIR> LAYER_PAIRS; + + +class LAYER_NOISE_WEIGHT : public ELEM +{ + friend class SPECCTRA_DB; + + LAYER_PAIRS layer_pairs; + +public: + + LAYER_NOISE_WEIGHT( ELEM* aParent ) : + ELEM( T_layer_noise_weight, aParent ) + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s\n", Name() ); + + for( LAYER_PAIRS::iterator i=layer_pairs.begin(); i!=layer_pairs.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } +}; + + +/** + * Class COPPER_PLANE + * corresponds to a <plane_descriptor> in the specctra dsn spec. + */ +class COPPER_PLANE : public KEEPOUT +{ + friend class SPECCTRA_DB; + +public: + COPPER_PLANE( ELEM* aParent ) : + KEEPOUT( aParent, T_plane ) + {} +}; +typedef boost::ptr_vector<COPPER_PLANE> COPPER_PLANES; + + +/** + * Class TOKPROP + * is a container for a single property whose value is another DSN_T token. + * The name of the property is obtained from the DSN_T Type(). + */ +class TOKPROP : public ELEM +{ + friend class SPECCTRA_DB; + + DSN_T value; + +public: + + TOKPROP( ELEM* aParent, DSN_T aType ) : + ELEM( aType, aParent ) + { + // Do not leave uninitialized members + value = T_NONE; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s %s)\n", Name(), + GetTokenText( value ) ); + } +}; + + +/** + * Class STRINGPROP + * is a container for a single property whose value is a string. + * The name of the property is obtained from the DSN_T. + */ +class STRINGPROP : public ELEM +{ + friend class SPECCTRA_DB; + + std::string value; + +public: + + STRINGPROP( ELEM* aParent, DSN_T aType ) : + ELEM( aType, aParent ) + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( value.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s)\n", Name(), + quote, value.c_str(), quote ); + } +}; + + +class REGION : public ELEM_HOLDER +{ + friend class SPECCTRA_DB; + + std::string region_id; + + //-----<mutually exclusive>-------------------------------------- + RECTANGLE* rectangle; + PATH* polygon; + //-----</mutually exclusive>------------------------------------- + + /* region_net | region_class | region_class_class are all mutually + exclusive and are put into the kids container. + */ + + RULE* rules; + +public: + REGION( ELEM* aParent ) : + ELEM_HOLDER( T_region, aParent ) + { + rectangle = 0; + polygon = 0; + rules = 0; + } + + ~REGION() + { + delete rectangle; + delete polygon; + delete rules; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( region_id.size() ) + { + const char* quote = out->GetQuoteChar( region_id.c_str() ); + out->Print( nestLevel, "%s%s%s\n", quote, region_id.c_str(), quote ); + } + + if( rectangle ) + rectangle->Format( out, nestLevel ); + + if( polygon ) + polygon->Format( out, nestLevel ); + + ELEM_HOLDER::FormatContents( out, nestLevel ); + + if( rules ) + rules->Format( out, nestLevel ); + } +}; + + +class GRID : public ELEM +{ + friend class SPECCTRA_DB; + + DSN_T grid_type; ///< T_via | T_wire | T_via_keepout | T_place | T_snap + double dimension; + DSN_T direction; ///< T_x | T_y | -1 for both + double offset; + DSN_T image_type; + +public: + + GRID( ELEM* aParent ) : + ELEM( T_grid, aParent ) + { + grid_type = T_via; + direction = T_NONE; + dimension = 0.0; + offset = 0.0; + image_type= T_NONE; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s %s %.6g", + Name(), + GetTokenText( grid_type ), dimension ); + + if( grid_type == T_place ) + { + if( image_type==T_smd || image_type==T_pin ) + out->Print( 0, " (image_type %s)", GetTokenText( image_type ) ); + } + else + { + if( direction==T_x || direction==T_y ) + out->Print( 0, " (direction %s)", GetTokenText( direction ) ); + } + + if( offset != 0.0 ) + out->Print( 0, " (offset %.6g)", offset ); + + out->Print( 0, ")\n"); + } +}; + + +class STRUCTURE_OUT : public ELEM +{ + friend class SPECCTRA_DB; + + LAYERS layers; + RULE* rules; + +public: + STRUCTURE_OUT( ELEM* aParent ) : + ELEM( T_structure_out, aParent ) + { + rules = 0; + } + + ~STRUCTURE_OUT() + { + delete rules; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( LAYERS::iterator i=layers.begin(); i!=layers.end(); ++i ) + i->Format( out, nestLevel ); + + if( rules ) + rules->Format( out, nestLevel ); + } +}; + + +class STRUCTURE : public ELEM_HOLDER +{ + friend class SPECCTRA_DB; + + UNIT_RES* unit; + + LAYERS layers; + + LAYER_NOISE_WEIGHT* layer_noise_weight; + + BOUNDARY* boundary; + BOUNDARY* place_boundary; + VIA* via; + CONTROL* control; + RULE* rules; + + KEEPOUTS keepouts; + + COPPER_PLANES planes; + + typedef boost::ptr_vector<REGION> REGIONS; + REGIONS regions; + + RULE* place_rules; + + typedef boost::ptr_vector<GRID> GRIDS; + GRIDS grids; + +public: + + STRUCTURE( ELEM* aParent ) : + ELEM_HOLDER( T_structure, aParent ) + { + unit = 0; + layer_noise_weight = 0; + boundary = 0; + place_boundary = 0; + via = 0; + control = 0; + rules = 0; + place_rules = 0; + } + + ~STRUCTURE() + { + delete unit; + delete layer_noise_weight; + delete boundary; + delete place_boundary; + delete via; + delete control; + delete rules; + delete place_rules; + } + + void SetBOUNDARY( BOUNDARY *aBoundary ) + { + delete boundary; + boundary = aBoundary; + if( boundary ) + { + boundary->SetParent( this ); + } + } + + void SetPlaceBOUNDARY( BOUNDARY *aBoundary ) + { + delete place_boundary; + place_boundary = aBoundary; + if( place_boundary ) + place_boundary->SetParent( this ); + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( unit ) + unit->Format( out, nestLevel ); + + for( LAYERS::iterator i=layers.begin(); i!=layers.end(); ++i ) + i->Format( out, nestLevel ); + + if( layer_noise_weight ) + layer_noise_weight->Format( out, nestLevel ); + + if( boundary ) + boundary->Format( out, nestLevel ); + + if( place_boundary ) + place_boundary->Format( out, nestLevel ); + + for( COPPER_PLANES::iterator i=planes.begin(); i!=planes.end(); ++i ) + i->Format( out, nestLevel ); + + for( REGIONS::iterator i=regions.begin(); i!=regions.end(); ++i ) + i->Format( out, nestLevel ); + + for( KEEPOUTS::iterator i=keepouts.begin(); i!=keepouts.end(); ++i ) + i->Format( out, nestLevel ); + + if( via ) + via->Format( out, nestLevel ); + + if( control ) + control->Format( out, nestLevel ); + + for( int i=0; i<Length(); ++i ) + { + At(i)->Format( out, nestLevel ); + } + + if( rules ) + rules->Format( out, nestLevel ); + + if( place_rules ) + place_rules->Format( out, nestLevel ); + + for( GRIDS::iterator i=grids.begin(); i!=grids.end(); ++i ) + i->Format( out, nestLevel ); + } + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; + + +/** + * Class PLACE + * implements the <placement_reference> in the specctra dsn spec. + */ +class PLACE : public ELEM +{ + friend class SPECCTRA_DB; + + std::string component_id; ///< reference designator + + DSN_T side; + + double rotation; + + bool hasVertex; + POINT vertex; + + DSN_T mirror; + DSN_T status; + + std::string logical_part; + + RULE* place_rules; + + PROPERTIES properties; + + DSN_T lock_type; + + //-----<mutually exclusive>-------------- + RULE* rules; + REGION* region; + //-----</mutually exclusive>------------- + + std::string part_number; + +public: + + PLACE( ELEM* aParent ) : + ELEM( T_place, aParent ) + { + side = T_front; + + rotation = 0.0; + + hasVertex = false; + + mirror = T_NONE; + status = T_NONE; + + place_rules = 0; + + lock_type = T_NONE; + rules = 0; + region = 0; + } + + ~PLACE() + { + delete place_rules; + delete rules; + delete region; + } + + void SetVertex( const POINT& aVertex ) + { + vertex = aVertex; + vertex.FixNegativeZero(); + hasVertex = true; + } + + void SetRotation( double aRotation ) + { + rotation = aRotation; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ); +}; +typedef boost::ptr_vector<PLACE> 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; + PLACES places; + +public: + COMPONENT( ELEM* aParent ) : + ELEM( T_component, aParent ) + { + } + + 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( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( image_id.c_str() ); + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + quote, image_id.c_str(), quote ); + + FormatContents( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( PLACES::iterator i=places.begin(); i!=places.end(); ++i ) + i->Format( out, nestLevel ); + } +}; +typedef boost::ptr_vector<COMPONENT> COMPONENTS; + + +class PLACEMENT : public ELEM +{ + friend class SPECCTRA_DB; + + UNIT_RES* unit; + + DSN_T flip_style; + + COMPONENTS components; + +public: + PLACEMENT( ELEM* aParent ) : + ELEM( T_placement, aParent ) + { + unit = 0; + flip_style = DSN_T( T_NONE ); + } + + ~PLACEMENT() + { + 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; i<components.size(); ++i ) + { + if( 0 == components[i].GetImageId().compare( imageName ) ) + return &components[i]; + } + + COMPONENT* added = new COMPONENT(this); + components.push_back( added ); + added->SetImageId( imageName ); + return added; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( unit ) + unit->Format( out, nestLevel ); + + if( flip_style != DSN_T( T_NONE ) ) + { + out->Print( nestLevel, "(place_control (flip_style %s))\n", + GetTokenText( flip_style ) ); + } + + for( COMPONENTS::iterator i=components.begin(); i!=components.end(); ++i ) + i->Format( out, nestLevel ); + } + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; + + +/** + * Class SHAPE + * corresponds to the "(shape ..)" element in the specctra dsn spec. + * It is not a <shape_descriptor>, which is one of things that this + * elements contains, i.e. in its "shape" field. This class also implements + * the "(outline ...)" element as a dual personality. + */ +class SHAPE : public WINDOW +{ + friend class SPECCTRA_DB; + + DSN_T connect; + + /* <shape_descriptor >::= + [<rectangle_descriptor> | + <circle_descriptor> | + <polygon_descriptor> | + <path_descriptor> | + <qarc_descriptor> ] + ELEM* shape; // inherited from WINDOW + */ + + WINDOWS windows; + +public: + + /** + * Constructor SHAPE + * alternatively takes a DSN_T aType of T_outline + */ + SHAPE( ELEM* aParent, DSN_T aType = T_shape ) : + WINDOW( aParent, aType ) + { + connect = T_on; + } + + void SetConnect( DSN_T aConnect ) + { + connect = aConnect; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s ", Name() ); + + if( shape ) + shape->Format( out, 0 ); + + if( connect == T_off ) + out->Print( 0, "(connect %s)", GetTokenText( connect ) ); + + if( windows.size() ) + { + out->Print( 0, "\n" ); + + for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + else + out->Print( 0, ")\n" ); + } +}; + + +class PIN : public ELEM +{ + friend class SPECCTRA_DB; + + std::string padstack_id; + double rotation; + bool isRotated; + 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 ) + { + rotation = aRotation; + isRotated = (aRotation != 0.0); + } + + void SetVertex( const POINT& aPoint ) + { + vertex = aPoint; + vertex.FixNegativeZero(); + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( padstack_id.c_str() ); + if( isRotated ) + out->Print( nestLevel, "(pin %s%s%s (rotate %.6g)", + quote, padstack_id.c_str(), quote, + rotation + ); + else + out->Print( nestLevel, "(pin %s%s%s", quote, padstack_id.c_str(), quote ); + + quote = out->GetQuoteChar( pin_id.c_str() ); + out->Print( 0, " %s%s%s %.6g %.6g)\n", quote, pin_id.c_str(), quote, + vertex.x, vertex.y ); + } +}; +typedef boost::ptr_vector<PIN> PINS; + + +class LIBRARY; +class IMAGE : public ELEM_HOLDER +{ + friend class SPECCTRA_DB; + friend class LIBRARY; + + std::string hash; ///< a hash string used by Compare(), not Format()ed/exported. + + std::string image_id; + DSN_T side; + UNIT_RES* unit; + + /* The grammar spec says only one outline is supported, but I am seeing + *.dsn examples with multiple outlines. So the outlines will go into + the kids list. + */ + + PINS pins; + + RULE* rules; + RULE* place_rules; + + KEEPOUTS keepouts; + + int duplicated; ///< no. times this image_id is duplicated + +public: + + IMAGE( ELEM* aParent ) : + ELEM_HOLDER( T_image, aParent ) + { + side = T_both; + unit = 0; + rules = 0; + place_rules = 0; + duplicated = 0; + } + ~IMAGE() + { + delete unit; + delete rules; + delete place_rules; + } + + /** + * Function Compare + * compares two objects of this type and returns <0, 0, or >0. + */ + static int Compare( IMAGE* lhs, IMAGE* rhs ); + + std::string GetImageId() + { + if( duplicated ) + { + char buf[32]; + + std::string ret = image_id; + ret += "::"; + sprintf( buf, "%d", duplicated ); + ret += buf; + return ret; + } + + return image_id; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + std::string imageId = GetImageId(); + + const char* quote = out->GetQuoteChar( imageId.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s", Name(), + quote, imageId.c_str(), quote ); + + FormatContents( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + + // this is here for makeHash() + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( side != T_both ) + out->Print( 0, " (side %s)", GetTokenText( side ) ); + + out->Print( 0, "\n"); + + if( unit ) + unit->Format( out, nestLevel ); + + // format the kids, which in this class are the shapes + ELEM_HOLDER::FormatContents( out, nestLevel ); + + for( PINS::iterator i=pins.begin(); i!=pins.end(); ++i ) + i->Format( out, nestLevel ); + + if( rules ) + rules->Format( out, nestLevel ); + + if( place_rules ) + place_rules->Format( out, nestLevel ); + + for( KEEPOUTS::iterator i=keepouts.begin(); i!=keepouts.end(); ++i ) + i->Format( out, nestLevel ); + } + + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; +typedef boost::ptr_vector<IMAGE> 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; + + /* The shapes are stored in the kids list */ + + DSN_T rotate; + DSN_T absolute; + DSN_T attach; + std::string via_id; + + RULE* rules; + +public: + + /** + * 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; + absolute = T_off; + rules = 0; + attach = T_off; + } + ~PADSTACK() + { + delete unit; + delete rules; + } + + const std::string& GetPadstackId() + { + return padstack_id; + } + + /** + * 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; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( padstack_id.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + 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( IO_ERROR ) + { + if( unit ) + unit->Format( out, nestLevel ); + + // format the kids, which in this class are the shapes + ELEM_HOLDER::FormatContents( out, nestLevel ); + + out->Print( nestLevel, "%s", "" ); + + // spec for <attach_descriptor> says default is on, so + // print the off condition to override this. + if( attach == T_off ) + out->Print( 0, "(attach off)" ); + else if( attach == T_on ) + { + const char* quote = out->GetQuoteChar( via_id.c_str() ); + out->Print( 0, "(attach on (use_via %s%s%s))", + quote, via_id.c_str(), quote ); + } + + if( rotate == T_off ) // print the non-default + out->Print( 0, "(rotate %s)", GetTokenText( rotate ) ); + + if( absolute == T_on ) // print the non-default + out->Print( 0, "(absolute %s)", GetTokenText( absolute ) ); + + out->Print( 0, "\n" ); + + if( rules ) + rules->Format( out, nestLevel ); + } + + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; +typedef boost::ptr_vector<PADSTACK> 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 + * corresponds to the <library_descriptor> in the specctra dsn specification. + * Only unit_descriptor, image_descriptors, and padstack_descriptors are + * included as children at this time. + */ +class LIBRARY : public ELEM +{ + friend class SPECCTRA_DB; + + UNIT_RES* unit; + IMAGES images; + + PADSTACKS padstacks; ///< all except vias, which are in 'vias' + PADSTACKS vias; + +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 ) + { + aPadstack->SetParent( this ); + padstacks.push_back( aPadstack ); + } + +/* + void SetViaStartIndex( int aIndex ) + { + via_start_index = aIndex; + } + int GetViaStartIndex() + { + 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 ) + { + unsigned i; + for( i=0; i<images.size(); ++i ) + { + if( 0 == IMAGE::Compare( aImage, &images[i] ) ) + return (int) i; + } + + // There is no match to the IMAGE contents, but now generate a unique + // name for it. + int dups = 1; + for( i=0; i<images.size(); ++i ) + { + if( 0 == aImage->image_id.compare( images[i].image_id ) ) + aImage->duplicated = dups++; + } + + return -1; + } + + + /** + * Function AppendIMAGE + * adds the image to the image list. + */ + void AppendIMAGE( IMAGE* aImage ) + { + aImage->SetParent( this ); + images.push_back( aImage ); + } + + /** + * Function LookupIMAGE + * will add the image only if one exactly like it does not already exist + * in the image container. + * @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 aImage; + } + return &images[ndx]; + } + + /** + * Function FindVia + * searches this LIBRARY for a via which matches the argument. + * @return int - if found the index into the padstack list, else -1. + */ + int FindVia( PADSTACK* aVia ) + { + for( unsigned i=0; i<vias.size(); ++i ) + { + if( 0 == PADSTACK::Compare( aVia, &vias[i] ) ) + return int( i ); + } + return -1; + } + + /** + * Function AppendVia + * adds \a aVia to the internal via container. + */ + void AppendVia( PADSTACK* aVia ) + { + aVia->SetParent( this ); + vias.push_back( aVia ); + } + + + /** + * Function AppendPADSTACK + * adds the padstack to the padstack container. + */ + void AppendPADSTACK( PADSTACK* aPadstack ) + { + aPadstack->SetParent( this ); + padstacks.push_back( aPadstack ); + } + + /** + * Function LookupVia + * will add the via only if one exactly like it does not already exist + * in the padstack container. + * @return PADSTACK* - the PADSTACK which is registered in the LIBRARY that + * matches the argument, and it will be either the argument or + * a previous padstack which is a duplicate. + */ + PADSTACK* LookupVia( PADSTACK* aVia ) + { + int ndx = FindVia( aVia ); + if( ndx == -1 ) + { + AppendVia( aVia ); + return aVia; + } + return &vias[ndx]; + } + + /** + * Function FindPADSTACK + * searches the padstack container by name. + * @return PADSTACK* - The PADSTACK with a matching name if it exists, else NULL. + */ + PADSTACK* FindPADSTACK( const std::string& aPadstackId ) + { + for( unsigned i=0; i<padstacks.size(); ++i ) + { + PADSTACK* ps = &padstacks[i]; + if( 0 == ps->GetPadstackId().compare( aPadstackId ) ) + return ps; + } + return NULL; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( unit ) + unit->Format( out, nestLevel ); + + for( IMAGES::iterator i=images.begin(); i!=images.end(); ++i ) + i->Format( out, nestLevel ); + + for( PADSTACKS::iterator i=padstacks.begin(); i!=padstacks.end(); ++i ) + i->Format( out, nestLevel ); + + for( PADSTACKS::iterator i=vias.begin(); i!=vias.end(); ++i ) + i->Format( out, nestLevel ); + } + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; + + +/** + * Class PIN_REF + * corresponds to the <pin_reference> definition in the specctra dsn spec. + */ +struct PIN_REF : public ELEM +{ + std::string component_id; + std::string pin_id; + + PIN_REF( ELEM* aParent ) : + ELEM( T_pin, aParent ) + { + } + + + /** + * Function FormatIt + * is like Format() but is not virual and returns the number of characters + * that were output. + */ + int FormatIt( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + // only print the newline if there is a nest level, and make + // the quotes unconditional on this one. + const char* newline = nestLevel ? "\n" : ""; + + const char* cquote = out->GetQuoteChar( component_id.c_str() ); + const char* pquote = out->GetQuoteChar( pin_id.c_str() ); + + return out->Print( nestLevel, "%s%s%s-%s%s%s%s", + cquote, component_id.c_str(), cquote, + pquote, pin_id.c_str(), pquote, + newline ); + } +}; +typedef std::vector<PIN_REF> PIN_REFS; + + +class FROMTO : public ELEM +{ + friend class SPECCTRA_DB; + + std::string fromText; + std::string toText; + + DSN_T fromto_type; + std::string net_id; + RULE* rules; +// std::string circuit; + LAYER_RULES layer_rules; + + +public: + FROMTO( ELEM* aParent ) : + ELEM( T_fromto, aParent ) + { + rules = 0; + fromto_type = DSN_T( T_NONE ); + } + ~FROMTO() + { + delete rules; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + // no quoting on these two, the lexer preserved the quotes on input + out->Print( nestLevel, "(%s %s %s ", + Name(), fromText.c_str(), toText.c_str() ); + + if( fromto_type != DSN_T( T_NONE ) ) + out->Print( 0, "(type %s)", GetTokenText( fromto_type ) ); + + if( net_id.size() ) + { + const char* quote = out->GetQuoteChar( net_id.c_str() ); + out->Print( 0, "(net %s%s%s)", quote, net_id.c_str(), quote ); + } + + bool singleLine = true; + + if( rules || layer_rules.size() ) + { + out->Print( 0, "\n" ); + singleLine = false; + } + + if( rules ) + rules->Format( out, nestLevel+1 ); + + /* + if( circuit.size() ) + out->Print( nestLevel, "%s\n", circuit.c_str() ); + */ + + for( LAYER_RULES::iterator i=layer_rules.begin(); i!=layer_rules.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( singleLine ? 0 : nestLevel, ")" ); + if( nestLevel || !singleLine ) + out->Print( 0, "\n" ); + } +}; +typedef boost::ptr_vector<FROMTO> FROMTOS; + + +/** + * Class COMP_ORDER + * corresponds to the <component_order_descriptor> + */ +class COMP_ORDER : public ELEM +{ + friend class SPECCTRA_DB; + + STRINGS placement_ids; + +public: + COMP_ORDER( ELEM* aParent ) : + ELEM( T_comp_order, aParent ) + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + out->Print( nestLevel, "(%s", Name() ); + + for( STRINGS::iterator i=placement_ids.begin(); i!=placement_ids.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( 0, " %s%s%s", quote, i->c_str(), quote ); + } + + out->Print( 0, ")" ); + if( nestLevel ) + out->Print( 0, "\n" ); + } +}; +typedef boost::ptr_vector<COMP_ORDER> COMP_ORDERS; + +/** + * Class NET + * corresponds to a <net_descriptor> + * in the DSN spec. + */ +class NET : public ELEM +{ + friend class SPECCTRA_DB; + + std::string net_id; + bool unassigned; + int net_number; + + 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 + + RULE* rules; + + LAYER_RULES layer_rules; + + FROMTOS fromtos; + + COMP_ORDER* comp_order; + +public: + + NET( ELEM* aParent ) : + ELEM( T_net, aParent ) + { + unassigned = false; + net_number = T_NONE; + pins_type = T_pins; + + type = T_NONE; + supply = T_NONE; + + rules = 0; + comp_order = 0; + } + + ~NET() + { + delete rules; + delete comp_order; + } + + int FindPIN_REF( const std::string& aComponent ) + { + for( unsigned i=0; i<pins.size(); ++i ) + { + if( 0 == aComponent.compare( pins[i].component_id ) ) + return int(i); + } + return -1; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( net_id.c_str() ); + const char* space = " "; + + out->Print( nestLevel, "(%s %s%s%s", Name(), + quote, net_id.c_str(), quote ); + + if( unassigned ) + { + out->Print( 0, "%s(unassigned)", space ); + space = ""; // only needed one space + } + + if( net_number != T_NONE ) + { + out->Print( 0, "%s(net_number %d)", space, net_number ); + // space = ""; + } + + out->Print( 0, "\n" ); + + if( pins.size() ) + { + const int RIGHTMARGIN = 80; + int perLine = out->Print( nestLevel+1, "(%s", GetTokenText( pins_type ) ); + + for( PIN_REFS::iterator i=pins.begin(); i!=pins.end(); ++i ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n"); + perLine = out->Print( nestLevel+2, "%s", "" ); + } + else + perLine += out->Print( 0, " " ); + + perLine += i->FormatIt( out, 0 ); + } + out->Print( 0, ")\n" ); + } + + if( comp_order ) + comp_order->Format( out, nestLevel+1 ); + + if( type != T_NONE ) + out->Print( nestLevel+1, "(type %s)\n", GetTokenText( type ) ); + + if( rules ) + rules->Format( out, nestLevel+1 ); + + for( LAYER_RULES::iterator i=layer_rules.begin(); i!=layer_rules.end(); ++i ) + i->Format( out, nestLevel+1 ); + + for( FROMTOS::iterator i=fromtos.begin(); i!=fromtos.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } +}; +typedef boost::ptr_vector<NET> NETS; + + +class TOPOLOGY : public ELEM +{ + friend class SPECCTRA_DB; + + FROMTOS fromtos; + + COMP_ORDERS comp_orders; + +public: + TOPOLOGY( ELEM* aParent ) : + ELEM( T_topology, aParent ) + { + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( FROMTOS::iterator i=fromtos.begin(); i!=fromtos.end(); ++i ) + i->Format( out, nestLevel ); + + for( COMP_ORDERS::iterator i=comp_orders.begin(); i!=comp_orders.end(); ++i ) + i->Format( out, nestLevel ); + } +}; + + +/** + * Class CLASS + * corresponds to the <class_descriptor> in the specctra spec. + */ +class CLASS : public ELEM +{ + friend class SPECCTRA_DB; + + std::string class_id; + + STRINGS net_ids; + + /// circuit descriptor list + STRINGS circuit; + + RULE* rules; + + LAYER_RULES layer_rules; + + TOPOLOGY* topology; + +public: + + CLASS( ELEM* aParent ) : + ELEM( T_class, aParent ) + { + rules = 0; + topology = 0; + } + ~CLASS() + { + delete rules; + delete topology; + } + + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( class_id.c_str() ); + + int perLine = out->Print( nestLevel, "(%s %s%s%s", + Name(), + quote, class_id.c_str(), quote ); + + const int RIGHTMARGIN = 72; + + for( STRINGS::iterator i=net_ids.begin(); i!=net_ids.end(); ++i ) + { + const char* space = " "; + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + space = ""; // no space at first net_id of the line + } + + quote = out->GetQuoteChar( i->c_str() ); + perLine += out->Print( 0, "%s%s%s%s", space, quote, i->c_str(), quote ); + } + + bool newLine = false; + if( circuit.size() || rules || layer_rules.size() || topology ) + { + out->Print( 0, "\n" ); + newLine = true; + } + + if( circuit.size() ) + { + out->Print( nestLevel+1, "(circuit\n" ); + for( STRINGS::iterator i=circuit.begin(); i!=circuit.end(); ++i ) + out->Print( nestLevel+2, "%s\n", i->c_str() ); + out->Print( nestLevel+1, ")\n" ); + } + + if( rules ) + rules->Format( out, nestLevel+1 ); + + for( LAYER_RULES::iterator i=layer_rules.begin(); i!=layer_rules.end(); ++i ) + i->Format( out, nestLevel+1 ); + + if( topology ) + topology->Format( out, nestLevel+1 ); + + out->Print( newLine ? nestLevel : 0, ")\n" ); + } +}; +typedef boost::ptr_vector<CLASS> CLASSLIST; + + +class NETWORK : public ELEM +{ + friend class SPECCTRA_DB; + + NETS nets; + CLASSLIST classes; + + +public: + + NETWORK( ELEM* aParent ) : + ELEM( T_network, aParent ) + { + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( NETS::iterator i=nets.begin(); i!=nets.end(); ++i ) + i->Format( out, nestLevel ); + + for( CLASSLIST::iterator i=classes.begin(); i!=classes.end(); ++i ) + i->Format( out, nestLevel ); + } +}; + + +class CONNECT : public ELEM +{ + // @todo not completed. + +public: + CONNECT( ELEM* parent ) : + ELEM( T_connect, parent ) {} +}; + + +/** + * Class WIRE + * corresponds to <wire_shape_descriptor> in the specctra dsn spec. + */ +class WIRE : public ELEM +{ + friend class SPECCTRA_DB; + + /* <shape_descriptor >::= + [<rectangle_descriptor> | + <circle_descriptor> | + <polygon_descriptor> | + <path_descriptor> | + <qarc_descriptor> ] + */ + ELEM* shape; + + std::string net_id; + int turret; + DSN_T wire_type; + DSN_T attr; + std::string shield; + WINDOWS windows; + CONNECT* connect; + bool supply; + +public: + WIRE( ELEM* aParent ) : + ELEM( T_wire, aParent ) + { + shape = 0; + connect = 0; + + turret = -1; + wire_type = T_NONE; + attr = T_NONE; + supply = false; + } + + ~WIRE() + { + delete shape; + delete connect; + } + + 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( IO_ERROR ) + { + out->Print( nestLevel, "(%s ", Name() ); + + if( shape ) + shape->Format( out, 0 ); + + if( net_id.size() ) + { + const char* quote = out->GetQuoteChar( net_id.c_str() ); + out->Print( 0, "(net %s%s%s)", + quote, net_id.c_str(), quote ); + } + + if( turret >= 0 ) + out->Print( 0, "(turrent %d)", turret ); + + if( wire_type != T_NONE ) + out->Print( 0, "(type %s)", GetTokenText( wire_type ) ); + + if( attr != T_NONE ) + out->Print( 0, "(attr %s)", GetTokenText( attr ) ); + + if( shield.size() ) + { + const char* quote = out->GetQuoteChar( shield.c_str() ); + out->Print( 0, "(shield %s%s%s)", + quote, shield.c_str(), quote ); + } + + if( windows.size() ) + { + out->Print( 0, "\n" ); + + for( WINDOWS::iterator i=windows.begin(); i!=windows.end(); ++i ) + i->Format( out, nestLevel+1 ); + } + + if( connect ) + connect->Format( out, 0 ); + + if( supply ) + out->Print( 0, "(supply)" ); + + out->Print( 0, ")\n" ); + } +}; +typedef boost::ptr_vector<WIRE> WIRES; + + +/** + * Class WIRE_VIA + * corresponds to <wire_via_descriptor> in the specctra dsn spec. + */ +class WIRE_VIA : public ELEM +{ + friend class SPECCTRA_DB; + + std::string padstack_id; + POINTS vertexes; + std::string net_id; + int via_number; + DSN_T via_type; + DSN_T attr; + std::string virtual_pin_name; + STRINGS contact_layers; + bool supply; + + +public: + WIRE_VIA( ELEM* aParent ) : + ELEM( T_via, aParent ) + { + via_number = -1; + via_type = T_NONE; + attr = T_NONE; + supply = false; + } + + const std::string& GetPadstackId() + { + return padstack_id; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( padstack_id.c_str() ); + + const int RIGHTMARGIN = 80; + int perLine = out->Print( nestLevel, "(%s %s%s%s", + Name(), + quote, padstack_id.c_str(), quote ); + + for( POINTS::iterator i=vertexes.begin(); i!=vertexes.end(); ++i ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + else + perLine += out->Print( 0, " " ); + + perLine += out->Print( 0, "%.6g %.6g", i->x, i->y ); + } + + if( net_id.size() || via_number!=-1 || via_type!=T_NONE || attr!=T_NONE || supply) + out->Print( 0, " " ); + + if( net_id.size() ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + const char* quote = out->GetQuoteChar( net_id.c_str() ); + perLine += out->Print( 0, "(net %s%s%s)", quote, net_id.c_str(), quote ); + } + + if( via_number != -1 ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + perLine += out->Print( 0, "(via_number %d)", via_number ); + } + + if( via_type != T_NONE ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + perLine += out->Print( 0, "(type %s)", GetTokenText( via_type ) ); + } + + if( attr != T_NONE ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + if( attr == T_virtual_pin ) + { + const char* quote = out->GetQuoteChar( virtual_pin_name.c_str() ); + perLine += out->Print( 0, "(attr virtual_pin %s%s%s)", + quote, virtual_pin_name.c_str(), quote ); + } + else + perLine += out->Print( 0, "(attr %s)", GetTokenText( attr ) ); + } + + if( supply ) + { + if( perLine > RIGHTMARGIN ) + { + out->Print( 0, "\n" ); + perLine = out->Print( nestLevel+1, "%s", "" ); + } + perLine += out->Print( 0, "(supply)" ); + } + + if( contact_layers.size() ) + { + out->Print( 0, "\n" ); + out->Print( nestLevel+1, "(contact\n" ); + + for( STRINGS::iterator i=contact_layers.begin(); i!=contact_layers.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( nestLevel+2, "%s%s%s\n", quote, i->c_str(), quote ); + } + out->Print( nestLevel+1, "))\n" ); + } + else + out->Print( 0, ")\n" ); + } +}; +typedef boost::ptr_vector<WIRE_VIA> WIRE_VIAS; + + +/** + * Class WIRING + * corresponds to <wiring_descriptor> in the specctra dsn spec. + */ +class WIRING : public ELEM +{ + friend class SPECCTRA_DB; + + UNIT_RES* unit; + WIRES wires; + WIRE_VIAS wire_vias; + +public: + + WIRING( ELEM* aParent ) : + ELEM( T_wiring, aParent ) + { + unit = 0; + } + ~WIRING() + { + delete unit; + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( unit ) + unit->Format( out, nestLevel ); + + for( WIRES::iterator i=wires.begin(); i!=wires.end(); ++i ) + i->Format( out, nestLevel ); + + for( WIRE_VIAS::iterator i=wire_vias.begin(); i!=wire_vias.end(); ++i ) + i->Format( out, nestLevel ); + } + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + return ELEM::GetUnits(); + } +}; + + +class PCB : public ELEM +{ + friend class SPECCTRA_DB; + + std::string pcbname; + PARSER* parser; + UNIT_RES* resolution; + UNIT_RES* unit; + STRUCTURE* structure; + PLACEMENT* placement; + LIBRARY* library; + NETWORK* network; + WIRING* wiring; + +public: + + PCB( ELEM* aParent = 0 ) : + ELEM( T_pcb, aParent ) + { + parser = 0; + resolution = 0; + unit = 0; + structure = 0; + placement = 0; + library = 0; + network = 0; + wiring = 0; + } + + ~PCB() + { + delete parser; + delete resolution; + delete unit; + delete structure; + delete placement; + delete library; + delete network; + delete wiring; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( pcbname.c_str() ); + + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + quote, pcbname.c_str(), quote ); + + if( parser ) + parser->Format( out, nestLevel+1 ); + + if( resolution ) + resolution->Format( out, nestLevel+1 ); + + if( unit ) + unit->Format( out, nestLevel+1 ); + + if( structure ) + structure->Format( out, nestLevel+1 ); + + if( placement ) + placement->Format( out, nestLevel+1 ); + + if( library ) + library->Format( out, nestLevel+1 ); + + if( network ) + network->Format( out, nestLevel+1 ); + + if( wiring ) + wiring->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } + + UNIT_RES* GetUnits() const + { + if( unit ) + return unit; + + if( resolution ) + return resolution->GetUnits(); + + return ELEM::GetUnits(); + } +}; + + +class ANCESTOR : public ELEM +{ + friend class SPECCTRA_DB; + + std::string filename; + std::string comment; + time_t time_stamp; + + +public: + ANCESTOR( ELEM* aParent ) : + ELEM( T_ancestor, aParent ) + { + time_stamp = time(NULL); + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + char temp[80]; + struct tm* tmp; + + tmp = localtime( &time_stamp ); + strftime( temp, sizeof(temp), "%b %d %H : %M : %S %Y", tmp ); + + // format the time first to temp + // filename may be empty, so quote it just in case. + out->Print( nestLevel, "(%s \"%s\" (created_time %s)\n", + Name(), + filename.c_str(), + temp ); + + if( comment.size() ) + { + const char* quote = out->GetQuoteChar( comment.c_str() ); + out->Print( nestLevel+1, "(comment %s%s%s)\n", + quote, comment.c_str(), quote ); + } + + out->Print( nestLevel, ")\n" ); + } +}; +typedef boost::ptr_vector<ANCESTOR> ANCESTORS; + + +class HISTORY : public ELEM +{ + friend class SPECCTRA_DB; + + ANCESTORS ancestors; + time_t time_stamp; + STRINGS comments; + +public: + + HISTORY( ELEM* aParent ) : + ELEM( T_history, aParent ) + { + time_stamp = time(NULL); + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( ANCESTORS::iterator i=ancestors.begin(); i!=ancestors.end(); ++i ) + i->Format( out, nestLevel ); + + char temp[80]; + struct tm* tmp; + + tmp = localtime( &time_stamp ); + strftime( temp, sizeof(temp), "%b %d %H : %M : %S %Y", tmp ); + + // format the time first to temp + out->Print( nestLevel, "(self (created_time %s)\n", temp ); + + for( STRINGS::iterator i=comments.begin(); i!=comments.end(); ++i ) + { + const char* quote = out->GetQuoteChar( i->c_str() ); + out->Print( nestLevel+1, "(comment %s%s%s)\n", + quote, i->c_str(), quote ); + } + + out->Print( nestLevel, ")\n" ); + } +}; + + +/** + * Class SUPPLY_PIN + * corresponds to the <supply_pin_descriptor> in the specctra dsn spec. +*/ +class SUPPLY_PIN : public ELEM +{ + friend class SPECCTRA_DB; + + PIN_REFS pin_refs; + std::string net_id; + +public: + SUPPLY_PIN( ELEM* aParent ) : + ELEM( T_supply_pin, aParent ) + { + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + bool singleLine = pin_refs.size() <= 1; + out->Print( nestLevel, "(%s", Name() ); + + if( singleLine ) + { + out->Print( 0, "%s", " " ); + pin_refs.begin()->Format( out, 0 ); + } + else + { + for( PIN_REFS::iterator i=pin_refs.begin(); i!=pin_refs.end(); ++i ) + i->FormatIt( out, nestLevel+1 ); + } + + if( net_id.size() ) + { + const char* newline = singleLine ? "" : "\n"; + + const char* quote = out->GetQuoteChar( net_id.c_str() ); + out->Print( singleLine ? 0 : nestLevel+1, + " (net %s%s%s)%s", quote, net_id.c_str(), quote, newline ); + } + + out->Print( singleLine ? 0 : nestLevel, ")\n"); + } +}; +typedef boost::ptr_vector<SUPPLY_PIN> SUPPLY_PINS; + + +/** + * Class NET_OUT + * corresponds to the <net_out_descriptor> of the specctra dsn spec. + */ +class NET_OUT : public ELEM +{ + friend class SPECCTRA_DB; + + std::string net_id; + int net_number; + RULE* rules; + WIRES wires; + WIRE_VIAS wire_vias; + SUPPLY_PINS supply_pins; + + +public: + NET_OUT( ELEM* aParent ) : + ELEM( T_net_out, aParent ) + { + rules = 0; + net_number = -1; + } + ~NET_OUT() + { + delete rules; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( net_id.c_str() ); + + // cannot use Type() here, it is T_net_out and we need "(net " + out->Print( nestLevel, "(net %s%s%s\n", + quote, net_id.c_str(), quote ); + + if( net_number>= 0 ) + out->Print( nestLevel+1, "(net_number %d)\n", net_number ); + + if( rules ) + rules->Format( out, nestLevel+1 ); + + for( WIRES::iterator i=wires.begin(); i!=wires.end(); ++i ) + i->Format( out, nestLevel+1 ); + + for( WIRE_VIAS::iterator i=wire_vias.begin(); i!=wire_vias.end(); ++i ) + i->Format( out, nestLevel+1 ); + + for( SUPPLY_PINS::iterator i=supply_pins.begin(); i!=supply_pins.end(); ++i ) + i->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } +}; +typedef boost::ptr_vector<NET_OUT> NET_OUTS; + + +class ROUTE : public ELEM +{ + friend class SPECCTRA_DB; + + UNIT_RES* resolution; + PARSER* parser; + STRUCTURE_OUT* structure_out; + LIBRARY* library; + NET_OUTS net_outs; +// TEST_POINTS* test_points; + +public: + + ROUTE( ELEM* aParent ) : + ELEM( T_route, aParent ) + { + resolution = 0; + parser = 0; + structure_out = 0; + library = 0; + } + ~ROUTE() + { + delete resolution; + delete parser; + delete structure_out; + delete library; +// delete test_points; + } + + UNIT_RES* GetUnits() const + { + if( resolution ) + return resolution; + + return ELEM::GetUnits(); + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + if( resolution ) + resolution->Format( out, nestLevel ); + + if( parser ) + parser->Format( out, nestLevel ); + + if( structure_out ) + structure_out->Format( out, nestLevel ); + + if( library ) + library->Format( out, nestLevel ); + + if( net_outs.size() ) + { + out->Print( nestLevel, "(network_out\n" ); + for( NET_OUTS::iterator i=net_outs.begin(); i!=net_outs.end(); ++i ) + i->Format( out, nestLevel+1 ); + out->Print( nestLevel, ")\n" ); + } + +// if( test_poinst ) +// test_points->Format( out, nestLevel ); + } +}; + + +/** + * Struct PIN_PAIR + * is used within the WAS_IS class below to hold a pair of PIN_REFs and + * corresponds to the (pins was is) construct within the specctra dsn spec. + */ +struct PIN_PAIR +{ + PIN_PAIR( ELEM* aParent = 0 ) : + was( aParent ), + is( aParent ) + { + } + + PIN_REF was; + PIN_REF is; +}; +typedef std::vector<PIN_PAIR> PIN_PAIRS; + + +/** + * Class WAS_IS + * corresponds to the <was_is_descriptor> in the specctra dsn spec. + */ +class WAS_IS : public ELEM +{ + friend class SPECCTRA_DB; + + PIN_PAIRS pin_pairs; + +public: + WAS_IS( ELEM* aParent ) : + ELEM( T_was_is, aParent ) + { + } + + void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + for( PIN_PAIRS::iterator i=pin_pairs.begin(); i!=pin_pairs.end(); ++i ) + { + out->Print( nestLevel, "(pins " ); + i->was.Format( out, 0 ); + out->Print( 0, " " ); + i->is.Format( out, 0 ); + out->Print( 0, ")\n" ); + } + } +}; + + +/** + * Class SESSION + * corresponds to the <session_file_descriptor> in the specctra dsn spec. + */ +class SESSION : public ELEM +{ + friend class SPECCTRA_DB; + + std::string session_id; + std::string base_design; + + HISTORY* history; + STRUCTURE* structure; + PLACEMENT* placement; + WAS_IS* was_is; + ROUTE* route; + +/* not supported: + FLOOR_PLAN* floor_plan; + NET_PIN_CHANGES* net_pin_changes; + SWAP_HISTORY* swap_history; +*/ + +public: + + SESSION( ELEM* aParent = 0 ) : + ELEM( T_session, aParent ) + { + history = 0; + structure = 0; + placement = 0; + was_is = 0; + route = 0; + } + ~SESSION() + { + delete history; + delete structure; + delete placement; + delete was_is; + delete route; + } + + void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) + { + const char* quote = out->GetQuoteChar( session_id.c_str() ); + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + quote, session_id.c_str(), quote ); + + out->Print( nestLevel+1, "(base_design \"%s\")\n", base_design.c_str() ); + + if( history ) + history->Format( out, nestLevel+1 ); + + if( structure ) + structure->Format( out, nestLevel+1 ); + + if( placement ) + placement->Format( out, nestLevel+1 ); + + if( was_is ) + was_is->Format( out, nestLevel+1 ); + + if( route ) + route->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); + } +}; + +typedef boost::ptr_set<PADSTACK> PADSTACKSET; + + +/** + * Class SPECCTRA_DB + * holds a DSN data tree, usually coming from a DSN file. Is essentially a + * SPECCTRA_PARSER class. + */ +class SPECCTRA_DB : public SPECCTRA_LEXER +{ + /// specctra DSN keywords + static const KEYWORD keywords[]; + static const unsigned keywordCount; + + PCB* pcb; + SESSION* session; + wxString filename; + std::string quote_char; + + bool modulesAreFlipped; + + STRING_FORMATTER sf; + + STRINGS layerIds; ///< indexed by PCB layer number + + /// maps BOARD layer number to PCB layer numbers + std::vector<int> kicadLayer2pcb; + + /// maps PCB layer number to BOARD layer numbers + std::vector<LAYER_ID> pcbLayer2kicad; + + /// used during FromSESSION() only, memory for it is not owned here. + UNIT_RES* routeResolution; + + /// a copy to avoid passing as an argument, memory for it is not owned here. + BOARD* sessionBoard; + + static const KICAD_T scanPADs[]; + + PADSTACKSET padstackset; + + /// we don't want ownership here permanently, so we don't use boost::ptr_vector + std::vector<NET*> nets; + + /// specctra cu layers, 0 based index: + int m_top_via_layer; + int m_bot_via_layer; + + + /** + * Function buildLayerMaps + * creates a few data translation structures for layer name and number + * mapping between the DSN::PCB structure and the KiCad BOARD structure. + * @param aBoard The BOARD to create the maps for. + */ + void buildLayerMaps( BOARD* aBoard ); + + /** + * Function findLayerName + * returns the PCB layer index for a given layer name, within the specctra session + * file. + * + * @return int - the layer index within the specctra session file, or -1 if + * aLayerName is not found. + */ + int findLayerName( const std::string& aLayerName ) const; + + /** + * Function readCOMPnPIN + * reads a <pin_reference> and splits it into the two parts which are + * on either side of the hyphen. This function is specialized because + * pin_reference may or may not be using double quotes. Both of these + * are legal: U2-14 or "U2"-"14". The lexer treats the first one as a + * single T_SYMBOL, so in that case we have to split it into two here. + * <p> + * The caller should have already read in the first token comprizing the + * pin_reference and it will be tested through CurTok(). + * + * @param component_id Where to put the text preceeding the '-' hyphen. + * @param pid_id Where to put the text which trails the '-'. + * @throw IO_ERROR, if the next token or two do no make up a pin_reference, + * or there is an error reading from the input stream. + */ + void readCOMPnPIN( std::string* component_id, std::string* pid_id ) throw( IO_ERROR ); + + /** + * Function readTIME + * reads a <time_stamp> which consists of 8 lexer tokens: + * "month date hour : minute : second year". + * This function is specialized because time_stamps occur more than + * once in a session file. + * <p> + * The caller should not have already read in the first token comprizing the + * time stamp. + * + * @param time_stamp Where to put the parsed time value. + * @throw IO_ERROR, if the next token or 8 do no make up a time stamp, + * or there is an error reading from the input stream. + */ + void readTIME( time_t* time_stamp ) throw( IO_ERROR ); + + void doPCB( PCB* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doPARSER( PARSER* growth ) throw( IO_ERROR ); + void doRESOLUTION( UNIT_RES* growth ) throw( IO_ERROR ); + void doUNIT( UNIT_RES* growth ) throw( IO_ERROR ); + void doSTRUCTURE( STRUCTURE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doSTRUCTURE_OUT( STRUCTURE_OUT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doLAYER_NOISE_WEIGHT( LAYER_NOISE_WEIGHT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doLAYER_PAIR( LAYER_PAIR* growth ) throw( IO_ERROR ); + void doBOUNDARY( BOUNDARY* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doRECTANGLE( RECTANGLE* growth ) throw( IO_ERROR ); + void doPATH( PATH* growth ) throw( IO_ERROR ); + void doSTRINGPROP( STRINGPROP* growth ) throw( IO_ERROR ); + void doTOKPROP( TOKPROP* growth ) throw( IO_ERROR ); + void doVIA( VIA* growth ) throw( IO_ERROR ); + void doCONTROL( CONTROL* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doLAYER( LAYER* growth ) throw( IO_ERROR ); + void doRULE( RULE* growth ) throw( IO_ERROR ); + void doKEEPOUT( KEEPOUT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doCIRCLE( CIRCLE* growth ) throw( IO_ERROR ); + void doQARC( QARC* growth ) throw( IO_ERROR ); + void doWINDOW( WINDOW* growth ) throw( IO_ERROR ); + void doCONNECT( CONNECT* growth ) throw( IO_ERROR ); + void doREGION( REGION* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doCLASS_CLASS( CLASS_CLASS* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doLAYER_RULE( LAYER_RULE* growth ) throw( IO_ERROR ); + void doCLASSES( CLASSES* growth ) throw( IO_ERROR ); + void doGRID( GRID* growth ) throw( IO_ERROR ); + void doPLACE( PLACE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doCOMPONENT( COMPONENT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doPLACEMENT( PLACEMENT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doPROPERTIES( PROPERTIES* growth ) throw( IO_ERROR ); + void doPADSTACK( PADSTACK* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doSHAPE( SHAPE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doIMAGE( IMAGE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doLIBRARY( LIBRARY* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doPIN( PIN* growth ) throw( IO_ERROR ); + void doNET( NET* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doNETWORK( NETWORK* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doCLASS( CLASS* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doTOPOLOGY( TOPOLOGY* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doFROMTO( FROMTO* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doCOMP_ORDER( COMP_ORDER* growth ) throw( IO_ERROR ); + void doWIRE( WIRE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doWIRE_VIA( WIRE_VIA* growth ) throw( IO_ERROR ); + void doWIRING( WIRING* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doSESSION( SESSION* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doANCESTOR( ANCESTOR* growth ) throw( IO_ERROR ); + void doHISTORY( HISTORY* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doROUTE( ROUTE* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doWAS_IS( WAS_IS* growth ) throw( IO_ERROR ); + void doNET_OUT( NET_OUT* growth ) throw( IO_ERROR, boost::bad_pointer ); + void doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IO_ERROR ); + + //-----<FromBOARD>------------------------------------------------------- + + /** + * Function fillBOUNDARY + * makes the board perimeter for the DSN file by filling the BOUNDARY element + * in the specctra element tree. + * @param aBoard The BOARD to get information from in order to make the BOUNDARY. + * @param aBoundary The empty BOUNDARY to fill in. + */ + void fillBOUNDARY( BOARD* aBoard, BOUNDARY* aBoundary ) throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function makeIMAGE + * allocates an IMAGE on the heap and creates all the PINs according + * 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( BOARD* aBoard, MODULE* aModule ); + + /** + * 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 aBoard The owner of the MODULE. + * @param aPad The D_PAD which needs to be made into a PADSTACK. + * @return PADSTACK* - The created padstack, including its padstack_id. + */ + 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, + int aTopLayer, int aBotLayer ); + + /** + * Function makeVia + * makes any kind of PADSTACK using the given KiCad VIA. + * @param aVia The VIA to build the padstack from. + * @return PADSTACK* - The padstack, which is on the heap only, user must save + * or delete it. + */ + PADSTACK* makeVia( const ::VIA* aVia ); + + /** + * Function deleteNETs + * deletes all the NETs that may be in here. + */ + void deleteNETs() + { + for( unsigned n=0; n<nets.size(); ++n ) + delete nets[n]; + + nets.clear(); + } + + /** + * Function exportNETCLASS + * exports \a aNetClass to the DSN file. + */ + void exportNETCLASS( boost::shared_ptr<NETCLASS> aNetClass, BOARD* aBoard ); + + //-----</FromBOARD>------------------------------------------------------ + + //-----<FromSESSION>----------------------------------------------------- + + /** + * Function makeTRACK + * creates a TRACK form the PATH and BOARD info. + */ + TRACK* makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR ); + + /** + * Function makeVIA + * instantiates a KiCad VIA on the heap and initializes it with internal + * values consistent with the given PADSTACK, POINT, and netcode. + */ + ::VIA* makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNetCode, int aViaDrillDefault ) + throw( IO_ERROR ); + + //-----</FromSESSION>---------------------------------------------------- + +public: + + SPECCTRA_DB() : + SPECCTRA_LEXER( 0 ) // LINE_READER* == NULL, no DSNLEXER::PushReader() + { + // The LINE_READER will be pushed from an automatic instantiation, + // we don't own it: + wxASSERT( !iOwnReaders ); + + pcb = 0; + session = 0; + quote_char += '"'; + modulesAreFlipped = false; + + SetSpecctraMode( true ); + + // Avoid not initialized members: + routeResolution = NULL; + sessionBoard = NULL; + m_top_via_layer = 0; + m_bot_via_layer = 0; + } + + virtual ~SPECCTRA_DB() + { + delete pcb; + delete session; + + deleteNETs(); + } + + /** + * Function MakePCB + * makes a PCB with all the default ELEMs and parts on the heap. + */ + static PCB* MakePCB(); + + /** + * Function SetPCB + * deletes any existing PCB and replaces it with the given one. + */ + void SetPCB( PCB* aPcb ) + { + delete pcb; + pcb = aPcb; + } + PCB* GetPCB() { return pcb; } + + /** + * Function SetSESSION + * deletes any existing SESSION and replaces it with the given one. + */ + void SetSESSION( SESSION* aSession ) + { + delete session; + session = aSession; + } + SESSION* GetSESSION() { return session; } + + /** + * Function LoadPCB + * is a recursive descent parser for a SPECCTRA DSN "design" file. + * A design file is nearly a full description of a PCB (seems to be + * missing only the silkscreen stuff). + * + * @param filename The name of the dsn file to load. + * @throw IO_ERROR if there is a lexer or parser error. + */ + void LoadPCB( const wxString& filename ) throw( IO_ERROR, boost::bad_pointer ); + + /** + * Function LoadSESSION + * is a recursive descent parser for a SPECCTRA DSN "session" file. + * A session file is a file that is fed back from the router to the layout + * tool (Pcbnew) and should be used to update a BOARD object with the new + * tracks, vias, and component locations. + * + * @param filename The name of the dsn file to load. + * @throw IO_ERROR if there is a lexer or parser error. + */ + void LoadSESSION( const wxString& filename ) throw( IO_ERROR, boost::bad_pointer ); + + void ThrowIOError( const wxString& fmt, ... ) throw( IO_ERROR ); + + /** + * Function ExportPCB + * writes the internal PCB instance out as a SPECTRA DSN format file. + * + * @param aFilename The file to save to. + * @param aNameChange If true, causes the pcb's name to change to "aFilename" + * and also to to be changed in the output file. + * @throw IO_ERROR, if an i/o error occurs saving the file. + */ + void ExportPCB( wxString aFilename, bool aNameChange=false ) throw( IO_ERROR ); + + /** + * Function FromBOARD + * adds the entire BOARD to the PCB but does not write it out. Note that + * the BOARD given to this function must have all the MODULEs on the component + * side of the BOARD. + * + * See void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) + * for how this can be done before calling this function. + * + * @param aBoard The BOARD to convert to a PCB. + */ + void FromBOARD( BOARD* aBoard ) throw( IO_ERROR, boost::bad_ptr_container_operation ); + + /** + * Function FromSESSION + * adds the entire SESSION info to a BOARD but does not write it out. The + * the BOARD given to this function will have all its tracks and via's replaced, + * and all its components are subject to being moved. + * + * @param aBoard The BOARD to merge the SESSION information into. + */ + void FromSESSION( BOARD* aBoard ) throw( IO_ERROR ); + + /** + * Function ExportSESSION + * writes the internal SESSION instance out as a SPECTRA DSN format file. + * + * @param aFilename The file to save to. + */ + void ExportSESSION( wxString aFilename ); + + /** + * Function FlipMODULEs + * flips the modules which are on the back side of the board to the front. + */ + void FlipMODULEs( BOARD* aBoard ); + + /** + * Function RevertMODULEs + * flips the modules which were on the back side of the board back to the back. + */ + void RevertMODULEs( BOARD* aBoard ); + + /** + * Function GetBoardPolygonOutlines + * Is not used in SPECCTRA export, but uses a lot of functions from it + * and is used to extract a board outlines (3D view, automatic zones build ...) + * makes the board perimeter by filling the BOUNDARY element + * any closed outline inside the main outline is a hole + * All contours should be closed, i.e. have valid vertices to build a closed polygon + * @param aBoard The BOARD to get information from in order to make the outlines. + * @param aOutlines The SHAPE_POLY_SET to fill in with main outlines. + * @param aHoles The empty SHAPE_POLY_SET to fill in with holes, if any. + * @param aErrorText = a wxString reference to display an error message + * with the coordinate of the point which creates the error + * (default = NULL , no message returned on error) + * @return true if success, false if a contour is not valid + */ + bool GetBoardPolygonOutlines( BOARD* aBoard, + SHAPE_POLY_SET& aOutlines, + SHAPE_POLY_SET& aHoles, + wxString* aErrorText = NULL ); +}; + + +} // namespace DSN + +#endif // SPECCTRA_H_ + +//EOF |