Commit f8f35a8c authored by Dr. Thomas Spindler's avatar Dr. Thomas Spindler Committed by Dick Hollenbeck

specctra_export supports interior polygons and circles on the Edge.Cuts layer.

Interior regions on Edge.Cuts are out as keepouts for specctra DSN file
and downstream routers.  Point to point matching during polygon assembly
can have individual thresholds, one for board edge and another for interior polygons.
This is more forgiving for sloppy graphical mousers, or those that work without
grid snap on.  Currently the threshold for board edge is at zero, meaning the
board edge has to be precisely defined as a polygon, just as before.  But it
is easily tunable for experimentation.
parent f50f31e5
...@@ -3704,14 +3704,14 @@ class SPECCTRA_DB : public SPECCTRA_LEXER ...@@ -3704,14 +3704,14 @@ class SPECCTRA_DB : public SPECCTRA_LEXER
//-----<FromBOARD>------------------------------------------------------- //-----<FromBOARD>-------------------------------------------------------
/** /**
* Function makeBOUNDARY * Function fillBOUNDARY
* makes the board perimeter for the DSN file. * makes the board perimeter for the DSN file by filling the BOUNDARY element
* in the specctra element tree.
* @param aBoard The BOARD to get information from in order to make the BOUNDARY. * @param aBoard The BOARD to get information from in order to make the BOUNDARY.
* @param aBoundary The empty BOUNDARY to fill in. * @param aBoundary The empty BOUNDARY to fill in.
*/ */
void fillBOUNDARY( BOARD* aBoard, BOUNDARY* aBoundary ) throw( IO_ERROR ); void fillBOUNDARY( BOARD* aBoard, BOUNDARY* aBoundary ) throw( IO_ERROR );
/** /**
* Function makeIMAGE * Function makeIMAGE
* allocates an IMAGE on the heap and creates all the PINs according * allocates an IMAGE on the heap and creates all the PINs according
...@@ -3722,7 +3722,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER ...@@ -3722,7 +3722,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER
*/ */
IMAGE* makeIMAGE( BOARD* aBoard, MODULE* aModule ); IMAGE* makeIMAGE( BOARD* aBoard, MODULE* aModule );
/** /**
* Function makePADSTACK * Function makePADSTACK
* creates a PADSTACK which matches the given pad. Only pads which do not * creates a PADSTACK which matches the given pad. Only pads which do not
...@@ -3755,7 +3754,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER ...@@ -3755,7 +3754,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER
*/ */
PADSTACK* makeVia( const SEGVIA* aVia ); PADSTACK* makeVia( const SEGVIA* aVia );
/** /**
* Function deleteNETs * Function deleteNETs
* deletes all the NETs that may be in here. * deletes all the NETs that may be in here.
...@@ -3768,14 +3766,12 @@ class SPECCTRA_DB : public SPECCTRA_LEXER ...@@ -3768,14 +3766,12 @@ class SPECCTRA_DB : public SPECCTRA_LEXER
nets.clear(); nets.clear();
} }
/** /**
* Function exportNETCLASS * Function exportNETCLASS
* exports \a aNetClass to the DSN file. * exports \a aNetClass to the DSN file.
*/ */
void exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard ); void exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard );
//-----</FromBOARD>------------------------------------------------------ //-----</FromBOARD>------------------------------------------------------
//-----<FromSESSION>----------------------------------------------------- //-----<FromSESSION>-----------------------------------------------------
...@@ -3786,7 +3782,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER ...@@ -3786,7 +3782,6 @@ class SPECCTRA_DB : public SPECCTRA_LEXER
*/ */
TRACK* makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR ); TRACK* makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR );
/** /**
* Function makeVIA * Function makeVIA
* instantiates a KiCad SEGVIA on the heap and initializes it with internal * instantiates a KiCad SEGVIA on the heap and initializes it with internal
...@@ -3847,7 +3842,6 @@ public: ...@@ -3847,7 +3842,6 @@ public:
} }
SESSION* GetSESSION() { return session; } SESSION* GetSESSION() { return session; }
/** /**
* Function LoadPCB * Function LoadPCB
* is a recursive descent parser for a SPECCTRA DSN "design" file. * is a recursive descent parser for a SPECCTRA DSN "design" file.
...@@ -3859,7 +3853,6 @@ public: ...@@ -3859,7 +3853,6 @@ public:
*/ */
void LoadPCB( const wxString& filename ) throw( IO_ERROR ); void LoadPCB( const wxString& filename ) throw( IO_ERROR );
/** /**
* Function LoadSESSION * Function LoadSESSION
* is a recursive descent parser for a SPECCTRA DSN "session" file. * is a recursive descent parser for a SPECCTRA DSN "session" file.
...@@ -3872,10 +3865,8 @@ public: ...@@ -3872,10 +3865,8 @@ public:
*/ */
void LoadSESSION( const wxString& filename ) throw( IO_ERROR ); void LoadSESSION( const wxString& filename ) throw( IO_ERROR );
void ThrowIOError( const wxChar* fmt, ... ) throw( IO_ERROR ); void ThrowIOError( const wxChar* fmt, ... ) throw( IO_ERROR );
/** /**
* Function ExportPCB * Function ExportPCB
* writes the internal PCB instance out as a SPECTRA DSN format file. * writes the internal PCB instance out as a SPECTRA DSN format file.
...@@ -3887,7 +3878,6 @@ public: ...@@ -3887,7 +3878,6 @@ public:
*/ */
void ExportPCB( wxString aFilename, bool aNameChange=false ) throw( IO_ERROR ); void ExportPCB( wxString aFilename, bool aNameChange=false ) throw( IO_ERROR );
/** /**
* Function FromBOARD * Function FromBOARD
* adds the entire BOARD to the PCB but does not write it out. Note that * adds the entire BOARD to the PCB but does not write it out. Note that
......
...@@ -66,21 +66,56 @@ using namespace DSN; ...@@ -66,21 +66,56 @@ using namespace DSN;
// add its own 0.1 to the clearances, I believe this is happening after // add its own 0.1 to the clearances, I believe this is happening after
// the load process (and moving traces) so I am of the opinion this is // the load process (and moving traces) so I am of the opinion this is
// still needed. // still needed.
static const double safetyMargin = 0.1; static const double safetyMargin = 0.1;
/**
* Function close_ness
* is a non-exact distance calculator used to approximate the distance between
* two points. The distance is very in-exact, but can be helpful when used
* to pick between alternative neighboring points.
* @param aLeft is the first point
* @param aRight is the second point
* @return unsigned - a measure of proximity that the caller knows about, in BIU,
* but remember it is only an approximation.
*/
static unsigned close_ness( const wxPoint& aLeft, const wxPoint& aRight )
{
// Don't need an accurate distance calculation, just something
// approximating it, for relative orering.
return unsigned( abs( aLeft.x - aRight.x ) + abs( aLeft.y - aRight.y ) );
}
/**
* Function close_enough
* is a local and tunable method of qualifying the proximity of two points.
*
* @param aLeft is the first point
* @param aRight is the second point
* @param aLimit is a measure of proximity that the caller knows about.
* @return bool - true if the two points are close enough, else false.
*/
inline bool close_enough( const wxPoint& aLeft, const wxPoint& aRight, unsigned aLimit )
{
// We don't use an accurate distance calculation, just something
// approximating it, since aLimit is non-exact anyway except when zero.
return close_ness( aLeft, aRight ) <= aLimit;
}
// see wxPcbStruct.h // see wxPcbStruct.h
void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
{ {
wxString fullFileName = GetBoard()->GetFileName(); wxString fullFileName = GetBoard()->GetFileName();
wxString path; wxString path;
wxString name; wxString name;
wxString ext; wxString ext;
wxString dsn_ext = wxT( ".dsn" );
wxString dsn_ext = wxT( ".dsn" ); wxString mask = wxT( "*" ) + dsn_ext;
wxString mask = wxT( "*" ) + dsn_ext;
wxFileName::SplitPath( fullFileName, &path, &name, &ext ); wxFileName::SplitPath( fullFileName, &path, &name, &ext );
name += dsn_ext; name += dsn_ext;
fullFileName = EDA_FileSelector( _( "Specctra DSN file:" ), fullFileName = EDA_FileSelector( _( "Specctra DSN file:" ),
...@@ -92,6 +127,7 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) ...@@ -92,6 +127,7 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
wxFD_SAVE, wxFD_SAVE,
false false
); );
if( fullFileName == wxEmptyString ) if( fullFileName == wxEmptyString )
return; return;
...@@ -104,11 +140,11 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) ...@@ -104,11 +140,11 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
db.SetPCB( SPECCTRA_DB::MakePCB() ); db.SetPCB( SPECCTRA_DB::MakePCB() );
SetLocaleTo_C_standard( ); // Switch the locale to standard C LOCALE_IO toggle; // Switch the locale to standard C
// DSN Images (=KiCad MODULES and pads) must be presented from the // DSN Images (=KiCad MODULES and pads) must be presented from the
// top view. So we temporarily flip any modules which are on the back // top view. So we temporarily flip any modules which are on the back
// side of the board to the front, and record this in the MODULE's flag field. // side of the board to the front, and record this in the MODULE's flag field.
db.FlipMODULEs( GetBoard() ); db.FlipMODULEs( GetBoard() );
try try
...@@ -128,12 +164,9 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) ...@@ -128,12 +164,9 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
errorText = ioe.errorText; errorText = ioe.errorText;
} }
SetLocaleTo_Default( ); // revert to the current locale
// done assuredly, even if an exception was thrown and caught. // done assuredly, even if an exception was thrown and caught.
db.RevertMODULEs( GetBoard() ); db.RevertMODULEs( GetBoard() );
// The two calls below to MODULE::Flip(), both set the // The two calls below to MODULE::Flip(), both set the
// modified flag, yet their actions cancel each other out, so it should // modified flag, yet their actions cancel each other out, so it should
// be ok to clear the modify flag. // be ok to clear the modify flag.
...@@ -146,16 +179,14 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) ...@@ -146,16 +179,14 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event )
} }
else else
{ {
errorText += '\n'; errorText += '\n';
errorText += _( "Unable to export, please fix and try again." ); errorText += _( "Unable to export, please fix and try again." );
DisplayError( this, errorText ); DisplayError( this, errorText );
} }
} }
namespace DSN { namespace DSN {
const KICAD_T SPECCTRA_DB::scanPADs[] = { PCB_PAD_T, EOT }; const KICAD_T SPECCTRA_DB::scanPADs[] = { PCB_PAD_T, EOT };
// "specctra reported units" are what we tell the external router that our // "specctra reported units" are what we tell the external router that our
...@@ -179,25 +210,27 @@ static inline double scale( int kicadDist ) ...@@ -179,25 +210,27 @@ static inline double scale( int kicadDist )
#else #else
// deci-mils to mils. // deci-mils to mils.
return kicadDist/10.0; return kicadDist / 10.0;
#endif #endif
} }
/// Convert integer internal units to float um
// / Convert integer internal units to float um
static inline double IU2um( int kicadDist ) static inline double IU2um( int kicadDist )
{ {
return kicadDist * (1000.0 / IU_PER_MM); return kicadDist * (1000.0 / IU_PER_MM);
} }
static inline double mapX( int x ) static inline double mapX( int x )
{ {
return scale(x); return scale( x );
} }
static inline double mapY( int y ) static inline double mapY( int y )
{ {
return -scale(y); // make y negative, since it is increasing going down. return -scale( y ); // make y negative, since it is increasing going down.
} }
...@@ -210,8 +243,9 @@ static inline double mapY( int y ) ...@@ -210,8 +243,9 @@ static inline double mapY( int y )
static POINT mapPt( const wxPoint& pt ) static POINT mapPt( const wxPoint& pt )
{ {
POINT ret; POINT ret;
ret.x = mapX( pt.x );
ret.y = mapY( pt.y ); ret.x = mapX( pt.x );
ret.y = mapY( pt.y );
ret.FixNegativeZero(); ret.FixNegativeZero();
return ret; return ret;
} }
...@@ -226,11 +260,16 @@ static POINT mapPt( const wxPoint& pt ) ...@@ -226,11 +260,16 @@ static POINT mapPt( const wxPoint& pt )
* @return DRAWSEGMENT* - The first DRAWSEGMENT that has a start or end point matching * @return DRAWSEGMENT* - The first DRAWSEGMENT that has a start or end point matching
* aPoint, otherwise NULL if none. * aPoint, otherwise NULL if none.
*/ */
static DRAWSEGMENT* findPoint( const wxPoint& aPoint, TYPE_COLLECTOR* items ) static DRAWSEGMENT* findPoint( const wxPoint& aPoint, TYPE_COLLECTOR* items, unsigned aLimit )
{ {
for( int i=0; i<items->GetCount(); ++i ) unsigned min_d = INT_MAX;
int ndx_min;
// find the point closest to aPoint and perhaps exactly matching aPoint.
for( int i = 0; i<items->GetCount(); ++i )
{ {
DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i]; DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i];
unsigned d;
wxASSERT( graphic->Type() == PCB_LINE_T ); wxASSERT( graphic->Type() == PCB_LINE_T );
...@@ -239,25 +278,60 @@ static DRAWSEGMENT* findPoint( const wxPoint& aPoint, TYPE_COLLECTOR* items ) ...@@ -239,25 +278,60 @@ static DRAWSEGMENT* findPoint( const wxPoint& aPoint, TYPE_COLLECTOR* items )
case S_ARC: case S_ARC:
if( aPoint == graphic->GetArcStart() || aPoint == graphic->GetArcEnd() ) if( aPoint == graphic->GetArcStart() || aPoint == graphic->GetArcEnd() )
{ {
items->Remove(i); items->Remove( i );
return graphic; return graphic;
} }
d = close_ness( aPoint, graphic->GetArcStart() );
if( d < min_d )
{
min_d = d;
ndx_min = i;
}
d = close_ness( aPoint, graphic->GetArcEnd() );
if( d < min_d )
{
min_d = d;
ndx_min = i;
}
break; break;
default: default:
if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() ) if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() )
{ {
items->Remove(i); items->Remove( i );
return graphic; return graphic;
} }
d = close_ness( aPoint, graphic->GetStart() );
if( d < min_d )
{
min_d = d;
ndx_min = i;
}
d = close_ness( aPoint, graphic->GetEnd() );
if( d < min_d )
{
min_d = d;
ndx_min = i;
}
} }
} }
if( min_d <= aLimit )
{
DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[ndx_min];
items->Remove( ndx_min );
return graphic;
}
#if defined(DEBUG) #if defined(DEBUG)
printf("Unable to find segment matching point (%d,%d)\n", printf( "Unable to find segment matching point (%d,%d)\n",
aPoint.x, aPoint.y ); aPoint.x, aPoint.y );
for( int i=0; i<items->GetCount(); ++i ) for( int i = 0; i< items->GetCount(); ++i )
{ {
DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i]; DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i];
...@@ -300,7 +374,7 @@ static bool isRoundKeepout( D_PAD* aPad ) ...@@ -300,7 +374,7 @@ static bool isRoundKeepout( D_PAD* aPad )
*/ */
static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName ) static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName )
{ {
PATH* path = new PATH( 0, T_path ); PATH* path = new PATH( 0, T_path );
path->AppendPoint( aStart ); path->AppendPoint( aStart );
path->AppendPoint( aEnd ); path->AppendPoint( aEnd );
...@@ -311,7 +385,7 @@ static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string ...@@ -311,7 +385,7 @@ static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string
PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{ {
char name[256]; // padstack name builder char name[256]; // padstack name builder
std::string uniqifier; std::string uniqifier;
// caller must do these checks before calling here. // caller must do these checks before calling here.
...@@ -319,7 +393,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -319,7 +393,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
PADSTACK* padstack = new PADSTACK(); PADSTACK* padstack = new PADSTACK();
int reportedLayers = 0; // how many in reported padstack int reportedLayers = 0; // how many in reported padstack
const char* layerName[NB_COPPER_LAYERS]; const char* layerName[NB_COPPER_LAYERS];
uniqifier = '['; uniqifier = '[';
...@@ -327,10 +401,10 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -327,10 +401,10 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
bool onAllCopperLayers = ( (aPad->GetLayerMask() & ALL_CU_LAYERS) == ALL_CU_LAYERS ); bool onAllCopperLayers = ( (aPad->GetLayerMask() & ALL_CU_LAYERS) == ALL_CU_LAYERS );
if( onAllCopperLayers ) if( onAllCopperLayers )
uniqifier += 'A'; // A for all layers uniqifier += 'A'; // A for all layers
const int copperCount = aBoard->GetCopperLayerCount(); const int copperCount = aBoard->GetCopperLayerCount();
for( LAYER_NUM layer=FIRST_LAYER; layer<copperCount; ++layer ) for( int layer=0; layer<copperCount; ++layer )
{ {
LAYER_NUM kilayer = pcbLayer2kicad[layer]; LAYER_NUM kilayer = pcbLayer2kicad[layer];
...@@ -342,10 +416,10 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -342,10 +416,10 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{ {
if( layer == 0 ) if( layer == 0 )
uniqifier += 'T'; uniqifier += 'T';
else if( layer == copperCount-1 ) else if( layer == copperCount - 1 )
uniqifier += 'B'; uniqifier += 'B';
else else
uniqifier += char('0' + layer); // layer index char uniqifier += char('0' + layer); // layer index char
} }
} }
} }
...@@ -374,14 +448,16 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -374,14 +448,16 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
default: default:
case PAD_CIRCLE: case PAD_CIRCLE:
{ {
double diameter = scale(aPad->GetSize().x); double diameter = scale( aPad->GetSize().x );
for( LAYER_NUM ndx=FIRST_LAYER; ndx<reportedLayers; ++ndx ) for( int ndx=0; ndx<reportedLayers; ++ndx )
{ {
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
CIRCLE* circle = new CIRCLE( shape ); CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle ); shape->SetShape( circle );
circle->SetLayerId( layerName[ndx] ); circle->SetLayerId( layerName[ndx] );
...@@ -390,9 +466,9 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -390,9 +466,9 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
} }
snprintf( name, sizeof(name), "Round%sPad_%.6g_um", snprintf( name, sizeof(name), "Round%sPad_%.6g_um",
uniqifier.c_str(), IU2um( aPad->GetSize().x ) ); uniqifier.c_str(), IU2um( aPad->GetSize().x ) );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name) - 1 ] = 0;
padstack->SetPadstackId( name ); padstack->SetPadstackId( name );
} }
...@@ -400,33 +476,35 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -400,33 +476,35 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
case PAD_RECT: case PAD_RECT:
{ {
double dx = scale( aPad->GetSize().x ) / 2.0; double dx = scale( aPad->GetSize().x ) / 2.0;
double dy = scale( aPad->GetSize().y ) / 2.0; double dy = scale( aPad->GetSize().y ) / 2.0;
POINT lowerLeft( -dx, -dy ); POINT lowerLeft( -dx, -dy );
POINT upperRight( dx, dy ); POINT upperRight( dx, dy );
lowerLeft += dsnOffset; lowerLeft += dsnOffset;
upperRight += dsnOffset; upperRight += dsnOffset;
for( LAYER_NUM ndx=FIRST_LAYER; ndx<reportedLayers; ++ndx ) for( int ndx=0; ndx<reportedLayers; ++ndx )
{ {
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
RECTANGLE* rect = new RECTANGLE( shape ); RECTANGLE* rect = new RECTANGLE( shape );
shape->SetShape( rect ); shape->SetShape( rect );
rect->SetLayerId( layerName[ndx] ); rect->SetLayerId( layerName[ndx] );
rect->SetCorners( lowerLeft, upperRight ); rect->SetCorners( lowerLeft, upperRight );
} }
snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_um", snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_um",
uniqifier.c_str(), uniqifier.c_str(),
IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().x ),
IU2um( aPad->GetSize().y ) ); IU2um( aPad->GetSize().y ) );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name) - 1 ] = 0;
padstack->SetPadstackId( name ); padstack->SetPadstackId( name );
} }
...@@ -434,9 +512,9 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -434,9 +512,9 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
case PAD_OVAL: case PAD_OVAL:
{ {
double dx = scale( aPad->GetSize().x ) / 2.0; double dx = scale( aPad->GetSize().x ) / 2.0;
double dy = scale( aPad->GetSize().y ) / 2.0; double dy = scale( aPad->GetSize().y ) / 2.0;
double dr = dx - dy; double dr = dx - dy;
double radius; double radius;
POINT start; POINT start;
POINT stop; POINT stop;
...@@ -445,38 +523,39 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -445,38 +523,39 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{ {
radius = dy; radius = dy;
start = POINT( -dr, 0.0 ); start = POINT( -dr, 0.0 );
stop = POINT( dr, 0.0 ); stop = POINT( dr, 0.0 );
} }
else // oval is vertical else // oval is vertical
{ {
radius = dx; radius = dx;
dr = -dr; dr = -dr;
start = POINT( 0.0, -dr ); start = POINT( 0.0, -dr );
stop = POINT( 0.0, dr ); stop = POINT( 0.0, dr );
} }
start += dsnOffset; start += dsnOffset;
stop += dsnOffset; stop += dsnOffset;
for( LAYER_NUM ndx=FIRST_LAYER; ndx<reportedLayers; ++ndx ) for( int ndx=0; ndx<reportedLayers; ++ndx )
{ {
SHAPE* shape; SHAPE* shape;
PATH* path; PATH* path;
// see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408 // see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
path = makePath( start, stop, layerName[ndx] ); path = makePath( start, stop, layerName[ndx] );
shape->SetShape( path ); shape->SetShape( path );
path->aperture_width = 2.0 * radius; path->aperture_width = 2.0 * radius;
} }
snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_um", snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_um",
uniqifier.c_str(), uniqifier.c_str(),
IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().x ),
IU2um( aPad->GetSize().y ) ); IU2um( aPad->GetSize().y ) );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name) - 1 ] = 0;
padstack->SetPadstackId( name ); padstack->SetPadstackId( name );
} }
...@@ -484,11 +563,11 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -484,11 +563,11 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
case PAD_TRAPEZOID: case PAD_TRAPEZOID:
{ {
double dx = scale( aPad->GetSize().x ) / 2.0; double dx = scale( aPad->GetSize().x ) / 2.0;
double dy = scale( aPad->GetSize().y ) / 2.0; double dy = scale( aPad->GetSize().y ) / 2.0;
double ddx = scale( aPad->GetDelta().x ) / 2.0; double ddx = scale( aPad->GetDelta().x ) / 2.0;
double ddy = scale( aPad->GetDelta().y ) / 2.0; double ddy = scale( aPad->GetDelta().y ) / 2.0;
// see class_pad_draw_functions.cpp which draws the trapezoid pad // see class_pad_draw_functions.cpp which draws the trapezoid pad
POINT lowerLeft( -dx - ddy, -dy - ddx ); POINT lowerLeft( -dx - ddy, -dy - ddx );
...@@ -496,18 +575,20 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -496,18 +575,20 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
POINT upperRight( +dx - ddy, +dy - ddx ); POINT upperRight( +dx - ddy, +dy - ddx );
POINT lowerRight( +dx + ddy, -dy + ddx ); POINT lowerRight( +dx + ddy, -dy + ddx );
lowerLeft += dsnOffset; lowerLeft += dsnOffset;
upperLeft += dsnOffset; upperLeft += dsnOffset;
upperRight += dsnOffset; upperRight += dsnOffset;
lowerRight += dsnOffset; lowerRight += dsnOffset;
for( LAYER_NUM ndx=FIRST_LAYER; ndx<reportedLayers; ++ndx ) for( int ndx=0; ndx<reportedLayers; ++ndx )
{ {
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
// a T_polygon exists as a PATH // a T_polygon exists as a PATH
PATH* polygon = new PATH( shape, T_polygon ); PATH* polygon = new PATH( shape, T_polygon );
shape->SetShape( polygon ); shape->SetShape( polygon );
polygon->SetLayerId( layerName[ndx] ); polygon->SetLayerId( layerName[ndx] );
...@@ -518,7 +599,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) ...@@ -518,7 +599,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
polygon->AppendPoint( lowerRight ); polygon->AppendPoint( lowerRight );
} }
D(printf( "m_DeltaSize: %d,%d\n", aPad->GetDelta().x, aPad->GetDelta().y );) D( printf( "m_DeltaSize: %d,%d\n", aPad->GetDelta().x, aPad->GetDelta().y ); )
// this string _must_ be unique for a given physical shape // this string _must_ be unique for a given physical shape
snprintf( name, sizeof(name), "Trapz%sPad_%.6gx%.6g_%c%.6gx%c%.6g_um", snprintf( name, sizeof(name), "Trapz%sPad_%.6gx%.6g_%c%.6gx%c%.6g_um",
...@@ -568,12 +649,14 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -568,12 +649,14 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
POINT vertex = mapPt( pad->GetPos0() ); POINT vertex = mapPt( pad->GetPos0() );
int layerCount = aBoard->GetCopperLayerCount(); int layerCount = aBoard->GetCopperLayerCount();
for( LAYER_NUM layer=FIRST_LAYER; layer<layerCount; ++layer ) for( int layer=0; layer<layerCount; ++layer )
{ {
KEEPOUT* keepout = new KEEPOUT(image, T_keepout); KEEPOUT* keepout = new KEEPOUT( image, T_keepout );
image->keepouts.push_back( keepout ); image->keepouts.push_back( keepout );
CIRCLE* circle = new CIRCLE( keepout ); CIRCLE* circle = new CIRCLE( keepout );
keepout->SetShape( circle ); keepout->SetShape( circle );
circle->SetDiameter( diameter ); circle->SetDiameter( diameter );
...@@ -581,14 +664,13 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -581,14 +664,13 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
circle->SetLayerId( layerIds[layer].c_str() ); circle->SetLayerId( layerIds[layer].c_str() );
} }
} }
// else if() could there be a square keepout here? // else if() could there be a square keepout here?
else else
{ {
PADSTACK* padstack = makePADSTACK( aBoard, pad ); PADSTACK* padstack = makePADSTACK( aBoard, pad );
PADSTACKSET::iterator iter = padstackset.find( *padstack );
PADSTACKSET::iterator iter = padstackset.find( *padstack );
if( iter != padstackset.end() ) if( iter != padstackset.end() )
{ {
// padstack is a duplicate, delete it and use the original // padstack is a duplicate, delete it and use the original
...@@ -600,10 +682,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -600,10 +682,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
padstackset.insert( padstack ); padstackset.insert( padstack );
} }
PIN* pin = new PIN(image); PIN* pin = new PIN( image );
padName = pad->GetPadName(); padName = pad->GetPadName();
pin->pin_id = TO_UTF8( padName ); pin->pin_id = TO_UTF8( padName );
if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() ) if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
{ {
...@@ -611,9 +693,9 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -611,9 +693,9 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
} }
else // pad name is a duplicate within this module else // pad name is a duplicate within this module
{ {
char buf[32]; char buf[32];
int duplicates = ++pinmap[ padName ]; int duplicates = ++pinmap[ padName ];
sprintf( buf, "@%d", duplicates ); sprintf( buf, "@%d", duplicates );
...@@ -626,26 +708,27 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -626,26 +708,27 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
pin->padstack_id = padstack->padstack_id; pin->padstack_id = padstack->padstack_id;
int angle = pad->GetOrientation() - aModule->GetOrientation(); // tenths of degrees int angle = pad->GetOrientation() - aModule->GetOrientation(); // tenths of degrees
if( angle ) if( angle )
{ {
NORMALIZE_ANGLE_POS(angle); NORMALIZE_ANGLE_POS( angle );
pin->SetRotation( angle / 10.0 ); pin->SetRotation( angle / 10.0 );
} }
wxPoint pos( pad->GetPos0() ); wxPoint pos( pad->GetPos0() );
pin->SetVertex( mapPt( pos ) ); pin->SetVertex( mapPt( pos ) );
} }
} }
#if 1 // enable image (outline) scopes. #if 1 // enable image (outline) scopes.
static const KICAD_T scanEDGEs[] = { PCB_MODULE_EDGE_T, EOT }; static const KICAD_T scanEDGEs[] = { PCB_MODULE_EDGE_T, EOT };
// get all the MODULE's EDGE_MODULEs and convert those to DSN outlines. // get all the MODULE's EDGE_MODULEs and convert those to DSN outlines.
moduleItems.Collect( aModule, scanEDGEs ); moduleItems.Collect( aModule, scanEDGEs );
for( int i=0; i<moduleItems.GetCount(); ++i ) for( int i = 0; i<moduleItems.GetCount(); ++i )
{ {
EDGE_MODULE* graphic = (EDGE_MODULE*) moduleItems[i]; EDGE_MODULE* graphic = (EDGE_MODULE*) moduleItems[i];
SHAPE* outline; SHAPE* outline;
...@@ -655,8 +738,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -655,8 +738,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
{ {
case S_SEGMENT: case S_SEGMENT:
outline = new SHAPE( image, T_outline ); outline = new SHAPE( image, T_outline );
image->Append( outline ); image->Append( outline );
path = new PATH( outline ); path = new PATH( outline );
outline->SetShape( path ); outline->SetShape( path );
path->SetAperture( scale( graphic->GetWidth() ) ); path->SetAperture( scale( graphic->GetWidth() ) );
path->SetLayerId( "signal" ); path->SetLayerId( "signal" );
...@@ -670,8 +755,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -670,8 +755,10 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
// for now, support by using line segments. // for now, support by using line segments.
outline = new SHAPE( image, T_outline ); outline = new SHAPE( image, T_outline );
image->Append( outline ); image->Append( outline );
path = new PATH( outline ); path = new PATH( outline );
outline->SetShape( path ); outline->SetShape( path );
path->SetAperture( scale( graphic->GetWidth() ) ); path->SetAperture( scale( graphic->GetWidth() ) );
path->SetLayerId( "signal" ); path->SetLayerId( "signal" );
...@@ -682,20 +769,22 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -682,20 +769,22 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
// lexer/beautifier, and the spec is not clear that this is // lexer/beautifier, and the spec is not clear that this is
// required. Fixed point floats are all that should be needed. // required. Fixed point floats are all that should be needed.
double radius = hypot( double( graphic->GetStart().x - graphic->GetEnd().x ), double radius = hypot( double(graphic->GetStart().x - graphic->GetEnd().x),
double( graphic->GetStart().y - graphic->GetEnd().y ) ); double(graphic->GetStart().y - graphic->GetEnd().y) );
// better if evenly divisible into 360 // better if evenly divisible into 360
const int DEGREE_INTERVAL = 18; // 18 means 20 line segments const int DEGREE_INTERVAL = 18; // 18 means 20 line segments
for( double radians = 0.0; radians < 2*M_PI; radians += DEGREE_INTERVAL * M_PI / 180.0 ) for( double radians = 0.0;
radians < 2 * M_PI;
radians += DEGREE_INTERVAL * M_PI / 180.0 )
{ {
wxPoint point( int( radius * cos( radians ) ), wxPoint point( int( radius * cos( radians ) ),
int( radius * sin( radians ) ) ); int( radius * sin( radians ) ) );
point += graphic->m_Start0; // an offset point += graphic->m_Start0; // an offset
path->AppendPoint( mapPt(point) ); path->AppendPoint( mapPt( point ) );
} }
} }
break; break;
...@@ -703,11 +792,12 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -703,11 +792,12 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
case S_RECT: case S_RECT:
case S_ARC: case S_ARC:
default: default:
D( printf("makeIMAGE(): unsupported shape %s\n", D( printf( "makeIMAGE(): unsupported shape %s\n",
TO_UTF8( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() )) );) TO_UTF8( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) ); )
continue; continue;
} }
} }
#endif #endif
return image; return image;
...@@ -715,32 +805,33 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) ...@@ -715,32 +805,33 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter, PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
LAYER_NUM aTopLayer, LAYER_NUM aBotLayer ) int aTopLayer, int aBotLayer )
{ {
char name[48]; char name[48];
PADSTACK* padstack = new PADSTACK(); PADSTACK* padstack = new PADSTACK();
double dsnDiameter = scale( aCopperDiameter ); double dsnDiameter = scale( aCopperDiameter );
for( LAYER_NUM layer=aTopLayer; layer<=aBotLayer; ++layer ) for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
{ {
SHAPE* shape = new SHAPE( padstack ); SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
CIRCLE* circle = new CIRCLE( shape ); CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle ); shape->SetShape( circle );
circle->SetDiameter( dsnDiameter ); circle->SetDiameter( dsnDiameter );
circle->SetLayerId( layerIds[layer].c_str() ); circle->SetLayerId( layerIds[layer].c_str() );
} }
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um", snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um",
aTopLayer, aBotLayer, dsnDiameter, aTopLayer, aBotLayer, dsnDiameter,
// encode the drill value into the name for later import // encode the drill value into the name for later import
IU2um( aDrillDiameter ) IU2um( aDrillDiameter )
); );
name[ sizeof(name)-1 ] = 0; name[ sizeof(name) - 1 ] = 0;
padstack->SetPadstackId( name ); padstack->SetPadstackId( name );
return padstack; return padstack;
...@@ -749,13 +840,13 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter, ...@@ -749,13 +840,13 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia ) PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
{ {
LAYER_NUM topLayer; LAYER_NUM topLayerNum;
LAYER_NUM botLayer; LAYER_NUM botLayerNum;
aVia->ReturnLayerPair( &topLayer, &botLayer ); aVia->ReturnLayerPair( &topLayerNum, &botLayerNum );
topLayer = kicadLayer2pcb[topLayer]; int topLayer = kicadLayer2pcb[topLayerNum];
botLayer = kicadLayer2pcb[botLayer]; int botLayer = kicadLayer2pcb[botLayerNum];
if( topLayer > botLayer ) if( topLayer > botLayer )
EXCHG( topLayer, botLayer ); EXCHG( topLayer, botLayer );
...@@ -767,15 +858,16 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia ) ...@@ -767,15 +858,16 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ERROR ) void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ERROR )
{ {
TYPE_COLLECTOR items; TYPE_COLLECTOR items;
unsigned prox; // a proximity BIU metric, not an accurate distance
// get all the DRAWSEGMENTS into 'items', then look for layer == EDGE_N, // Get all the DRAWSEGMENTS and module graphics into 'items',
// and those segments comprise the board's perimeter. // then keep only those on layer == EDGE_N.
static const KICAD_T scan_graphics[] = { PCB_LINE_T, PCB_MODULE_EDGE_T, EOT }; static const KICAD_T scan_graphics[] = { PCB_LINE_T, PCB_MODULE_EDGE_T, EOT };
items.Collect( aBoard, scan_graphics ); items.Collect( aBoard, scan_graphics );
for( int i=0; i<items.GetCount(); ) for( int i = 0; i<items.GetCount(); )
{ {
if( items[i]->GetLayer() != EDGE_N ) if( items[i]->GetLayer() != EDGE_N )
{ {
...@@ -796,16 +888,105 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -796,16 +888,105 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
wxPoint prevPt; wxPoint prevPt;
DRAWSEGMENT* graphic = (DRAWSEGMENT*) items[0]; DRAWSEGMENT* graphic;
// Find edge point with minimum x, this should be in the outer polygon
// which will define the perimeter Edge.Cuts polygon.
wxPoint xmin = wxPoint( INT_MAX, 0 );
int xmini = 0;
for( int i = 0; i < items.GetCount(); i++ )
{
graphic = (DRAWSEGMENT*) items[i];
switch( graphic->GetShape() )
{
case S_SEGMENT:
{
if( graphic->GetStart().x < xmin.x )
{
xmin = graphic->GetStart();
xmini = i;
}
if( graphic->GetEnd().x < xmin.x )
{
xmin = graphic->GetEnd();
xmini = i;
}
}
break;
case S_ARC:
// freerouter does not yet understand arcs, so approximate
// an arc with a series of short lines and put those
// line segments into the !same! PATH.
{
const int STEPS = 9; // in an arc of 90 degrees
wxPoint start = graphic->GetArcStart();
wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle();
wxPoint pt;
for( int step = 1; step<=STEPS; ++step )
{
double rotation = ( angle * step ) / STEPS;
pt = start;
RotatePoint( &pt.x, &pt.y, center.x, center.y, rotation );
if( pt.x < xmin.x )
{
xmin = pt;
xmini = i;
}
}
}
break;
// the first DRAWSEGMENT is in 'graphic*', ok to remove it from 'items' case S_CIRCLE:
items.Remove( 0 ); // Freerouter does not understand circles.
// This might be a mounting hole or something, ignore it without error
// because some of our demo boards have used the edges pcb layer to
// hold islanded circles, rather than simply using holes.
break;
default:
{
wxString error = wxString::Format( _( "Unsupported DRAWSEGMENT type %s" ),
GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) );
ThrowIOError( error );
}
break;
}
}
// Grab the left most point, assume its on the board's perimeter, and see if we
// can put enough graphics together by matching endpoints to formulate a cohesive
// polygon.
graphic = (DRAWSEGMENT*) items[xmini];
// The first DRAWSEGMENT is in 'graphic', ok to remove it from 'items'
items.Remove( xmini );
wxPoint startPt = wxPoint( graphic->GetEnd() );
prevPt = graphic->GetEnd(); prevPt = graphic->GetEnd();
path->AppendPoint( mapPt( prevPt ) ); path->AppendPoint( mapPt( prevPt ) );
// do not append the other end point yet, this first 'graphic' might be an arc // Do not append the other end point yet of this 'graphic', this first
// 'graphic' might be an arc.
// Set maximum proximity threshold for point to point nearness metric for
// board perimeter only, not interior keepouts yet.
prox = Mils2iu( 0 );
// Output the Edge.Cuts perimeter polygon.
for(;;) for(;;)
{ {
switch( graphic->GetShape() ) switch( graphic->GetShape() )
...@@ -814,24 +995,24 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -814,24 +995,24 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
{ {
wxPoint nextPt; wxPoint nextPt;
if( prevPt != graphic->GetStart() ) if( !close_enough( prevPt, graphic->GetStart(), prox ) )
{ {
wxASSERT( prevPt == graphic->GetEnd() ); wxASSERT( close_enough( prevPt, graphic->GetEnd(), prox ) );
nextPt = graphic->GetStart(); nextPt = graphic->GetStart();
} }
else else
{ {
wxASSERT( prevPt == graphic->GetStart() ); wxASSERT( close_enough( prevPt, graphic->GetStart(), prox ) );
nextPt = graphic->GetEnd(); nextPt = graphic->GetEnd();
} }
path->AppendPoint( mapPt(nextPt) ); path->AppendPoint( mapPt( nextPt ) );
prevPt = nextPt; prevPt = nextPt;
} }
break; break;
case S_ARC: case S_ARC:
// freerouter does not yet understand arcs, so approximate // Freerouter does not yet understand arcs, so approximate
// an arc with a series of short lines and put those // an arc with a series of short lines and put those
// line segments into the !same! PATH. // line segments into the !same! PATH.
{ {
...@@ -842,9 +1023,9 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -842,9 +1023,9 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
wxPoint center = graphic->GetCenter(); wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle(); double angle = -graphic->GetAngle();
if( prevPt != start ) if( !close_enough( prevPt, start, prox ) )
{ {
wxASSERT( prevPt == graphic->GetArcEnd() ); wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), prox ) );
angle = -angle; angle = -angle;
EXCHG( start, end ); EXCHG( start, end );
...@@ -852,9 +1033,9 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -852,9 +1033,9 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
wxPoint nextPt; wxPoint nextPt;
for( int step=1; step<=STEPS; ++step ) for( int step = 1; step<=STEPS; ++step )
{ {
double rotation = ( angle * step )/STEPS; double rotation = ( angle * step ) / STEPS;
nextPt = start; nextPt = start;
...@@ -868,26 +1049,17 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -868,26 +1049,17 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
break; break;
case S_CIRCLE: case S_CIRCLE:
#if 0 // Freerouter does not understand circles. And although we can mimic
// do not output a circle, freerouter does not understand it. // a circle for it by line segments, we'd have to ensure that the circle
// this might be a mounting hole or something, ignore it without error // was the only graphic on the board's edge. @todo that.
// because some of our demo boards have used the edges pcb layer to //
// hold islanded circles, rather than simply using holes. // Tell user his board has a problem, this is better than silently
break; // ignoring the error.
#else
// Do not output a circle, freerouter does not understand it.
// tell user his board has a problem, this is better than silently
// ignoring the error. "edges pcb" layer should not be used
// to hold islanded circles which could or should be better done
// as simple holes. (Some of our demo boards have this problem.)
// fall thru here to report the error. // fall thru here to report the error.
#endif
default: default:
{ {
wxString error; wxString error = wxString::Format( _( "Unsupported DRAWSEGMENT type %s" ),
error.Printf( _( "Unsupported DRAWSEGMENT type %s" ),
GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) ); GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) );
ThrowIOError( error ); ThrowIOError( error );
...@@ -895,31 +1067,166 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -895,31 +1067,166 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
break; break;
} }
if( items.GetCount() == 0 ) if( close_enough( startPt, prevPt, prox ) ) // the polygon is closed.
break; break;
graphic = findPoint( prevPt, &items ); graphic = findPoint( prevPt, &items, prox );
if( !graphic ) if( !graphic )
{ {
wxString error; wxString error = wxString::Format(
_( "Unable to find the next segment with an endpoint of (%d,%d).\n"
error << _("Unable to find the next segment with an endpoint of "); "Edit Edge.Cuts line segments, making them contiguous." ),
error << prevPt; prevPt.x,
error << wxChar('\n'); prevPt.y );
error << _("Edit Edges_Pcb segments, making them contiguous.");
ThrowIOError( error ); ThrowIOError( error );
} }
} }
#if 0 && defined(DEBUG) // Output the interior Edge.Cuts graphics as keepouts, using nearness metric
STRING_FORMATTER sf; // for sloppy graphical items.
path->Format( &sf, 0 ); prox = Mils2iu( 10 );
printf( "%s\n", sf.GetString().c_str() );
#endif while( items.GetCount() )
{
// emit a signal layers keepout for every interior polygon left...
KEEPOUT* keepout = new KEEPOUT( NULL, T_keepout );
PATH* poly_ko = new PATH( NULL, T_polygon );
keepout->SetShape( poly_ko );
poly_ko->SetLayerId( "signal" );
pcb->structure->keepouts.push_back( keepout );
graphic = (DRAWSEGMENT*) items[0];
items.Remove( 0 );
if( graphic->GetShape() == S_CIRCLE )
{
// do a circle segmentation
const int STEPS = 36;
wxPoint start;
wxPoint center = graphic->GetCenter();
int radius = graphic->GetRadius();
double angle = 3600.0;
start = center;
start.x += radius;
wxPoint nextPt;
for( int step = 0; step<STEPS; ++step )
{
double rotation = ( angle * step ) / STEPS;
nextPt = start;
RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
poly_ko->AppendPoint( mapPt( nextPt ) );
}
}
else
{
wxPoint startPt = wxPoint( graphic->GetEnd() );
prevPt = graphic->GetEnd();
poly_ko->AppendPoint( mapPt( prevPt ) );
// do not append the other end point yet, this first 'graphic' might be an arc
for(;;)
{
switch( graphic->GetShape() )
{
case S_SEGMENT:
{
wxPoint nextPt;
if( !close_enough( prevPt, graphic->GetStart(), prox ) )
{
wxASSERT( close_enough( prevPt, graphic->GetEnd(), prox ) );
nextPt = graphic->GetStart();
}
else
{
wxASSERT( close_enough( prevPt, graphic->GetStart(), prox ) );
nextPt = graphic->GetEnd();
}
prevPt = nextPt;
poly_ko->AppendPoint( mapPt( prevPt ) );
}
break;
case S_ARC:
// freerouter does not yet understand arcs, so approximate
// an arc with a series of short lines and put those
// line segments into the !same! PATH.
{
const int STEPS = 9; // in an arc of 90 degrees
wxPoint start = graphic->GetArcStart();
wxPoint end = graphic->GetArcEnd();
wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle();
if( !close_enough( prevPt, start, prox ) )
{
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), prox ) );
angle = -angle;
EXCHG( start, end );
}
wxPoint nextPt;
for( int step = 1; step<=STEPS; ++step )
{
double rotation = ( angle * step ) / STEPS;
nextPt = start;
RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
poly_ko->AppendPoint( mapPt( nextPt ) );
}
prevPt = nextPt;
}
break;
default:
{
wxString error = wxString::Format(
_( "Unsupported DRAWSEGMENT type %s" ),
GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) );
ThrowIOError( error );
}
break;
}
if( close_enough( startPt, prevPt, prox ) )
break;
graphic = findPoint( prevPt, &items, prox );
if( !graphic )
{
wxString error = wxString::Format(
_( "Unable to find the next segment with an endpoint of (%d,%d)\n."
"Edit Edge.Cuts interior graphics, making them contiguous polygons each." ),
prevPt
);
ThrowIOError( error );
}
}
}
}
} }
else else
{ {
// User has not defined a board perimeter yet...
EDA_RECT bbbox = aBoard->ComputeBoundingBox(); EDA_RECT bbbox = aBoard->ComputeBoundingBox();
RECTANGLE* rect = new RECTANGLE( boundary ); RECTANGLE* rect = new RECTANGLE( boundary );
...@@ -936,9 +1243,8 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER ...@@ -936,9 +1243,8 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary ) throw( IO_ER
} }
typedef std::set<std::string> STRINGSET;
typedef std::set<std::string> STRINGSET; typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
...@@ -990,29 +1296,38 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -990,29 +1296,38 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
int layerCount = aBoard->GetCopperLayerCount(); int layerCount = aBoard->GetCopperLayerCount();
for( LAYER_NUM pcbNdx=FIRST_LAYER; pcbNdx<layerCount; ++pcbNdx ) for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
{ {
LAYER* layer = new LAYER( pcb->structure ); LAYER* layer = new LAYER( pcb->structure );
pcb->structure->layers.push_back( layer ); pcb->structure->layers.push_back( layer );
layer->name = layerIds[pcbNdx]; layer->name = layerIds[pcbNdx];
DSN_T layerType; DSN_T layerType;
switch( aBoard->GetLayerType( pcbLayer2kicad[pcbNdx] ) ) switch( aBoard->GetLayerType( pcbLayer2kicad[pcbNdx] ) )
{ {
default: default:
case LT_SIGNAL: layerType = T_signal; break; case LT_SIGNAL:
case LT_POWER: layerType = T_power; break; layerType = T_signal; break;
case LT_MIXED: layerType = T_mixed; break;
case LT_JUMPER: layerType = T_jumper; break; case LT_POWER:
layerType = T_power; break;
case LT_MIXED:
layerType = T_mixed; break;
case LT_JUMPER:
layerType = T_jumper; break;
} }
layer->layer_type = layerType; layer->layer_type = layerType;
layer->properties.push_back( PROPERTY() ); layer->properties.push_back( PROPERTY() );
PROPERTY* property = &layer->properties.back(); PROPERTY* property = &layer->properties.back();
property->name = "index"; property->name = "index";
char temp[32]; char temp[32];
sprintf( temp, "%d", pcbNdx ); sprintf( temp, "%d", pcbNdx );
property->value = temp; property->value = temp;
} }
...@@ -1023,15 +1338,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1023,15 +1338,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
//-----<unit_descriptor> & <resolution_descriptor>-------------------- //-----<unit_descriptor> & <resolution_descriptor>--------------------
{ {
#if defined(USE_PCBNEW_NANOMETRES) #if defined(USE_PCBNEW_NANOMETRES)
// tell freerouter to use "tenths of micrometers", // tell freerouter to use "tenths of micrometers",
// which is 100 nm resolution. Possibly more resolution is possible // which is 100 nm resolution. Possibly more resolution is possible
// in freerouter, but it would need testing. // in freerouter, but it would need testing.
pcb->unit->units = T_um; pcb->unit->units = T_um;
pcb->resolution->units = T_um; pcb->resolution->units = T_um;
pcb->resolution->value = 10; // tenths of a um pcb->resolution->value = 10; // tenths of a um
// pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm") // pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm")
#else #else
...@@ -1052,7 +1366,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1052,7 +1366,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// Because fillBOUNDARY() can throw an exception, we link in an // Because fillBOUNDARY() can throw an exception, we link in an
// empty boundary so the BOUNDARY does not get lost in the event of // empty boundary so the BOUNDARY does not get lost in the event of
// of an exception. // of an exception.
BOUNDARY* boundary = new BOUNDARY(0); BOUNDARY* boundary = new BOUNDARY( 0 );
pcb->structure->SetBOUNDARY( boundary ); pcb->structure->SetBOUNDARY( boundary );
fillBOUNDARY( aBoard, boundary ); fillBOUNDARY( aBoard, boundary );
} }
...@@ -1060,19 +1375,19 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1060,19 +1375,19 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
//-----<rules>-------------------------------------------------------- //-----<rules>--------------------------------------------------------
{ {
char rule[80]; char rule[80];
int defaultTrackWidth = aBoard->m_NetClasses.GetDefault()->GetTrackWidth(); int defaultTrackWidth = aBoard->m_NetClasses.GetDefault()->GetTrackWidth();
int defaultClearance = aBoard->m_NetClasses.GetDefault()->GetClearance(); int defaultClearance = aBoard->m_NetClasses.GetDefault()->GetClearance();
double clearance = scale( defaultClearance ); double clearance = scale( defaultClearance );
STRINGS& rules = pcb->structure->rules->rules; STRINGS& rules = pcb->structure->rules->rules;
sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) ); sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) );
rules.push_back( rule ); rules.push_back( rule );
sprintf( rule, "(clearance %.6g)", clearance+safetyMargin ); sprintf( rule, "(clearance %.6g)", clearance + safetyMargin );
rules.push_back( rule ); rules.push_back( rule );
// On a high density board (a board with 4 mil tracks, 4 mil spacing) // On a high density board (a board with 4 mil tracks, 4 mil spacing)
...@@ -1084,6 +1399,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1084,6 +1399,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// a different net. So if the baseline trace to trace clearance was say 4 mils, then // a different net. So if the baseline trace to trace clearance was say 4 mils, then
// the SMD to trace clearance should be at least 6 mils. // the SMD to trace clearance should be at least 6 mils.
double default_smd = clearance + safetyMargin; double default_smd = clearance + safetyMargin;
if( default_smd <= 6.0 ) if( default_smd <= 6.0 )
default_smd = 6.0; default_smd = 6.0;
...@@ -1114,13 +1430,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1114,13 +1430,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
rules.push_back( rule ); rules.push_back( rule );
*/ */
// well, the user is going to text edit these in the DSN file anyway,
// at least until we have an export dialog.
// Pad to pad spacing on a single SMT part can be closer than our // Pad to pad spacing on a single SMT part can be closer than our
// clearance, we don't want freerouter complaining about that, so // clearance, we don't want freerouter complaining about that, so
// output a significantly smaller pad to pad clearance to freerouter. // output a significantly smaller pad to pad clearance to freerouter.
clearance = scale( defaultClearance )/4; clearance = scale( defaultClearance ) / 4;
sprintf( rule, "(clearance %.6g (type smd_smd))", clearance ); sprintf( rule, "(clearance %.6g (type smd_smd))", clearance );
rules.push_back( rule ); rules.push_back( rule );
...@@ -1132,10 +1445,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1132,10 +1445,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
{ {
int netlessZones = 0; int netlessZones = 0;
static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT }; static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
items.Collect( aBoard, scanZONEs ); items.Collect( aBoard, scanZONEs );
for( int i=0; i<items.GetCount(); ++i ) for( int i = 0; i<items.GetCount(); ++i )
{ {
ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i]; ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
...@@ -1143,9 +1456,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1143,9 +1456,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
continue; continue;
COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure ); COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure );
pcb->structure->planes.push_back( plane ); pcb->structure->planes.push_back( plane );
PATH* mainPolygon = new PATH( plane, T_polygon ); PATH* mainPolygon = new PATH( plane, T_polygon );
plane->SetShape( mainPolygon ); plane->SetShape( mainPolygon );
plane->name = TO_UTF8( item->GetNetName() ); plane->name = TO_UTF8( item->GetNetName() );
...@@ -1183,8 +1498,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1183,8 +1498,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
break; break;
} }
WINDOW* window = 0; WINDOW* window = 0;
PATH* cutout = 0; PATH* cutout = 0;
// handle the cutouts // handle the cutouts
for( ++ndx; ndx<count; ++ndx ) for( ++ndx; ndx<count; ++ndx )
...@@ -1192,9 +1507,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1192,9 +1507,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
if( item->Outline()->m_CornersList[ndx-1].end_contour ) if( item->Outline()->m_CornersList[ndx-1].end_contour )
{ {
window = new WINDOW( plane ); window = new WINDOW( plane );
plane->AddWindow( window ); plane->AddWindow( window );
cutout = new PATH( window, T_polygon ); cutout = new PATH( window, T_polygon );
window->SetShape( cutout ); window->SetShape( cutout );
cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ]; cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
...@@ -1287,24 +1604,27 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1287,24 +1604,27 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
//-----<build the images, components, and netlist>----------------------- //-----<build the images, components, and netlist>-----------------------
{ {
PIN_REF empty( pcb->network ); PIN_REF empty( pcb->network );
std::string componentId; std::string componentId;
// find the highest numbered netCode within the board. // find the highest numbered netCode within the board.
int highestNetCode = aBoard->GetNetCount() - 1; int highestNetCode = aBoard->GetNetCount() - 1;
deleteNETs(); deleteNETs();
// expand the net vector to highestNetCode+1, setting empty to NULL // expand the net vector to highestNetCode+1, setting empty to NULL
nets.resize( highestNetCode+1, NULL ); nets.resize( highestNetCode + 1, NULL );
// skip netcode = 0 // skip netcode = 0
for( unsigned i=1; i<nets.size(); ++i ) for( unsigned i = 1; i<nets.size(); ++i )
nets[i] = new NET( pcb->network ); nets[i] = new NET( pcb->network );
for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ ) for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ )
{ {
NETINFO_ITEM* net = aBoard->FindNet(ii); NETINFO_ITEM* net = aBoard->FindNet( ii );
int netcode = net->GetNet(); int netcode = net->GetNet();
if( netcode > 0 ) if( netcode > 0 )
nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() ); nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() );
} }
...@@ -1313,11 +1633,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1313,11 +1633,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
padstackset.clear(); padstackset.clear();
for( int m=0; m<items.GetCount(); ++m ) for( int m = 0; m<items.GetCount(); ++m )
{ {
MODULE* module = (MODULE*) items[m]; MODULE* module = (MODULE*) items[m];
IMAGE* image = makeIMAGE( aBoard, module ); IMAGE* image = makeIMAGE( aBoard, module );
componentId = TO_UTF8( module->GetReference() ); componentId = TO_UTF8( module->GetReference() );
...@@ -1329,12 +1649,12 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1329,12 +1649,12 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// exported netlist will have some fabricated pin names in it. // exported netlist will have some fabricated pin names in it.
// If you don't like fabricated pin names, then make sure all pads // If you don't like fabricated pin names, then make sure all pads
// within your MODULEs are uniquely named! // within your MODULEs are uniquely named!
for( unsigned p = 0; p<image->pins.size(); ++p )
for( unsigned p=0; p<image->pins.size(); ++p )
{ {
PIN* pin = &image->pins[p]; PIN* pin = &image->pins[p];
int netcode = pin->kiNetCode;
int netcode = pin->kiNetCode;
if( netcode > 0 ) if( netcode > 0 )
{ {
NET* net = nets[netcode]; NET* net = nets[netcode];
...@@ -1349,7 +1669,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1349,7 +1669,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
} }
IMAGE* registered = pcb->library->LookupIMAGE( image ); IMAGE* registered = pcb->library->LookupIMAGE( image );
if( registered != image ) if( registered != image )
{ {
// If our new 'image' is not a unique IMAGE, delete it. // If our new 'image' is not a unique IMAGE, delete it.
...@@ -1358,9 +1679,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1358,9 +1679,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
image = registered; image = registered;
} }
COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() ); COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
PLACE* place = new PLACE( comp );
PLACE* place = new PLACE( comp );
comp->places.push_back( place ); comp->places.push_back( place );
place->SetRotation( module->GetOrientation()/10.0 ); place->SetRotation( module->GetOrientation()/10.0 );
...@@ -1372,8 +1694,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1372,8 +1694,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
if( module->GetFlag() ) if( module->GetFlag() )
{ {
int angle = 1800 - module->GetOrientation(); int angle = 1800 - module->GetOrientation();
NORMALIZE_ANGLE_POS(angle); NORMALIZE_ANGLE_POS( angle );
place->SetRotation( angle/10.0 ); place->SetRotation( angle / 10.0 );
place->side = T_back; place->side = T_back;
} }
...@@ -1381,8 +1703,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1381,8 +1703,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are // copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
// removing, do not increment the iterator // removing, do not increment the iterator
for( PADSTACKSET::iterator i=padstackset.begin(); i!=padstackset.end(); for( PADSTACKSET::iterator i = padstackset.begin(); i!=padstackset.end();
i=padstackset.begin() ) i = padstackset.begin() )
{ {
PADSTACKSET::auto_type ps = padstackset.release( i ); PADSTACKSET::auto_type ps = padstackset.release( i );
PADSTACK* padstack = ps.release(); PADSTACK* padstack = ps.release();
...@@ -1391,9 +1713,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1391,9 +1713,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
} }
// copy our SPECCTRA_DB::nets to the pcb->network // copy our SPECCTRA_DB::nets to the pcb->network
for( unsigned n=1; n<nets.size(); ++n ) for( unsigned n = 1; n<nets.size(); ++n )
{ {
NET* net = nets[n]; NET* net = nets[n];
if( net->pins.size() ) if( net->pins.size() )
{ {
// give ownership to pcb->network // give ownership to pcb->network
...@@ -1411,7 +1734,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1411,7 +1734,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// Add the via from the Default netclass first. The via container // Add the via from the Default netclass first. The via container
// in pcb->library preserves the sequence of addition. // in pcb->library preserves the sequence of addition.
NETCLASS* netclass = nclasses.GetDefault(); NETCLASS* netclass = nclasses.GetDefault();
PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(), PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); FIRST_LAYER, aBoard->GetCopperLayerCount()-1 );
...@@ -1424,16 +1747,17 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1424,16 +1747,17 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// output the stock vias, but preserve uniqueness in the via container by // output the stock vias, but preserve uniqueness in the via container by
// using LookupVia(). // using LookupVia().
for( unsigned i=0; i < aBoard->m_ViasDimensionsList.size(); ++i ) for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
{ {
int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter; int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill; int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
via = makeVia( viaSize, viaDrill, via = makeVia( viaSize, viaDrill,
FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); FIRST_LAYER, aBoard->GetCopperLayerCount()-1 );
// maybe add 'via' to the library, but only if unique. // maybe add 'via' to the library, but only if unique.
PADSTACK* registered = pcb->library->LookupVia( via ); PADSTACK* registered = pcb->library->LookupVia( via );
if( registered != via ) if( registered != via )
delete via; delete via;
} }
...@@ -1442,7 +1766,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1442,7 +1766,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// pcb->library->spareViaIndex = pcb->library->vias.size(); // pcb->library->spareViaIndex = pcb->library->vias.size();
// output the non-Default netclass vias // output the non-Default netclass vias
for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc ) for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
{ {
netclass = nc->second; netclass = nc->second;
...@@ -1451,13 +1775,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1451,13 +1775,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// maybe add 'via' to the library, but only if unique. // maybe add 'via' to the library, but only if unique.
PADSTACK* registered = pcb->library->LookupVia( via ); PADSTACK* registered = pcb->library->LookupVia( via );
if( registered != via ) if( registered != via )
delete via; delete via;
} }
} }
#if 1 // do existing wires and vias #if 1 // do existing wires and vias
//-----<create the wires from tracks>----------------------------------- //-----<create the wires from tracks>-----------------------------------
{ {
...@@ -1502,15 +1827,17 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1502,15 +1827,17 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
} }
WIRE* wire = new WIRE( wiring ); WIRE* wire = new WIRE( wiring );
wiring->wires.push_back( wire ); wiring->wires.push_back( wire );
wire->net_id = netname; wire->net_id = netname;
wire->wire_type = T_protect; // @todo, this should be configurable wire->wire_type = T_protect; // @todo, this should be configurable
LAYER_NUM kiLayer = track->GetLayer(); LAYER_NUM kiLayer = track->GetLayer();
LAYER_NUM pcbLayer = kicadLayer2pcb[kiLayer]; LAYER_NUM pcbLayer = kicadLayer2pcb[kiLayer];
path = new PATH( wire ); path = new PATH( wire );
wire->SetShape( path ); wire->SetShape( path );
path->layer_id = layerIds[pcbLayer]; path->layer_id = layerIds[pcbLayer];
...@@ -1532,17 +1859,18 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1532,17 +1859,18 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
items.Collect( aBoard, scanVIAs ); items.Collect( aBoard, scanVIAs );
for( int i=0; i<items.GetCount(); ++i ) for( int i = 0; i<items.GetCount(); ++i )
{ {
SEGVIA* via = (SEGVIA*) items[i]; SEGVIA* via = (SEGVIA*) items[i];
wxASSERT( via->Type() == PCB_VIA_T ); wxASSERT( via->Type() == PCB_VIA_T );
int netcode = via->GetNet(); int netcode = via->GetNet();
if( netcode == 0 ) if( netcode == 0 )
continue; continue;
PADSTACK* padstack = makeVia( via ); PADSTACK* padstack = makeVia( via );
PADSTACK* registered = pcb->library->LookupVia( padstack ); PADSTACK* registered = pcb->library->LookupVia( padstack );
// if the one looked up is not our padstack, then delete our padstack // if the one looked up is not our padstack, then delete our padstack
// since it was a duplicate of one already registered. // since it was a duplicate of one already registered.
...@@ -1552,6 +1880,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1552,6 +1880,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
} }
WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring ); WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
pcb->wiring->wire_vias.push_back( dsnVia ); pcb->wiring->wire_vias.push_back( dsnVia );
dsnVia->padstack_id = registered->padstack_id; dsnVia->padstack_id = registered->padstack_id;
...@@ -1566,7 +1895,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1566,7 +1895,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
} }
} }
#endif // do existing wires and vias #endif // do existing wires and vias
//-----<via_descriptor>------------------------------------------------- //-----<via_descriptor>-------------------------------------------------
{ {
...@@ -1576,9 +1905,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1576,9 +1905,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
// Output the vias in the padstack list here, by name only. This must // Output the vias in the padstack list here, by name only. This must
// be done after exporting existing vias as WIRE_VIAs. // be done after exporting existing vias as WIRE_VIAs.
VIA* vias = pcb->structure->via; VIA* vias = pcb->structure->via;
for( unsigned viaNdx=0; viaNdx < pcb->library->vias.size(); ++viaNdx ) for( unsigned viaNdx = 0; viaNdx < pcb->library->vias.size(); ++viaNdx )
{ {
vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() ); vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() );
} }
...@@ -1590,9 +1919,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1590,9 +1919,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
exportNETCLASS( nclasses.GetDefault(), aBoard ); exportNETCLASS( nclasses.GetDefault(), aBoard );
for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc ) for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
{ {
NETCLASS* netclass = nc->second; NETCLASS* netclass = nc->second;
exportNETCLASS( netclass, aBoard ); exportNETCLASS( netclass, aBoard );
} }
} }
...@@ -1600,38 +1929,38 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) ...@@ -1600,38 +1929,38 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR )
void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard ) void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard )
{ {
/* From page 11 of specctra spec: /* From page 11 of specctra spec:
*
* Routing and Placement Rule Hierarchies
*
* Routing and placement rules can be defined at multiple levels of design
* specification. When a routing or placement rule is defined for an object at
* multiple levels, a predefined routing or placement precedence order
* automatically determines which rule to apply to the object. The routing rule
* precedence order is
*
* pcb < layer < class < class layer < group_set < group_set layer < net <
* net layer < group < group layer < fromto < fromto layer < class_class <
* class_class layer < padstack < region < class region < net region <
* class_class region
*
* A pcb rule (global rule for the PCB design) has the lowest precedence in the
* hierarchy. A class-to-class region rule has the highest precedence. Rules
* set at one level of the hierarchy override conflicting rules set at lower
* levels. The placement rule precedence order is
*
* pcb < image_set < image < component < super cluster < room <
* room_image_set < family_family < image_image
*
* A pcb rule (global rule for the PCB design) has the lowest precedence in the
* hierarchy. An image-to-image rule has the highest precedence. Rules set at
* one level of the hierarchy override conflicting rules set at lower levels.
*/
Routing and Placement Rule Hierarchies char text[256];
Routing and placement rules can be defined at multiple levels of design
specification. When a routing or placement rule is defined for an object at
multiple levels, a predefined routing or placement precedence order
automatically determines which rule to apply to the object. The routing rule
precedence order is
pcb < layer < class < class layer < group_set < group_set layer < net <
net layer < group < group layer < fromto < fromto layer < class_class <
class_class layer < padstack < region < class region < net region <
class_class region
A pcb rule (global rule for the PCB design) has the lowest precedence in the
hierarchy. A class-to-class region rule has the highest precedence. Rules
set at one level of the hierarchy override conflicting rules set at lower
levels. The placement rule precedence order is
pcb < image_set < image < component < super cluster < room <
room_image_set < family_family < image_image
A pcb rule (global rule for the PCB design) has the lowest precedence in the
hierarchy. An image-to-image rule has the highest precedence. Rules set at
one level of the hierarchy override conflicting rules set at lower levels.
*/
char text[256];
CLASS* clazz = new CLASS( pcb->network ); CLASS* clazz = new CLASS( pcb->network );
pcb->network->classes.push_back( clazz ); pcb->network->classes.push_back( clazz );
// freerouter creates a class named 'default' anyway, and if we // freerouter creates a class named 'default' anyway, and if we
...@@ -1639,13 +1968,13 @@ void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard ) ...@@ -1639,13 +1968,13 @@ void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard )
// something else as the name of our default class. // something else as the name of our default class.
clazz->class_id = TO_UTF8( aNetClass->GetName() ); clazz->class_id = TO_UTF8( aNetClass->GetName() );
for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net ) for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net )
clazz->net_ids.push_back( TO_UTF8( *net ) ); clazz->net_ids.push_back( TO_UTF8( *net ) );
clazz->rules = new RULE( clazz, T_rule ); clazz->rules = new RULE( clazz, T_rule );
// output the track width. // output the track width.
int trackWidth = aNetClass->GetTrackWidth(); int trackWidth = aNetClass->GetTrackWidth();
sprintf( text, "(width %.6g)", scale( trackWidth ) ); sprintf( text, "(width %.6g)", scale( trackWidth ) );
clazz->rules->rules.push_back( text ); clazz->rules->rules.push_back( text );
...@@ -1679,7 +2008,6 @@ void SPECCTRA_DB::FlipMODULEs( BOARD* aBoard ) ...@@ -1679,7 +2008,6 @@ void SPECCTRA_DB::FlipMODULEs( BOARD* aBoard )
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{ {
module->SetFlag( 0 ); module->SetFlag( 0 );
if( module->GetLayer() == LAYER_N_BACK ) if( module->GetLayer() == LAYER_N_BACK )
{ {
module->Flip( module->GetPosition() ); module->Flip( module->GetPosition() );
...@@ -1696,8 +2024,8 @@ void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard ) ...@@ -1696,8 +2024,8 @@ void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard )
if( !modulesAreFlipped ) if( !modulesAreFlipped )
return; return;
// DSN Images (=KiCad MODULES and pads) must be presented from the // DSN Images (=KiCad MODULES and pads) must be presented from the
// top view. Restore those that were flipped. // top view. Restore those that were flipped.
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{ {
if( module->GetFlag() ) if( module->GetFlag() )
...@@ -1709,6 +2037,4 @@ void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard ) ...@@ -1709,6 +2037,4 @@ void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard )
modulesAreFlipped = false; modulesAreFlipped = false;
} }
} // namespace DSN } // namespace DSN
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment