4017 lines
98 KiB
C++
4017 lines
98 KiB
C++
/*
|
|
* 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-2023 KiCad Developers, see AUTHORS.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 <specctra_import_export/specctra_lexer.h>
|
|
|
|
#include <memory>
|
|
#include <geometry/shape_poly_set.h>
|
|
|
|
// all outside the DSN namespace:
|
|
class BOARD;
|
|
class PCB_TRACK;
|
|
class PCB_VIA;
|
|
class NETCLASS;
|
|
class FOOTPRINT;
|
|
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 constructor, then boost::ptr_vector
|
|
* cannot be beat.
|
|
*/
|
|
namespace DSN {
|
|
|
|
|
|
class SPECCTRA_DB;
|
|
|
|
|
|
/**
|
|
* @brief Helper method to export board to DSN file
|
|
* @param aBoard board object
|
|
* @param aFullFilename specctra file name
|
|
*/
|
|
void ExportBoardToSpecctraFile( BOARD* aBoard, const wxString& aFullFilename );
|
|
|
|
|
|
/**
|
|
* The DSN namespace and returns the C string representing a SPECCTRA_DB::keyword.
|
|
*
|
|
* We needed a non-instance function to get at the SPECCTRA_DB::keyword[] and class
|
|
* SPECCTRA_DB is not defined yet.
|
|
*/
|
|
const char* GetTokenText( T aTok );
|
|
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Write 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 precede 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
|
|
{
|
|
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;
|
|
|
|
/**
|
|
* Write 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 precede 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
|
|
{
|
|
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;
|
|
|
|
/**
|
|
* A base class for any DSN element class.
|
|
*
|
|
* See class #ELEM_HOLDER also.
|
|
*/
|
|
class ELEM
|
|
{
|
|
public:
|
|
|
|
ELEM( DSN_T aType, ELEM* aParent = nullptr );
|
|
|
|
virtual ~ELEM();
|
|
|
|
DSN_T Type() const { return type; }
|
|
|
|
const char* Name() const;
|
|
|
|
|
|
/**
|
|
* Return the units for this section.
|
|
*
|
|
* Derived classes may override this to check for section specific overrides.
|
|
*
|
|
* @return an element from a local or parent scope.
|
|
*/
|
|
virtual UNIT_RES* GetUnits() const;
|
|
|
|
/**
|
|
* Write 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 precede 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 );
|
|
|
|
/**
|
|
* Write 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 precede 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 )
|
|
{
|
|
// overridden in ELEM_HOLDER
|
|
}
|
|
|
|
void SetParent( ELEM* aParent )
|
|
{
|
|
parent = aParent;
|
|
}
|
|
|
|
protected:
|
|
|
|
/**
|
|
* Return a string which uniquely represents this ELEM among other ELEMs of the same
|
|
* derived class as "this" one.
|
|
*
|
|
* It is not usable 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;
|
|
|
|
DSN_T type;
|
|
ELEM* parent;
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
};
|
|
|
|
|
|
/**
|
|
* A holder for any DSN class.
|
|
*
|
|
* It can contain other class instances, including classes derived from this class.
|
|
*/
|
|
class ELEM_HOLDER : public ELEM
|
|
{
|
|
public:
|
|
|
|
ELEM_HOLDER( DSN_T aType, ELEM* aParent = nullptr ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
}
|
|
|
|
virtual void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override;
|
|
|
|
|
|
//-----< list operations >--------------------------------------------
|
|
|
|
/**
|
|
* Find 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 );
|
|
|
|
|
|
/**
|
|
* Return the number of ELEMs in this holder.
|
|
*
|
|
* @return the count of children elements.
|
|
*/
|
|
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 ); }
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
typedef boost::ptr_vector<ELEM> ELEM_ARRAY;
|
|
|
|
ELEM_ARRAY kids; ///< ELEM pointers
|
|
};
|
|
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
public:
|
|
|
|
PARSER( ELEM* aParent );
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override;
|
|
|
|
private:
|
|
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;
|
|
};
|
|
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
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 ) override
|
|
{
|
|
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 );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
DSN_T units;
|
|
int value;
|
|
};
|
|
|
|
|
|
class RECTANGLE : public ELEM
|
|
{
|
|
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 ) override
|
|
{
|
|
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 );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string layer_id;
|
|
|
|
POINT point0; ///< one of two opposite corners
|
|
POINT point1;
|
|
};
|
|
|
|
|
|
/**
|
|
* A <rule_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class RULE : public ELEM
|
|
{
|
|
public:
|
|
|
|
RULE( ELEM* aParent, DSN_T aType ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s", Name() );
|
|
|
|
bool singleLine;
|
|
|
|
if( m_rules.size() == 1 )
|
|
{
|
|
singleLine = true;
|
|
out->Print( 0, " %s)", m_rules.begin()->c_str() );
|
|
}
|
|
|
|
else
|
|
{
|
|
out->Print( 0, "\n" );
|
|
singleLine = false;
|
|
|
|
for( STRINGS::const_iterator i = m_rules.begin(); i != m_rules.end(); ++i )
|
|
out->Print( nestLevel+1, "%s\n", i->c_str() );
|
|
|
|
out->Print( nestLevel, ")" );
|
|
}
|
|
|
|
if( nestLevel || !singleLine )
|
|
out->Print( 0, "\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
STRINGS m_rules; ///< rules are saved in std::string form.
|
|
};
|
|
|
|
|
|
class LAYER_RULE : public ELEM
|
|
{
|
|
public:
|
|
|
|
LAYER_RULE( ELEM* aParent ) :
|
|
ELEM( T_layer_rule, aParent )
|
|
{
|
|
m_rule = nullptr;
|
|
}
|
|
|
|
~LAYER_RULE()
|
|
{
|
|
delete m_rule;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s", Name() );
|
|
|
|
for( STRINGS::const_iterator i = m_layer_ids.begin(); i != m_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( m_rule )
|
|
m_rule->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
STRINGS m_layer_ids;
|
|
RULE* m_rule;
|
|
};
|
|
|
|
|
|
typedef boost::ptr_vector<LAYER_RULE> LAYER_RULES;
|
|
|
|
|
|
/**
|
|
* Support both the <path_descriptor> and the <polygon_descriptor> per
|
|
* the specctra dsn spec.
|
|
*/
|
|
class PATH : public ELEM
|
|
{
|
|
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 ) override
|
|
{
|
|
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 );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string layer_id;
|
|
double aperture_width;
|
|
|
|
POINTS points;
|
|
DSN_T aperture_type;
|
|
};
|
|
|
|
typedef boost::ptr_vector<PATH> PATHS;
|
|
|
|
|
|
class BOUNDARY : public ELEM
|
|
{
|
|
public:
|
|
|
|
BOUNDARY( ELEM* aParent, DSN_T aType = T_boundary ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
rectangle = nullptr;
|
|
}
|
|
|
|
~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 ) override
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
// only one or the other of these two is used, not both
|
|
PATHS paths;
|
|
RECTANGLE* rectangle;
|
|
};
|
|
|
|
|
|
class CIRCLE : public ELEM
|
|
{
|
|
public:
|
|
CIRCLE( ELEM* aParent ) :
|
|
ELEM( T_circle, aParent )
|
|
{
|
|
diameter = 0.0;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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;
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string layer_id;
|
|
|
|
double diameter;
|
|
POINT vertex; // POINT's constructor sets to (0,0)
|
|
};
|
|
|
|
|
|
class QARC : public ELEM
|
|
{
|
|
public:
|
|
QARC( ELEM* aParent ) :
|
|
ELEM( T_qarc, aParent )
|
|
{
|
|
aperture_width = 0.0;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string layer_id;
|
|
double aperture_width;
|
|
POINT vertex[3];
|
|
};
|
|
|
|
|
|
class WINDOW : public ELEM
|
|
{
|
|
public:
|
|
|
|
WINDOW( ELEM* aParent, DSN_T aType = T_window ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
shape = nullptr;
|
|
}
|
|
|
|
~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 ) override
|
|
{
|
|
out->Print( nestLevel, "(%s ", Name() );
|
|
|
|
if( shape )
|
|
shape->Format( out, 0 );
|
|
|
|
out->Print( 0, ")\n" );
|
|
}
|
|
|
|
protected:
|
|
/* <shape_descriptor >::=
|
|
[<rectangle_descriptor> |
|
|
<circle_descriptor> |
|
|
<polygon_descriptor> |
|
|
<path_descriptor> |
|
|
<qarc_descriptor> ]
|
|
*/
|
|
ELEM* shape;
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
};
|
|
|
|
typedef boost::ptr_vector<WINDOW> WINDOWS;
|
|
|
|
|
|
/**
|
|
* Used for <keepout_descriptor> and <plane_descriptor>.
|
|
*/
|
|
class KEEPOUT : public ELEM
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Require 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 )
|
|
{
|
|
m_rules = nullptr;
|
|
m_place_rules = nullptr;
|
|
m_shape = nullptr;
|
|
|
|
m_sequence_number = -1;
|
|
}
|
|
|
|
~KEEPOUT()
|
|
{
|
|
delete m_rules;
|
|
delete m_place_rules;
|
|
delete m_shape;
|
|
}
|
|
|
|
void SetShape( ELEM* aShape )
|
|
{
|
|
delete m_shape;
|
|
m_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 );
|
|
m_windows.push_back( aWindow );
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* newline = "\n";
|
|
|
|
out->Print( nestLevel, "(%s", Name() );
|
|
|
|
if( m_name.size() )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_name.c_str() );
|
|
out->Print( 0, " %s%s%s", quote, m_name.c_str(), quote );
|
|
}
|
|
// Could be not needed:
|
|
#if 1
|
|
else
|
|
{
|
|
out->Print( 0, " \"\"" ); // the zone with no name or net_code == 0
|
|
}
|
|
#endif
|
|
|
|
if( m_sequence_number != -1 )
|
|
out->Print( 0, " (sequence_number %d)", m_sequence_number );
|
|
|
|
if( m_shape )
|
|
{
|
|
out->Print( 0, " " );
|
|
m_shape->Format( out, 0 );
|
|
}
|
|
|
|
if( m_rules )
|
|
{
|
|
out->Print( 0, "%s", newline );
|
|
newline = "";
|
|
m_rules->Format( out, nestLevel+1 );
|
|
}
|
|
|
|
if( m_place_rules )
|
|
{
|
|
out->Print( 0, "%s", newline );
|
|
newline = "";
|
|
m_place_rules->Format( out, nestLevel+1 );
|
|
}
|
|
|
|
if( m_windows.size() )
|
|
{
|
|
out->Print( 0, "%s", newline );
|
|
newline = "";
|
|
|
|
for( WINDOWS::iterator i = m_windows.begin(); i != m_windows.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
else
|
|
{
|
|
out->Print( 0, ")\n" );
|
|
}
|
|
}
|
|
|
|
protected:
|
|
std::string m_name;
|
|
int m_sequence_number;
|
|
RULE* m_rules;
|
|
RULE* m_place_rules;
|
|
|
|
WINDOWS m_windows;
|
|
|
|
/* <shape_descriptor >::=
|
|
[<rectangle_descriptor> |
|
|
<circle_descriptor> |
|
|
<polygon_descriptor> |
|
|
<path_descriptor> |
|
|
<qarc_descriptor> ]
|
|
*/
|
|
ELEM* m_shape;
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
};
|
|
|
|
typedef boost::ptr_vector<KEEPOUT> KEEPOUTS;
|
|
|
|
|
|
/**
|
|
* A <via_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class VIA : public ELEM
|
|
{
|
|
public:
|
|
|
|
VIA( ELEM* aParent ) :
|
|
ELEM( T_via, aParent )
|
|
{
|
|
}
|
|
|
|
void AppendVia( const char* aViaName )
|
|
{
|
|
m_padstacks.push_back( aViaName );
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const int RIGHTMARGIN = 80;
|
|
int perLine = out->Print( nestLevel, "(%s", Name() );
|
|
|
|
for( STRINGS::iterator i = m_padstacks.begin(); i != m_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( m_spares.size() )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
|
|
perLine = out->Print( nestLevel+1, "(spare" );
|
|
|
|
for( STRINGS::iterator i = m_spares.begin(); i != m_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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
STRINGS m_padstacks;
|
|
STRINGS m_spares;
|
|
};
|
|
|
|
|
|
class CLASSES : public ELEM
|
|
{
|
|
public:
|
|
CLASSES( ELEM* aParent ) :
|
|
ELEM( T_classes, aParent )
|
|
{
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 );
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
STRINGS class_ids;
|
|
};
|
|
|
|
|
|
class CLASS_CLASS : public ELEM_HOLDER
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* @param aParent is the 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 = nullptr;
|
|
}
|
|
|
|
~CLASS_CLASS()
|
|
{
|
|
delete classes;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
if( classes )
|
|
classes->Format( out, nestLevel );
|
|
|
|
// format the kids
|
|
ELEM_HOLDER::FormatContents( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
CLASSES* classes;
|
|
|
|
// rule | layer_rule are put into the kids container.
|
|
};
|
|
|
|
|
|
class CONTROL : public ELEM_HOLDER
|
|
{
|
|
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 ) override
|
|
{
|
|
out->Print( nestLevel, "(%s\n", Name() );
|
|
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
bool via_at_smd;
|
|
bool via_at_smd_grid_on;
|
|
};
|
|
|
|
|
|
class LAYER : public ELEM
|
|
{
|
|
public:
|
|
LAYER( ELEM* aParent ) :
|
|
ELEM( T_layer, aParent )
|
|
{
|
|
layer_type = T_signal;
|
|
direction = -1;
|
|
cost = -1;
|
|
cost_type = -1;
|
|
|
|
rules = nullptr;
|
|
}
|
|
|
|
~LAYER()
|
|
{
|
|
delete rules;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 )
|
|
// positive integer, stored as negative.
|
|
out->Print( nestLevel+1, "(cost %d", -cost );
|
|
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 )
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string name;
|
|
DSN_T layer_type; ///< one of: T_signal, T_power, T_mixed, T_jumper
|
|
int direction;
|
|
|
|
///< [forbidden | high | medium | low | free | \<positive_integer\> | -1]
|
|
int cost;
|
|
int cost_type; ///< T_length | T_way
|
|
RULE* rules;
|
|
STRINGS use_net;
|
|
|
|
PROPERTIES properties;
|
|
};
|
|
|
|
typedef boost::ptr_vector<LAYER> LAYERS;
|
|
|
|
|
|
class SPECCTRA_LAYER_PAIR : public ELEM
|
|
{
|
|
public:
|
|
SPECCTRA_LAYER_PAIR( ELEM* aParent ) :
|
|
ELEM( T_layer_pair, aParent )
|
|
{
|
|
layer_weight = 0.0;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string layer_id0;
|
|
std::string layer_id1;
|
|
|
|
double layer_weight;
|
|
};
|
|
|
|
typedef boost::ptr_vector<SPECCTRA_LAYER_PAIR> SPECCTRA_LAYER_PAIRS;
|
|
|
|
|
|
class LAYER_NOISE_WEIGHT : public ELEM
|
|
{
|
|
friend class SPECCTRA_DB;
|
|
|
|
SPECCTRA_LAYER_PAIRS layer_pairs;
|
|
|
|
public:
|
|
|
|
LAYER_NOISE_WEIGHT( ELEM* aParent ) :
|
|
ELEM( T_layer_noise_weight, aParent )
|
|
{
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s\n", Name() );
|
|
|
|
for( SPECCTRA_LAYER_PAIRS::iterator i = layer_pairs.begin(); i != layer_pairs.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* A <plane_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class COPPER_PLANE : public KEEPOUT
|
|
{
|
|
public:
|
|
COPPER_PLANE( ELEM* aParent ) :
|
|
KEEPOUT( aParent, T_plane )
|
|
{}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
};
|
|
|
|
typedef boost::ptr_vector<COPPER_PLANE> COPPER_PLANES;
|
|
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
public:
|
|
TOKPROP( ELEM* aParent, DSN_T aType ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
// Do not leave uninitialized members
|
|
value = T_NONE;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s %s)\n", Name(), GetTokenText( value ) );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
DSN_T value;
|
|
};
|
|
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
public:
|
|
STRINGPROP( ELEM* aParent, DSN_T aType ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( value.c_str() );
|
|
|
|
out->Print( nestLevel, "(%s %s%s%s)\n",
|
|
Name(),
|
|
quote, value.c_str(), quote );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string value;
|
|
};
|
|
|
|
|
|
class REGION : public ELEM_HOLDER
|
|
{
|
|
public:
|
|
REGION( ELEM* aParent ) :
|
|
ELEM_HOLDER( T_region, aParent )
|
|
{
|
|
m_rectangle = nullptr;
|
|
m_polygon = nullptr;
|
|
m_rules = nullptr;
|
|
}
|
|
|
|
~REGION()
|
|
{
|
|
delete m_rectangle;
|
|
delete m_polygon;
|
|
delete m_rules;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
if( m_region_id.size() )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_region_id.c_str() );
|
|
out->Print( nestLevel, "%s%s%s\n", quote, m_region_id.c_str(), quote );
|
|
}
|
|
|
|
if( m_rectangle )
|
|
m_rectangle->Format( out, nestLevel );
|
|
|
|
if( m_polygon )
|
|
m_polygon->Format( out, nestLevel );
|
|
|
|
ELEM_HOLDER::FormatContents( out, nestLevel );
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_region_id;
|
|
|
|
//-----<mutually exclusive>--------------------------------------
|
|
RECTANGLE* m_rectangle;
|
|
PATH* m_polygon;
|
|
//-----</mutually exclusive>-------------------------------------
|
|
|
|
/* region_net | region_class | region_class_class are all mutually
|
|
exclusive and are put into the kids container.
|
|
*/
|
|
|
|
RULE* m_rules;
|
|
};
|
|
|
|
|
|
class GRID : public ELEM
|
|
{
|
|
public:
|
|
GRID( ELEM* aParent ) :
|
|
ELEM( T_grid, aParent )
|
|
{
|
|
m_grid_type = T_via;
|
|
m_direction = T_NONE;
|
|
m_dimension = 0.0;
|
|
m_offset = 0.0;
|
|
m_image_type = T_NONE;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s %s %.6g", Name(), GetTokenText( m_grid_type ), m_dimension );
|
|
|
|
if( m_grid_type == T_place )
|
|
{
|
|
if( m_image_type == T_smd || m_image_type == T_pin )
|
|
out->Print( 0, " (image_type %s)", GetTokenText( m_image_type ) );
|
|
}
|
|
else
|
|
{
|
|
if( m_direction == T_x || m_direction == T_y )
|
|
out->Print( 0, " (direction %s)", GetTokenText( m_direction ) );
|
|
}
|
|
|
|
if( m_offset != 0.0 )
|
|
out->Print( 0, " (offset %.6g)", m_offset );
|
|
|
|
out->Print( 0, ")\n");
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
DSN_T m_grid_type; ///< T_via | T_wire | T_via_keepout | T_place | T_snap
|
|
double m_dimension;
|
|
DSN_T m_direction; ///< T_x | T_y | -1 for both
|
|
double m_offset;
|
|
DSN_T m_image_type;
|
|
};
|
|
|
|
|
|
class STRUCTURE_OUT : public ELEM
|
|
{
|
|
public:
|
|
STRUCTURE_OUT( ELEM* aParent ) :
|
|
ELEM( T_structure_out, aParent )
|
|
{
|
|
m_rules = nullptr;
|
|
}
|
|
|
|
~STRUCTURE_OUT()
|
|
{
|
|
delete m_rules;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
for( LAYERS::iterator i = m_layers.begin(); i != m_layers.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
LAYERS m_layers;
|
|
RULE* m_rules;
|
|
};
|
|
|
|
|
|
class STRUCTURE : public ELEM_HOLDER
|
|
{
|
|
public:
|
|
STRUCTURE( ELEM* aParent ) :
|
|
ELEM_HOLDER( T_structure, aParent )
|
|
{
|
|
m_unit = nullptr;
|
|
m_layer_noise_weight = nullptr;
|
|
m_boundary = nullptr;
|
|
m_place_boundary = nullptr;
|
|
m_via = nullptr;
|
|
m_control = nullptr;
|
|
m_rules = nullptr;
|
|
m_place_rules = nullptr;
|
|
}
|
|
|
|
~STRUCTURE()
|
|
{
|
|
delete m_unit;
|
|
delete m_layer_noise_weight;
|
|
delete m_boundary;
|
|
delete m_place_boundary;
|
|
delete m_via;
|
|
delete m_control;
|
|
delete m_rules;
|
|
delete m_place_rules;
|
|
}
|
|
|
|
void SetBOUNDARY( BOUNDARY *aBoundary )
|
|
{
|
|
delete m_boundary;
|
|
m_boundary = aBoundary;
|
|
|
|
if( m_boundary )
|
|
m_boundary->SetParent( this );
|
|
}
|
|
|
|
void SetPlaceBOUNDARY( BOUNDARY *aBoundary )
|
|
{
|
|
delete m_place_boundary;
|
|
m_place_boundary = aBoundary;
|
|
|
|
if( m_place_boundary )
|
|
m_place_boundary->SetParent( this );
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
if( m_unit )
|
|
m_unit->Format( out, nestLevel );
|
|
|
|
for( LAYERS::iterator i=m_layers.begin(); i!=m_layers.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
if( m_layer_noise_weight )
|
|
m_layer_noise_weight->Format( out, nestLevel );
|
|
|
|
if( m_boundary )
|
|
m_boundary->Format( out, nestLevel );
|
|
|
|
if( m_place_boundary )
|
|
m_place_boundary->Format( out, nestLevel );
|
|
|
|
for( COPPER_PLANES::iterator i=m_planes.begin(); i!=m_planes.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( REGIONS::iterator i=m_regions.begin(); i!=m_regions.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( KEEPOUTS::iterator i=m_keepouts.begin(); i!=m_keepouts.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
if( m_via )
|
|
m_via->Format( out, nestLevel );
|
|
|
|
if( m_control )
|
|
m_control->Format( out, nestLevel );
|
|
|
|
for( int i=0; i<Length(); ++i )
|
|
{
|
|
At(i)->Format( out, nestLevel );
|
|
}
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel );
|
|
|
|
if( m_place_rules )
|
|
m_place_rules->Format( out, nestLevel );
|
|
|
|
for( GRIDS::iterator i=m_grids.begin(); i!=m_grids.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
UNIT_RES* m_unit;
|
|
|
|
LAYERS m_layers;
|
|
|
|
LAYER_NOISE_WEIGHT* m_layer_noise_weight;
|
|
|
|
BOUNDARY* m_boundary;
|
|
BOUNDARY* m_place_boundary;
|
|
VIA* m_via;
|
|
CONTROL* m_control;
|
|
RULE* m_rules;
|
|
|
|
KEEPOUTS m_keepouts;
|
|
|
|
COPPER_PLANES m_planes;
|
|
|
|
typedef boost::ptr_vector<REGION> REGIONS;
|
|
REGIONS m_regions;
|
|
|
|
RULE* m_place_rules;
|
|
|
|
typedef boost::ptr_vector<GRID> GRIDS;
|
|
GRIDS m_grids;
|
|
};
|
|
|
|
|
|
/**
|
|
* Implement a <placement_reference> in the specctra dsn spec.
|
|
*/
|
|
class PLACE : public ELEM
|
|
{
|
|
public:
|
|
PLACE( ELEM* aParent ) :
|
|
ELEM( T_place, aParent )
|
|
{
|
|
m_side = T_front;
|
|
|
|
m_rotation = 0.0;
|
|
|
|
m_hasVertex = false;
|
|
|
|
m_mirror = T_NONE;
|
|
m_status = T_NONE;
|
|
|
|
m_place_rules = nullptr;
|
|
|
|
m_lock_type = T_NONE;
|
|
m_rules = nullptr;
|
|
m_region = nullptr;
|
|
}
|
|
|
|
~PLACE()
|
|
{
|
|
delete m_place_rules;
|
|
delete m_rules;
|
|
delete m_region;
|
|
}
|
|
|
|
void SetVertex( const POINT& aVertex )
|
|
{
|
|
m_vertex = aVertex;
|
|
m_vertex.FixNegativeZero();
|
|
m_hasVertex = true;
|
|
}
|
|
|
|
void SetRotation( double aRotation )
|
|
{
|
|
m_rotation = aRotation;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override;
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_component_id; ///< reference designator
|
|
|
|
DSN_T m_side;
|
|
|
|
double m_rotation;
|
|
|
|
bool m_hasVertex;
|
|
POINT m_vertex;
|
|
|
|
DSN_T m_mirror;
|
|
DSN_T m_status;
|
|
|
|
std::string m_logical_part;
|
|
|
|
RULE* m_place_rules;
|
|
|
|
PROPERTIES m_properties;
|
|
|
|
DSN_T m_lock_type;
|
|
|
|
//-----<mutually exclusive>--------------
|
|
RULE* m_rules;
|
|
REGION* m_region;
|
|
//-----</mutually exclusive>-------------
|
|
|
|
std::string m_part_number;
|
|
};
|
|
|
|
typedef boost::ptr_vector<PLACE> PLACES;
|
|
|
|
|
|
/**
|
|
* Implement a <component_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class COMPONENT : public ELEM
|
|
{
|
|
public:
|
|
COMPONENT( ELEM* aParent ) :
|
|
ELEM( T_component, aParent )
|
|
{
|
|
}
|
|
|
|
const std::string& GetImageId() const { return m_image_id; }
|
|
void SetImageId( const std::string& aImageId )
|
|
{
|
|
m_image_id = aImageId;
|
|
}
|
|
|
|
|
|
/**
|
|
* Compare two objects of this type and returns <0, 0, or >0.
|
|
*/
|
|
// static int Compare( IMAGE* lhs, IMAGE* rhs );
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_image_id.c_str() );
|
|
out->Print( nestLevel, "(%s %s%s%s\n", Name(), quote, m_image_id.c_str(), quote );
|
|
|
|
FormatContents( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
for( PLACES::iterator i=m_places.begin(); i!=m_places.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
// std::string m_hash; ///< a hash string used by Compare(), not Format()ed/exported.
|
|
|
|
std::string m_image_id;
|
|
PLACES m_places;
|
|
};
|
|
|
|
typedef boost::ptr_vector<COMPONENT> COMPONENTS;
|
|
|
|
|
|
class PLACEMENT : public ELEM
|
|
{
|
|
public:
|
|
PLACEMENT( ELEM* aParent ) :
|
|
ELEM( T_placement, aParent )
|
|
{
|
|
m_unit = nullptr;
|
|
m_flip_style = DSN_T( T_NONE );
|
|
}
|
|
|
|
~PLACEMENT()
|
|
{
|
|
delete m_unit;
|
|
}
|
|
|
|
/**
|
|
* Look 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 existing or new COMPONENT.
|
|
*/
|
|
COMPONENT* LookupCOMPONENT( const std::string& imageName )
|
|
{
|
|
for( unsigned i = 0; i < m_components.size(); ++i )
|
|
{
|
|
if( 0 == m_components[i].GetImageId().compare( imageName ) )
|
|
return &m_components[i];
|
|
}
|
|
|
|
COMPONENT* added = new COMPONENT(this);
|
|
m_components.push_back( added );
|
|
added->SetImageId( imageName );
|
|
return added;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
if( m_unit )
|
|
m_unit->Format( out, nestLevel );
|
|
|
|
if( m_flip_style != DSN_T( T_NONE ) )
|
|
{
|
|
out->Print( nestLevel, "(place_control (flip_style %s))\n",
|
|
GetTokenText( m_flip_style ) );
|
|
}
|
|
|
|
for( COMPONENTS::iterator i = m_components.begin(); i != m_components.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
UNIT_RES* m_unit;
|
|
|
|
DSN_T m_flip_style;
|
|
|
|
COMPONENTS m_components;
|
|
};
|
|
|
|
|
|
/**
|
|
* A "(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
|
|
{
|
|
public:
|
|
/**
|
|
* Takes a DSN_T aType of T_outline
|
|
*/
|
|
SHAPE( ELEM* aParent, DSN_T aType = T_shape ) :
|
|
WINDOW( aParent, aType )
|
|
{
|
|
m_connect = T_on;
|
|
}
|
|
|
|
void SetConnect( DSN_T aConnect )
|
|
{
|
|
m_connect = aConnect;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s ", Name() );
|
|
|
|
if( shape )
|
|
shape->Format( out, 0 );
|
|
|
|
if( m_connect == T_off )
|
|
out->Print( 0, "(connect %s)", GetTokenText( m_connect ) );
|
|
|
|
if( m_windows.size() )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
|
|
for( WINDOWS::iterator i=m_windows.begin(); i!=m_windows.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
else
|
|
{
|
|
out->Print( 0, ")\n" );
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
DSN_T m_connect;
|
|
|
|
/* <shape_descriptor >::=
|
|
[<rectangle_descriptor> |
|
|
<circle_descriptor> |
|
|
<polygon_descriptor> |
|
|
<path_descriptor> |
|
|
<qarc_descriptor> ]
|
|
ELEM* shape; // inherited from WINDOW
|
|
*/
|
|
|
|
WINDOWS m_windows;
|
|
};
|
|
|
|
|
|
class PIN : public ELEM
|
|
{
|
|
public:
|
|
PIN( ELEM* aParent ) :
|
|
ELEM( T_pin, aParent )
|
|
{
|
|
m_rotation = 0.0;
|
|
m_isRotated = false;
|
|
m_kiNetCode = 0;
|
|
}
|
|
|
|
void SetRotation( double aRotation )
|
|
{
|
|
m_rotation = aRotation;
|
|
m_isRotated = (aRotation != 0.0);
|
|
}
|
|
|
|
void SetVertex( const POINT& aPoint )
|
|
{
|
|
m_vertex = aPoint;
|
|
m_vertex.FixNegativeZero();
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_padstack_id.c_str() );
|
|
if( m_isRotated )
|
|
out->Print( nestLevel, "(pin %s%s%s (rotate %.6g)", quote, m_padstack_id.c_str(), quote,
|
|
m_rotation );
|
|
else
|
|
out->Print( nestLevel, "(pin %s%s%s", quote, m_padstack_id.c_str(), quote );
|
|
|
|
quote = out->GetQuoteChar( m_pin_id.c_str() );
|
|
out->Print( 0, " %s%s%s %.6g %.6g)\n", quote, m_pin_id.c_str(), quote, m_vertex.x, m_vertex.y );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_padstack_id;
|
|
double m_rotation;
|
|
bool m_isRotated;
|
|
std::string m_pin_id;
|
|
POINT m_vertex;
|
|
|
|
int m_kiNetCode; ///< KiCad netcode
|
|
};
|
|
|
|
typedef boost::ptr_vector<PIN> PINS;
|
|
|
|
|
|
class LIBRARY;
|
|
|
|
class IMAGE : public ELEM_HOLDER
|
|
{
|
|
public:
|
|
IMAGE( ELEM* aParent ) :
|
|
ELEM_HOLDER( T_image, aParent )
|
|
{
|
|
m_side = T_both;
|
|
m_unit = nullptr;
|
|
m_rules = nullptr;
|
|
m_place_rules = nullptr;
|
|
m_duplicated = 0;
|
|
}
|
|
|
|
~IMAGE()
|
|
{
|
|
delete m_unit;
|
|
delete m_rules;
|
|
delete m_place_rules;
|
|
}
|
|
|
|
/**
|
|
* Compare two objects of this type and returns <0, 0, or >0.
|
|
*/
|
|
static int Compare( IMAGE* lhs, IMAGE* rhs );
|
|
|
|
std::string GetImageId()
|
|
{
|
|
if( m_duplicated )
|
|
{
|
|
return m_image_id + "::" + std::to_string( m_duplicated );
|
|
}
|
|
|
|
return m_image_id;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 ) override
|
|
{
|
|
if( m_side != T_both )
|
|
out->Print( 0, " (side %s)", GetTokenText( m_side ) );
|
|
|
|
out->Print( 0, "\n");
|
|
|
|
if( m_unit )
|
|
m_unit->Format( out, nestLevel );
|
|
|
|
// format the kids, which in this class are the shapes
|
|
ELEM_HOLDER::FormatContents( out, nestLevel );
|
|
|
|
for( PINS::iterator i=m_pins.begin(); i!=m_pins.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel );
|
|
|
|
if( m_place_rules )
|
|
m_place_rules->Format( out, nestLevel );
|
|
|
|
for( KEEPOUTS::iterator i=m_keepouts.begin(); i!=m_keepouts.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
friend class LIBRARY;
|
|
|
|
std::string m_hash; ///< a hash string used by Compare(), not Format()ed/exported.
|
|
|
|
std::string m_image_id;
|
|
DSN_T m_side;
|
|
UNIT_RES* m_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 m_pins;
|
|
|
|
RULE* m_rules;
|
|
RULE* m_place_rules;
|
|
|
|
KEEPOUTS m_keepouts;
|
|
|
|
int m_duplicated; ///< no. times this image_id is duplicated
|
|
};
|
|
|
|
typedef boost::ptr_vector<IMAGE> IMAGES;
|
|
|
|
|
|
/**
|
|
* Hold either a via or a pad definition.
|
|
*/
|
|
class PADSTACK : public ELEM_HOLDER
|
|
{
|
|
public:
|
|
/**
|
|
* 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, nullptr )
|
|
{
|
|
m_unit = nullptr;
|
|
m_rotate = T_on;
|
|
m_absolute = T_off;
|
|
m_rules = nullptr;
|
|
m_attach = T_off;
|
|
}
|
|
|
|
~PADSTACK()
|
|
{
|
|
delete m_unit;
|
|
delete m_rules;
|
|
}
|
|
|
|
const std::string& GetPadstackId()
|
|
{
|
|
return m_padstack_id;
|
|
}
|
|
|
|
/**
|
|
* Compare two objects of this type and returns <0, 0, or >0.
|
|
*/
|
|
static int Compare( PADSTACK* lhs, PADSTACK* rhs );
|
|
|
|
void SetPadstackId( const char* aPadstackId )
|
|
{
|
|
m_padstack_id = aPadstackId;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_padstack_id.c_str() );
|
|
|
|
out->Print( nestLevel, "(%s %s%s%s\n", Name(), quote, m_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 ) override
|
|
{
|
|
if( m_unit )
|
|
m_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( m_attach == T_off )
|
|
{
|
|
out->Print( 0, "(attach off)" );
|
|
}
|
|
else if( m_attach == T_on )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_via_id.c_str() );
|
|
|
|
out->Print( 0, "(attach on (use_via %s%s%s))", quote, m_via_id.c_str(), quote );
|
|
}
|
|
|
|
if( m_rotate == T_off ) // print the non-default
|
|
out->Print( 0, "(rotate %s)", GetTokenText( m_rotate ) );
|
|
|
|
if( m_absolute == T_on ) // print the non-default
|
|
out->Print( 0, "(absolute %s)", GetTokenText( m_absolute ) );
|
|
|
|
out->Print( 0, "\n" );
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel );
|
|
}
|
|
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_hash; ///< a hash string used by Compare(), not Format()ed/exported.
|
|
|
|
std::string m_padstack_id;
|
|
UNIT_RES* m_unit;
|
|
|
|
/* The shapes are stored in the kids list */
|
|
|
|
DSN_T m_rotate;
|
|
DSN_T m_absolute;
|
|
DSN_T m_attach;
|
|
std::string m_via_id;
|
|
|
|
RULE* m_rules;
|
|
};
|
|
|
|
typedef boost::ptr_vector<PADSTACK> PADSTACKS;
|
|
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
|
|
/**
|
|
* A <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
|
|
{
|
|
public:
|
|
LIBRARY( ELEM* aParent, DSN_T aType = T_library ) :
|
|
ELEM( aType, aParent )
|
|
{
|
|
m_unit = nullptr;
|
|
// via_start_index = -1; // 0 or greater means there is at least one via
|
|
}
|
|
|
|
~LIBRARY()
|
|
{
|
|
delete m_unit;
|
|
}
|
|
|
|
void AddPadstack( PADSTACK* aPadstack )
|
|
{
|
|
aPadstack->SetParent( this );
|
|
m_padstacks.push_back( aPadstack );
|
|
}
|
|
|
|
/*
|
|
void SetViaStartIndex( int aIndex )
|
|
{
|
|
via_start_index = aIndex;
|
|
}
|
|
int GetViaStartIndex()
|
|
{
|
|
return via_start_index;
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* Search this LIBRARY for an image which matches the argument.
|
|
*
|
|
* @return index of image if found, else -1.
|
|
*/
|
|
int FindIMAGE( IMAGE* aImage )
|
|
{
|
|
unsigned i;
|
|
|
|
for( i=0; i<m_images.size(); ++i )
|
|
{
|
|
if( 0 == IMAGE::Compare( aImage, &m_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<m_images.size(); ++i )
|
|
{
|
|
if( 0 == aImage->m_image_id.compare( m_images[i].m_image_id ) )
|
|
aImage->m_duplicated = dups++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the image to the image list.
|
|
*/
|
|
void AppendIMAGE( IMAGE* aImage )
|
|
{
|
|
aImage->SetParent( this );
|
|
m_images.push_back( aImage );
|
|
}
|
|
|
|
/**
|
|
* Add the image only if one exactly like it does not already exist in the image container.
|
|
*
|
|
* @return 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 &m_images[ndx];
|
|
}
|
|
|
|
/**
|
|
* Search this LIBRARY for a via which matches the argument.
|
|
*
|
|
* @return the index found in the padstack list, else -1.
|
|
*/
|
|
int FindVia( PADSTACK* aVia )
|
|
{
|
|
for( unsigned i = 0; i < m_vias.size(); ++i )
|
|
{
|
|
if( 0 == PADSTACK::Compare( aVia, &m_vias[i] ) )
|
|
return int( i );
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Add \a aVia to the internal via container.
|
|
*/
|
|
void AppendVia( PADSTACK* aVia )
|
|
{
|
|
aVia->SetParent( this );
|
|
m_vias.push_back( aVia );
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the padstack to the padstack container.
|
|
*/
|
|
void AppendPADSTACK( PADSTACK* aPadstack )
|
|
{
|
|
aPadstack->SetParent( this );
|
|
m_padstacks.push_back( aPadstack );
|
|
}
|
|
|
|
/**
|
|
* Add the via only if one exactly like it does not already exist in the padstack container.
|
|
*
|
|
* @return 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 &m_vias[ndx];
|
|
}
|
|
|
|
/**
|
|
* Search the padstack container by name.
|
|
*
|
|
* @return The PADSTACK with a matching name if it exists, else nullptr.
|
|
*/
|
|
PADSTACK* FindPADSTACK( const std::string& aPadstackId )
|
|
{
|
|
for( unsigned i = 0; i < m_padstacks.size(); ++i )
|
|
{
|
|
PADSTACK* ps = &m_padstacks[i];
|
|
|
|
if( ps->GetPadstackId().compare( aPadstackId ) == 0 )
|
|
return ps;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
if( m_unit )
|
|
m_unit->Format( out, nestLevel );
|
|
|
|
for( IMAGES::iterator i = m_images.begin(); i != m_images.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( PADSTACKS::iterator i = m_padstacks.begin(); i != m_padstacks.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( PADSTACKS::iterator i = m_vias.begin(); i != m_vias.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
UNIT_RES* m_unit;
|
|
IMAGES m_images;
|
|
|
|
PADSTACKS m_padstacks; ///< all except vias, which are in 'vias'
|
|
PADSTACKS m_vias;
|
|
};
|
|
|
|
|
|
/**
|
|
* A <pin_reference> definition in the specctra dsn spec.
|
|
*/
|
|
struct PIN_REF : public ELEM
|
|
{
|
|
PIN_REF( ELEM* aParent ) :
|
|
ELEM( T_pin, aParent )
|
|
{
|
|
}
|
|
|
|
|
|
/**
|
|
* Like Format() but is not virtual.
|
|
*
|
|
* @return the number of characters that were output.
|
|
*/
|
|
int FormatIt( OUTPUTFORMATTER* out, int nestLevel )
|
|
{
|
|
// 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 );
|
|
}
|
|
|
|
std::string component_id;
|
|
std::string pin_id;
|
|
};
|
|
|
|
typedef std::vector<PIN_REF> PIN_REFS;
|
|
|
|
|
|
class FROMTO : public ELEM
|
|
{
|
|
public:
|
|
FROMTO( ELEM* aParent ) :
|
|
ELEM( T_fromto, aParent )
|
|
{
|
|
m_rules = nullptr;
|
|
m_fromto_type = DSN_T( T_NONE );
|
|
}
|
|
~FROMTO()
|
|
{
|
|
delete m_rules;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
// no quoting on these two, the lexer preserved the quotes on input
|
|
out->Print( nestLevel, "(%s %s %s ",
|
|
Name(), m_fromText.c_str(), m_toText.c_str() );
|
|
|
|
if( m_fromto_type != DSN_T( T_NONE ) )
|
|
out->Print( 0, "(type %s)", GetTokenText( m_fromto_type ) );
|
|
|
|
if( m_net_id.size() )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_net_id.c_str() );
|
|
out->Print( 0, "(net %s%s%s)", quote, m_net_id.c_str(), quote );
|
|
}
|
|
|
|
bool singleLine = true;
|
|
|
|
if( m_rules || m_layer_rules.size() )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
singleLine = false;
|
|
}
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel+1 );
|
|
|
|
/*
|
|
if( circuit.size() )
|
|
out->Print( nestLevel, "%s\n", circuit.c_str() );
|
|
*/
|
|
|
|
for( LAYER_RULES::iterator i = m_layer_rules.begin(); i != m_layer_rules.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
out->Print( singleLine ? 0 : nestLevel, ")" );
|
|
|
|
if( nestLevel || !singleLine )
|
|
out->Print( 0, "\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_fromText;
|
|
std::string m_toText;
|
|
|
|
DSN_T m_fromto_type;
|
|
std::string m_net_id;
|
|
RULE* m_rules;
|
|
// std::string m_circuit;
|
|
LAYER_RULES m_layer_rules;
|
|
};
|
|
|
|
typedef boost::ptr_vector<FROMTO> FROMTOS;
|
|
|
|
|
|
/**
|
|
* The <component_order_descriptor>
|
|
*/
|
|
class COMP_ORDER : public ELEM
|
|
{
|
|
public:
|
|
COMP_ORDER( ELEM* aParent ) :
|
|
ELEM( T_comp_order, aParent )
|
|
{
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
out->Print( nestLevel, "(%s", Name() );
|
|
|
|
for( STRINGS::iterator i = m_placement_ids.begin(); i != m_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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
STRINGS m_placement_ids;
|
|
};
|
|
|
|
typedef boost::ptr_vector<COMP_ORDER> COMP_ORDERS;
|
|
|
|
/**
|
|
* A <net_descriptor> in the DSN spec.
|
|
*/
|
|
class NET : public ELEM
|
|
{
|
|
public:
|
|
NET( ELEM* aParent ) :
|
|
ELEM( T_net, aParent )
|
|
{
|
|
m_unassigned = false;
|
|
m_net_number = T_NONE;
|
|
m_pins_type = T_pins;
|
|
|
|
m_type = T_NONE;
|
|
m_supply = T_NONE;
|
|
|
|
m_rules = nullptr;
|
|
m_comp_order = nullptr;
|
|
}
|
|
|
|
~NET()
|
|
{
|
|
delete m_rules;
|
|
delete m_comp_order;
|
|
}
|
|
|
|
int FindPIN_REF( const std::string& aComponent )
|
|
{
|
|
for( unsigned i = 0; i < m_pins.size(); ++i )
|
|
{
|
|
if( aComponent.compare( m_pins[i].component_id ) == 0 )
|
|
return int(i);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_net_id.c_str() );
|
|
const char* space = " ";
|
|
|
|
out->Print( nestLevel, "(%s %s%s%s", Name(), quote, m_net_id.c_str(), quote );
|
|
|
|
if( m_unassigned )
|
|
{
|
|
out->Print( 0, "%s(unassigned)", space );
|
|
space = ""; // only needed one space
|
|
}
|
|
|
|
if( m_net_number != T_NONE )
|
|
{
|
|
out->Print( 0, "%s(net_number %d)", space, m_net_number );
|
|
// space = "";
|
|
}
|
|
|
|
out->Print( 0, "\n" );
|
|
|
|
if( m_pins.size() )
|
|
{
|
|
const int RIGHTMARGIN = 80;
|
|
int perLine = out->Print( nestLevel+1, "(%s", GetTokenText( m_pins_type ) );
|
|
|
|
for( PIN_REFS::iterator i = m_pins.begin(); i != m_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( m_comp_order )
|
|
m_comp_order->Format( out, nestLevel+1 );
|
|
|
|
if( m_type != T_NONE )
|
|
out->Print( nestLevel+1, "(type %s)\n", GetTokenText( m_type ) );
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel+1 );
|
|
|
|
for( LAYER_RULES::iterator i = m_layer_rules.begin(); i != m_layer_rules.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
for( FROMTOS::iterator i = m_fromtos.begin(); i != m_fromtos.end(); ++i )
|
|
i->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_net_id;
|
|
bool m_unassigned;
|
|
int m_net_number;
|
|
|
|
DSN_T m_pins_type; ///< T_pins | T_order, type of field 'pins' below
|
|
PIN_REFS m_pins;
|
|
|
|
PIN_REFS m_expose;
|
|
PIN_REFS m_noexpose;
|
|
PIN_REFS m_source;
|
|
PIN_REFS m_load;
|
|
PIN_REFS m_terminator;
|
|
|
|
DSN_T m_type; ///< T_fix | T_normal
|
|
|
|
DSN_T m_supply; ///< T_power | T_ground
|
|
|
|
RULE* m_rules;
|
|
|
|
LAYER_RULES m_layer_rules;
|
|
|
|
FROMTOS m_fromtos;
|
|
|
|
COMP_ORDER* m_comp_order;
|
|
};
|
|
|
|
typedef boost::ptr_vector<NET> NETS;
|
|
|
|
|
|
class TOPOLOGY : public ELEM
|
|
{
|
|
public:
|
|
TOPOLOGY( ELEM* aParent ) :
|
|
ELEM( T_topology, aParent )
|
|
{
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
for( FROMTOS::iterator i = m_fromtos.begin(); i != m_fromtos.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( COMP_ORDERS::iterator i = m_comp_orders.begin(); i != m_comp_orders.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
FROMTOS m_fromtos;
|
|
|
|
COMP_ORDERS m_comp_orders;
|
|
};
|
|
|
|
|
|
/**
|
|
* The <class_descriptor> in the specctra spec.
|
|
*/
|
|
class CLASS : public ELEM
|
|
{
|
|
public:
|
|
CLASS( ELEM* aParent ) :
|
|
ELEM( T_class, aParent )
|
|
{
|
|
m_rules = nullptr;
|
|
m_topology = nullptr;
|
|
}
|
|
|
|
~CLASS()
|
|
{
|
|
delete m_rules;
|
|
delete m_topology;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_class_id.c_str() );
|
|
|
|
int perLine = out->Print( nestLevel, "(%s %s%s%s", Name(), quote, m_class_id.c_str(), quote );
|
|
|
|
const int RIGHTMARGIN = 72;
|
|
|
|
for( STRINGS::iterator i=m_net_ids.begin(); i!=m_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( m_circuit.size() || m_rules || m_layer_rules.size() || m_topology )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
newLine = true;
|
|
}
|
|
|
|
if( m_circuit.size() )
|
|
{
|
|
out->Print( nestLevel+1, "(circuit\n" );
|
|
|
|
for( STRINGS::iterator i = m_circuit.begin(); i != m_circuit.end(); ++i )
|
|
out->Print( nestLevel + 2, "%s\n", i->c_str() );
|
|
|
|
out->Print( nestLevel+1, ")\n" );
|
|
}
|
|
|
|
if( m_rules )
|
|
m_rules->Format( out, nestLevel+1 );
|
|
|
|
for( LAYER_RULES::iterator i = m_layer_rules.begin(); i != m_layer_rules.end(); ++i )
|
|
i->Format( out, nestLevel + 1 );
|
|
|
|
if( m_topology )
|
|
m_topology->Format( out, nestLevel+1 );
|
|
|
|
out->Print( newLine ? nestLevel : 0, ")\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_class_id;
|
|
|
|
STRINGS m_net_ids;
|
|
|
|
/// circuit descriptor list
|
|
STRINGS m_circuit;
|
|
|
|
RULE* m_rules;
|
|
|
|
LAYER_RULES m_layer_rules;
|
|
|
|
TOPOLOGY* m_topology;
|
|
};
|
|
|
|
typedef boost::ptr_vector<CLASS> CLASSLIST;
|
|
|
|
|
|
class NETWORK : public ELEM
|
|
{
|
|
public:
|
|
NETWORK( ELEM* aParent ) :
|
|
ELEM( T_network, aParent )
|
|
{
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
for( NETS::iterator i = m_nets.begin(); i != m_nets.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
|
|
for( CLASSLIST::iterator i = m_classes.begin(); i != m_classes.end(); ++i )
|
|
i->Format( out, nestLevel );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
NETS m_nets;
|
|
CLASSLIST m_classes;
|
|
};
|
|
|
|
|
|
class CONNECT : public ELEM
|
|
{
|
|
// @todo not completed.
|
|
|
|
public:
|
|
CONNECT( ELEM* aParent ) :
|
|
ELEM( T_connect, aParent ) {}
|
|
};
|
|
|
|
|
|
/**
|
|
* A <wire_shape_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class WIRE : public ELEM
|
|
{
|
|
public:
|
|
WIRE( ELEM* aParent ) :
|
|
ELEM( T_wire, aParent )
|
|
{
|
|
m_shape = nullptr;
|
|
m_connect = nullptr;
|
|
|
|
m_turret = -1;
|
|
m_wire_type = T_NONE;
|
|
m_attr = T_NONE;
|
|
m_supply = false;
|
|
}
|
|
|
|
~WIRE()
|
|
{
|
|
delete m_shape;
|
|
delete m_connect;
|
|
}
|
|
|
|
void SetShape( ELEM* aShape )
|
|
{
|
|
delete m_shape;
|
|
m_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 ) override
|
|
{
|
|
out->Print( nestLevel, "(%s ", Name() );
|
|
|
|
if( m_shape )
|
|
m_shape->Format( out, 0 );
|
|
|
|
if( m_net_id.size() )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_net_id.c_str() );
|
|
out->Print( 0, "(net %s%s%s)", quote, m_net_id.c_str(), quote );
|
|
}
|
|
|
|
if( m_turret >= 0 )
|
|
out->Print( 0, "(turrent %d)", m_turret );
|
|
|
|
if( m_wire_type != T_NONE )
|
|
out->Print( 0, "(type %s)", GetTokenText( m_wire_type ) );
|
|
|
|
if( m_attr != T_NONE )
|
|
out->Print( 0, "(attr %s)", GetTokenText( m_attr ) );
|
|
|
|
if( m_shield.size() )
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_shield.c_str() );
|
|
out->Print( 0, "(shield %s%s%s)", quote, m_shield.c_str(), quote );
|
|
}
|
|
|
|
if( m_windows.size() )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
|
|
for( WINDOWS::iterator i = m_windows.begin(); i != m_windows.end(); ++i )
|
|
i->Format( out, nestLevel + 1 );
|
|
}
|
|
|
|
if( m_connect )
|
|
m_connect->Format( out, 0 );
|
|
|
|
if( m_supply )
|
|
out->Print( 0, "(supply)" );
|
|
|
|
out->Print( 0, ")\n" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
/* <shape_descriptor >::=
|
|
[<rectangle_descriptor> |
|
|
<circle_descriptor> |
|
|
<polygon_descriptor> |
|
|
<path_descriptor> |
|
|
<qarc_descriptor> ]
|
|
*/
|
|
ELEM* m_shape;
|
|
|
|
std::string m_net_id;
|
|
int m_turret;
|
|
DSN_T m_wire_type;
|
|
DSN_T m_attr;
|
|
std::string m_shield;
|
|
WINDOWS m_windows;
|
|
CONNECT* m_connect;
|
|
bool m_supply;
|
|
};
|
|
|
|
typedef boost::ptr_vector<WIRE> WIRES;
|
|
|
|
|
|
/**
|
|
* A <wire_via_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class WIRE_VIA : public ELEM
|
|
{
|
|
public:
|
|
WIRE_VIA( ELEM* aParent ) :
|
|
ELEM( T_via, aParent )
|
|
{
|
|
m_via_number = -1;
|
|
m_via_type = T_NONE;
|
|
m_attr = T_NONE;
|
|
m_supply = false;
|
|
}
|
|
|
|
const std::string& GetPadstackId()
|
|
{
|
|
return m_padstack_id;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_padstack_id.c_str() );
|
|
|
|
const int RIGHTMARGIN = 80;
|
|
int perLine = out->Print( nestLevel, "(%s %s%s%s", Name(), quote, m_padstack_id.c_str(),
|
|
quote );
|
|
|
|
for( POINTS::iterator i = m_vertexes.begin(); i != m_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( m_net_id.size() || m_via_number!=-1 || m_via_type!=T_NONE || m_attr!=T_NONE || m_supply)
|
|
out->Print( 0, " " );
|
|
|
|
if( m_net_id.size() )
|
|
{
|
|
if( perLine > RIGHTMARGIN )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
|
}
|
|
|
|
quote = out->GetQuoteChar( m_net_id.c_str() );
|
|
perLine += out->Print( 0, "(net %s%s%s)", quote, m_net_id.c_str(), quote );
|
|
}
|
|
|
|
if( m_via_number != -1 )
|
|
{
|
|
if( perLine > RIGHTMARGIN )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
|
}
|
|
|
|
perLine += out->Print( 0, "(via_number %d)", m_via_number );
|
|
}
|
|
|
|
if( m_via_type != T_NONE )
|
|
{
|
|
if( perLine > RIGHTMARGIN )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
|
}
|
|
|
|
perLine += out->Print( 0, "(type %s)", GetTokenText( m_via_type ) );
|
|
}
|
|
|
|
if( m_attr != T_NONE )
|
|
{
|
|
if( perLine > RIGHTMARGIN )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
|
}
|
|
|
|
if( m_attr == T_virtual_pin )
|
|
{
|
|
quote = out->GetQuoteChar( m_virtual_pin_name.c_str() );
|
|
perLine += out->Print( 0, "(attr virtual_pin %s%s%s)", quote,
|
|
m_virtual_pin_name.c_str(), quote );
|
|
}
|
|
else
|
|
{
|
|
perLine += out->Print( 0, "(attr %s)", GetTokenText( m_attr ) );
|
|
}
|
|
}
|
|
|
|
if( m_supply )
|
|
{
|
|
if( perLine > RIGHTMARGIN )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
perLine = out->Print( nestLevel+1, "%s", "" );
|
|
}
|
|
|
|
perLine += out->Print( 0, "(supply)" );
|
|
}
|
|
|
|
if( m_contact_layers.size() )
|
|
{
|
|
out->Print( 0, "\n" );
|
|
out->Print( nestLevel+1, "(contact\n" );
|
|
|
|
for( STRINGS::iterator i = m_contact_layers.begin(); i != m_contact_layers.end(); ++i )
|
|
{
|
|
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" );
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_padstack_id;
|
|
POINTS m_vertexes;
|
|
std::string m_net_id;
|
|
int m_via_number;
|
|
DSN_T m_via_type;
|
|
DSN_T m_attr;
|
|
std::string m_virtual_pin_name;
|
|
STRINGS m_contact_layers;
|
|
bool m_supply;
|
|
};
|
|
|
|
typedef boost::ptr_vector<WIRE_VIA> WIRE_VIAS;
|
|
|
|
|
|
/**
|
|
* A <wiring_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class WIRING : public ELEM
|
|
{
|
|
public:
|
|
WIRING( ELEM* aParent ) :
|
|
ELEM( T_wiring, aParent )
|
|
{
|
|
unit = nullptr;
|
|
}
|
|
|
|
~WIRING()
|
|
{
|
|
delete unit;
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 override
|
|
{
|
|
if( unit )
|
|
return unit;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
UNIT_RES* unit;
|
|
WIRES wires;
|
|
WIRE_VIAS wire_vias;
|
|
};
|
|
|
|
|
|
class PCB : public ELEM
|
|
{
|
|
public:
|
|
PCB( ELEM* aParent = nullptr ) :
|
|
ELEM( T_pcb, aParent )
|
|
{
|
|
m_parser = nullptr;
|
|
m_resolution = nullptr;
|
|
m_unit = nullptr;
|
|
m_structure = nullptr;
|
|
m_placement = nullptr;
|
|
m_library = nullptr;
|
|
m_network = nullptr;
|
|
m_wiring = nullptr;
|
|
}
|
|
|
|
~PCB()
|
|
{
|
|
delete m_parser;
|
|
delete m_resolution;
|
|
delete m_unit;
|
|
delete m_structure;
|
|
delete m_placement;
|
|
delete m_library;
|
|
delete m_network;
|
|
delete m_wiring;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
const char* quote = out->GetQuoteChar( m_pcbname.c_str() );
|
|
|
|
out->Print( nestLevel, "(%s %s%s%s\n", Name(), quote, m_pcbname.c_str(), quote );
|
|
|
|
if( m_parser )
|
|
m_parser->Format( out, nestLevel+1 );
|
|
|
|
if( m_resolution )
|
|
m_resolution->Format( out, nestLevel+1 );
|
|
|
|
if( m_unit )
|
|
m_unit->Format( out, nestLevel+1 );
|
|
|
|
if( m_structure )
|
|
m_structure->Format( out, nestLevel+1 );
|
|
|
|
if( m_placement )
|
|
m_placement->Format( out, nestLevel+1 );
|
|
|
|
if( m_library )
|
|
m_library->Format( out, nestLevel+1 );
|
|
|
|
if( m_network )
|
|
m_network->Format( out, nestLevel+1 );
|
|
|
|
if( m_wiring )
|
|
m_wiring->Format( out, nestLevel+1 );
|
|
|
|
out->Print( nestLevel, ")\n" );
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( m_unit )
|
|
return m_unit;
|
|
|
|
if( m_resolution )
|
|
return m_resolution->GetUnits();
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string m_pcbname;
|
|
PARSER* m_parser;
|
|
UNIT_RES* m_resolution;
|
|
UNIT_RES* m_unit;
|
|
STRUCTURE* m_structure;
|
|
PLACEMENT* m_placement;
|
|
LIBRARY* m_library;
|
|
NETWORK* m_network;
|
|
WIRING* m_wiring;
|
|
};
|
|
|
|
|
|
class ANCESTOR : public ELEM
|
|
{
|
|
public:
|
|
ANCESTOR( ELEM* aParent ) :
|
|
ELEM( T_ancestor, aParent )
|
|
{
|
|
time_stamp = time(nullptr);
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string filename;
|
|
std::string comment;
|
|
time_t time_stamp;
|
|
};
|
|
|
|
typedef boost::ptr_vector<ANCESTOR> ANCESTORS;
|
|
|
|
|
|
class HISTORY : public ELEM
|
|
{
|
|
public:
|
|
HISTORY( ELEM* aParent ) :
|
|
ELEM( T_history, aParent )
|
|
{
|
|
time_stamp = time(nullptr);
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
ANCESTORS ancestors;
|
|
time_t time_stamp;
|
|
STRINGS comments;
|
|
};
|
|
|
|
|
|
/**
|
|
* A <supply_pin_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class SUPPLY_PIN : public ELEM
|
|
{
|
|
public:
|
|
SUPPLY_PIN( ELEM* aParent ) :
|
|
ELEM( T_supply_pin, aParent )
|
|
{
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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");
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
PIN_REFS pin_refs;
|
|
std::string net_id;
|
|
};
|
|
|
|
typedef boost::ptr_vector<SUPPLY_PIN> SUPPLY_PINS;
|
|
|
|
|
|
/**
|
|
* A <net_out_descriptor> of the specctra dsn spec.
|
|
*/
|
|
class NET_OUT : public ELEM
|
|
{
|
|
public:
|
|
NET_OUT( ELEM* aParent ) :
|
|
ELEM( T_net_out, aParent )
|
|
{
|
|
rules = nullptr;
|
|
net_number = -1;
|
|
}
|
|
|
|
~NET_OUT()
|
|
{
|
|
delete rules;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
std::string net_id;
|
|
int net_number;
|
|
RULE* rules;
|
|
WIRES wires;
|
|
WIRE_VIAS wire_vias;
|
|
SUPPLY_PINS supply_pins;
|
|
};
|
|
|
|
typedef boost::ptr_vector<NET_OUT> NET_OUTS;
|
|
|
|
|
|
class ROUTE : public ELEM
|
|
{
|
|
public:
|
|
ROUTE( ELEM* aParent ) :
|
|
ELEM( T_route, aParent )
|
|
{
|
|
resolution = nullptr;
|
|
parser = nullptr;
|
|
structure_out = nullptr;
|
|
library = nullptr;
|
|
}
|
|
|
|
~ROUTE()
|
|
{
|
|
delete resolution;
|
|
delete parser;
|
|
delete structure_out;
|
|
delete library;
|
|
// delete test_points;
|
|
}
|
|
|
|
UNIT_RES* GetUnits() const override
|
|
{
|
|
if( resolution )
|
|
return resolution;
|
|
|
|
return ELEM::GetUnits();
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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 );
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
UNIT_RES* resolution;
|
|
PARSER* parser;
|
|
STRUCTURE_OUT* structure_out;
|
|
LIBRARY* library;
|
|
NET_OUTS net_outs;
|
|
// TEST_POINTS* test_points;
|
|
};
|
|
|
|
|
|
/**
|
|
* 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 = nullptr ) :
|
|
was( aParent ),
|
|
is( aParent )
|
|
{
|
|
}
|
|
|
|
PIN_REF was;
|
|
PIN_REF is;
|
|
};
|
|
|
|
typedef std::vector<PIN_PAIR> PIN_PAIRS;
|
|
|
|
|
|
/**
|
|
* A <was_is_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class WAS_IS : public ELEM
|
|
{
|
|
public:
|
|
WAS_IS( ELEM* aParent ) :
|
|
ELEM( T_was_is, aParent )
|
|
{
|
|
}
|
|
|
|
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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" );
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class SPECCTRA_DB;
|
|
|
|
PIN_PAIRS pin_pairs;
|
|
};
|
|
|
|
|
|
/**
|
|
* A <session_file_descriptor> in the specctra dsn spec.
|
|
*/
|
|
class SESSION : public ELEM
|
|
{
|
|
public:
|
|
SESSION( ELEM* aParent = nullptr ) :
|
|
ELEM( T_session, aParent )
|
|
{
|
|
history = nullptr;
|
|
structure = nullptr;
|
|
placement = nullptr;
|
|
was_is = nullptr;
|
|
route = nullptr;
|
|
}
|
|
|
|
~SESSION()
|
|
{
|
|
delete history;
|
|
delete structure;
|
|
delete placement;
|
|
delete was_is;
|
|
delete route;
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* out, int nestLevel ) override
|
|
{
|
|
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" );
|
|
}
|
|
|
|
private:
|
|
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;
|
|
*/
|
|
};
|
|
|
|
typedef boost::ptr_set<PADSTACK> PADSTACKSET;
|
|
|
|
|
|
/**
|
|
* A DSN data tree, usually coming from a DSN file. Is essentially a SPECCTRA_PARSER class.
|
|
*/
|
|
class SPECCTRA_DB : public SPECCTRA_LEXER
|
|
{
|
|
public:
|
|
|
|
SPECCTRA_DB() :
|
|
SPECCTRA_LEXER( 0 ) // LINE_READER* == nullptr, no DSNLEXER::PushReader()
|
|
{
|
|
// The LINE_READER will be pushed from an automatic instantiation,
|
|
// we don't own it:
|
|
wxASSERT( !iOwnReaders );
|
|
|
|
m_pcb = nullptr;
|
|
m_session = nullptr;
|
|
m_quote_char += '"';
|
|
m_footprintsAreFlipped = false;
|
|
|
|
SetSpecctraMode( true );
|
|
|
|
// Avoid not initialized members:
|
|
m_routeResolution = nullptr;
|
|
m_sessionBoard = nullptr;
|
|
m_top_via_layer = 0;
|
|
m_bot_via_layer = 0;
|
|
}
|
|
|
|
virtual ~SPECCTRA_DB()
|
|
{
|
|
delete m_pcb;
|
|
delete m_session;
|
|
|
|
deleteNETs();
|
|
}
|
|
|
|
/**
|
|
* Make a PCB with all the default ELEMs and parts on the heap.
|
|
*/
|
|
static PCB* MakePCB();
|
|
|
|
/**
|
|
* Delete any existing PCB and replaces it with the given one.
|
|
*/
|
|
void SetPCB( PCB* aPcb )
|
|
{
|
|
delete m_pcb;
|
|
m_pcb = aPcb;
|
|
}
|
|
|
|
PCB* GetPCB() { return m_pcb; }
|
|
|
|
/**
|
|
* Delete any existing SESSION and replaces it with the given one.
|
|
*/
|
|
void SetSESSION( SESSION* aSession )
|
|
{
|
|
delete m_session;
|
|
m_session = aSession;
|
|
}
|
|
|
|
SESSION* GetSESSION() { return m_session; }
|
|
|
|
/**
|
|
* 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 aFilename The name of the dsn file to load.
|
|
* @throw IO_ERROR if there is a lexer or parser error.
|
|
*/
|
|
void LoadPCB( const wxString& aFilename );
|
|
|
|
/**
|
|
* 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 aFilename The name of the dsn file to load.
|
|
* @throw IO_ERROR if there is a lexer or parser error.
|
|
*/
|
|
void LoadSESSION( const wxString& aFilename );
|
|
|
|
/**
|
|
* Write 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( const wxString& aFilename, bool aNameChange=false );
|
|
|
|
/**
|
|
* Add the entire BOARD to the PCB but does not write it out.
|
|
*
|
|
* @note The #BOARD given to this function must have all the FOOTPRINTs on the component
|
|
* side of the BOARD.
|
|
*
|
|
* @see PCB_EDIT_FRAME::ExportToSpecctra() for an example before calling this function.
|
|
*
|
|
* @param aBoard The BOARD to convert to a PCB.
|
|
*/
|
|
void FromBOARD( BOARD* aBoard );
|
|
|
|
/**
|
|
* Add the entire #SESSION info to a #BOARD but does not write it out.
|
|
*
|
|
* 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 );
|
|
|
|
/**
|
|
* Write the internal #SESSION instance out as a #SPECTRA DSN format file.
|
|
*
|
|
* @param aFilename The file to save to.
|
|
*/
|
|
void ExportSESSION( const wxString& aFilename );
|
|
|
|
/**
|
|
* Build the board outlines and store it in m_brd_outlines.
|
|
*
|
|
* Because it calls GetBoardPolygonOutlines() it *must be* called before flipping footprints
|
|
*
|
|
* @return false if the board outlines cannot be built (not closed outlines)
|
|
*/
|
|
bool BuiltBoardOutlines( BOARD* aBoard );
|
|
|
|
/**
|
|
* Flip the footprints which are on the back side of the board to the front.
|
|
*/
|
|
void FlipFOOTPRINTs( BOARD* aBoard );
|
|
|
|
/**
|
|
* Flip the footprints which were on the back side of the board back to the back.
|
|
*/
|
|
void RevertFOOTPRINTs( BOARD* aBoard );
|
|
|
|
private:
|
|
/**
|
|
* Create 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 );
|
|
|
|
/**
|
|
* Return the PCB layer index for a given layer name, within the specctra sessionfile.
|
|
*
|
|
* @return the layer index within the specctra session file, or -1 if \a aLayerName is not
|
|
* found.
|
|
*/
|
|
int findLayerName( const std::string& aLayerName ) const;
|
|
|
|
/**
|
|
* Read 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 comprising the pin_reference and
|
|
* it will be tested through CurTok().
|
|
* </p>
|
|
* @param component_id Where to put the text preceding 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 );
|
|
|
|
/**
|
|
* Read 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.
|
|
* The caller should not have already read in the first token comprising 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 );
|
|
|
|
void doPCB( PCB* growth );
|
|
void doPARSER( PARSER* growth );
|
|
void doRESOLUTION( UNIT_RES* growth );
|
|
void doUNIT( UNIT_RES* growth );
|
|
void doSTRUCTURE( STRUCTURE* growth );
|
|
void doSTRUCTURE_OUT( STRUCTURE_OUT* growth );
|
|
void doLAYER_NOISE_WEIGHT( LAYER_NOISE_WEIGHT* growth );
|
|
void doSPECCTRA_LAYER_PAIR( SPECCTRA_LAYER_PAIR* growth );
|
|
void doBOUNDARY( BOUNDARY* growth );
|
|
void doRECTANGLE( RECTANGLE* growth );
|
|
void doPATH( PATH* growth );
|
|
void doSTRINGPROP( STRINGPROP* growth );
|
|
void doTOKPROP( TOKPROP* growth );
|
|
void doVIA( VIA* growth );
|
|
void doCONTROL( CONTROL* growth );
|
|
void doLAYER( LAYER* growth );
|
|
void doRULE( RULE* growth );
|
|
void doKEEPOUT( KEEPOUT* growth );
|
|
void doCIRCLE( CIRCLE* growth );
|
|
void doQARC( QARC* growth );
|
|
void doWINDOW( WINDOW* growth );
|
|
void doCONNECT( CONNECT* growth );
|
|
void doREGION( REGION* growth );
|
|
void doCLASS_CLASS( CLASS_CLASS* growth );
|
|
void doLAYER_RULE( LAYER_RULE* growth );
|
|
void doCLASSES( CLASSES* growth );
|
|
void doGRID( GRID* growth );
|
|
void doPLACE( PLACE* growth );
|
|
void doCOMPONENT( COMPONENT* growth );
|
|
void doPLACEMENT( PLACEMENT* growth );
|
|
void doPROPERTIES( PROPERTIES* growth );
|
|
void doPADSTACK( PADSTACK* growth );
|
|
void doSHAPE( SHAPE* growth );
|
|
void doIMAGE( IMAGE* growth );
|
|
void doLIBRARY( LIBRARY* growth );
|
|
void doPIN( PIN* growth );
|
|
void doNET( NET* growth );
|
|
void doNETWORK( NETWORK* growth );
|
|
void doCLASS( CLASS* growth );
|
|
void doTOPOLOGY( TOPOLOGY* growth );
|
|
void doFROMTO( FROMTO* growth );
|
|
void doCOMP_ORDER( COMP_ORDER* growth );
|
|
void doWIRE( WIRE* growth );
|
|
void doWIRE_VIA( WIRE_VIA* growth );
|
|
void doWIRING( WIRING* growth );
|
|
void doSESSION( SESSION* growth );
|
|
void doANCESTOR( ANCESTOR* growth );
|
|
void doHISTORY( HISTORY* growth );
|
|
void doROUTE( ROUTE* growth );
|
|
void doWAS_IS( WAS_IS* growth );
|
|
void doNET_OUT( NET_OUT* growth );
|
|
void doSUPPLY_PIN( SUPPLY_PIN* growth );
|
|
|
|
//-----<FromBOARD>-------------------------------------------------------
|
|
|
|
/**
|
|
* Make 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 );
|
|
|
|
/**
|
|
* Allocates an I#MAGE on the heap and creates all the PINs according to the PADs in the
|
|
* FOOTPRINT.
|
|
*
|
|
* @param aBoard The owner of the FOOTPRINT.
|
|
* @param aFootprint The FOOTPRINT from which to build the IMAGE.
|
|
* @return not tested for duplication yet.
|
|
*/
|
|
IMAGE* makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint );
|
|
|
|
/**
|
|
* Create a #PADSTACK which matches the given pad.
|
|
*
|
|
* @note Only pads which do not satisfy the function isKeepout() should be passed to this
|
|
* function.
|
|
*
|
|
* @param aBoard The owner of the PAD's footprint.
|
|
* @param aPad The PAD which needs to be made into a PADSTACK.
|
|
* @return The created padstack, including its m_padstack_id.
|
|
*/
|
|
PADSTACK* makePADSTACK( BOARD* aBoard, PAD* aPad );
|
|
|
|
/**
|
|
* Make 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 The padstack, which is on the heap only, user must save or delete it.
|
|
*/
|
|
PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter,
|
|
int aTopLayer, int aBotLayer );
|
|
|
|
/**
|
|
* Make any kind of #PADSTACK using the given KiCad #VIA.
|
|
*
|
|
* @param aVia The #VIA to build the padstack from.
|
|
* @return The padstack, which is on the heap only, user must save or delete it.
|
|
*/
|
|
PADSTACK* makeVia( const ::PCB_VIA* aVia );
|
|
|
|
/**
|
|
* Delete all the NETs that may be in here.
|
|
*/
|
|
void deleteNETs()
|
|
{
|
|
for( unsigned n = 0; n < m_nets.size(); ++n )
|
|
delete m_nets[n];
|
|
|
|
m_nets.clear();
|
|
}
|
|
|
|
/**
|
|
* Export \a aNetClass to the DSN file.
|
|
*/
|
|
void exportNETCLASS( const std::shared_ptr<NETCLASS>& aNetClass, BOARD* aBoard );
|
|
|
|
//-----</FromBOARD>------------------------------------------------------
|
|
|
|
//-----<FromSESSION>-----------------------------------------------------
|
|
|
|
/**
|
|
* Create a #TRACK form the #PATH and #BOARD info.
|
|
*/
|
|
PCB_TRACK* makeTRACK( WIRE* wire, PATH* aPath, int aPointIndex, int aNetcode );
|
|
|
|
/**
|
|
* Instantiate a KiCad #VIA on the heap and initializes it with internal
|
|
* values consistent with the given #PADSTACK, #POINT, and netcode.
|
|
*/
|
|
PCB_VIA* makeVIA( WIRE_VIA*aVia, PADSTACK* aPadstack, const POINT& aPoint, int aNetCode,
|
|
int aViaDrillDefault );
|
|
|
|
//-----</FromSESSION>----------------------------------------------------
|
|
|
|
/// specctra DSN keywords
|
|
static const KEYWORD keywords[];
|
|
|
|
PCB* m_pcb;
|
|
SHAPE_POLY_SET m_brd_outlines; // the board outlines for DSN export
|
|
SESSION* m_session;
|
|
wxString m_filename;
|
|
std::string m_quote_char;
|
|
|
|
bool m_footprintsAreFlipped;
|
|
|
|
STRING_FORMATTER m_sf;
|
|
|
|
STRINGS m_layerIds; ///< indexed by PCB layer number
|
|
|
|
std::vector<int> m_kicadLayer2pcb; ///< maps BOARD layer number to PCB layer numbers
|
|
std::vector<PCB_LAYER_ID> m_pcbLayer2kicad; ///< maps PCB layer number to BOARD layer numbers
|
|
|
|
/// used during FromSESSION() only, memory for it is not owned here.
|
|
UNIT_RES* m_routeResolution;
|
|
|
|
/// a copy to avoid passing as an argument, memory for it is not owned here.
|
|
BOARD* m_sessionBoard;
|
|
|
|
static const KICAD_T scanPADs[];
|
|
|
|
PADSTACKSET m_padstackset;
|
|
|
|
/// we don't want ownership here permanently, so we don't use boost::ptr_vector
|
|
std::vector<NET*> m_nets;
|
|
|
|
/// specctra cu layers, 0 based index:
|
|
int m_top_via_layer;
|
|
int m_bot_via_layer;
|
|
};
|
|
|
|
/**
|
|
* @brief Helper method to import SES file to a board
|
|
*
|
|
* @param aBoard board object
|
|
* @param aFullFilename specctra file name
|
|
*/
|
|
|
|
bool ImportSpecctraSession( BOARD* aBoard, const wxString& fullFileName );
|
|
|
|
} // namespace DSN
|
|
|
|
#endif // SPECCTRA_H_
|