kicad/pcbnew/specctra_export.cpp

1263 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-12 01:02:53 +00:00
#include "trigo.h" // RotatePoint()
2008-02-09 08:34:45 +00:00
#include <set> // std::set
2008-02-14 01:07:52 +00:00
#include <map> // std::map
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
#include <boost/utility.hpp> // boost::addressof()
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
2008-02-14 15:34:40 +00:00
// this is called in FromBOARD() too, but if it throws an exception, that call
// does not happen, so call it again just in case here.
db.RevertMODULEs( m_Pcb );
2008-02-07 20:23:58 +00:00
// 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
2008-02-14 01:59:31 +00:00
* decides if the pad is a copper-less through hole which needs to be made into
2008-02-09 08:34:45 +00:00
* a round keepout.
*/
static bool isKeepout( D_PAD* aPad )
{
return aPad->m_PadShape==PAD_CIRCLE && aPad->m_Drill.x >= aPad->m_Size.x;
}
2008-02-14 01:07:52 +00:00
/*
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-02-14 01:07:52 +00:00
*/
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-02-14 01:07:52 +00:00
/**
* Struct wxString_less_than_
* is used the std:set<> and std::map<> instantiations below.
* See STRINGSET typedef and PINMAP typedef below.
*/
struct wxString_less_than
2008-01-29 16:45:14 +00:00
{
2008-02-14 01:07:52 +00:00
// 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
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
/**
* Function makePADSTACK
* creates a PADSTACK which matches the given pad. Only pads which do not
* satisfy the function isKeepout() should be passed to this function.
* @param aPad The D_PAD which needs to be made into a PADSTACK.
* @return PADSTACK* - The created padstack, including its padstack_id.
*/
PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{
char name[80]; // padstack name builder
std::string uniqifier;
2008-01-29 16:45:14 +00:00
2008-02-14 01:07:52 +00:00
bool doLayer[2] = { // top and bottom layers only
aPad->IsOnLayer( LAYER_CMP_N ),
aPad->IsOnLayer( COPPER_LAYER_N )
};
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
// caller must do this screen before calling here.
wxASSERT( !isKeepout( aPad ) );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
wxASSERT( doLayer[0] || doLayer[1] );
2008-01-29 16:45:14 +00:00
2008-02-14 01:07:52 +00:00
PADSTACK* padstack = new PADSTACK();
int reportedLayers = 0; // how many in reported padstack
const char* layerName[NB_COPPER_LAYERS];
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
if( aPad->m_Attribut==PAD_SMD || aPad->m_Attribut==PAD_CONN )
{
// PAD_SMD and PAD_CONN are reported on each layer for which
// they are present.
uniqifier = '[';
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
if( doLayer[0] )
{
layerName[reportedLayers++] = layerIds[0].c_str();
uniqifier += 'T'; // T for top, could have used a layer index here alternatively
}
2008-02-14 01:07:52 +00:00
if( doLayer[1] )
{
2008-02-14 01:07:52 +00:00
int pcbLayerNdx = kicadLayer2pcb[COPPER_LAYER_N];
layerName[reportedLayers++] = layerIds[ pcbLayerNdx ].c_str();
uniqifier += 'B'; // B for bottom
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
uniqifier += ']';
}
2008-02-12 02:09:39 +00:00
2008-02-14 01:07:52 +00:00
else // through hole pad
{
#if 0
/* 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.
*/
2008-02-12 01:02:53 +00:00
2008-02-14 01:07:52 +00:00
reportedLayers = 1;
layerName[0] = signal;
uniqifier = "[A]"; // A for all
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
#else
// Through hole pads are reported on *all* copper layers.
int copperLayers = aBoard->GetCopperLayerCount();
2008-02-12 02:09:39 +00:00
2008-02-14 01:07:52 +00:00
for( int layer=0; layer<copperLayers; ++layer )
{
layerName[reportedLayers++] = layerIds[layer].c_str();
}
2008-02-14 01:07:52 +00:00
uniqifier = "[A]"; // A for all
#endif
2008-01-29 16:45:14 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
switch( aPad->m_PadShape )
2008-02-05 02:13:16 +00:00
{
2008-02-14 01:07:52 +00:00
default:
case PAD_CIRCLE:
{
double diameter = scale(aPad->m_Size.x);
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
{
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
circle->SetLayerId( layerName[ndx] );
circle->SetDiameter( diameter );
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
snprintf( name, sizeof(name), "Round%sPad_%.6g_mil",
uniqifier.c_str(), scale(aPad->m_Size.x) );
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
}
2008-02-05 02:13:16 +00:00
break;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
case PAD_RECT:
{
double dx = scale( aPad->m_Size.x ) / 2.0;
double dy = scale( aPad->m_Size.y ) / 2.0;
2008-02-05 02:13:16 +00:00
2008-02-14 01:07:52 +00:00
POINT lowerLeft( -dx, -dy );
POINT upperRight( dx, dy );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
{
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
RECTANGLE* rect = new RECTANGLE( shape );
shape->SetShape( rect );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
rect->SetLayerId( layerName[ndx] );
rect->SetCorners( lowerLeft, upperRight );
}
snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) );
name[ sizeof(name)-1 ] = 0;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
padstack->SetPadstackId( name );
}
2008-02-05 02:13:16 +00:00
break;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
case PAD_OVAL:
{
double dx = scale( aPad->m_Size.x ) / 2.0;
double dy = scale( aPad->m_Size.y ) / 2.0;
double dr = dx - dy;
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
if( dr >= 0 ) // oval is horizontal
{
double radius = dy;
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
{
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;
}
}
else // oval is vertical
{
double radius = dx;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
dr = -dr;
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
for( int ndx=0; ndx<reportedLayers; ++ndx )
{
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-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) );
name[ sizeof(name)-1 ] = 0;
2008-02-01 01:09:39 +00:00
2008-02-14 01:07:52 +00:00
padstack->SetPadstackId( name );
}
break;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
/*
case PAD_TRAPEZOID:
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-14 01:07:52 +00:00
/// data type used to ensure unique-ness of pin names
typedef std::map<wxString, int, wxString_less_than> PINMAP;
2008-02-09 08:34:45 +00:00
2008-02-14 01:07:52 +00:00
IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
2008-01-24 21:47:54 +00:00
{
2008-02-14 01:07:52 +00:00
PINMAP pinmap;
TYPE_COLLECTOR pads;
wxString padName;
2008-01-24 21:47:54 +00:00
2008-01-25 22:03:36 +00:00
2008-02-14 01:07:52 +00:00
// get all the MODULE's pads.
pads.Collect( aModule, scanPADs );
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
IMAGE* image = new IMAGE(0);
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
image->image_id = CONV_TO_UTF8( aModule->m_LibRef );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
// from the pads, and make an IMAGE using collated padstacks.
for( int p=0; p<pads.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) pads[p];
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
// see if this pad is a through hole with no copper on its perimeter
if( isKeepout( pad ) )
2008-01-24 21:47:54 +00:00
{
2008-02-14 01:07:52 +00:00
double diameter = scale( pad->m_Drill.x );
POINT vertex = mapPt( pad->m_Pos0 );
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
int layerCount = aBoard->GetCopperLayerCount();
for( int layer=0; layer<layerCount; ++layer )
{
KEEPOUT* keepout = new KEEPOUT(image, T_keepout);
image->keepouts.push_back( keepout );
2008-02-08 15:00:50 +00:00
2008-02-14 01:07:52 +00:00
CIRCLE* circle = new CIRCLE( keepout );
keepout->SetShape( circle );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
circle->SetDiameter( diameter );
circle->SetVertex( vertex );
circle->SetLayerId( layerIds[layer].c_str() );
}
}
else
2008-02-08 15:00:50 +00:00
{
2008-02-14 01:07:52 +00:00
PADSTACK* padstack = makePADSTACK( aBoard, pad );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
PADSTACKSET::iterator iter = padstackset.find( *padstack );
if( iter != padstackset.end() )
2008-02-08 15:00:50 +00:00
{
2008-02-14 01:07:52 +00:00
// padstack is a duplicate, delete it and use the original
delete padstack;
2008-02-14 01:59:31 +00:00
padstack = (PADSTACK*) *iter.base(); // folk lore, be careful here
2008-02-08 15:00:50 +00:00
}
2008-02-14 01:07:52 +00:00
else
2008-02-08 15:00:50 +00:00
{
2008-02-14 01:07:52 +00:00
padstackset.insert( padstack );
2008-02-08 15:00:50 +00:00
}
2008-01-31 01:30:52 +00:00
2008-02-14 01:07:52 +00:00
PIN* pin = new PIN(image);
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
padName = pad->ReturnStringPadName();
pin->pin_id = CONV_TO_UTF8( padName );
if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
2008-01-24 21:47:54 +00:00
{
2008-02-14 01:07:52 +00:00
pinmap[ padName ] = 0;
}
else
{
char buf[32];
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
int duplicates = ++pinmap[ padName ];
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
sprintf( buf, "@%d", duplicates );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
pin->pin_id += buf; // append "@1" or "@2", etc. to pin name
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
pin->kiNetCode = pad->GetNet();
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
image->pins.push_back( pin );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
pin->padstack_id = padstack->padstack_id;
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
wxPoint pos( pad->m_Pos0 );
wxPoint offset( pad->m_Offset.x, pad->m_Offset.y );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
int angle = pad->m_Orient - aModule->m_Orient; // tenths of degrees
if( angle )
{
NORMALIZE_ANGLE_POS(angle);
pin->SetRotation( angle / 10.0 );
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
if( pad->m_Offset.x || pad->m_Offset.y )
2008-01-24 21:47:54 +00:00
{
2008-02-14 01:07:52 +00:00
RotatePoint( &offset, angle );
2008-01-24 21:47:54 +00:00
}
2008-02-14 01:07:52 +00:00
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
pos += offset;
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
pin->SetVertex( mapPt( pos ) );
}
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
return image;
}
2008-02-07 20:23:58 +00:00
2008-01-25 22:03:36 +00:00
2008-02-14 01:07:52 +00:00
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
int aTopLayer, int aBotLayer )
{
char name[48];
PADSTACK* padstack = new PADSTACK();
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
double dsnDiameter = scale(aCopperDiameter);
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
{
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
2008-01-25 22:03:36 +00:00
2008-02-14 01:07:52 +00:00
circle->SetDiameter( dsnDiameter );
circle->SetLayerId( layerIds[layer].c_str() );
2008-01-24 21:47:54 +00:00
}
2008-01-26 02:02:27 +00:00
2008-02-14 01:07:52 +00:00
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil",
aTopLayer, aBotLayer, dsnDiameter,
// encode the drill value into the name for later import
scale( aDrillDiameter )
);
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
2008-01-26 02:02:27 +00:00
2008-02-14 01:07:52 +00:00
return padstack;
}
2008-01-29 16:45:14 +00:00
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
{
int topLayer;
int botLayer;
2008-01-26 02:02:27 +00:00
2008-02-14 01:07:52 +00:00
aVia->ReturnLayerPair( &topLayer, &botLayer );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
topLayer = kicadLayer2pcb[topLayer];
botLayer = kicadLayer2pcb[botLayer];
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
if( topLayer > botLayer )
EXCHG( topLayer, botLayer );
return makeVia( aVia->m_Width, aVia->GetDrillValue(), topLayer, botLayer );
2008-01-21 22:16:45 +00:00
}
2008-01-22 20:48:02 +00:00
2008-02-14 01:07:52 +00:00
typedef std::set<wxString, wxString_less_than> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
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
2008-02-14 01:07:52 +00:00
// back to us later from the router. Also check that all pad names within
// a part are unique, otherwise Electra and Freerouter will not draw the
// pads properly.
2008-02-09 08:34:45 +00:00
{
2008-02-14 01:07:52 +00:00
TYPE_COLLECTOR padItems;
2008-02-09 08:34:45 +00:00
2008-02-14 01:07:52 +00:00
items.Collect( aBoard, scanMODULEs );
2008-02-09 08:34:45 +00:00
2008-02-14 01:07:52 +00:00
STRINGSET refs; // holds module reference designators
2008-02-09 08:34:45 +00:00
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.
2008-02-14 01:07:52 +00:00
STRINGSET_PAIR refpair = refs.insert( module->GetReference() );
if( !refpair.second ) // insert failed
2008-02-09 08:34:45 +00:00
{
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.
2008-02-14 15:34:40 +00:00
flipMODULEs( aBoard );
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.
}
}
// 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.
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
//-----<build the images, components, and netlist>-----------------------
2008-01-23 22:36:37 +00:00
{
2008-02-14 01:07:52 +00:00
// find the highest numbered netCode within the board.
int highestNetCode = -1;
for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() )
highestNetCode = MAX( highestNetCode, equipot->GetNet() );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
deleteNETs();
2008-01-24 21:47:54 +00:00
2008-02-14 01:07:52 +00:00
// expand the net vector to highestNetCode+1, setting empty to NULL
nets.resize( highestNetCode+1, NULL );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
// skip netcode = 0
for( unsigned i=1; i<nets.size(); ++i )
nets[i] = new NET( pcb->network );
2008-01-29 16:45:14 +00:00
2008-02-14 01:07:52 +00:00
for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() )
{
int netcode = equipot->GetNet();
if( netcode > 0 )
nets[ netcode ]->net_id = CONV_TO_UTF8( equipot->m_Netname );
}
2008-02-07 20:23:58 +00:00
2008-01-24 21:47:54 +00:00
items.Collect( aBoard, scanMODULEs );
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
padstackset.clear();
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-02-14 01:07:52 +00:00
IMAGE* image = makeIMAGE( aBoard, module );
// create a net list entry for all the actual pins in the image
// for the current module. location of this code is critical
// because we fabricated some pin names to ensure unique-ness
// of pin names within a module, do not move this code. The
// exported netlist will have some fabricated pin names in it.
// If you don't like fabricated pin names, then make sure all pads
// within your MODULEs are uniquely named!
PIN_REF empty( pcb->network );
for( unsigned p=0; p<image->pins.size(); ++p )
{
PIN* pin = &image->pins[p];
int netcode = pin->kiNetCode;
if( netcode > 0 )
{
NET* net = nets[netcode];
net->pins.push_back( empty );
PIN_REF& pin_ref = net->pins.back();
pin_ref.component_id = CONV_TO_UTF8( module->GetReference() );
pin_ref.pin_id = pin->pin_id;
}
}
2008-01-29 16:45:14 +00:00
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.
2008-02-14 01:07:52 +00:00
// and use the registered one, known as 'image' after this.
2008-01-29 16:45:14 +00:00
delete image;
2008-02-14 01:07:52 +00:00
image = registered;
2008-01-29 16:45:14 +00:00
}
2008-02-14 01:07:52 +00:00
COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->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;
NORMALIZE_ANGLE_POS(angle);
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
2008-02-14 01:07:52 +00:00
// copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
// removing, do not increment the iterator
for( PADSTACKSET::iterator i=padstackset.begin(); i!=padstackset.end();
i=padstackset.begin() )
{
PADSTACKSET::auto_type ps = padstackset.release( i );
PADSTACK* padstack = ps.release();
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
pcb->library->AddPadstack( padstack );
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
// copy our SPECCTRA_DB::nets to the pcb->network
for( unsigned n=1; n<nets.size(); ++n )
{
NET* net = nets[n];
if( net->pins.size() )
{
// give ownership to pcb->network
pcb->network->nets.push_back( net );
nets[n] = 0;
}
}
}
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
//-----< output the vias >-----------------------------------------------
{
// ASSUME: unique pads are now in the padstack list! i.e. this code
// must follow the initial padstack construction code.
// Next we add the via's which may be used.
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize )
{
PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill,
0, aBoard->GetCopperLayerCount()-1 );
pcb->library->AddPadstack( padstack );
// remember this index, it is the default via and also the start of the
// 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-14 01:07:52 +00:00
for( int i=0; i<HISTORY_NUMBER; ++i )
{
2008-02-14 01:07:52 +00:00
int viaSize = aBoard->m_BoardSettings->m_ViaSizeHistory[i];
if( !viaSize )
break;
2008-02-07 20:23:58 +00:00
2008-02-14 01:07:52 +00:00
if( viaSize == defaultViaSize )
2008-01-30 19:16:46 +00:00
continue;
2008-02-14 01:07:52 +00:00
PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill,
0, aBoard->GetCopperLayerCount()-1 );
pcb->library->AddPadstack( padstack );
}
}
2008-01-30 19:16:46 +00:00
2008-02-14 01:07:52 +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-02-14 15:34:40 +00:00
//-----<flip modules back>----------------------------------------------
RevertMODULEs( aBoard );
}
void SPECCTRA_DB::flipMODULEs( BOARD* aBoard )
{
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;
}
}
modulesAreFlipped = true;
}
void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard )
{
if( !modulesAreFlipped )
return;
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-02-14 15:34:40 +00:00
modulesAreFlipped = false;
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