2008-02-06 22:32:15 +00:00
|
|
|
/*
|
2011-09-30 18:15:37 +00:00
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
2008-02-06 22:32:15 +00:00
|
|
|
*
|
2013-05-01 15:48:00 +00:00
|
|
|
* Copyright (C) 2007-2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
2011-09-30 18:15:37 +00:00
|
|
|
* Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors.
|
2008-02-07 20:23:58 +00:00
|
|
|
*
|
2008-02-06 22:32:15 +00:00
|
|
|
* 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.
|
2008-02-07 20:23:58 +00:00
|
|
|
*
|
2008-02-06 22:32:15 +00:00
|
|
|
* 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.
|
2008-02-07 20:23:58 +00:00
|
|
|
*
|
2008-02-06 22:32:15 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
2008-02-07 20:23:58 +00:00
|
|
|
* 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.,
|
2008-02-06 22:32:15 +00:00
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-06 22:32:15 +00:00
|
|
|
/* This source is a complement to specctra.cpp and implements the import of
|
2008-02-07 20:23:58 +00:00
|
|
|
a specctra session file (*.ses), and import of a specctra design file
|
|
|
|
(*.dsn) file. The specification for the grammar of the specctra dsn file
|
2008-02-06 22:32:15 +00:00
|
|
|
used to develop this code is given here:
|
2008-09-17 13:32:43 +00:00
|
|
|
http://tech.groups.yahoo.com/group/kicad-users/files/ then file "specctra.pdf"
|
2008-02-06 22:32:15 +00:00
|
|
|
Also see the comments at the top of the specctra.cpp file itself.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <class_drawpanel.h> // m_canvas
|
|
|
|
#include <confirm.h> // DisplayError()
|
|
|
|
#include <gestfich.h> // EDA_FileSelector()
|
|
|
|
#include <wxPcbStruct.h>
|
2013-05-02 18:06:58 +00:00
|
|
|
#include <macros.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
|
|
|
|
#include <class_board.h>
|
|
|
|
#include <class_module.h>
|
|
|
|
#include <class_edge_mod.h>
|
|
|
|
#include <class_track.h>
|
|
|
|
#include <class_zone.h>
|
|
|
|
#include <class_drawsegment.h>
|
|
|
|
|
|
|
|
#include <specctra.h>
|
2008-02-06 22:32:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
using namespace DSN;
|
|
|
|
|
2011-03-01 19:26:17 +00:00
|
|
|
void PCB_EDIT_FRAME::ImportSpecctraDesign( wxCommandEvent& event )
|
2008-02-06 22:32:15 +00:00
|
|
|
{
|
2008-02-07 20:23:58 +00:00
|
|
|
/* @todo write this someday
|
|
|
|
|
2008-02-07 06:49:16 +00:00
|
|
|
if( !Clear_Pcb( true ) )
|
|
|
|
return;
|
2008-02-07 20:23:58 +00:00
|
|
|
*/
|
2008-02-06 22:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-01 19:26:17 +00:00
|
|
|
void PCB_EDIT_FRAME::ImportSpecctraSession( wxCommandEvent& event )
|
2008-02-06 22:32:15 +00:00
|
|
|
{
|
2008-02-07 20:23:58 +00:00
|
|
|
/*
|
2008-02-07 06:49:16 +00:00
|
|
|
if( GetScreen()->IsModify() )
|
|
|
|
{
|
|
|
|
if( !IsOK( this, _( "Board Modified: Continue ?" ) ) )
|
|
|
|
return;
|
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
*/
|
2008-02-07 06:49:16 +00:00
|
|
|
|
2012-08-29 16:59:50 +00:00
|
|
|
wxString fullFileName = GetBoard()->GetFileName();
|
2008-02-20 07:19:40 +00:00
|
|
|
wxString path;
|
|
|
|
wxString name;
|
|
|
|
wxString ext;
|
|
|
|
|
2008-02-07 06:49:16 +00:00
|
|
|
wxString sessionExt( wxT( ".ses" ) );
|
|
|
|
wxString mask = wxT( "*" ) + sessionExt;
|
|
|
|
|
2008-02-20 07:19:40 +00:00
|
|
|
wxFileName::SplitPath( fullFileName, &path, &name, &ext );
|
|
|
|
name += sessionExt;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-20 07:19:40 +00:00
|
|
|
fullFileName = EDA_FileSelector( _( "Merge Specctra Session file:" ),
|
2008-02-20 19:13:20 +00:00
|
|
|
path,
|
|
|
|
name,
|
|
|
|
sessionExt,
|
|
|
|
mask,
|
|
|
|
this,
|
|
|
|
wxFD_OPEN,
|
2011-09-07 19:41:04 +00:00
|
|
|
false
|
2008-02-20 19:13:20 +00:00
|
|
|
);
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-20 07:19:40 +00:00
|
|
|
if( fullFileName == wxEmptyString )
|
2008-02-07 06:49:16 +00:00
|
|
|
return;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-07 06:49:16 +00:00
|
|
|
SPECCTRA_DB db;
|
2012-01-16 21:43:07 +00:00
|
|
|
LOCALE_IO toggle;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2008-02-20 07:19:40 +00:00
|
|
|
db.LoadSESSION( fullFileName );
|
2009-01-05 05:21:35 +00:00
|
|
|
db.FromSESSION( GetBoard() );
|
2008-02-07 06:49:16 +00:00
|
|
|
}
|
2014-04-09 13:33:04 +00:00
|
|
|
catch( const IO_ERROR& ioe )
|
2008-02-07 06:49:16 +00:00
|
|
|
{
|
2014-04-09 13:33:04 +00:00
|
|
|
wxString msg = ioe.errorText;
|
|
|
|
msg += '\n';
|
|
|
|
msg += _("BOARD may be corrupted, do not save it.");
|
|
|
|
msg += '\n';
|
|
|
|
msg += _("Fix problem and try again.");
|
2008-02-09 08:34:45 +00:00
|
|
|
|
2014-04-09 13:33:04 +00:00
|
|
|
DisplayError( this, msg );
|
2008-02-07 06:49:16 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-02-07 17:10:12 +00:00
|
|
|
|
2010-02-19 13:23:58 +00:00
|
|
|
OnModify();
|
2009-01-05 05:21:35 +00:00
|
|
|
GetBoard()->m_Status_Pcb = 0;
|
2009-04-17 06:37:23 +00:00
|
|
|
|
2009-02-26 09:33:14 +00:00
|
|
|
/* At this point we should call Compile_Ratsnest()
|
|
|
|
* but this could be time consumming.
|
2013-05-01 15:48:00 +00:00
|
|
|
* So if incorrect number of Connected and No connected pads is accepted
|
2009-02-26 09:33:14 +00:00
|
|
|
* until Compile_Ratsnest() is called (when track tool selected for instance)
|
|
|
|
* leave the next line commented
|
|
|
|
* Otherwise uncomment this line
|
|
|
|
*/
|
|
|
|
//Compile_Ratsnest( NULL, true );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2011-02-11 20:48:13 +00:00
|
|
|
SetStatusText( wxString( _( "Session file imported and merged OK." ) ) );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2011-12-22 13:28:11 +00:00
|
|
|
m_canvas->Refresh( true );
|
2008-02-07 06:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace DSN {
|
2008-02-07 17:10:12 +00:00
|
|
|
|
2008-06-30 13:47:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function scale
|
2011-09-30 18:15:37 +00:00
|
|
|
* converts a session file distance to KiCad units of deci-mils.
|
2008-06-30 13:47:55 +00:00
|
|
|
* @param distance The session file length to convert.
|
|
|
|
* @param aResolution The session UNIT_RES which holds the engineering unit
|
|
|
|
* specifier
|
2011-09-30 18:15:37 +00:00
|
|
|
* @return int - The KiCad length in deci-mils
|
2008-06-30 13:47:55 +00:00
|
|
|
*/
|
2008-02-08 00:16:59 +00:00
|
|
|
static int scale( double distance, UNIT_RES* aResolution )
|
2008-02-07 17:10:12 +00:00
|
|
|
{
|
2008-02-07 20:23:58 +00:00
|
|
|
double resValue = aResolution->GetValue();
|
2012-04-11 14:49:11 +00:00
|
|
|
double factor;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-04-10 16:28:26 +00:00
|
|
|
switch( aResolution->GetEngUnits() )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case T_inch:
|
|
|
|
factor = 25.4e6; // nanometers per inch
|
|
|
|
break;
|
|
|
|
case T_mil:
|
|
|
|
factor = 25.4e3; // nanometers per mil
|
|
|
|
break;
|
|
|
|
case T_cm:
|
|
|
|
factor = 1e7; // nanometers per cm
|
|
|
|
break;
|
|
|
|
case T_mm:
|
|
|
|
factor = 1e6; // nanometers per mm
|
|
|
|
break;
|
|
|
|
case T_um:
|
|
|
|
factor = 1e3; // nanometers per um
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
int ret = KiROUND( factor * distance / resValue );
|
2012-04-10 16:28:26 +00:00
|
|
|
|
2008-02-09 16:33:03 +00:00
|
|
|
return ret;
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 01:02:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function mapPt
|
|
|
|
* translates a point from the Specctra Session format coordinate system
|
2011-09-30 18:15:37 +00:00
|
|
|
* to the KiCad coordinate system.
|
2008-02-12 01:02:53 +00:00
|
|
|
* @param aPoint The session point to translate
|
2010-12-14 15:56:30 +00:00
|
|
|
* @param aResolution - The amount to scale the point.
|
2011-09-30 18:15:37 +00:00
|
|
|
* @return wxPoint - The KiCad coordinate system point.
|
2008-02-12 01:02:53 +00:00
|
|
|
*/
|
2008-02-08 00:16:59 +00:00
|
|
|
static wxPoint mapPt( const POINT& aPoint, UNIT_RES* aResolution )
|
|
|
|
{
|
|
|
|
wxPoint ret( scale( aPoint.x, aResolution ),
|
2008-02-29 06:49:34 +00:00
|
|
|
-scale( aPoint.y, aResolution ) ); // negate y
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-07 17:10:12 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2008-02-07 06:49:16 +00:00
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2010-11-09 15:45:11 +00:00
|
|
|
TRACK* SPECCTRA_DB::makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR )
|
2008-02-08 00:16:59 +00:00
|
|
|
{
|
2013-05-05 10:11:30 +00:00
|
|
|
int layerNdx = findLayerName( aPath->layer_id );
|
2008-02-08 00:16:59 +00:00
|
|
|
|
|
|
|
if( layerNdx == -1 )
|
|
|
|
{
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString layerName = FROM_UTF8( aPath->layer_id.c_str() );
|
2008-02-08 00:16:59 +00:00
|
|
|
ThrowIOError( _("Session file uses invalid layer id \"%s\""),
|
2014-01-18 09:07:05 +00:00
|
|
|
GetChars( layerName ) );
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TRACK* track = new TRACK( sessionBoard );
|
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
track->SetStart( mapPt( aPath->points[aPointIndex+0], routeResolution ) );
|
|
|
|
track->SetEnd( mapPt( aPath->points[aPointIndex+1], routeResolution ) );
|
2008-02-08 00:16:59 +00:00
|
|
|
track->SetLayer( pcbLayer2kicad[layerNdx] );
|
2013-01-13 00:04:00 +00:00
|
|
|
track->SetWidth( scale( aPath->aperture_width, routeResolution ) );
|
2014-02-25 10:40:34 +00:00
|
|
|
track->SetNetCode( aNetcode );
|
2008-02-08 00:16:59 +00:00
|
|
|
|
|
|
|
return track;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
::VIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNetCode ) throw( IO_ERROR )
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
2014-04-25 06:00:04 +00:00
|
|
|
::VIA* via = 0;
|
2008-02-09 08:34:45 +00:00
|
|
|
SHAPE* shape;
|
|
|
|
|
|
|
|
int shapeCount = aPadstack->Length();
|
|
|
|
int drillDiam = -1;
|
2008-02-12 01:02:53 +00:00
|
|
|
int copperLayerCount = sessionBoard->GetCopperLayerCount();
|
2008-02-09 08:34:45 +00:00
|
|
|
|
|
|
|
|
2011-09-30 18:15:37 +00:00
|
|
|
// The drill diameter is encoded in the padstack name if Pcbnew did the DSN export.
|
2008-02-09 08:34:45 +00:00
|
|
|
// It is in mils and is after the colon and before the last '_'
|
|
|
|
int drillStartNdx = aPadstack->padstack_id.find( ':' );
|
|
|
|
|
|
|
|
if( drillStartNdx != -1 )
|
|
|
|
{
|
2008-02-12 01:02:53 +00:00
|
|
|
++drillStartNdx; // skip over the ':'
|
2008-02-09 08:34:45 +00:00
|
|
|
int drillEndNdx = aPadstack->padstack_id.rfind( '_' );
|
|
|
|
if( drillEndNdx != -1 )
|
|
|
|
{
|
2008-02-12 01:02:53 +00:00
|
|
|
std::string diamTxt( aPadstack->padstack_id, drillStartNdx, drillEndNdx-drillStartNdx );
|
2008-02-09 16:33:03 +00:00
|
|
|
const char* sdiamTxt = diamTxt.c_str();
|
|
|
|
double drillMils = strtod( sdiamTxt, 0 );
|
|
|
|
|
|
|
|
// drillMils is not in the session units, but actual mils so we don't use scale()
|
2008-02-12 01:02:53 +00:00
|
|
|
drillDiam = (int) (drillMils * 10);
|
2009-10-21 19:16:25 +00:00
|
|
|
/** @todo: see if we use default netclass or specific value
|
|
|
|
*/
|
|
|
|
drillDiam = -1; // import as default: real drill is the netclass value
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( shapeCount == 0 )
|
|
|
|
{
|
2014-01-18 09:07:05 +00:00
|
|
|
ThrowIOError( _( "Session via padstack has no shapes" ) );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
else if( shapeCount == 1 )
|
|
|
|
{
|
|
|
|
shape = (SHAPE*) (*aPadstack)[0];
|
2008-02-12 01:02:53 +00:00
|
|
|
DSN_T type = shape->shape->Type();
|
|
|
|
if( type != T_circle )
|
2009-12-11 04:55:24 +00:00
|
|
|
ThrowIOError( _( "Unsupported via shape: %s"),
|
|
|
|
GetChars( GetTokenString( type ) ) );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
|
|
|
CIRCLE* circle = (CIRCLE*) shape->shape;
|
|
|
|
int viaDiam = scale( circle->diameter, routeResolution );
|
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
via = new ::VIA( sessionBoard );
|
2008-02-12 01:02:53 +00:00
|
|
|
via->SetPosition( mapPt( aPoint, routeResolution ) );
|
2011-12-14 04:29:25 +00:00
|
|
|
via->SetDrill( drillDiam );
|
2014-04-25 06:00:04 +00:00
|
|
|
via->SetViaType( VIA_THROUGH );
|
2013-01-13 00:04:00 +00:00
|
|
|
via->SetWidth( viaDiam );
|
2009-12-07 03:46:13 +00:00
|
|
|
via->SetLayerPair( LAYER_N_FRONT, LAYER_N_BACK );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
2008-02-12 01:02:53 +00:00
|
|
|
else if( shapeCount == copperLayerCount )
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
|
|
|
shape = (SHAPE*) (*aPadstack)[0];
|
2008-02-12 01:02:53 +00:00
|
|
|
DSN_T type = shape->shape->Type();
|
|
|
|
if( type != T_circle )
|
2009-12-11 04:55:24 +00:00
|
|
|
ThrowIOError( _( "Unsupported via shape: %s"),
|
|
|
|
GetChars( GetTokenString( type ) ) );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
|
|
|
CIRCLE* circle = (CIRCLE*) shape->shape;
|
|
|
|
int viaDiam = scale( circle->diameter, routeResolution );
|
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
via = new ::VIA( sessionBoard );
|
2008-02-12 01:02:53 +00:00
|
|
|
via->SetPosition( mapPt( aPoint, routeResolution ) );
|
2011-12-14 04:29:25 +00:00
|
|
|
via->SetDrill( drillDiam );
|
2014-04-25 06:00:04 +00:00
|
|
|
via->SetViaType( VIA_THROUGH );
|
2013-01-13 00:04:00 +00:00
|
|
|
via->SetWidth( viaDiam );
|
2009-12-07 03:46:13 +00:00
|
|
|
via->SetLayerPair( LAYER_N_FRONT, LAYER_N_BACK );
|
2008-02-12 01:02:53 +00:00
|
|
|
}
|
|
|
|
else // VIA_MICROVIA or VIA_BLIND_BURIED
|
|
|
|
{
|
2013-04-29 16:35:07 +00:00
|
|
|
int topLayerNdx = -1; // session layer detectors
|
|
|
|
int botLayerNdx = INT_MAX;
|
|
|
|
|
2008-02-12 01:02:53 +00:00
|
|
|
int viaDiam = -1;
|
|
|
|
|
|
|
|
for( int i=0; i<shapeCount; ++i )
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
2008-02-12 01:02:53 +00:00
|
|
|
shape = (SHAPE*) (*aPadstack)[i];
|
|
|
|
DSN_T type = shape->shape->Type();
|
|
|
|
if( type != T_circle )
|
2009-12-11 04:55:24 +00:00
|
|
|
ThrowIOError( _( "Unsupported via shape: %s"),
|
|
|
|
GetChars( GetTokenString( type ) ) );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2008-02-09 08:34:45 +00:00
|
|
|
CIRCLE* circle = (CIRCLE*) shape->shape;
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2013-04-29 16:35:07 +00:00
|
|
|
int layerNdx = findLayerName( circle->layer_id );
|
|
|
|
if( layerNdx == -1 )
|
2008-02-12 01:02:53 +00:00
|
|
|
{
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString layerName = FROM_UTF8( circle->layer_id.c_str() );
|
2008-02-12 01:02:53 +00:00
|
|
|
ThrowIOError( _("Session file uses invalid layer id \"%s\""),
|
2009-04-17 06:37:23 +00:00
|
|
|
GetChars( layerName ) );
|
2008-02-12 01:02:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( layerNdx > topLayerNdx )
|
|
|
|
topLayerNdx = layerNdx;
|
|
|
|
|
|
|
|
if( layerNdx < botLayerNdx )
|
|
|
|
botLayerNdx = layerNdx;
|
|
|
|
|
|
|
|
if( viaDiam == -1 )
|
|
|
|
viaDiam = scale( circle->diameter, routeResolution );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
via = new ::VIA( sessionBoard );
|
2008-02-12 01:02:53 +00:00
|
|
|
via->SetPosition( mapPt( aPoint, routeResolution ) );
|
2011-12-14 04:29:25 +00:00
|
|
|
via->SetDrill( drillDiam );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
|
|
|
if( (topLayerNdx==0 && botLayerNdx==1)
|
|
|
|
|| (topLayerNdx==copperLayerCount-2 && botLayerNdx==copperLayerCount-1))
|
2014-04-25 06:00:04 +00:00
|
|
|
via->SetViaType( VIA_MICROVIA );
|
2008-02-12 01:02:53 +00:00
|
|
|
else
|
2014-04-25 06:00:04 +00:00
|
|
|
via->SetViaType( VIA_BLIND_BURIED );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
via->SetWidth( viaDiam );
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2013-04-29 16:35:07 +00:00
|
|
|
LAYER_NUM topLayer = pcbLayer2kicad[topLayerNdx];
|
|
|
|
LAYER_NUM botLayer = pcbLayer2kicad[botLayerNdx];
|
2008-02-12 01:02:53 +00:00
|
|
|
|
2013-04-29 16:35:07 +00:00
|
|
|
via->SetLayerPair( topLayer, botLayer );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( via )
|
2014-02-25 10:40:34 +00:00
|
|
|
via->SetNetCode( aNetCode );
|
2008-02-09 08:34:45 +00:00
|
|
|
|
|
|
|
return via;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
// no UI code in this function, throw exception to report problems to the
|
2011-03-01 19:26:17 +00:00
|
|
|
// UI handler: void PCB_EDIT_FRAME::ImportSpecctraSession( wxCommandEvent& event )
|
2008-02-07 06:49:16 +00:00
|
|
|
|
2010-11-09 15:45:11 +00:00
|
|
|
void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IO_ERROR )
|
2008-02-07 06:49:16 +00:00
|
|
|
{
|
2008-02-08 00:16:59 +00:00
|
|
|
sessionBoard = aBoard; // not owned here
|
2008-02-07 06:49:16 +00:00
|
|
|
|
2008-02-07 17:10:12 +00:00
|
|
|
if( !session )
|
|
|
|
ThrowIOError( _("Session file is missing the \"session\" section") );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
/* Dick 16-Jan-2012: session need not have a placement section.
|
2008-02-07 06:49:16 +00:00
|
|
|
if( !session->placement )
|
|
|
|
ThrowIOError( _("Session file is missing the \"placement\" section") );
|
2012-01-16 21:43:07 +00:00
|
|
|
*/
|
2008-02-07 06:49:16 +00:00
|
|
|
|
|
|
|
if( !session->route )
|
|
|
|
ThrowIOError( _("Session file is missing the \"routes\" section") );
|
|
|
|
|
|
|
|
if( !session->route->library )
|
|
|
|
ThrowIOError( _("Session file is missing the \"library_out\" section") );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-07 17:10:12 +00:00
|
|
|
// delete all the old tracks and vias
|
2008-12-04 04:28:11 +00:00
|
|
|
aBoard->m_Track.DeleteAll();
|
2008-02-07 17:10:12 +00:00
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
aBoard->DeleteMARKERs();
|
2008-02-07 17:10:12 +00:00
|
|
|
|
2008-02-08 00:16:59 +00:00
|
|
|
buildLayerMaps( aBoard );
|
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
if( session->placement )
|
2008-02-07 06:49:16 +00:00
|
|
|
{
|
2012-01-16 21:43:07 +00:00
|
|
|
// Walk the PLACEMENT object's COMPONENTs list, and for each PLACE within
|
|
|
|
// each COMPONENT, reposition and re-orient each component and put on
|
|
|
|
// correct side of the board.
|
|
|
|
COMPONENTS& components = session->placement->components;
|
|
|
|
for( COMPONENTS::iterator comp=components.begin(); comp!=components.end(); ++comp )
|
2008-02-07 17:10:12 +00:00
|
|
|
{
|
2012-01-16 21:43:07 +00:00
|
|
|
PLACES& places = comp->places;
|
|
|
|
for( unsigned i=0; i<places.size(); ++i )
|
2008-02-07 17:10:12 +00:00
|
|
|
{
|
2012-01-16 21:43:07 +00:00
|
|
|
PLACE* place = &places[i]; // '&' even though places[] holds a pointer!
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
wxString reference = FROM_UTF8( place->component_id.c_str() );
|
|
|
|
MODULE* module = aBoard->FindModuleByReference( reference );
|
|
|
|
if( !module )
|
|
|
|
{
|
|
|
|
ThrowIOError(
|
|
|
|
_("Session file has 'reference' to non-existent component \"%s\""),
|
|
|
|
GetChars( reference ) );
|
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
if( !place->hasVertex )
|
|
|
|
continue;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
UNIT_RES* resolution = place->GetUnits();
|
|
|
|
wxASSERT( resolution );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
wxPoint newPos = mapPt( place->vertex, resolution );
|
|
|
|
module->SetPosition( newPos );
|
|
|
|
|
|
|
|
if( place->side == T_front )
|
2008-02-07 20:23:58 +00:00
|
|
|
{
|
2012-01-16 21:43:07 +00:00
|
|
|
// convert from degrees to tenths of degrees used in KiCad.
|
2013-05-04 11:57:09 +00:00
|
|
|
int orientation = KiROUND( place->rotation * 10.0 );
|
2013-03-13 18:53:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
if( module->GetLayer() != LAYER_N_FRONT )
|
|
|
|
{
|
|
|
|
// module is on copper layer (back)
|
2013-03-13 18:53:58 +00:00
|
|
|
module->Flip( module->GetPosition() );
|
2012-01-16 21:43:07 +00:00
|
|
|
}
|
2013-03-13 18:53:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
module->SetOrientation( orientation );
|
2008-02-07 20:23:58 +00:00
|
|
|
}
|
2012-01-16 21:43:07 +00:00
|
|
|
else if( place->side == T_back )
|
2008-02-07 20:23:58 +00:00
|
|
|
{
|
2013-05-04 11:57:09 +00:00
|
|
|
int orientation = KiROUND( (place->rotation + 180.0) * 10.0 );
|
2013-03-13 18:53:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
if( module->GetLayer() != LAYER_N_BACK )
|
|
|
|
{
|
|
|
|
// module is on component layer (front)
|
2013-03-13 18:53:58 +00:00
|
|
|
module->Flip( module->GetPosition() );
|
2012-01-16 21:43:07 +00:00
|
|
|
}
|
2013-03-13 18:53:58 +00:00
|
|
|
|
2012-01-16 21:43:07 +00:00
|
|
|
module->SetOrientation( orientation );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// as I write this, the PARSER *is* catching this, so we should never see below:
|
|
|
|
wxFAIL_MSG( wxT("DSN::PARSER did not catch an illegal side := 'back|front'") );
|
2009-08-07 04:44:42 +00:00
|
|
|
}
|
2008-02-07 17:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-07 06:49:16 +00:00
|
|
|
}
|
|
|
|
|
2008-02-08 00:16:59 +00:00
|
|
|
routeResolution = session->route->GetUnits();
|
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
// Walk the NET_OUTs and create tracks and vias anew.
|
2008-02-07 06:49:16 +00:00
|
|
|
NET_OUTS& net_outs = session->route->net_outs;
|
2008-02-08 00:16:59 +00:00
|
|
|
for( NET_OUTS::iterator net=net_outs.begin(); net!=net_outs.end(); ++net )
|
2008-02-07 06:49:16 +00:00
|
|
|
{
|
2008-02-09 08:34:45 +00:00
|
|
|
int netCode = 0;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-09 08:34:45 +00:00
|
|
|
// page 143 of spec says wire's net_id is optional
|
|
|
|
if( net->net_id.size() )
|
2008-02-08 00:16:59 +00:00
|
|
|
{
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString netName = FROM_UTF8( net->net_id.c_str() );
|
2008-02-09 08:34:45 +00:00
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
NETINFO_ITEM* net = aBoard->FindNet( netName );
|
|
|
|
if( net )
|
|
|
|
netCode = net->GetNet();
|
2008-02-29 06:49:34 +00:00
|
|
|
else // else netCode remains 0
|
|
|
|
{
|
|
|
|
// int breakhere = 1;
|
|
|
|
}
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WIRES& wires = net->wires;
|
|
|
|
for( unsigned i=0; i<wires.size(); ++i )
|
|
|
|
{
|
|
|
|
WIRE* wire = &wires[i];
|
|
|
|
DSN_T shape = wire->shape->Type();
|
|
|
|
|
|
|
|
if( shape != T_path )
|
|
|
|
{
|
2008-02-29 06:49:34 +00:00
|
|
|
/* shape == T_polygon is expected from freerouter if you have
|
|
|
|
a zone on a non "power" type layer, i.e. a T_signal layer
|
|
|
|
and the design does a round trip back in as session here.
|
|
|
|
We kept our own zones in the BOARD, so ignore this so called
|
|
|
|
'wire'.
|
|
|
|
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString netId = FROM_UTF8( wire->net_id.c_str() );
|
2008-02-08 00:16:59 +00:00
|
|
|
ThrowIOError(
|
|
|
|
_("Unsupported wire shape: \"%s\" for net: \"%s\""),
|
2009-12-11 04:55:24 +00:00
|
|
|
DLEX::GetTokenString(shape).GetData(),
|
2008-02-08 00:16:59 +00:00
|
|
|
netId.GetData()
|
|
|
|
);
|
2008-02-29 06:49:34 +00:00
|
|
|
*/
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
2008-02-29 06:49:34 +00:00
|
|
|
else
|
2008-02-08 00:16:59 +00:00
|
|
|
{
|
2008-02-29 06:49:34 +00:00
|
|
|
PATH* path = (PATH*) wire->shape;
|
|
|
|
for( unsigned pt=0; pt<path->points.size()-1; ++pt )
|
|
|
|
{
|
|
|
|
/* a debugging aid, may come in handy
|
|
|
|
if( path->points[pt].x == 547800
|
|
|
|
&& path->points[pt].y == -380250 )
|
|
|
|
{
|
|
|
|
int breakhere = 1;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
TRACK* track = makeTRACK( path, pt, netCode );
|
|
|
|
aBoard->Add( track );
|
|
|
|
}
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WIRE_VIAS& wire_vias = net->wire_vias;
|
2008-02-09 08:34:45 +00:00
|
|
|
LIBRARY& library = *session->route->library;
|
2008-02-08 00:16:59 +00:00
|
|
|
for( unsigned i=0; i<wire_vias.size(); ++i )
|
|
|
|
{
|
2008-02-09 08:34:45 +00:00
|
|
|
int netCode = 0;
|
|
|
|
|
|
|
|
// page 144 of spec says wire_via's net_id is optional
|
|
|
|
if( net->net_id.size() )
|
|
|
|
{
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString netName = FROM_UTF8( net->net_id.c_str() );
|
2008-02-09 08:34:45 +00:00
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
NETINFO_ITEM* net = aBoard->FindNet( netName );
|
|
|
|
if( net )
|
|
|
|
netCode = net->GetNet();
|
2008-02-08 00:16:59 +00:00
|
|
|
|
2008-02-09 08:34:45 +00:00
|
|
|
// else netCode remains 0
|
|
|
|
}
|
|
|
|
|
|
|
|
WIRE_VIA* wire_via = &wire_vias[i];
|
|
|
|
|
|
|
|
// example: (via Via_15:8_mil 149000 -71000 )
|
|
|
|
|
|
|
|
PADSTACK* padstack = library.FindPADSTACK( wire_via->GetPadstackId() );
|
|
|
|
if( !padstack )
|
|
|
|
{
|
2008-02-29 23:01:30 +00:00
|
|
|
// Dick Feb 29, 2008:
|
|
|
|
// Freerouter has a bug where it will not round trip all vias.
|
|
|
|
// Vias which have a (use_via) element will be round tripped.
|
|
|
|
// Vias which do not, don't come back in in the session library,
|
|
|
|
// even though they may be actually used in the pre-routed,
|
|
|
|
// protected wire_vias. So until that is fixed, create the
|
|
|
|
// padstack from its name as a work around.
|
|
|
|
|
|
|
|
|
2010-08-09 02:03:16 +00:00
|
|
|
// Could use a STRING_FORMATTER here and convert the entire
|
2008-02-09 08:34:45 +00:00
|
|
|
// wire_via to text and put that text into the exception.
|
2011-02-02 15:31:48 +00:00
|
|
|
wxString psid( FROM_UTF8( wire_via->GetPadstackId().c_str() ) );
|
2008-02-09 08:34:45 +00:00
|
|
|
|
|
|
|
ThrowIOError( _("A wire_via references a missing padstack \"%s\""),
|
2009-04-17 06:37:23 +00:00
|
|
|
GetChars( psid ) );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for( unsigned v=0; v<wire_via->vertexes.size(); ++v )
|
|
|
|
{
|
2014-04-25 06:00:04 +00:00
|
|
|
::VIA* via = makeVIA( padstack, wire_via->vertexes[v], netCode );
|
2008-02-12 01:02:53 +00:00
|
|
|
aBoard->Add( via );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
2008-02-08 00:16:59 +00:00
|
|
|
}
|
2008-02-07 06:49:16 +00:00
|
|
|
}
|
2008-02-06 22:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-07 06:49:16 +00:00
|
|
|
} // namespace DSN
|
|
|
|
|