kicad/pcbnew/specctra_export.cpp

1247 lines
39 KiB
C++
Raw Normal View History

2008-01-21 21:24:39 +00:00
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors.
2008-02-07 20:23:58 +00:00
*
2008-01-21 21:24:39 +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-01-21 21:24:39 +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-01-21 21:24:39 +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-01-21 21:24:39 +00:00
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
2008-02-07 20:23:58 +00:00
2008-01-21 21:24:39 +00:00
/* This source is a complement to specctra.cpp and implements the export to
specctra dsn file format. The specification for the grammar of the specctra
dsn file used to develop this code is given here:
http://www.autotraxeda.com/docs/SPECCTRA/SPECCTRA.pdf
2008-02-07 20:23:58 +00:00
2008-01-21 21:24:39 +00:00
Also see the comments at the top of the specctra.cpp file itself.
*/
#include "specctra.h"
2008-01-22 20:48:02 +00:00
#include "collectors.h"
2008-01-24 21:47:54 +00:00
#include "wxPcbStruct.h" // Change_Side_Module()
2008-01-26 02:02:27 +00:00
#include "pcbstruct.h" // HISTORY_NUMBER
2008-02-01 01:09:39 +00:00
#include "autorout.h" // NET_CODES_OK
2008-02-09 08:34:45 +00:00
#include <set> // std::set
2008-02-01 01:09:39 +00:00
2008-01-21 21:24:39 +00:00
2008-01-21 22:16:45 +00:00
using namespace DSN;
2008-01-21 21:24:39 +00:00
// see wxPcbStruct.h
2008-02-06 22:32:15 +00:00
void WinEDA_PcbFrame::ExportToSpecctra( wxCommandEvent& event )
2008-01-21 21:24:39 +00:00
{
2008-01-22 20:48:02 +00:00
wxString fullFileName = GetScreen()->m_FileName;
wxString std_ext = wxT( ".dsn" );
wxString mask = wxT( "*" ) + std_ext;
2008-02-07 20:23:58 +00:00
2008-01-22 20:48:02 +00:00
ChangeFileNameExt( fullFileName, std_ext );
2008-02-07 20:23:58 +00:00
2008-01-22 20:48:02 +00:00
fullFileName = EDA_FileSelector( _( "Specctra DSN file:" ),
wxEmptyString, /* Chemin par defaut */
fullFileName, /* nom fichier par defaut */
std_ext, /* extension par defaut */
mask, /* Masque d'affichage */
this,
wxFD_SAVE,
FALSE
);
if( fullFileName == wxEmptyString )
return;
2008-01-21 22:16:45 +00:00
2008-01-22 20:48:02 +00:00
SPECCTRA_DB db;
2008-01-24 21:47:54 +00:00
bool ok = true;
wxString errorText;
2008-02-01 20:32:18 +00:00
BASE_SCREEN* screen = GetScreen();
bool wasModified = screen->IsModify() && !screen->IsSave();
2008-02-07 20:23:58 +00:00
2008-01-21 22:16:45 +00:00
db.SetPCB( SPECCTRA_DB::MakePCB() );
2008-01-24 21:47:54 +00:00
2008-02-07 20:23:58 +00:00
setlocale( LC_NUMERIC, "C" ); // Switch the locale to standard C
try
{
2008-01-21 22:16:45 +00:00
db.FromBOARD( m_Pcb );
2008-01-22 20:48:02 +00:00
db.ExportPCB( fullFileName, true );
2008-02-07 20:23:58 +00:00
// if an exception is thrown by FromBOARD or ExportPCB(), then
2008-01-23 01:52:49 +00:00
// ~SPECCTRA_DB() will close the file.
2008-02-07 20:23:58 +00:00
}
catch( IOError ioe )
2008-01-21 22:16:45 +00:00
{
2008-01-24 21:47:54 +00:00
ok = false;
2008-02-07 20:23:58 +00:00
// copy the error string to safe place, ioe is in this scope only.
2008-01-24 21:47:54 +00:00
errorText = ioe.errorText;
}
2008-02-07 20:23:58 +00:00
setlocale( LC_NUMERIC, "" ); // revert to the current locale
// The two calls below to BOARD::Change_Side_Module(), both set the
// modified flag, yet their actions cancel each other out, so it should
2008-02-01 20:32:18 +00:00
// be ok to clear the modify flag.
if( !wasModified )
screen->ClrModify();
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
if( ok )
{
2008-02-07 20:23:58 +00:00
Affiche_Message( wxString( _("BOARD exported OK.")) );
2008-01-24 21:47:54 +00:00
}
else
2008-02-09 08:34:45 +00:00
{
errorText += '\n';
errorText += _("Unable to export, please fix and try again.");
2008-01-24 21:47:54 +00:00
DisplayError( this, errorText );
2008-02-09 08:34:45 +00:00
}
2008-01-21 21:24:39 +00:00
}
namespace DSN {
2008-01-22 20:48:02 +00:00
struct POINT_PAIR
{
2008-02-01 20:32:18 +00:00
POINT start;
POINT end;
2008-01-22 20:48:02 +00:00
BOARD_ITEM* item; ///< the item which has these points, TRACK or DRAWSEGMENT
};
2008-02-07 20:23:58 +00:00
typedef std::vector<POINT_PAIR> POINT_PAIRS;
2008-01-21 22:16:45 +00:00
2008-01-22 20:48:02 +00:00
2008-02-03 15:23:00 +00:00
const KICAD_T SPECCTRA_DB::scanPADs[] = { TYPEPAD, EOT };
2008-01-22 20:48:02 +00:00
static inline void swap( POINT_PAIR& pair )
{
2008-02-01 20:32:18 +00:00
POINT temp = pair.start;
pair.start = pair.end;
pair.end = temp;
2008-01-22 20:48:02 +00:00
}
/**
* Function scale
* converts a distance from kicad units to our reported specctra dsn units:
* 1/10000 inches (deci-mils) to mils. So the factor of 10 comes in.
*/
2008-01-24 21:47:54 +00:00
static inline double scale( int kicadDist )
{
return kicadDist/10.0;
}
static inline double mapX( int x )
{
return scale(x);
}
static inline double mapY( int y )
{
return -scale(y); // make y negative, since it is increasing going down.
}
2008-01-23 01:52:49 +00:00
/**
* Function mapPt
* converts a Kicad point into a DSN file point. Kicad's BOARD coordinates
* are in deci-mils (i.e. 1/10,000th of an inch) and we are exporting in units
* of mils, so we have to divide by 10.
*/
2008-01-22 20:48:02 +00:00
static POINT mapPt( const wxPoint& pt )
2008-01-21 22:16:45 +00:00
{
2008-01-22 20:48:02 +00:00
POINT ret;
2008-01-24 21:47:54 +00:00
ret.x = mapX( pt.x );
ret.y = mapY( pt.y );
ret.FixNegativeZero();
2008-01-22 20:48:02 +00:00
return ret;
}
2008-01-21 22:16:45 +00:00
2008-01-22 20:48:02 +00:00
2008-02-01 20:32:18 +00:00
/**
* Function findPOINT
* searches the list of POINT_PAIRS for a matching end to the given POINT.
2008-02-07 06:49:16 +00:00
* @return int - 0 if no match, or positive one based index of a POINT_PAIR with a matching ".start",
* or a negated one based index of a POINT_PAIR with a matching ".end".
2008-02-01 20:32:18 +00:00
*/
static int findPOINT( const POINT& pt, const POINT_PAIR source[], int count )
{
for( int i=0; i<count; ++i )
{
if( pt == source[i].start )
{
2008-02-07 20:23:58 +00:00
return +( i + 1 );
2008-02-01 20:32:18 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
if( pt == source[i].end )
{
2008-02-07 20:23:58 +00:00
return -( i + 1 );
2008-02-01 20:32:18 +00:00
}
}
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
return 0;
}
2008-01-22 20:48:02 +00:00
/**
* Function swapEnds
* will swap ends of any POINT_PAIR in the POINT_PAIRS list in order to
* make the consecutive POINT_PAIRs be "connected" at their ends.
*/
static void swapEnds( POINT_PAIRS& aList )
{
2008-02-01 20:32:18 +00:00
if( !aList.size() )
2008-01-22 20:48:02 +00:00
return;
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
// do an extraction sort based on matching ends here.
POINT_PAIRS sorted;
POINT_PAIRS source( aList );
// try and start the search using a POINT which has at least one match elsewhere.
if( findPOINT( source.begin()->start, &source[1], source.size()-1 ) != 0 )
swap( *source.begin() ); // swap start and end of first PAIR
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
while( source.size() )
2008-01-22 20:48:02 +00:00
{
2008-02-01 20:32:18 +00:00
sorted.push_back( *source.begin() );
source.erase( source.begin() );
2008-01-22 20:48:02 +00:00
2008-02-07 20:23:58 +00:00
// keep looping through the source list looking for a match to the end of the last sorted.
2008-02-01 20:32:18 +00:00
int result;
while( (result = findPOINT( sorted.back().end, &source[0], source.size() ) ) != 0 )
2008-01-22 20:48:02 +00:00
{
2008-02-07 20:23:58 +00:00
int ndx = ABS(result)-1;
2008-02-01 20:32:18 +00:00
sorted.push_back( source[ ndx ] );
source.erase( source.begin()+ndx );
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
if( result < 0 )
swap( sorted.back() );
2008-01-22 20:48:02 +00:00
}
}
2008-02-07 20:23:58 +00:00
2008-02-03 21:46:12 +00:00
#if 0 && defined(DEBUG)
2008-02-01 20:32:18 +00:00
printf( "swapEnds():\n" );
for( unsigned i=0; i<sorted.size(); ++i )
{
2008-02-07 20:23:58 +00:00
printf( "(%.6g,%.6g) (%.6g,%.6g)\n",
sorted[i].start.x, sorted[i].start.y,
2008-02-01 20:32:18 +00:00
sorted[i].end.x, sorted[i].end.y );
}
#endif
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
aList = sorted;
2008-01-22 20:48:02 +00:00
}
/**
* Function isRectangle
2008-02-07 20:23:58 +00:00
* tests to see if the POINT_PAIRS list makes up a vertically/horizontally
2008-01-22 20:48:02 +00:00
* oriented rectangle.
* @return bool - true if there are 4 point pairs making a rectangle.
2008-02-07 20:23:58 +00:00
*/
2008-01-22 20:48:02 +00:00
static bool isRectangle( POINT_PAIRS& aList )
{
if( aList.size() == 4 )
{
for( unsigned i=0; i<aList.size(); ++i )
{
if( i < aList.size()-1 )
2008-02-01 20:32:18 +00:00
if( aList[i].end != aList[i+1].start )
2008-01-22 20:48:02 +00:00
return false;
2008-02-07 20:23:58 +00:00
if( aList[i].start.x != aList[i].end.x
2008-02-01 20:32:18 +00:00
&& aList[i].start.y != aList[i].end.y )
2008-01-22 20:48:02 +00:00
return false;
}
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
return ( aList[0].start == aList[3].end );
2008-01-22 20:48:02 +00:00
}
return false;
}
2008-02-09 08:34:45 +00:00
/**
* Function isKeepout
* decides if the pad is a copper less through hole which needs to be made into
* a round keepout.
*/
static bool isKeepout( D_PAD* aPad )
{
return aPad->m_PadShape==PAD_CIRCLE && aPad->m_Drill.x >= aPad->m_Size.x;
}
2008-01-24 21:47:54 +00:00
/**************************************************************************/
static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
/**************************************************************************/
2008-01-22 20:48:02 +00:00
{
2008-01-24 21:47:54 +00:00
const D_PAD* padref = *(D_PAD**)refptr;
const D_PAD* padcmp = *(D_PAD**)objptr;
2008-02-07 20:23:58 +00:00
return D_PAD::Compare( padref, padcmp );
2008-01-24 21:47:54 +00:00
}
2008-01-25 22:03:36 +00:00
/**
* Function makePath
* creates a PATH element with a single straight line, a pair of vertices.
*/
static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string& aLayerName )
{
PATH* path = new PATH( 0, T_path );
path->AppendPoint( aStart );
path->AppendPoint( aEnd );
path->SetLayerId( aLayerName.c_str() );
return path;
}
2008-01-29 16:45:14 +00:00
IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
{
PADSTACKS& padstacks = pcb->library->padstacks;
TYPE_COLLECTOR pads;
2008-02-07 20:23:58 +00:00
// get all the MODULE's pads.
pads.Collect( aModule, scanPADs );
2008-01-29 16:45:14 +00:00
IMAGE* image = new IMAGE(0);
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
image->image_id = CONV_TO_UTF8( aModule->m_LibRef );
2008-02-07 20:23:58 +00:00
// from the pads, and make an IMAGE using collated padstacks.
for( int p=0; p<pads.GetCount(); ++p )
2008-01-29 16:45:14 +00:00
{
D_PAD* pad = (D_PAD*) pads[p];
2008-01-29 16:45:14 +00:00
// see if this pad is a through hole with no copper on its perimeter
2008-02-09 08:34:45 +00:00
if( isKeepout( pad ) )
{
2008-02-05 05:08:10 +00:00
KEEPOUT* keepout = new KEEPOUT(image, T_keepout);
image->keepouts.push_back( keepout );
2008-02-07 20:23:58 +00:00
2008-02-05 05:08:10 +00:00
CIRCLE* circle = new CIRCLE(keepout);
keepout->SetShape( circle );
2008-02-07 20:23:58 +00:00
2008-02-05 05:08:10 +00:00
circle->SetDiameter( scale(pad->m_Drill.x) );
circle->SetVertex( mapPt( pad->m_Pos0 ) );
circle->layer_id = "signal";
}
else
{
PADSTACK* padstack = &padstacks[pad->m_logical_connexion];
2008-02-07 20:23:58 +00:00
PIN* pin = new PIN(image);
image->pins.push_back( pin );
2008-02-07 20:23:58 +00:00
pin->padstack_id = padstack->padstack_id;
pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
// copper shape's position is hole position + offset
wxPoint pos = pad->m_Pos0 + pad->m_Offset;
2008-02-07 20:23:58 +00:00
2008-02-01 20:32:18 +00:00
pin->SetVertex( mapPt( pos ) );
}
2008-01-29 16:45:14 +00:00
}
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
return image;
2008-02-07 20:23:58 +00:00
}
2008-01-29 16:45:14 +00:00
2008-02-01 01:09:39 +00:00
PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
{
2008-02-05 02:13:16 +00:00
CIRCLE* circle;
SHAPE* shape;
double dsnDiameter;
2008-02-01 01:09:39 +00:00
char name[48];
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
PADSTACK* padstack = new PADSTACK( pcb->library );
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
switch( aVia->Shape() )
{
case VIA_THROUGH:
shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-01 01:09:39 +00:00
2008-02-05 02:13:16 +00:00
circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-02-07 20:23:58 +00:00
dsnDiameter = scale( aVia->m_Width );
2008-02-05 02:13:16 +00:00
circle->SetDiameter( dsnDiameter );
2008-02-07 20:23:58 +00:00
circle->SetLayerId( "signal" );
2008-02-09 08:34:45 +00:00
snprintf( name, sizeof(name), "Via_%.6g:%.6g_mil", dsnDiameter,
// encode the drill value in the name for later import
scale( aVia->GetDrillValue() ) );
2008-02-05 02:13:16 +00:00
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
case VIA_BLIND_BURIED:
case VIA_MICROVIA:
int topLayer;
int botLayer;
aVia->ReturnLayerPair( &topLayer, &botLayer );
topLayer = kicadLayer2pcb[topLayer];
botLayer = kicadLayer2pcb[botLayer];
if( topLayer > botLayer )
EXCHG( topLayer, botLayer );
2008-02-07 20:23:58 +00:00
dsnDiameter = scale( aVia->m_Width );
2008-02-05 02:13:16 +00:00
for( int layer=topLayer; layer<=botLayer; ++layer )
{
shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
circle->SetDiameter( dsnDiameter );
2008-02-07 20:23:58 +00:00
circle->SetLayerId( layerIds[layer].c_str() );
2008-02-05 02:13:16 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-09 08:34:45 +00:00
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil",
topLayer, botLayer, dsnDiameter,
// encode the drill value in the name for later import
scale( aVia->GetDrillValue() )
);
2008-02-05 02:13:16 +00:00
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
}
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
return padstack;
2008-02-07 20:23:58 +00:00
}
2008-02-01 01:09:39 +00:00
2008-02-09 08:34:45 +00:00
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter )
2008-02-01 01:09:39 +00:00
{
char name[48];
PADSTACK* padstack = new PADSTACK( pcb->library );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-02-07 20:23:58 +00:00
double dsnDiameter = scale(aCopperDiameter);
2008-02-01 01:09:39 +00:00
circle->SetDiameter( dsnDiameter );
2008-02-07 20:23:58 +00:00
circle->SetLayerId( "signal" );
2008-02-09 08:34:45 +00:00
snprintf( name, sizeof(name), "Via_%.6g:%.6g_mil", dsnDiameter,
// encode the drill value in the name for later import
scale( aDrillDiameter ) );
2008-02-01 01:09:39 +00:00
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
return padstack;
2008-02-07 20:23:58 +00:00
}
2008-02-01 01:09:39 +00:00
2008-02-09 08:34:45 +00:00
/**
* Struct ltWX
* is used secretly by the std:set<> class below. See STRINGSET typedef.
*/
struct ltWX
{
// a "less than" test on two wxStrings, by pointer.
bool operator()( const wxString* s1, const wxString* s2) const
{
return s1->Cmp( *s2 ) < 0; // case specific wxString compare
}
};
2008-01-29 16:45:14 +00:00
void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
2008-01-24 21:47:54 +00:00
{
2008-02-08 15:00:50 +00:00
char name[80]; // padstack name builder
std::string uniqifier;
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
if( aPads.GetCount() )
{
2008-01-25 15:13:57 +00:00
qsort( (void*) aPads.BasePtr(), aPads.GetCount(), sizeof(D_PAD*), Pad_list_Sort_by_Shapes );
2008-01-24 21:47:54 +00:00
}
D_PAD* old_pad = NULL;
2008-01-25 22:03:36 +00:00
2008-01-24 21:47:54 +00:00
for( int i=0; i<aPads.GetCount(); ++i )
{
D_PAD* pad = (D_PAD*) aPads[i];
2008-02-07 20:23:58 +00:00
bool doLayer[2] = { // top and bottom layers only
2008-01-26 02:02:27 +00:00
pad->IsOnLayer( LAYER_CMP_N ),
2008-02-07 20:23:58 +00:00
pad->IsOnLayer( COPPER_LAYER_N )
2008-01-26 02:02:27 +00:00
};
2008-02-07 20:23:58 +00:00
2008-01-26 02:02:27 +00:00
if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
{
2008-01-29 16:45:14 +00:00
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
// this is the same as the last pad, so do not add it to the padstack list.
2008-01-26 02:02:27 +00:00
continue;
}
2008-01-24 21:47:54 +00:00
2008-01-26 02:02:27 +00:00
// if pad has no copper presence, then it will be made into
2008-02-07 20:23:58 +00:00
// an "image->keepout" later. No copper pad here, it is probably a hole.
2008-02-09 08:34:45 +00:00
if( (!doLayer[0] && !doLayer[1]) || isKeepout( pad ) )
2008-01-24 21:47:54 +00:00
{
continue;
}
old_pad = pad;
2008-01-29 16:45:14 +00:00
PADSTACK* padstack = new PADSTACK( pcb->library );
pcb->library->AddPadstack( padstack );
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
/* Through hole pads are reported on the <reserved_layer_name>
"signal". Reporting through hole pads on the special
"signal" layer may have problems when power layers are in the layer
stack. See bottom of page 74 of the SECCTRA Design Language
Reference, May 2000. We could do better if there was actually a
"layer type" field within Kicad which would hold one of: T_signal,
T_power, T_mixed, T_jumper.
PAD_SMD and PAD_CONN are reported on each layer for which
they are present.
*/
2008-02-09 08:34:45 +00:00
int reportedLayers; // how many in reported padstack
2008-02-08 15:00:50 +00:00
const char* layerName[NB_COPPER_LAYERS];
static const char signal[] = "signal";
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
if( pad->m_Attribut==PAD_SMD || pad->m_Attribut==PAD_CONN )
{
reportedLayers = 0;
uniqifier = '[';
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
if( doLayer[0] )
{
layerName[reportedLayers++] = layerIds[0].c_str();
uniqifier += 'T'; // T for top, could have used a layer index here alternatively
}
if( doLayer[1] )
{
int pcbLayerNdx = kicadLayer2pcb[COPPER_LAYER_N];
layerName[reportedLayers++] = layerIds[ pcbLayerNdx ].c_str();
uniqifier += 'B'; // B for bottom
}
2008-01-31 01:30:52 +00:00
2008-02-08 15:00:50 +00:00
uniqifier += ']';
}
else
{
reportedLayers = 1;
layerName[0] = signal;
uniqifier = "[A]"; // A for all
}
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
switch( pad->m_PadShape )
{
default:
case PAD_CIRCLE:
{
double diameter = scale(pad->m_Size.x);
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
2008-01-24 21:47:54 +00:00
{
2008-02-08 15:00:50 +00:00
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
circle->SetLayerId( layerName[ndx] );
circle->SetDiameter( diameter );
2008-01-24 21:47:54 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
snprintf( name, sizeof(name), "Round%sPad_%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x) );
2008-01-24 21:47:54 +00:00
name[ sizeof(name)-1 ] = 0;
2008-02-07 20:23:58 +00:00
// @todo verify that all pad names are unique, there is a chance that
2008-01-24 21:47:54 +00:00
// D_PAD::Compare() could say two pads are different, yet the get the same
// name here. If so, blend in the padNdx into the name.
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
padstack->SetPadstackId( name );
}
break;
case PAD_RECT:
{
double dx = scale( pad->m_Size.x ) / 2.0;
double dy = scale( pad->m_Size.y ) / 2.0;
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
POINT lowerLeft( -dx, -dy );
POINT upperRight( dx, dy );
2008-01-24 21:47:54 +00:00
2008-02-08 15:00:50 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
2008-01-24 21:47:54 +00:00
{
2008-02-08 15:00:50 +00:00
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
RECTANGLE* rect = new RECTANGLE( shape );
shape->SetShape( rect );
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
rect->SetLayerId( layerName[ndx] );
rect->SetCorners( lowerLeft, upperRight );
2008-01-24 21:47:54 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x), scale(pad->m_Size.y) );
2008-01-24 21:47:54 +00:00
name[ sizeof(name)-1 ] = 0;
2008-02-07 20:23:58 +00:00
// @todo verify that all pad names are unique, there is a chance that
2008-01-25 22:03:36 +00:00
// D_PAD::Compare() could say two pads are different, yet they get the same
2008-01-24 21:47:54 +00:00
// name here. If so, blend in the padNdx into the name.
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
padstack->SetPadstackId( name );
}
break;
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
case PAD_OVAL:
2008-01-24 21:47:54 +00:00
{
2008-01-25 22:03:36 +00:00
double dx = scale( pad->m_Size.x ) / 2.0;
double dy = scale( pad->m_Size.y ) / 2.0;
double dr = dx - dy;
if( dr >= 0 ) // oval is horizontal
{
double radius = dy;
2008-02-08 15:00:50 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
2008-01-25 22:03:36 +00:00
{
2008-02-08 15:00:50 +00:00
SHAPE* shape;
PATH* path;
// see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
shape = new SHAPE( padstack );
padstack->Append( shape );
path = makePath( POINT(-dr, 0.0), POINT(dr, 0.0), layerName[ndx] );
shape->SetShape( path );
path->aperture_width = 2.0 * radius;
2008-01-25 22:03:36 +00:00
}
}
else // oval is vertical
{
double radius = dx;
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
dr = -dr;
2008-02-08 15:00:50 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
2008-01-25 22:03:36 +00:00
{
2008-02-08 15:00:50 +00:00
SHAPE* shape;
PATH* path;
// see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
shape = new SHAPE( padstack );
padstack->Append( shape );
path = makePath( POINT(0.0, -dr), POINT(0.0, dr), layerName[ndx] );
shape->SetShape( path );
path->aperture_width = 2.0 * radius;
2008-01-25 22:03:36 +00:00
}
}
2008-02-07 20:23:58 +00:00
2008-02-08 15:00:50 +00:00
snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x), scale(pad->m_Size.y) );
2008-01-25 22:03:36 +00:00
name[ sizeof(name)-1 ] = 0;
2008-02-07 20:23:58 +00:00
// @todo verify that all pad names are unique, there is a chance that
2008-01-25 22:03:36 +00:00
// D_PAD::Compare() could say two pads are different, yet they get the same
// name here. If so, blend in the padNdx into the name.
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
padstack->SetPadstackId( name );
2008-01-24 21:47:54 +00:00
}
break;
2008-01-25 22:03:36 +00:00
2008-02-07 20:23:58 +00:00
/*
2008-01-24 21:47:54 +00:00
case PAD_TRAPEZOID:
break;
2008-02-07 20:23:58 +00:00
*/
2008-01-24 21:47:54 +00:00
}
}
2008-01-26 02:02:27 +00:00
2008-02-07 20:23:58 +00:00
// unique pads are now in the padstack list.
// next we add the via's which may be used.
2008-01-26 02:02:27 +00:00
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize )
{
2008-02-09 08:34:45 +00:00
PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill );
2008-01-29 16:45:14 +00:00
pcb->library->AddPadstack( padstack );
2008-02-07 20:23:58 +00:00
// remember this index, it is the default via and also the start of the
2008-01-29 16:45:14 +00:00
// vias within the padstack list. Before this index are the pads.
// At this index and later are the vias.
pcb->library->SetViaStartIndex( pcb->library->padstacks.size()-1 );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
// padstack->SetPadstackId( "Via_Default" ); I like the padstack_id with the size in it.
2008-01-26 02:02:27 +00:00
}
for( int i=0; i<HISTORY_NUMBER; ++i )
{
2008-02-07 20:23:58 +00:00
int viaSize = aBoard->m_BoardSettings->m_ViaSizeHistory[i];
2008-01-26 02:02:27 +00:00
if( !viaSize )
break;
2008-02-07 20:23:58 +00:00
2008-01-26 02:02:27 +00:00
if( viaSize == defaultViaSize )
continue;
2008-02-07 20:23:58 +00:00
2008-02-09 08:34:45 +00:00
PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill );
2008-01-29 16:45:14 +00:00
pcb->library->AddPadstack( padstack );
2008-01-26 02:02:27 +00:00
}
2008-01-21 22:16:45 +00:00
}
2008-01-22 20:48:02 +00:00
2008-02-09 08:34:45 +00:00
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
2008-01-22 20:48:02 +00:00
{
TYPE_COLLECTOR items;
POINT_PAIRS ppairs;
POINT_PAIR pair;
2008-02-03 15:23:00 +00:00
static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT };
2008-02-07 20:23:58 +00:00
2008-02-09 08:34:45 +00:00
// Not all boards are exportable. Check that all reference Ids are unique.
// Unless they are unique, we cannot import the session file which comes
// back to us later from the router.
{
items.Collect( aBoard, scanMODULEs );
typedef std::set<const wxString*, ltWX> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> PAIR;
STRINGSET references; // holds unique component references
for( int i=0; i<items.GetCount(); ++i )
{
MODULE* module = (MODULE*) items[i];
if( module->GetReference() == wxEmptyString )
{
ThrowIOError( _("Component with value of \"%s\" has empty reference id."),
module->GetValue().GetData() );
}
// if we cannot insert OK, that means the reference has been seen before.
PAIR pair = references.insert( &module->GetReference() );
if( !pair.second ) // insert failed
{
ThrowIOError( _("Multiple components have identical reference IDs of \"%s\"."),
module->GetReference().GetData() );
}
}
}
2008-02-07 20:23:58 +00:00
2008-01-22 20:48:02 +00:00
if( !pcb )
pcb = SPECCTRA_DB::MakePCB();
2008-01-25 22:03:36 +00:00
// DSN Images (=Kicad MODULES and pads) must be presented from the
// 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.
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{
module->flag = 0;
if( module->GetLayer() == COPPER_LAYER_N )
{
aBoard->Change_Side_Module( module, NULL );
module->flag = 1;
}
}
2008-01-31 01:30:52 +00:00
// Since none of these statements cause any immediate output, the order
// of them is somewhat flexible. The outputting to disk is done at the
// end. We start by gathering all the layer information from the board.
2008-02-07 20:23:58 +00:00
2008-01-31 01:30:52 +00:00
//-----<layer_descriptor>-----------------------------------------------
{
2008-02-07 20:23:58 +00:00
// specctra wants top physical layer first, then going down to the
2008-01-31 01:30:52 +00:00
// bottom most physical layer in physical sequence.
// @question : why does Kicad not display layers in that order?
2008-01-31 06:46:31 +00:00
buildLayerMaps( aBoard );
2008-02-07 20:23:58 +00:00
int layerCount = aBoard->GetCopperLayerCount();
2008-01-31 01:30:52 +00:00
for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
{
2008-01-31 01:30:52 +00:00
LAYER* layer = new LAYER( pcb->structure );
pcb->structure->layers.push_back( layer );
2008-02-07 20:23:58 +00:00
layer->name = layerIds[pcbNdx];
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
layer->properties.push_back( PROPERTY() );
PROPERTY* property = &layer->properties.back();
property->name = "index";
char temp[32];
sprintf( temp, "%d", pcbNdx );
2008-02-07 20:23:58 +00:00
property->value = temp;
2008-01-31 01:30:52 +00:00
// layer->type = @todo need this, the export would be better.
}
}
2008-02-07 20:23:58 +00:00
2008-01-31 01:30:52 +00:00
// for now, report on only the top and bottom layers with respect to the copper
2008-02-07 20:23:58 +00:00
// within a pad's padstack. this is usually correct, but not rigorous.
2008-01-31 01:30:52 +00:00
// a space in a quoted token is NOT a terminator, true establishes this.
pcb->parser->space_in_quoted_tokens = true;
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
//-----<unit_descriptor> & <resolution_descriptor>--------------------
2008-02-07 20:23:58 +00:00
{
2008-01-23 01:52:49 +00:00
pcb->unit->units = T_mil;
pcb->resolution->units = T_mil;
pcb->resolution->value = 100;
}
2008-01-22 20:48:02 +00:00
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
//-----<boundary_descriptor>------------------------------------------
2008-01-22 20:48:02 +00:00
{
2008-01-23 01:52:49 +00:00
// get all the DRAWSEGMENTS into 'items', then look for layer == EDGE_N,
// and those segments comprise the board's perimeter.
2008-01-23 22:36:37 +00:00
static const KICAD_T scanDRAWSEGMENTS[] = { TYPEDRAWSEGMENT, EOT };
2008-01-23 01:52:49 +00:00
items.Collect( aBoard, scanDRAWSEGMENTS );
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
bool haveEdges = false;
ppairs.clear();
for( int i=0; i<items.GetCount(); ++i )
2008-01-22 20:48:02 +00:00
{
2008-01-23 01:52:49 +00:00
DRAWSEGMENT* item = (DRAWSEGMENT*) items[i];
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
wxASSERT( item->Type() == TYPEDRAWSEGMENT );
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
if( item->GetLayer() == EDGE_N )
{
2008-02-01 20:32:18 +00:00
pair.start = mapPt( item->m_Start );
pair.end = mapPt( item->m_End );
2008-01-23 01:52:49 +00:00
pair.item = item;
ppairs.push_back( pair );
haveEdges = true;
}
2008-01-22 20:48:02 +00:00
}
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
if( haveEdges )
2008-01-22 20:48:02 +00:00
{
2008-01-23 01:52:49 +00:00
swapEnds( ppairs );
2008-02-07 20:23:58 +00:00
#if 0 && defined(DEBUG)
2008-01-23 01:52:49 +00:00
for( unsigned i=0; i<ppairs.size(); ++i )
{
POINT_PAIR* p = &ppairs[i];
p->item->Show( 0, std::cout );
}
2008-02-07 20:23:58 +00:00
#endif
2008-01-23 01:52:49 +00:00
BOUNDARY* boundary = new BOUNDARY(0);
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
if( isRectangle( ppairs ) )
{
RECTANGLE* rect = new RECTANGLE( boundary );
rect->layer_id = "pcb";
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
// opposite corners
2008-02-01 20:32:18 +00:00
rect->SetCorners( ppairs[0].start, ppairs[2].start );
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
boundary->rectangle = rect;
}
else
{
PATH* path = new PATH( boundary );
2008-02-01 20:52:49 +00:00
boundary->paths.push_back( path );
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
path->layer_id = "pcb";
for( unsigned i=0; i<ppairs.size(); ++i )
{
// unless its a closed polygon, this probably won't work,
// otherwise it will.
2008-02-01 20:32:18 +00:00
path->points.push_back( ppairs[i].start );
2008-01-23 01:52:49 +00:00
}
}
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
pcb->structure->SetBOUNDARY( boundary );
2008-01-22 20:48:02 +00:00
}
2008-01-23 01:52:49 +00:00
else
2008-01-22 20:48:02 +00:00
{
2008-01-23 01:52:49 +00:00
aBoard->ComputeBoundaryBox();
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
BOUNDARY* boundary = new BOUNDARY(0);
RECTANGLE* rect = new RECTANGLE( boundary );
2008-02-07 20:23:58 +00:00
2008-01-22 20:48:02 +00:00
rect->layer_id = "pcb";
2008-02-07 20:23:58 +00:00
2008-01-22 20:48:02 +00:00
// opposite corners
2008-01-23 01:52:49 +00:00
wxPoint bottomRight;
bottomRight.x = aBoard->m_BoundaryBox.GetRight();
bottomRight.y = aBoard->m_BoundaryBox.GetBottom();
2008-02-07 20:23:58 +00:00
rect->SetCorners( mapPt( aBoard->m_BoundaryBox.GetOrigin() ),
mapPt( bottomRight ) );
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
boundary->rectangle = rect;
2008-02-07 20:23:58 +00:00
2008-01-23 01:52:49 +00:00
pcb->structure->SetBOUNDARY( boundary );
2008-01-22 20:48:02 +00:00
}
}
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
//-----<rules>--------------------------------------------------------
{
// put out these rules, the user can then edit them with a text editor
2008-02-09 08:34:45 +00:00
char rule[80];
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
int curTrackWidth = aBoard->m_BoardSettings->m_CurrentTrackWidth;
int curTrackClear = aBoard->m_BoardSettings->m_TrackClearence;
2008-02-09 16:33:03 +00:00
// The +5 is to give freerouter a little extra room, this is 0.5 mils.
// If we export without this, then on import freerouter violates our
// DRC checks with track to via spacing.
double clearance = scale(curTrackClear+5);
2008-01-31 06:46:31 +00:00
STRINGS& rules = pcb->structure->rules->rules;
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(width %.6g)", scale( curTrackWidth ) );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g)", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
sprintf( rule, "(clearance %.6g (type pad_to_turn_gap))", clearance );
2008-01-31 06:46:31 +00:00
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type smd_to_turn_gap))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type via_via))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type via_smd))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type via_pin))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type pin_pin))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
sprintf( rule, "(clearance %.6g (type smd_pin))", clearance );
rules.push_back( rule );
2008-02-07 20:23:58 +00:00
2008-02-09 16:33:03 +00:00
// well, the user is going to text edit these in the DSN file anyway,
// at least until we have an export dialog.
clearance = scale(curTrackClear)/4;
sprintf( rule, "(clearance %.6g (type smd_smd))", clearance );
2008-01-31 06:46:31 +00:00
rules.push_back( rule );
}
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
//-----<zone containers become planes>--------------------------------
2008-01-23 22:36:37 +00:00
{
static const KICAD_T scanZONEs[] = { TYPEZONE_CONTAINER, EOT };
items.Collect( aBoard, scanZONEs );
for( int i=0; i<items.GetCount(); ++i )
{
ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure );
PATH* polygon = new PATH( plane, T_polygon );
2008-01-30 19:16:46 +00:00
plane->SetShape( polygon );
2008-02-07 20:23:58 +00:00
2008-01-31 01:30:52 +00:00
plane->name = CONV_TO_UTF8( item->m_Netname );
wxString layerName = aBoard->GetLayerName( item->GetLayer() );
2008-01-23 22:36:37 +00:00
polygon->layer_id = CONV_TO_UTF8( layerName );
2008-02-07 20:23:58 +00:00
2008-01-23 22:36:37 +00:00
int count = item->m_Poly->corner.size();
for( int j=0; j<count; ++j )
{
2008-02-09 08:34:45 +00:00
wxPoint point( item->m_Poly->corner[j].x,
item->m_Poly->corner[j].y );
2008-01-23 22:36:37 +00:00
polygon->points.push_back( mapPt(point) );
}
2008-02-07 20:23:58 +00:00
2008-01-23 22:36:37 +00:00
pcb->structure->planes.push_back( plane );
}
}
2008-01-24 21:47:54 +00:00
// keepouts could go here, there are none in Kicad at this time.
// although COPPER_PLANEs probably will need them for the thru holes, etc.
// but in that case they are WINDOWs within the COPPER_PLANEs.
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
//-----<build the initial padstack list>--------------------------------
2008-01-23 22:36:37 +00:00
{
2008-01-24 21:47:54 +00:00
TYPE_COLLECTOR pads;
2008-02-07 20:23:58 +00:00
// get all the D_PADs into 'pads'.
2008-01-24 21:47:54 +00:00
pads.Collect( aBoard, scanPADs );
2008-01-29 16:45:14 +00:00
makePADSTACKs( aBoard, pads );
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
#if 0 && defined(DEBUG)
2008-01-24 21:47:54 +00:00
for( int p=0; p<pads.GetCount(); ++p )
pads[p]->Show( 0, std::cout );
2008-02-07 20:23:58 +00:00
#endif
2008-01-26 02:02:27 +00:00
}
2008-01-29 16:45:14 +00:00
2008-02-07 20:23:58 +00:00
//-----<build the images and components>---------------------------------
2008-01-26 02:02:27 +00:00
{
2008-01-24 21:47:54 +00:00
items.Collect( aBoard, scanMODULEs );
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
for( int m=0; m<items.GetCount(); ++m )
2008-01-23 22:36:37 +00:00
{
2008-01-24 21:47:54 +00:00
MODULE* module = (MODULE*) items[m];
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
IMAGE* image = makeIMAGE( module );
2008-02-07 20:23:58 +00:00
IMAGE* registered = pcb->library->LookupIMAGE( image );
if( registered != image )
2008-01-24 21:47:54 +00:00
{
// If our new 'image' is not a unique IMAGE, delete it.
// In either case, 'registered' is the one we'll work with henceforth.
2008-01-29 16:45:14 +00:00
delete image;
}
2008-02-01 20:32:18 +00:00
// @todo: this only works if the user has not modified the MODULE within the PCB
// and made it different from what is in the PCBNEW library. Need to test
// each image for uniqueness, not just based on name as is done here:
2008-02-07 20:23:58 +00:00
2008-02-03 21:46:12 +00:00
COMPONENT* comp = pcb->placement->LookupCOMPONENT( registered->GetImageId() );
2008-02-07 20:23:58 +00:00
PLACE* place = new PLACE( comp );
comp->places.push_back( place );
2008-02-07 20:23:58 +00:00
place->SetRotation( module->m_Orient/10.0 );
place->SetVertex( mapPt( module->m_Pos ) );
place->component_id = CONV_TO_UTF8( module->GetReference() );
2008-01-30 19:16:46 +00:00
place->part_number = CONV_TO_UTF8( module->GetValue() );
2008-02-07 20:23:58 +00:00
// module is flipped from bottom side, set side to T_back
2008-02-05 02:13:16 +00:00
if( module->flag )
{
int angle = 1800 - module->m_Orient;
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
NORMALIZE_ANGLE_POS(angle);
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
place->SetRotation( angle/10.0 );
2008-02-07 20:23:58 +00:00
place->side = T_back;
2008-02-05 02:13:16 +00:00
}
2008-01-29 16:45:14 +00:00
}
}
2008-02-07 20:23:58 +00:00
//-----<create the nets>------------------------------------------------
{
2008-02-03 15:23:00 +00:00
NETWORK* network = pcb->network;
TYPE_COLLECTOR nets;
TYPE_COLLECTOR pads;
2008-02-07 20:23:58 +00:00
static const KICAD_T scanNETs[] = { PCB_EQUIPOT_STRUCT_TYPE, EOT };
2008-02-03 15:23:00 +00:00
nets.Collect( aBoard, scanNETs );
2008-02-07 20:23:58 +00:00
2008-02-03 15:23:00 +00:00
items.Collect( aBoard, scanMODULEs );
2008-02-07 20:23:58 +00:00
PIN_REF emptypin(0);
2008-02-07 20:23:58 +00:00
2008-02-03 15:23:00 +00:00
for( int n=0; n<nets.GetCount(); ++n )
{
2008-02-03 15:23:00 +00:00
EQUIPOT* kinet = (EQUIPOT*) nets[n];
2008-02-07 20:23:58 +00:00
2008-01-30 19:16:46 +00:00
if( kinet->GetNet() == 0 )
continue;
NET* net = new NET( network );
network->nets.push_back( net );
2008-02-07 20:23:58 +00:00
net->net_id = CONV_TO_UTF8( kinet->m_Netname );
net->net_number = kinet->GetNet();
2008-02-03 15:23:00 +00:00
for( int m=0; m<items.GetCount(); ++m )
{
2008-02-03 15:23:00 +00:00
MODULE* module = (MODULE*) items[m];
2008-02-03 15:23:00 +00:00
pads.Collect( module, scanPADs );
2008-02-07 20:23:58 +00:00
2008-02-03 15:23:00 +00:00
for( int p=0; p<pads.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) pads[p];
2008-02-07 20:23:58 +00:00
2008-02-03 15:23:00 +00:00
if( pad->GetNet() == kinet->GetNet() )
{
// push on an empty one, then fill it via 'pin_ref'
net->pins.push_back( emptypin );
PIN_REF* pin_ref = &net->pins.back();
2008-02-07 20:23:58 +00:00
2008-02-03 15:23:00 +00:00
pin_ref->SetParent( net );
pin_ref->component_id = CONV_TO_UTF8( module->GetReference() );
pin_ref->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
}
}
}
}
}
2008-01-30 19:16:46 +00:00
2008-02-03 21:46:12 +00:00
#if 1 // do existing wires and vias
2008-01-30 19:16:46 +00:00
//-----<create the wires from tracks>-----------------------------------
{
// export all of them for now, later we'll decide what controls we need
// on this.
2008-02-01 01:09:39 +00:00
static const KICAD_T scanTRACKs[] = { TYPETRACK, EOT };
2008-02-07 20:23:58 +00:00
2008-01-30 19:16:46 +00:00
items.Collect( aBoard, scanTRACKs );
2008-01-31 01:30:52 +00:00
2008-02-07 20:23:58 +00:00
std::string netname;
2008-01-31 06:46:31 +00:00
WIRING* wiring = pcb->wiring;
PATH* path = 0;
2008-01-31 01:30:52 +00:00
2008-02-07 20:23:58 +00:00
int old_netcode = -1;
int old_width = -1;
int old_layer = -1;
2008-01-31 01:30:52 +00:00
2008-01-30 19:16:46 +00:00
for( int i=0; i<items.GetCount(); ++i )
{
2008-01-31 06:46:31 +00:00
TRACK* track = (TRACK*) items[i];
2008-02-07 20:23:58 +00:00
2008-01-31 01:30:52 +00:00
if( track->GetNet() == 0 )
continue;
2008-01-31 06:46:31 +00:00
if( old_netcode != track->GetNet()
2008-02-07 20:23:58 +00:00
|| old_width != track->m_Width
2008-01-31 06:46:31 +00:00
|| old_layer != track->GetLayer()
2008-02-07 20:23:58 +00:00
|| (path && path->points.back() != mapPt(track->m_Start) )
)
2008-01-31 01:30:52 +00:00
{
2008-01-31 06:46:31 +00:00
old_width = track->m_Width;
old_layer = track->GetLayer();
2008-01-31 01:30:52 +00:00
2008-01-31 06:46:31 +00:00
if( old_netcode != track->GetNet() )
2008-01-31 01:30:52 +00:00
{
2008-01-31 06:46:31 +00:00
old_netcode = track->GetNet();
EQUIPOT* equipot = aBoard->FindNet( track->GetNet() );
wxASSERT( equipot );
netname = CONV_TO_UTF8( equipot->m_Netname );
2008-01-31 01:30:52 +00:00
}
2008-01-31 06:46:31 +00:00
WIRE* wire = new WIRE( wiring );
wiring->wires.push_back( wire );
2008-02-01 01:09:39 +00:00
wire->net_id = netname;
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
wire->wire_type = T_normal; // @todo, this should be configurable
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
int kiLayer = track->GetLayer();
int pcbLayer = kicadLayer2pcb[kiLayer];
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
path = new PATH( wire );
wire->SetShape( path );
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
path->layer_id = layerIds[pcbLayer];
path->aperture_width = scale( old_width );
path->AppendPoint( mapPt( track->m_Start ) );
2008-01-31 01:30:52 +00:00
}
2008-02-07 20:23:58 +00:00
2008-01-31 06:46:31 +00:00
path->AppendPoint( mapPt( track->m_End ) );
2008-01-30 19:16:46 +00:00
}
2008-02-01 01:09:39 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-09 08:34:45 +00:00
//-----<export the existing real BOARD instantiated vias>-----------------
2008-02-01 01:09:39 +00:00
{
// export all of them for now, later we'll decide what controls we need
// on this.
static const KICAD_T scanVIAs[] = { TYPEVIA, EOT };
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
items.Collect( aBoard, scanVIAs );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
for( int i=0; i<items.GetCount(); ++i )
{
SEGVIA* via = (SEGVIA*) items[i];
wxASSERT( via->Type() == TYPEVIA );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
PADSTACK* padstack = makeVia( via );
PADSTACK* registered = pcb->library->LookupVia( padstack );
if( padstack != registered )
{
delete padstack;
}
WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
pcb->wiring->wire_vias.push_back( dsnVia );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
dsnVia->padstack_id = registered->padstack_id;
dsnVia->vertexes.push_back( mapPt( via->GetPosition() ) );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
int netcode = via->GetNet();
EQUIPOT* equipot = aBoard->FindNet( netcode );
wxASSERT( equipot );
2008-02-07 20:23:58 +00:00
2008-02-01 01:09:39 +00:00
dsnVia->net_id = CONV_TO_UTF8( equipot->m_Netname );
2008-02-07 20:23:58 +00:00
2008-02-05 02:13:16 +00:00
dsnVia->via_type = T_normal; // @todo, this should be configurable
2008-02-01 01:09:39 +00:00
}
}
2008-02-07 20:23:58 +00:00
#endif // do existing wires and vias
2008-02-01 01:09:39 +00:00
//-----<via_descriptor>-------------------------------------------------
{
// Output the vias in the padstack list here, by name. This must
// be done after exporting existing vias as WIRE_VIAs.
VIA* vias = pcb->structure->via;
PADSTACKS& padstacks = pcb->library->padstacks;
int viaNdx = pcb->library->via_start_index;
if( viaNdx != -1 )
{
for( ; viaNdx < (int)padstacks.size(); ++viaNdx )
{
vias->AppendVia( padstacks[viaNdx].padstack_id.c_str() );
}
}
2008-01-30 19:16:46 +00:00
}
2008-02-01 01:09:39 +00:00
2008-02-07 20:23:58 +00:00
2008-01-29 16:45:14 +00:00
//-----<restore MODULEs>------------------------------------------------
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
// DSN Images (=Kicad MODULES and pads) must be presented from the
// top view. Restore those that were flipped.
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
{
if( module->flag )
{
aBoard->Change_Side_Module( module, NULL );
module->flag = 0;
}
}
2008-01-22 20:48:02 +00:00
}
2008-02-07 20:23:58 +00:00
2008-01-21 21:24:39 +00:00
} // namespace DSN